rewards_search_page.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. import 'package:cpt_rewards/modules/rewards_detail/rewards_detail_page.dart';
  2. import 'package:cs_resources/generated/l10n.dart';
  3. import 'package:cs_resources/theme/app_colors_theme.dart';
  4. import 'package:cs_resources/theme/theme_config.dart';
  5. import 'package:domain/entity/rewards_search_entity.dart';
  6. import 'package:flutter/cupertino.dart';
  7. import 'package:flutter/material.dart';
  8. import 'package:auto_route/auto_route.dart';
  9. import 'package:flutter_hooks/flutter_hooks.dart';
  10. import 'package:hooks_riverpod/hooks_riverpod.dart';
  11. import 'package:router/ext/auto_router_extensions.dart';
  12. import 'package:shared/utils/log_utils.dart';
  13. import 'package:shared/utils/color_utils.dart';
  14. import 'package:widgets/ext/ex_widget.dart';
  15. import 'package:widgets/load_state_layout.dart';
  16. import 'package:widgets/my_appbar.dart';
  17. import 'package:widgets/my_load_image.dart';
  18. import 'package:widgets/shatter/picker_container.dart';
  19. import 'package:widgets/utils/dark_theme_util.dart';
  20. import 'package:widgets/widget_export.dart';
  21. import 'package:cs_resources/generated/assets.dart';
  22. import '../../../router/page/rewards_page_router.dart';
  23. import './rewards_search_vm.dart';
  24. @RoutePage()
  25. class RewardsSearchPage extends HookConsumerWidget {
  26. const RewardsSearchPage({Key? key}) : super(key: key);
  27. //启动当前页面
  28. static void startInstance({BuildContext? context}) {
  29. if (context != null) {
  30. context.router.push(const RewardsSearchPageRoute());
  31. } else {
  32. appRouter.push(const RewardsSearchPageRoute());
  33. }
  34. }
  35. Widget _buildItemLeftSection(BuildContext context, WidgetRef ref, item, _vm) {
  36. int point = item!['point'] ?? 0;
  37. int originalPoint = item!['original_point'] ?? 0;
  38. int id = item!['id'];
  39. return Column(
  40. children: [
  41. Column(
  42. crossAxisAlignment: CrossAxisAlignment.start,
  43. children: [
  44. MyLoadImage(
  45. item?['resources']?[0] ?? '',
  46. width: MediaQuery.of(context).size.width,
  47. height: 150,
  48. ),
  49. Text(
  50. maxLines: 1, // 设置最大行数为2
  51. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  52. item?['name'] ?? '',
  53. style: TextStyle(fontSize: 16.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  54. ).marginOnly(bottom: 5, top: 10),
  55. Row(
  56. children: [
  57. Text(
  58. '$point',
  59. style: TextStyle(fontSize: 19.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  60. ),
  61. Text(
  62. '$originalPoint',
  63. style: TextStyle(
  64. decoration: TextDecoration.lineThrough,
  65. decorationColor: context.appColors.textBlack,
  66. decorationStyle: TextDecorationStyle.solid,
  67. fontSize: 12.0,
  68. color: context.appColors.textBlack,
  69. fontWeight: FontWeight.w400),
  70. ).marginOnly(left: 5, right: 5),
  71. Text(
  72. S.current.points,
  73. style: TextStyle(fontSize: 13.0, color: context.appColors.textBlack, fontWeight: FontWeight.w400),
  74. ),
  75. ],
  76. ),
  77. ],
  78. ).onTap(() {
  79. RewardsDetailPage.startInstance(id: id);
  80. }),
  81. ],
  82. ).paddingOnly(top: 0);
  83. }
  84. // listitem
  85. Widget _buildSaleItem(BuildContext context, WidgetRef ref, _vm, item) {
  86. return Container(
  87. decoration: BoxDecoration(
  88. color: context.appColors.whiteBG,
  89. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  90. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  91. ),
  92. child: Column(
  93. children: [
  94. SizedBox(
  95. width: MediaQuery.of(context).size.width - 30,
  96. height: 235,
  97. // margin: const EdgeInsets.only(left: 15, right: 15, top: 12.5),
  98. child: Column(
  99. crossAxisAlignment: CrossAxisAlignment.start,
  100. mainAxisAlignment: MainAxisAlignment.start,
  101. children: [
  102. _buildItemLeftSection(context, ref, item, _vm).marginOnly(bottom: 5),
  103. ],
  104. ).paddingOnly(left: 20, right: 20),
  105. ).constrained(
  106. minHeight: 235,
  107. ),
  108. ],
  109. ),
  110. ).marginOnly(left: 15, bottom: 15, right: 15);
  111. }
  112. // SearchOf
  113. Widget _buildSearchOf(BuildContext context, WidgetRef ref, _vm, detailInfo) {
  114. List recent = detailInfo.recent;
  115. List trending = detailInfo.trending;
  116. List<RewardsSearchRewards> rewards = detailInfo.rewards;
  117. return Column(
  118. crossAxisAlignment: CrossAxisAlignment.start,
  119. mainAxisAlignment: MainAxisAlignment.start,
  120. children: [
  121. recent.length > 0 ? _buildSearchRecent(context, ref, _vm, recent) : Container(),
  122. trending.length > 0 ? _buildSearchTrending(context, ref, _vm, trending) : Container(),
  123. rewards.length > 0 ? _buildSearchRecently(context, ref, _vm, rewards) : Container(),
  124. ],
  125. );
  126. }
  127. // Recent
  128. Widget _buildSearchRecent(BuildContext context, WidgetRef ref, _vm, recent) {
  129. // List itemsList = _vm.state.list.toList();
  130. return Column(
  131. crossAxisAlignment: CrossAxisAlignment.start,
  132. mainAxisAlignment: MainAxisAlignment.start,
  133. children: [
  134. Text(
  135. S.current.recent_searches,
  136. style: TextStyle(fontSize: 16.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  137. ).marginOnly(bottom: 20),
  138. Wrap(
  139. direction: Axis.horizontal, // 水平方向排列
  140. spacing: 10.0, // 子组件之间的间距
  141. runSpacing: 15.0, // 子组件行与行之间的间距
  142. children: List.generate(recent.length, (index) {
  143. return _buildSearchRecentItem(context, ref, _vm, recent[index]);
  144. }))
  145. ],
  146. ).marginOnly(bottom: 20);
  147. }
  148. Widget _buildSearchRecentItem(BuildContext context, WidgetRef ref, _vm, recent) {
  149. return Container(
  150. decoration: BoxDecoration(
  151. color: context.appColors.whiteBG,
  152. borderRadius: BorderRadius.all(Radius.circular(3.0)),
  153. ),
  154. padding: EdgeInsets.all(10),
  155. child: Text(
  156. recent,
  157. style: TextStyle(
  158. fontSize: 14.0,
  159. color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#969696'), darkColor: Colors.white),
  160. fontWeight: FontWeight.w400),
  161. ),
  162. ).onTap(() {
  163. _vm.searchIn(recent);
  164. });
  165. }
  166. // Trending
  167. Widget _buildSearchTrending(BuildContext context, WidgetRef ref, _vm, trending) {
  168. // List itemsList = _vm.state.list.toList();
  169. return Column(
  170. crossAxisAlignment: CrossAxisAlignment.start,
  171. mainAxisAlignment: MainAxisAlignment.start,
  172. children: [
  173. Text(
  174. S.current.trending_searches,
  175. style: TextStyle(fontSize: 16.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  176. ).marginOnly(bottom: 20),
  177. Wrap(
  178. direction: Axis.horizontal, // 水平方向排列
  179. spacing: 10.0, // 子组件之间的间距
  180. runSpacing: 15.0, // 子组件行与行之间的间距
  181. children: List.generate(trending.length, (index) {
  182. return _buildSearchTrendingItem(context, ref, _vm, trending[index]);
  183. }))
  184. ],
  185. ).marginOnly(bottom: 20);
  186. }
  187. Widget _buildSearchTrendingItem(BuildContext context, WidgetRef ref, _vm, trending) {
  188. return Container(
  189. decoration: BoxDecoration(
  190. color: context.appColors.whiteBG,
  191. borderRadius: BorderRadius.all(Radius.circular(3.0)),
  192. ),
  193. padding: const EdgeInsets.all(10),
  194. child: Row(
  195. mainAxisSize: MainAxisSize.min,
  196. children: [
  197. const MyAssetImage(
  198. Assets.rewardsRewardsHost,
  199. width: 12,
  200. height: 14,
  201. ).marginOnly(right: 5),
  202. Text(
  203. trending,
  204. style: TextStyle(
  205. fontSize: 14.0,
  206. color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#969696'), darkColor: Colors.white),
  207. fontWeight: FontWeight.w400),
  208. ),
  209. ],
  210. ),
  211. ).onTap(() {
  212. _vm.searchIn(trending);
  213. });
  214. }
  215. // Recently
  216. Widget _buildSearchRecently(BuildContext context, WidgetRef ref, _vm, rewards) {
  217. // List itemsList = _vm.state.list.toList();
  218. return Column(
  219. crossAxisAlignment: CrossAxisAlignment.start,
  220. mainAxisAlignment: MainAxisAlignment.start,
  221. children: [
  222. Text(
  223. S.current.recently_viewed,
  224. style: TextStyle(fontSize: 16.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  225. ).marginOnly(bottom: 18),
  226. Column(
  227. crossAxisAlignment: CrossAxisAlignment.center,
  228. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  229. children: List.generate(rewards.length, (index) {
  230. return _buildSearchItem(context, ref, _vm, rewards[index]);
  231. }))
  232. ],
  233. );
  234. }
  235. Widget _buildSearchItem(BuildContext context, WidgetRef ref, _vm, item) {
  236. RewardsSearchRewards itm = item;
  237. int point = itm.point ?? 0;
  238. int originalPoint = itm.originalPoint ?? 0;
  239. int id = itm.id;
  240. return Container(
  241. // width: MediaQuery.of(context).size.width / 2 - 25,
  242. // height: 240,
  243. padding: const EdgeInsets.only(bottom: 20),
  244. decoration: BoxDecoration(
  245. color: context.appColors.whiteBG,
  246. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  247. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  248. ),
  249. child: Column(
  250. children: [
  251. MyLoadImage(
  252. item.resources?[0] ?? '',
  253. width: MediaQuery.of(context).size.width,
  254. height: 150,
  255. ),
  256. Column(
  257. crossAxisAlignment: CrossAxisAlignment.start,
  258. children: [
  259. Text(
  260. maxLines: 1, // 设置最大行数为2
  261. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  262. item.name ?? '',
  263. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  264. ).marginOnly(bottom: 5, top: 10),
  265. Row(
  266. children: [
  267. Text(
  268. '$point',
  269. style: TextStyle(fontSize: 18.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  270. ),
  271. Text(
  272. '$originalPoint',
  273. style: TextStyle(
  274. decoration: TextDecoration.lineThrough,
  275. decorationColor: ColorUtils.string2Color('#808DAF'),
  276. decorationStyle: TextDecorationStyle.solid,
  277. fontSize: 13.0,
  278. color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#808DAF'),darkColor: Colors.white),
  279. fontWeight: FontWeight.w400),
  280. ).marginOnly(left: 5, right: 5),
  281. Text(
  282. S.current.points,
  283. style: TextStyle(fontSize: 13.0, color: context.appColors.textBlack, fontWeight: FontWeight.w400),
  284. ),
  285. ],
  286. )
  287. ],
  288. ).paddingOnly(top: 12, left: 12, right: 12)
  289. ],
  290. )).marginOnly(bottom: 13).onTap(() {
  291. RewardsDetailPage.startInstance(id: id);
  292. });
  293. }
  294. // list
  295. Widget _buildSaleList(BuildContext context, WidgetRef ref, _vm) {
  296. final state = ref.watch(rewardsSearchVmProvider);
  297. return SliverList(
  298. delegate: SliverChildBuilderDelegate((context, index) {
  299. return _buildSaleItem(context, ref, _vm, state.list![index]);
  300. }, childCount: state.list!.length));
  301. }
  302. @override
  303. Widget build(BuildContext context, WidgetRef ref) {
  304. final _vm = ref.read(rewardsSearchVmProvider.notifier);
  305. final state = ref.watch(rewardsSearchVmProvider);
  306. bool searchIs = state.searchIs ?? true;
  307. RewardsSearchEntity? detailInfo = state.detailInfo;
  308. useEffect(() {
  309. // 组件挂载时执行 - 执行接口请求
  310. Future.microtask(() => _vm.initPageData());
  311. return () {
  312. // 组件卸载时执行
  313. Log.d("property_news_page 组件卸载时执行");
  314. };
  315. }, []);
  316. return Scaffold(
  317. appBar: MyAppBar.searchAppBar(
  318. context,
  319. onSearch: (value) {
  320. _vm.searchIn(value);
  321. },
  322. value: state.keyword,
  323. backgroundColor: context.appColors.backgroundWhite,
  324. systemUiOverlayStyle: ThemeConfig.systemUiOverlayStyleLightThemeBlack,
  325. ),
  326. body: searchIs
  327. ? LoadStateLayout(
  328. state: state.loadingState,
  329. errorMessage: state.errorMessage,
  330. errorRetry: () {
  331. _vm.retryRequest();
  332. },
  333. successWidget: SingleChildScrollView(
  334. scrollDirection: Axis.vertical,
  335. physics: const BouncingScrollPhysics(),
  336. clipBehavior: Clip.none,
  337. child: Container(
  338. width: MediaQuery.of(context).size.width,
  339. color: context.appColors.backgroundDark,
  340. padding: const EdgeInsets.only(top: 20, left: 15, right: 15),
  341. child: _buildSearchOf(context, ref, _vm, detailInfo)),
  342. ))
  343. : Container(
  344. child: Column(
  345. children: [
  346. Expanded(
  347. child: EasyRefresh(
  348. controller: _vm.refreshController,
  349. // 上拉加载
  350. onLoad: () async {
  351. Log.d("----onLoad");
  352. _vm.loadMore();
  353. },
  354. // 下拉刷新
  355. onRefresh: () async {
  356. Log.d("----onRefresh");
  357. _vm.onRefresh();
  358. },
  359. child: Container(
  360. color: context.appColors.backgroundDark,
  361. padding: const EdgeInsets.only(top: 15),
  362. child: LoadStateLayout(
  363. state: state.loadingState,
  364. errorMessage: state.errorMessage,
  365. errorRetry: () {
  366. _vm.retryRequest();
  367. },
  368. successSliverWidget: [_buildSaleList(context, ref, _vm)]),
  369. ),
  370. ),
  371. )
  372. ],
  373. ),
  374. ),
  375. );
  376. }
  377. }