rewards_search_page.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. MyAssetImage(
  198. Assets.rewardsRewardsHost,
  199. width: 12,
  200. height: 14,
  201. color: DarkThemeUtil.multiColors(context, AppColorsTheme.colorPrimary, darkColor: Colors.white),
  202. ).marginOnly(right: 5),
  203. Text(
  204. trending,
  205. style: TextStyle(
  206. fontSize: 14.0,
  207. color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#969696'), darkColor: Colors.white),
  208. fontWeight: FontWeight.w400),
  209. ),
  210. ],
  211. ),
  212. ).onTap(() {
  213. _vm.searchIn(trending);
  214. });
  215. }
  216. // Recently
  217. Widget _buildSearchRecently(BuildContext context, WidgetRef ref, _vm, rewards) {
  218. // List itemsList = _vm.state.list.toList();
  219. return Column(
  220. crossAxisAlignment: CrossAxisAlignment.start,
  221. mainAxisAlignment: MainAxisAlignment.start,
  222. children: [
  223. Text(
  224. S.current.recently_viewed,
  225. style: TextStyle(fontSize: 16.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  226. ).marginOnly(bottom: 18),
  227. Column(
  228. crossAxisAlignment: CrossAxisAlignment.center,
  229. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  230. children: List.generate(rewards.length, (index) {
  231. return _buildSearchItem(context, ref, _vm, rewards[index]);
  232. }))
  233. ],
  234. );
  235. }
  236. Widget _buildSearchItem(BuildContext context, WidgetRef ref, _vm, item) {
  237. RewardsSearchRewards itm = item;
  238. int point = itm.point ?? 0;
  239. int originalPoint = itm.originalPoint ?? 0;
  240. int id = itm.id;
  241. return Container(
  242. // width: MediaQuery.of(context).size.width / 2 - 25,
  243. // height: 240,
  244. padding: const EdgeInsets.only(bottom: 20),
  245. decoration: BoxDecoration(
  246. color: context.appColors.whiteBG,
  247. borderRadius: const BorderRadius.all(Radius.circular(6.0)),
  248. boxShadow: [BoxShadow(color: context.appColors.itemBGShadow)],
  249. ),
  250. child: Column(
  251. children: [
  252. MyLoadImage(
  253. item.resources?[0] ?? '',
  254. width: MediaQuery.of(context).size.width,
  255. height: 150,
  256. ),
  257. Column(
  258. crossAxisAlignment: CrossAxisAlignment.start,
  259. children: [
  260. Text(
  261. maxLines: 1, // 设置最大行数为2
  262. overflow: TextOverflow.ellipsis, // 超出部分用省略号表示
  263. item.name ?? '',
  264. style: TextStyle(fontSize: 15.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  265. ).marginOnly(bottom: 5, top: 10),
  266. Row(
  267. children: [
  268. Text(
  269. '$point',
  270. style: TextStyle(fontSize: 18.0, color: context.appColors.textBlack, fontWeight: FontWeight.w500),
  271. ),
  272. Text(
  273. '$originalPoint',
  274. style: TextStyle(
  275. decoration: TextDecoration.lineThrough,
  276. decorationColor: ColorUtils.string2Color('#808DAF'),
  277. decorationStyle: TextDecorationStyle.solid,
  278. fontSize: 13.0,
  279. color: DarkThemeUtil.multiColors(context, ColorUtils.string2Color('#808DAF'),darkColor: Colors.white),
  280. fontWeight: FontWeight.w400),
  281. ).marginOnly(left: 5, right: 5),
  282. Text(
  283. S.current.points,
  284. style: TextStyle(fontSize: 13.0, color: context.appColors.textBlack, fontWeight: FontWeight.w400),
  285. ),
  286. ],
  287. )
  288. ],
  289. ).paddingOnly(top: 12, left: 12, right: 12)
  290. ],
  291. )).marginOnly(bottom: 13).onTap(() {
  292. RewardsDetailPage.startInstance(id: id);
  293. });
  294. }
  295. // list
  296. Widget _buildSaleList(BuildContext context, WidgetRef ref, _vm) {
  297. final state = ref.watch(rewardsSearchVmProvider);
  298. return SliverList(
  299. delegate: SliverChildBuilderDelegate((context, index) {
  300. return _buildSaleItem(context, ref, _vm, state.list![index]);
  301. }, childCount: state.list!.length));
  302. }
  303. @override
  304. Widget build(BuildContext context, WidgetRef ref) {
  305. final _vm = ref.read(rewardsSearchVmProvider.notifier);
  306. final state = ref.watch(rewardsSearchVmProvider);
  307. bool searchIs = state.searchIs ?? true;
  308. RewardsSearchEntity? detailInfo = state.detailInfo;
  309. useEffect(() {
  310. // 组件挂载时执行 - 执行接口请求
  311. Future.microtask(() => _vm.initPageData());
  312. return () {
  313. // 组件卸载时执行
  314. Log.d("property_news_page 组件卸载时执行");
  315. };
  316. }, []);
  317. return Scaffold(
  318. appBar: MyAppBar.searchAppBar(
  319. context,
  320. onSearch: (value) {
  321. _vm.searchIn(value);
  322. },
  323. value: state.keyword,
  324. backgroundColor: context.appColors.backgroundWhite,
  325. systemUiOverlayStyle: ThemeConfig.systemUiOverlayStyleLightThemeBlack,
  326. ),
  327. body: searchIs
  328. ? LoadStateLayout(
  329. state: state.loadingState,
  330. errorMessage: state.errorMessage,
  331. errorRetry: () {
  332. _vm.retryRequest();
  333. },
  334. successWidget: SingleChildScrollView(
  335. scrollDirection: Axis.vertical,
  336. physics: const BouncingScrollPhysics(),
  337. clipBehavior: Clip.none,
  338. child: Container(
  339. width: MediaQuery.of(context).size.width,
  340. color: context.appColors.backgroundDark,
  341. padding: const EdgeInsets.only(top: 20, left: 15, right: 15),
  342. child: _buildSearchOf(context, ref, _vm, detailInfo)),
  343. ))
  344. : Container(
  345. child: Column(
  346. children: [
  347. Expanded(
  348. child: EasyRefresh(
  349. controller: _vm.refreshController,
  350. // 上拉加载
  351. onLoad: () async {
  352. Log.d("----onLoad");
  353. _vm.loadMore();
  354. },
  355. // 下拉刷新
  356. onRefresh: () async {
  357. Log.d("----onRefresh");
  358. _vm.onRefresh();
  359. },
  360. child: Container(
  361. color: context.appColors.backgroundDark,
  362. padding: const EdgeInsets.only(top: 15),
  363. child: LoadStateLayout(
  364. state: state.loadingState,
  365. errorMessage: state.errorMessage,
  366. errorRetry: () {
  367. _vm.retryRequest();
  368. },
  369. successSliverWidget: [_buildSaleList(context, ref, _vm)]),
  370. ),
  371. ),
  372. )
  373. ],
  374. ),
  375. ),
  376. );
  377. }
  378. }