community_page.dart 12 KB

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