community_page.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. import 'package:cs_resources/generated/assets.dart';
  2. import 'package:flutter/material.dart';
  3. import 'package:auto_route/auto_route.dart';
  4. import 'package:flutter/rendering.dart';
  5. import 'package:flutter_hooks/flutter_hooks.dart';
  6. import 'package:hooks_riverpod/hooks_riverpod.dart';
  7. import 'package:router/ext/auto_router_extensions.dart';
  8. import 'package:shared/utils/color_utils.dart';
  9. import 'package:shared/utils/log_utils.dart';
  10. import 'package:widgets/my_load_image.dart';
  11. import 'package:widgets/ext/ex_widget.dart';
  12. import 'package:widgets/my_text_view.dart';
  13. import 'package:widgets/my_appbar.dart';
  14. import 'package:cs_resources/theme/app_colors_theme.dart';
  15. import 'package:widgets/widget_export.dart';
  16. import '../../router/page/community_page_router.dart';
  17. import '../my_posts/my_posts_page.dart';
  18. import 'newsfeed_tabs.dart';
  19. import 'community_vm.dart';
  20. import 'customSilverHeaderTabs.dart';
  21. final tabsRouterKey = GlobalKey<AutoTabsRouterState>();
  22. @RoutePage()
  23. class CommunityPage extends HookConsumerWidget {
  24. const CommunityPage({Key? key}) : super(key: key);
  25. //启动当前页面
  26. static void startInstance({BuildContext? context}) {
  27. if (context != null) {
  28. context.router.push(const CommunityPageRoute());
  29. } else {
  30. appRouter.push(const CommunityPageRoute());
  31. }
  32. }
  33. @override
  34. Widget build(BuildContext context, WidgetRef ref) {
  35. final vm = ref.read(communityVmProvider.notifier);
  36. final state = ref.watch(communityVmProvider);
  37. useEffect((){
  38. Log.d("CommunityPage initState");
  39. // 延迟监听
  40. WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
  41. if(tabsRouterKey.currentState?.controller != null){
  42. tabsRouterKey.currentState?.controller?.addListener((){
  43. vm.tabsRouterChange();
  44. });
  45. }
  46. });
  47. return (){
  48. Log.d("CommunityPage dispose");
  49. tabsRouterKey.currentState?.controller?.removeListener(vm.tabsRouterChange);
  50. };
  51. },[tabsRouterKey.currentState?.controller]);
  52. return Scaffold(
  53. appBar: state.currentCategoryIdx == 0 ? MyAppBar.appBar(
  54. context,
  55. "Community",
  56. backgroundColor: context.appColors.backgroundWhite,
  57. ): MyAppBar.searchAppBar(
  58. context,
  59. actions: [
  60. IconButton(
  61. icon: const Icon(Icons.search),
  62. onPressed: () {
  63. // do something
  64. vm.handlerChooseGarageCategory(context);
  65. },
  66. ),
  67. ],
  68. backgroundColor: context.appColors.backgroundWhite,
  69. ),
  70. backgroundColor: context.appColors.backgroundDefault,
  71. body: AutoTabsRouter.pageView(
  72. key: tabsRouterKey,
  73. routes: const [
  74. NewsPageRoute(),
  75. FollowingPageRoute(),
  76. ForyouPageRoute(),
  77. ForsalePageRoute(),
  78. ForrentPageRoute(),
  79. ],
  80. // physics: const NeverScrollableScrollPhysics(), // 禁止滚动
  81. builder: (context, child, pageController) {
  82. final tabsRouter = AutoTabsRouter.of(context);
  83. return NestedScrollView(
  84. headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
  85. return [
  86. // top 组件,转换为 Sliver 组件
  87. SliverToBoxAdapter(
  88. child: _buildTopSection(context, ref, vm, state),
  89. ),
  90. // tab 组件,使用 SliverPersistentHeader 实现吸顶
  91. // SliverPersistentHeader(
  92. // pinned: true,
  93. // delegate: CustomSliverPersistentHeaderDelegate(
  94. // child: _buildTabsSection(context, ref, tabsRouter, vm, state),
  95. // ),
  96. // ),
  97. // SliverToBoxAdapter(
  98. // child: _buildPostSection(context, ref, vm, state),
  99. // ),
  100. ];
  101. },
  102. body: Column(
  103. mainAxisSize: MainAxisSize.max,
  104. children: [
  105. _buildTabsSection(context, ref, tabsRouter, vm, state),
  106. _buildPostSection(context, ref, vm, state),
  107. Expanded(
  108. child: child
  109. ),
  110. ],
  111. ), // post 组件和其他内容
  112. );
  113. },
  114. ),
  115. );
  116. }
  117. Widget _buildTopSection(BuildContext context, WidgetRef ref, vm, state) {
  118. final topSectionsData = vm.topSectionsData;
  119. // final currentPageIdx = tabsRouterKey.currentState?.controller?.activeIndex ?? 0;
  120. int curTagIdx = 0;
  121. int currentPageIdx = state.currentPageViewIdx;
  122. int newsfeedTabCount = state.newsFeedTabsList.length;
  123. if(currentPageIdx >= newsfeedTabCount){
  124. curTagIdx = 1;
  125. }else {
  126. curTagIdx = 0;
  127. }
  128. return Container(
  129. color: context.appColors.whiteBG,
  130. padding: const EdgeInsets.only(top: 23, bottom: 30),
  131. child: Center(
  132. child: Row(
  133. mainAxisSize: MainAxisSize.max,
  134. mainAxisAlignment: MainAxisAlignment.center,
  135. crossAxisAlignment: CrossAxisAlignment.center,
  136. children: List.generate(topSectionsData.length, (index) {
  137. final item = topSectionsData[index];
  138. return Column(
  139. children: [
  140. Container(
  141. width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
  142. height: 70,
  143. decoration: BoxDecoration(
  144. shape: BoxShape.circle, // 设置为圆形
  145. boxShadow: index == curTagIdx ? [
  146. BoxShadow(
  147. color: context.appColors.tabLightBlueShadow, // 设置阴影颜色
  148. blurRadius: 5, // 设置模糊半径
  149. spreadRadius: 0.05, // 控制阴影扩散
  150. offset: const Offset(0, 4), // 设置阴影偏移量
  151. ),] : [],// 未选中时无阴影,
  152. ),
  153. child: MyAssetImage(
  154. item['icon'],
  155. width: MediaQuery.of(context).size.width / topSectionsData.length - 36,
  156. height: 70,
  157. ).onTap(() {
  158. vm.handlerSwitchNewsfeedOrGaragesale(index, context, null);
  159. },
  160. type: ClickType.throttle,
  161. ),
  162. ),
  163. SizedBox.fromSize(size: const Size(0, 9)),
  164. MyTextView(
  165. item['title'],
  166. fontSize: 15,
  167. textColor: index == curTagIdx ? ColorUtils.string2Color('#4161D0'):Colors.black,
  168. textAlign: TextAlign.center,
  169. isFontMedium: true,
  170. ),
  171. ],
  172. ).marginOnly(left: 18, right: 18, top: 10, bottom: 10);
  173. }),
  174. ),
  175. ),
  176. );
  177. }
  178. Widget _buildTabsSection(BuildContext context, WidgetRef ref, tabsRouter, vm, state){
  179. int currentPageIndex = tabsRouter!.activeIndex ?? 0;
  180. int newsfeedTabCount = state.newsFeedTabsList.length;
  181. List<String> tabsList;
  182. if(currentPageIndex < newsfeedTabCount){
  183. // news feed
  184. tabsList = state.newsFeedTabsList ?? [];
  185. }else {
  186. tabsList = state.garageSaleTabsList ?? [];
  187. }
  188. return Container(
  189. width: double.infinity,
  190. padding: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 12),
  191. color: ColorUtils.string2Color('#F2F3F6'),
  192. child: NewsfeedTabs(
  193. key: UniqueKey(),
  194. tabsList: tabsList,
  195. tabsRouter: tabsRouter,
  196. onClickAction:(Map<String, dynamic>? params){
  197. if (params != null) {
  198. // 解构 params
  199. final int? currentCatgoryIdx = params['currentCatgoryIdx'] as int?;
  200. final int? tabIdx = params['tabIdx'] as int?;
  201. vm.handlerChangeTab(tabIdx, tabsRouter, currentCatgoryIdx);
  202. }
  203. }
  204. ),
  205. );
  206. }
  207. Widget _buildPostSection(BuildContext context, WidgetRef ref, vm, state){
  208. int currentPageIndex = state.currentPageViewIdx;
  209. int newsfeedTabCount = state.newsFeedTabsList.length;
  210. if(currentPageIndex < newsfeedTabCount){
  211. // news feed
  212. return _buildNewsFeedPost(context, ref, vm, state);
  213. }else {
  214. return _buildGarageSalePost(context, ref, vm, state);
  215. }
  216. }
  217. Widget _buildNewsFeedPost(BuildContext context, WidgetRef ref, vm, state){
  218. return Container(
  219. height: 65.5,
  220. width: double.infinity,
  221. padding: const EdgeInsets.only(left: 20, right: 20),
  222. color: Colors.white,
  223. child: Row(
  224. children: [
  225. const MyAssetImage(Assets.communityNesFeed, width: 45,height: 45,),
  226. Expanded(
  227. child: MyTextView(
  228. "What’s on your mind?",
  229. textColor: context.appColors.textBlack,
  230. fontSize: 15,
  231. marginLeft: 15,
  232. alignment: Alignment.centerLeft,
  233. textAlign: TextAlign.left,
  234. backgroundColor: ColorUtils.string2Color('#ffffff'),
  235. maxLines: 1,
  236. isFontMedium: true,
  237. ),
  238. ),
  239. const MyAssetImage(
  240. Assets.communityCamera,
  241. width: 21,
  242. height: 16.5,
  243. ),
  244. ],
  245. ).onTap((){
  246. vm.handlerGotoNewsfeedPost(context);
  247. }),
  248. );
  249. }
  250. Widget _buildGarageSalePost(BuildContext context, WidgetRef ref, vm, state){
  251. return Container(
  252. height: 65.5,
  253. width: double.infinity,
  254. padding: const EdgeInsets.only(left: 20, right: 20),
  255. color: Colors.white,
  256. child: Row(
  257. children: [
  258. const MyAssetImage(Assets.communityNesFeed, width: 45,height: 45,),
  259. Expanded(
  260. child: MyTextView(
  261. "Sell Item",
  262. textColor: context.appColors.textBlack,
  263. fontSize: 15,
  264. marginLeft: 15,
  265. alignment: Alignment.centerLeft,
  266. textAlign: TextAlign.left,
  267. backgroundColor: ColorUtils.string2Color('#ffffff'),
  268. maxLines: 1,
  269. isFontMedium: true,
  270. ),
  271. ),
  272. const MyAssetImage(
  273. Assets.communityCamera,
  274. width: 21,
  275. height: 16.5,
  276. ),
  277. ],
  278. ).onTap((){
  279. vm.handlerGotoGaragePost(context);
  280. }),
  281. );
  282. }
  283. }