glglove 4 days ago
parent
commit
ec6a3acd8c
31 changed files with 1096 additions and 630 deletions
  1. 233 0
      packages/cpt_community/lib/components/garage_card.dart
  2. 0 69
      packages/cpt_community/lib/components/garage_card_content.dart
  3. 0 111
      packages/cpt_community/lib/components/garage_card_footer.dart
  4. 0 149
      packages/cpt_community/lib/components/garage_card_header.dart
  5. 14 7
      packages/cpt_community/lib/modules/community/community_page.dart
  6. 4 0
      packages/cpt_community/lib/modules/community/community_state.dart
  7. 7 2
      packages/cpt_community/lib/modules/community/community_vm.dart
  8. 1 0
      packages/cpt_community/lib/modules/community/following/following_page.dart
  9. 65 11
      packages/cpt_community/lib/modules/community/foryou/foryou_page.dart
  10. 2 4
      packages/cpt_community/lib/modules/community/foryou/foryou_vm.dart
  11. 82 18
      packages/cpt_community/lib/modules/community/news/news_page.dart
  12. 1 3
      packages/cpt_community/lib/modules/community/news/news_vm.dart
  13. 79 30
      packages/cpt_community/lib/modules/garage/for_rent/for_rent_page.dart
  14. 24 68
      packages/cpt_community/lib/modules/garage/for_rent/for_rent_vm.dart
  15. 42 50
      packages/cpt_community/lib/modules/garage/for_sale/for_sale_page.dart
  16. 6 6
      packages/cpt_community/lib/modules/garage/for_sale/for_sale_vm.dart
  17. 27 18
      packages/cpt_community/lib/modules/garage/garage_page.dart
  18. 6 1
      packages/cpt_community/lib/modules/garage/garage_state.dart
  19. 75 0
      packages/cpt_community/lib/modules/garage/garage_vm.dart
  20. 1 1
      packages/cpt_property/lib/modules/ioan/property_ioan_vm.dart
  21. 1 1
      packages/cpt_property/lib/modules/ioan/property_ioan_vm.g.dart
  22. 15 2
      packages/cpt_property/lib/modules/news/page/property_news_page.dart
  23. 42 23
      packages/cpt_property/lib/modules/news/page/property_news_state.dart
  24. 1 1
      packages/cpt_property/lib/modules/news/repository/property_news_repository.dart
  25. 102 47
      packages/cpt_property/lib/modules/news/vm/property_news_vm.dart
  26. 1 1
      packages/cpt_property/lib/modules/news/vm/property_news_vm.g.dart
  27. 1 1
      packages/cpt_property/lib/modules/property/vm/property_vm.g.dart
  28. 5 4
      packages/cs_widgets/lib/app_check_box.dart
  29. 165 0
      packages/cs_widgets/lib/dialog/app_custom_dialog.dart
  30. 5 2
      packages/cs_widgets/lib/dialog/app_default_dialog.dart
  31. 89 0
      packages/cs_widgets/lib/my_checkbox_group.dart

+ 233 - 0
packages/cpt_community/lib/components/garage_card.dart

@@ -0,0 +1,233 @@
+import 'package:cs_resources/generated/assets.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_hooks/flutter_hooks.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:shared/utils/color_utils.dart';
+import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import 'package:widgets/my_text_view.dart';
+
+import '../modules/garage/for_sale/for_sale_vm.dart';
+
+// 'id':1,
+// 'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+// 'title': 'Electronic keyboard',
+// 'price': '\$66',
+// 'isCollection': true,
+// 'collection_num': '12',
+// 'publisher': 'William Jefferson',
+// 'publish_time': 'June 17,2016 at 7:23 p.m.',
+// 'publisher_avator': Assets.communityCamera,'
+
+
+
+
+
+class GarageCard extends StatelessWidget {
+  Map<String, dynamic> itemObj;
+  double? cardHeight;
+  final Function()? onTap;
+  final Function(dynamic)? onClickColleciotn;
+
+  GarageCard({
+    Key? key,
+    required this.itemObj,
+    this.onTap,
+    this.onClickColleciotn,
+    double? cardHeight,
+  }) : super(key: key) {
+    this.cardHeight ??= 214;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      // height: cardHeight,
+      child: Expanded(
+        child: Column(
+          children: [
+            // 图片
+            Row(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                Expanded(
+                  child: ClipRRect(
+                    borderRadius: const BorderRadius.only(topLeft: Radius.circular(8), topRight: Radius.circular(8),),
+                    child: MyLoadImage(
+                      itemObj['goods_img'],
+                      width: 166.5,
+                      height: 102.5,
+                      isCircle: false,
+                      fit: BoxFit.cover,
+                    ).onTap(() {
+                      // 点击头像
+                      // onTap?.call();
+                    }),
+                  ),
+                ),
+              ],
+            ),
+            // 标题
+            Padding(
+              padding: const EdgeInsets.only(left: 10, right: 10, top: 12, bottom: 12),
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  Expanded(
+                    child: MyTextView(
+                      itemObj['title'],
+                      maxLines: 1,
+                      isTextEllipsis: true,
+                      textAlign: TextAlign.left,
+                      textColor: context.appColors.textBlack,
+                      fontSize: 16,
+                      isFontRegular: true,
+                    ),
+                  ),
+                ],
+              ),
+            ),
+            // 价格 及 收藏
+            Padding(
+              padding: const EdgeInsets.only(left: 10, right: 10,top: 10, bottom: 10),
+              child: Row(
+                mainAxisAlignment: MainAxisAlignment.spaceAround,
+                crossAxisAlignment: CrossAxisAlignment.center,
+                children: [
+                  Expanded(
+                    child: MyTextView(
+                      itemObj['price'],
+                      maxLines: 1,
+                      isTextEllipsis: true,
+                      textAlign: TextAlign.start,
+                      textColor: ColorUtils.string2Color('#4161D0'),
+                      fontSize: 18,
+                      isFontMedium: true,
+                    ),
+                  ),
+                  // 动态的 收藏数
+                  CollectionWidget(
+                      collectionNum: itemObj['collection_num'],
+                      isCollection: itemObj['isCollection'],
+                      onClickColleciotn: onClickColleciotn,
+                  ),
+                ],
+              ),
+            ),
+            // 发布人信息
+            Expanded(
+              child: Padding(
+                padding: const EdgeInsets.only(left: 10, right: 10),
+                child: Row(
+                  mainAxisAlignment: MainAxisAlignment.spaceAround,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  children: [
+                    MyLoadImage(
+                      itemObj['publisher_avator'],
+                      width: 30,
+                      height: 30,
+                      isCircle: true,
+                    ),
+                    Expanded(
+                      child: Column(
+                        mainAxisAlignment: MainAxisAlignment.center,
+                        crossAxisAlignment: CrossAxisAlignment.start,
+                        mainAxisSize: MainAxisSize.max,
+                        children: [
+                          MyTextView(
+                            itemObj['publisher'],
+                            maxLines: 1,
+                            isTextEllipsis: true,
+                            textAlign: TextAlign.start,
+                            marginLeft: 13,
+                            fontSize: 12,
+                            textColor: ColorUtils.string2Color('#2956B7'),
+                            isFontRegular: true,
+                          ),
+                          MyTextView(
+                            itemObj['publish_time'],
+                            maxLines: 1,
+                            isTextEllipsis: true,
+                            textAlign: TextAlign.start,
+                            marginLeft: 13,
+                            marginTop: 5,
+                            fontSize: 10,
+                            textColor: context.appColors.textBlack,
+                            isFontRegular: true,
+                          ),
+                        ]
+                      )
+                    ),
+                  ]
+                )
+              ),
+            )
+          ],
+        ),
+      ),
+    );
+  }
+}
+
+
+
+class CollectionWidget extends HookConsumerWidget {
+  int collectionNum = 0;
+  bool isCollection = false;
+  final Function(dynamic)? onClickColleciotn;
+  CollectionWidget({
+    Key? key,
+    required this.collectionNum,
+    required this.isCollection,
+    this.onClickColleciotn,
+  }) : super(key: key);
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final collectionNumState = useState(collectionNum);
+    final isCollectionState = useState(isCollection);
+    return Container(
+      width: 60,
+      height: 30,
+      alignment: Alignment.center,
+      // decoration: BoxDecoration(
+      //   color: ColorUtils.string2Color('#E5E5E5'),
+      //   borderRadius: BorderRadius.circular(15),
+      // ),
+      child: Row(
+        mainAxisAlignment: MainAxisAlignment.center,
+        children: [
+          MyTextView(
+            '${collectionNumState.value}',
+            textColor: ColorUtils.string2Color('#000000'),
+            fontSize: 14,
+            isFontRegular: true,
+            marginRight: 7,
+          ),
+          MyLoadImage(
+            isCollectionState.value? Assets.communityLikeActive: Assets.communityLike,
+            width: 15,
+            height: 14,
+          )
+        ]
+        // 点击 收餐/取消收藏
+    ).onTap((){
+        // Log.d("点击了收藏按钮  ${isCollectionState.value}");
+        // ToastEngine.show("点击了收藏按钮 ${isCollectionState.value}");
+        bool result = onClickColleciotn?.call(isCollectionState.value);
+        if(result){
+          isCollectionState.value = !isCollectionState.value;
+          if(isCollectionState.value){
+            ToastEngine.show("Collect Success");
+          }else {
+            ToastEngine.show("Cancel Collect Success");
+          }
+        }
+      })
+    );
+  }
+}

+ 0 - 69
packages/cpt_community/lib/components/garage_card_content.dart

@@ -1,69 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter/widgets.dart';
-import 'package:shared/utils/color_utils.dart';
-import 'package:widgets/my_text_view.dart';
-
-// 'id':1,
-// 'avator': Assets.communityCamera,
-// 'title': 'William Jefferson',
-// 'isFollow': false,
-// 'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-// 'imageUrls': ['https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg','https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg','https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg'],
-// 'time': 'June 17,2016 at 7:23 p.m.',
-// 'likeno': 12
-
-class GarageCardContent extends StatelessWidget {
-  const GarageCardContent({
-    Key? key,
-    required this.content,
-    this.imageUrls,
-  }) : super(key: key);
-
-  final String content;
-  final List? imageUrls;
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      padding: const EdgeInsets.symmetric(horizontal: 16),
-      child: Column(
-          children: [
-            Expanded(
-              child: Container(
-                // color: Colors.red,
-                child: MyTextView(
-                  content,
-                  textColor: ColorUtils.string2Color('#000000'),
-                  fontSize: 15,
-                  maxLines: 3,
-                  isTextEllipsis: true,
-                ),
-              ),
-            ),
-            const SizedBox(height: 12),
-            // 图片
-            if (imageUrls != null && imageUrls!.isNotEmpty)
-              Container(
-                width: double.infinity,
-                height: 87,
-                child: Row(
-                  mainAxisAlignment: MainAxisAlignment.center,
-                  children: [
-                    for (var item in imageUrls!)
-                      Expanded(
-                        child: Container(
-                          // width: 87,
-                          // height: 87,
-                          // margin: const EdgeInsets.only(right: 30),
-                          margin: const EdgeInsets.only(left: 15,right: 18),
-                          color: ColorUtils.string2Color("#F2F3F6"),
-                        ),
-                      )
-                  ],
-                ),
-              )
-          ]
-      ),
-    );
-  }
-}

+ 0 - 111
packages/cpt_community/lib/components/garage_card_footer.dart

@@ -1,111 +0,0 @@
-import 'package:cpt_community/components/newfeed_card_header.dart';
-import 'package:cs_resources/generated/assets.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/widgets.dart';
-import 'package:shared/utils/color_utils.dart';
-import 'package:shared/utils/log_utils.dart';
-import 'package:widgets/ext/ex_widget.dart';
-import 'package:widgets/my_load_image.dart';
-import 'package:widgets/my_text_view.dart';
-
-// 'id':1,
-// 'avator': Assets.communityCamera,
-// 'title': 'William Jefferson',
-// 'isFollow': false,
-// 'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-// 'imageUrls': ['https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg','https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg','https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg'],
-// 'time': 'June 17,2016 at 7:23 p.m.',
-// 'likeno': 12
-
-class GarageCardFooter extends StatelessWidget {
-  final bool isLike;
-  final VoidCallback? onLike;
-  final VoidCallback? onComment;
-  final VoidCallback? onShare;
-
-  const GarageCardFooter({
-    Key? key,
-    required this.isLike,
-    this.onLike,
-    this.onComment,
-    this.onShare
-  })
-      : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-        height: 40,
-        width: double.infinity,
-        padding: const EdgeInsets.symmetric(horizontal: 16),
-        // color: Colors.red,
-        child: Expanded(
-          child:  Row(
-              mainAxisAlignment: MainAxisAlignment.spaceBetween,
-              children: [
-                Container(
-                  height: 40,
-                  padding: const EdgeInsets.all(8),
-                  child: Row(
-                    children: [
-                      const MyAssetImage(Assets.communityLike, width: 16,height: 16,),
-                      MyTextView(
-                        'Like',
-                        textColor: ColorUtils.string2Color('#767676'),
-                        fontSize: 14,
-                        isFontRegular: true,
-                        textAlign: TextAlign.left,
-                        marginLeft: 8,
-                      ),
-                    ],
-                  ),
-                ).onTap((){
-                  Log.d("点击了like");
-                  onLike?.call();
-                }),
-                Container(
-                  height: 40,
-                  padding: const EdgeInsets.all(8),
-                  child: Row(
-                    children: [
-                      const MyAssetImage(Assets.communityComments, width: 16,height: 16,),
-                      MyTextView(
-                        'Comments',
-                        textColor: ColorUtils.string2Color('#767676'),
-                        fontSize: 14,
-                        isFontRegular: true,
-                        textAlign: TextAlign.left,
-                        marginLeft: 8,
-                      ),
-                    ],
-                  ),
-                ).onTap((){
-                  Log.d("点击了comments");
-                  onComment?.call();
-                }),
-                Container(
-                  height: 40,
-                  padding: const EdgeInsets.all(8),
-                  child: Row(
-                    children: [
-                      const MyAssetImage(Assets.communityShare, width: 16,height: 16,),
-                      MyTextView(
-                        'Share',
-                        textColor: ColorUtils.string2Color('#767676'),
-                        fontSize: 14,
-                        isFontRegular: true,
-                        textAlign: TextAlign.left,
-                        marginLeft: 8,
-                      ),
-                    ],
-                  ),
-                ).onTap((){
-                  Log.d("点击了share");
-                  onShare?.call();
-                }),
-              ]
-          ),
-        )
-    );
-  }
-}

+ 0 - 149
packages/cpt_community/lib/components/garage_card_header.dart

@@ -1,149 +0,0 @@
-import 'package:cs_resources/generated/assets.dart';
-import 'package:cs_resources/theme/app_colors_theme.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/widgets.dart';
-import 'package:flutter_hooks/flutter_hooks.dart';
-import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:shared/utils/color_utils.dart';
-import 'package:shared/utils/log_utils.dart';
-import 'package:widgets/ext/ex_widget.dart';
-import 'package:widgets/my_load_image.dart';
-import 'package:widgets/my_text_view.dart';
-
-import '../modules/garage/for_sale/for_sale_vm.dart';
-
-// 'id':1,
-// 'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
-// 'title': 'Electronic keyboard',
-// 'price': '\$66',
-// 'isCollection': true,
-// 'collection_num': '12',
-// 'publisher': 'William Jefferson',
-// 'publish_time': 'June 17,2016 at 7:23 p.m.',
-// 'publisher_avator': Assets.communityCamera,'
-
-
-
-
-
-class GarageCardHeader extends StatelessWidget {
-  Map<String, dynamic> itemObj;
-  final Function()? onTap;
-
-  GarageCardHeader({
-    Key? key,
-    required this.itemObj,
-    this.onTap,
-  }) : super(key: key);
-
-
-
-  @override
-  Widget build(BuildContext context) {
-    return Column(
-      children: [
-        Row(
-          mainAxisAlignment: MainAxisAlignment.center,
-          crossAxisAlignment: CrossAxisAlignment.center,
-          children: [
-            Expanded(
-              child: MyLoadImage(
-                itemObj['goods_img'],
-                width: 166.5,
-                height: 102.5,
-                isCircle: false,
-                fit: BoxFit.cover,
-              ).onTap(() {
-                // 点击头像
-                // onTap?.call();
-              }),
-            ),
-          ],
-        ),
-        Row(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: [
-            Expanded(
-              child: MyTextView(
-                itemObj['title'],
-                maxLines: 1,
-                isTextEllipsis: true,
-                textAlign: TextAlign.center,
-                textColor: context.appColors.textBlack,
-                fontSize: 16,
-                isFontRegular: true,
-                marginLeft: 12,
-                marginRight: 12,
-              ),
-            ),
-          ],
-        ),
-        Row(
-          mainAxisAlignment: MainAxisAlignment.spaceAround,
-          crossAxisAlignment: CrossAxisAlignment.center,
-          children: [
-            Expanded(
-              child: MyTextView(
-                itemObj['price'],
-                maxLines: 1,
-                isTextEllipsis: true,
-                textAlign: TextAlign.start,
-                textColor: ColorUtils.string2Color('#4161D0'),
-                fontSize: 18,
-                isFontMedium: true,
-              ),
-            ),
-            // 动态的 收藏数
-            CollectionWidget(collectionNum: itemObj['collection_num'], isCollection: itemObj['isCollection']),
-          ],
-        ),
-      ],
-    );
-  }
-}
-
-
-
-class CollectionWidget extends HookConsumerWidget {
-  int collectionNum = 0;
-  bool isCollection = false;
-  CollectionWidget({
-    Key? key,
-    required this.collectionNum,
-    required this.isCollection,
-  }) : super(key: key);
-  @override
-  Widget build(BuildContext context, WidgetRef ref) {
-    final collectionNumState = useState(collectionNum);
-    final isCollectionState = useState(isCollection);
-
-    return Container(
-      width: 60,
-      height: 30,
-      alignment: Alignment.center,
-      decoration: BoxDecoration(
-        color: ColorUtils.string2Color('#E5E5E5'),
-        borderRadius: BorderRadius.circular(15),
-      ),
-      child: Row(
-        mainAxisAlignment: MainAxisAlignment.center,
-        children: [
-          MyTextView(
-            '${collectionNumState.value}',
-            textColor: ColorUtils.string2Color('#999999'),
-            fontSize: 14,
-            isFontRegular: true,
-          ),
-          MyLoadImage(
-            isCollectionState.value? Assets.communityLikeActive: Assets.communityLike,
-            width: 14,
-            height: 14,
-          )
-        ]
-      ).onTap((){
-        // 点击 收餐/取消收藏
-        Log.d("点击了收藏按钮");
-      })
-    );
-  }
-}

+ 14 - 7
packages/cpt_community/lib/modules/community/community_page.dart

@@ -62,7 +62,13 @@ class CommunityPage extends HookConsumerWidget {
 
 
         // 只有当上下滚动时才拦截通知
         // 只有当上下滚动时才拦截通知
         if (isDownOrUp) {
         if (isDownOrUp) {
-          final tabsRouter = ref.watch(communityVmProvider).tabsRouter;
+          final vm = ref.read(communityVmProvider.notifier);
+          final currentTabRouter = vm.state!.tabsRouter;
+          if(currentTabRouter!.activeIndex == 0){
+            return false;  // false 不拦截
+          }else {
+            return true;   // true 拦截
+          }
         }
         }
       }
       }
       return false;
       return false;
@@ -71,9 +77,6 @@ class CommunityPage extends HookConsumerWidget {
     @override
     @override
     Widget build(BuildContext context, WidgetRef ref) {
     Widget build(BuildContext context, WidgetRef ref) {
         final vm = ref.read(communityVmProvider.notifier);
         final vm = ref.read(communityVmProvider.notifier);
-        final state = ref.watch(communityVmProvider);
-        final stateTabsRouter = ref.watch(communityVmProvider).tabsRouter;
-        // final state = ref.watch(communityVmProvider);
         BuildContext contextPage = context;
         BuildContext contextPage = context;
         // 创建 GlobalKey
         // 创建 GlobalKey
         final _tabsRouterKey = GlobalKey<AutoTabsRouterState>();
         final _tabsRouterKey = GlobalKey<AutoTabsRouterState>();
@@ -92,7 +95,7 @@ class CommunityPage extends HookConsumerWidget {
               backgroundColor: context.appColors.whiteBG,
               backgroundColor: context.appColors.whiteBG,
             ),
             ),
             backgroundColor: context.appColors.backgroundDefault,
             backgroundColor: context.appColors.backgroundDefault,
-            body:  NestedScrollView(
+            body: NestedScrollView(
               headerSliverBuilder: (context, innerBoxIsScrolled) {
               headerSliverBuilder: (context, innerBoxIsScrolled) {
                 return [
                 return [
                   SliverToBoxAdapter(
                   SliverToBoxAdapter(
@@ -130,8 +133,12 @@ class CommunityPage extends HookConsumerWidget {
                     // ref.read(communityVmProvider.notifier).state.tabsRouter = tabsRouter;
                     // ref.read(communityVmProvider.notifier).state.tabsRouter = tabsRouter;
                     // ref.read(communityVmProvider.notifier).state.pageController = pageController;
                     // ref.read(communityVmProvider.notifier).state.pageController = pageController;
                     // Log.d("communityVmProvider.notifier state.tabsRouter.tabsRouter.activeIndex:  ${ref.read(communityVmProvider.notifier).state.tabsRouter.activeIndex}");
                     // Log.d("communityVmProvider.notifier state.tabsRouter.tabsRouter.activeIndex:  ${ref.read(communityVmProvider.notifier).state.tabsRouter.activeIndex}");
+                    WidgetsBinding.instance.addPostFrameCallback((_) {
+                      vm.setTabsRouterAndPageController(tabsRouter, pageController);
+                    });
 
 
                     return Column(
                     return Column(
+                      mainAxisSize: MainAxisSize.max,
                       children: [
                       children: [
                         // tab 组件
                         // tab 组件
                         _buildTabsSection(contextPage, ref, tabsRouter),
                         _buildTabsSection(contextPage, ref, tabsRouter),
@@ -154,9 +161,10 @@ class CommunityPage extends HookConsumerWidget {
         int curTagIdx = 0;
         int curTagIdx = 0;
         return Container(
         return Container(
           color: Colors.white,
           color: Colors.white,
-          padding: const EdgeInsets.only(top: 30, bottom: 30),
+          padding: const EdgeInsets.only(top: 23, bottom: 30),
           child: Center(
           child: Center(
             child: Row(
             child: Row(
+              mainAxisSize: MainAxisSize.max,
               mainAxisAlignment: MainAxisAlignment.center,
               mainAxisAlignment: MainAxisAlignment.center,
               crossAxisAlignment: CrossAxisAlignment.center,
               crossAxisAlignment: CrossAxisAlignment.center,
               children: List.generate(topSectionsData.length, (index) {
               children: List.generate(topSectionsData.length, (index) {
@@ -208,7 +216,6 @@ class CommunityPage extends HookConsumerWidget {
 
 
      Widget _buildTabsSection(BuildContext context, WidgetRef ref, tabsRouter){
      Widget _buildTabsSection(BuildContext context, WidgetRef ref, tabsRouter){
        final vm = ref.read(communityVmProvider.notifier);
        final vm = ref.read(communityVmProvider.notifier);
-       final state = ref.watch(communityVmProvider);
        final tabsList = ref.watch(communityVmProvider.select((state) => state.tabsList));
        final tabsList = ref.watch(communityVmProvider.select((state) => state.tabsList));
        return Container(
        return Container(
         width: double.infinity,
         width: double.infinity,

+ 4 - 0
packages/cpt_community/lib/modules/community/community_state.dart

@@ -6,12 +6,14 @@ import '../garage/garage_page.dart';
 class CommunityVmState {
 class CommunityVmState {
   List<Map<String, dynamic>>? topSectionsData;
   List<Map<String, dynamic>>? topSectionsData;
   List? tabsList = ["News", "Following", "For You"];
   List? tabsList = ["News", "Following", "For You"];
+  int currentTabIndex = 0;
   dynamic? tabsRouter;
   dynamic? tabsRouter;
   dynamic? pageController;
   dynamic? pageController;
 
 
 
 
   CommunityVmState({
   CommunityVmState({
     List<Map<String, dynamic>>? topSectionsData,
     List<Map<String, dynamic>>? topSectionsData,
+    required this.currentTabIndex,
     this.tabsList,
     this.tabsList,
     this.tabsRouter,
     this.tabsRouter,
     this.pageController,
     this.pageController,
@@ -33,12 +35,14 @@ class CommunityVmState {
   CommunityVmState copyWith({
   CommunityVmState copyWith({
     List<Map<String, dynamic>>? topSectionsData,
     List<Map<String, dynamic>>? topSectionsData,
     List? tabsList,
     List? tabsList,
+    int? currentTabIndex,
     dynamic? tabsRouter,
     dynamic? tabsRouter,
     dynamic? pageController,
     dynamic? pageController,
   }) {
   }) {
     return CommunityVmState(
     return CommunityVmState(
       topSectionsData: topSectionsData ?? this.topSectionsData,
       topSectionsData: topSectionsData ?? this.topSectionsData,
       tabsList: tabsList ?? this.tabsList,
       tabsList: tabsList ?? this.tabsList,
+      currentTabIndex: currentTabIndex ?? this.currentTabIndex,
       tabsRouter: tabsRouter ?? this.tabsRouter,
       tabsRouter: tabsRouter ?? this.tabsRouter,
       pageController: pageController ?? this.pageController,
       pageController: pageController ?? this.pageController,
     );
     );

+ 7 - 2
packages/cpt_community/lib/modules/community/community_vm.dart

@@ -16,11 +16,11 @@ part 'community_vm.g.dart';
 
 
 @riverpod
 @riverpod
 class CommunityVm extends _$CommunityVm {
 class CommunityVm extends _$CommunityVm {
-  late PageController _pageController;
   get topSectionsData => state.topSectionsData;
   get topSectionsData => state.topSectionsData;
 
 
   CommunityVmState initState() {
   CommunityVmState initState() {
     return CommunityVmState(
     return CommunityVmState(
+      currentTabIndex: 0,
       tabsList: ["News", "Following", "For You"],
       tabsList: ["News", "Following", "For You"],
     );
     );
   }
   }
@@ -44,12 +44,17 @@ class CommunityVm extends _$CommunityVm {
 
 
   // 切换tab
   // 切换tab
   handlerChangeTab(int index, tabsRouter) {
   handlerChangeTab(int index, tabsRouter) {
-
     tabsRouter.setActiveIndex(index);
     tabsRouter.setActiveIndex(index);
     // state = state.copyWith(tabsRouter: tabsRouter ,activeTabIdx: index);
     // state = state.copyWith(tabsRouter: tabsRouter ,activeTabIdx: index);
     Log.d("community_vm handlerChangeTab--index:    $index");
     Log.d("community_vm handlerChangeTab--index:    $index");
   }
   }
 
 
+  // 设置当前的 tabsRouter 和 pageController
+  setTabsRouterAndPageController(dynamic tabsRouter, dynamic pageController) {
+    Log.d("setTabsRouterAndPageController---:$tabsRouter");
+    state =  state.copyWith(tabsRouter: tabsRouter ,pageController: pageController, currentTabIndex: tabsRouter.activeIndex);
+  }
+
 
 
   handlerChangeCommunityType(BuildContext context, int index){
   handlerChangeCommunityType(BuildContext context, int index){
     if(index == 1){
     if(index == 1){

+ 1 - 0
packages/cpt_community/lib/modules/community/following/following_page.dart

@@ -39,6 +39,7 @@ class FollowingPage extends HookConsumerWidget {
       // ),
       // ),
       // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
       // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
       body: Column(
       body: Column(
+        mainAxisSize: MainAxisSize.max,
         children: [
         children: [
           Text("newspage-following"),
           Text("newspage-following"),
         ],
         ],

+ 65 - 11
packages/cpt_community/lib/modules/community/foryou/foryou_page.dart

@@ -14,6 +14,7 @@ import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:widgets/widget_export.dart';
 import 'package:widgets/widget_export.dart';
 
 
 import '../../../router/page/community_page_router.dart';
 import '../../../router/page/community_page_router.dart';
+import '../community_vm.dart';
 import 'foryou_vm.dart';
 import 'foryou_vm.dart';
 
 
 @RoutePage()
 @RoutePage()
@@ -29,6 +30,49 @@ class ForyouPage extends HookConsumerWidget {
     }
     }
   }
   }
 
 
+  bool _isPreventScroll(ScrollNotification notification, WidgetRef ref){
+    // 检查当前页面是否是可见的
+    bool isDownOrUp = notification.metrics.axis == Axis.vertical;
+    if (notification is UserScrollNotification) {
+      // 检查滚动方向
+      switch (notification.direction) {
+        case ScrollDirection.forward:
+          print('Scrolling down');
+          break;
+        case ScrollDirection.reverse:
+          print('Scrolling up');
+          break;
+        case ScrollDirection.idle:
+          print('Scrolling stopped');
+          break;
+      }
+    } else if (notification is ScrollUpdateNotification) {
+      // 检查滚动位置变化
+      double currentScrollPosition = notification.metrics.pixels;
+      double maxScrollExtent = notification.metrics.maxScrollExtent;
+
+      // 判断是否满足某个条件
+      if (currentScrollPosition > 0 && currentScrollPosition < maxScrollExtent) {
+        print('Current scroll position: $currentScrollPosition');
+        // 在这里添加你的条件判断逻辑
+      }
+
+      // 只有当上下滚动时才拦截通知
+      if (isDownOrUp) {
+        final vm = ref.read(communityVmProvider.notifier);
+        final currentTabRouter = vm.state!.tabsRouter;
+        if(currentTabRouter!.activeIndex == 2){
+          return false;  // false 不拦截
+        }else {
+          Log.d("----news_page 滚动时---拦截了其他的");
+          return true;   // true 拦截
+        }
+      }
+    }
+    return false;
+  }
+
+
   @override
   @override
   Widget build(BuildContext context, WidgetRef ref) {
   Widget build(BuildContext context, WidgetRef ref) {
     final vm = ref.read(foryouVmProvider.notifier);
     final vm = ref.read(foryouVmProvider.notifier);
@@ -40,20 +84,30 @@ class ForyouPage extends HookConsumerWidget {
       // ),
       // ),
       // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
       // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
         body: Column(
         body: Column(
+          mainAxisSize: MainAxisSize.max,
           children: [
           children: [
             Expanded(
             Expanded(
-              child: EasyRefresh(
-                // 上拉加载
-                onLoad: () async{
-                  Log.d("----onLoad");
-                  vm.onLoadData();
-                },
-                // 下拉刷新
-                onRefresh: () async{
-                  Log.d("----onRefresh");
-                  vm.refreshListData();
+              child: NotificationListener<ScrollNotification>(
+                onNotification: (ScrollNotification notification) {
+                  // 是否拦截滚动  false 表示不拦截通知
+                  return _isPreventScroll(notification, ref);
+                  // return false;
                 },
                 },
-                child: _buildForyouList(context, ref, vm),
+                child: EasyRefresh(
+                  key: UniqueKey(),
+                  controller: EasyRefreshController(),
+                  // 上拉加载
+                  onLoad: () async{
+                    Log.d("----onLoad");
+                    vm.onLoadData();
+                  },
+                  // 下拉刷新
+                  onRefresh: () async{
+                    Log.d("----onRefresh");
+                    vm.refreshListData();
+                  },
+                  child: _buildForyouList(context, ref, vm),
+                ),
               ),
               ),
             )
             )
           ],
           ],

+ 2 - 4
packages/cpt_community/lib/modules/community/foryou/foryou_vm.dart

@@ -6,6 +6,7 @@ import 'package:router/ext/auto_router_extensions.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 
 
 import '../../../router/page/community_page_router.dart';
 import '../../../router/page/community_page_router.dart';
+import '../community_vm.dart';
 import '../newsfeed_detail/newsfeed_detail_page.dart';
 import '../newsfeed_detail/newsfeed_detail_page.dart';
 import 'foryou_respository.dart';
 import 'foryou_respository.dart';
 import 'foryou_state.dart';
 import 'foryou_state.dart';
@@ -157,14 +158,11 @@ class ForyouVm extends _$ForyouVm {
   // 下拉刷新
   // 下拉刷新
   Future refreshListData() async {
   Future refreshListData() async {
     Log.d("----property_foryou_vm-----refreshListData ");
     Log.d("----property_foryou_vm-----refreshListData ");
-
     // await Future.delayed(const Duration(seconds: 2));
     // await Future.delayed(const Duration(seconds: 2));
-
     state = state.copyWith(curPage: 1, pageSize: 10);
     state = state.copyWith(curPage: 1, pageSize: 10);
     // ref.invalidateSelf();
     // ref.invalidateSelf();
-    // ref.invalidate(ForyouVmProvider);
+    // ref.invalidate(NewsVmProvider);
     getListData();
     getListData();
-
   }
   }
 
 
 
 

+ 82 - 18
packages/cpt_community/lib/modules/community/news/news_page.dart

@@ -19,6 +19,7 @@ import '../../../components/newfeed_card_header.dart';
 import '../../../components/newsfeed_card_content.dart';
 import '../../../components/newsfeed_card_content.dart';
 import '../../../components/newsfeed_card_footer.dart';
 import '../../../components/newsfeed_card_footer.dart';
 import '../../../router/page/community_page_router.dart';
 import '../../../router/page/community_page_router.dart';
+import '../community_vm.dart';
 import 'news_vm.dart';
 import 'news_vm.dart';
 
 
 @RoutePage()
 @RoutePage()
@@ -34,6 +35,66 @@ class NewsPage extends HookConsumerWidget {
     }
     }
   }
   }
 
 
+  bool _isPreventScroll(ScrollNotification notification, WidgetRef ref){
+    // 检查当前页面是否是可见的
+    bool isDownOrUp = notification.metrics.axis == Axis.vertical;
+
+
+    if (notification is ScrollUpdateNotification) {
+      // 检查滚动位置变化
+      double currentScrollPosition = notification.metrics.pixels;
+      double maxScrollExtent = notification.metrics.maxScrollExtent;
+
+      // 判断是否满足某个条件
+      if (currentScrollPosition > 0 && currentScrollPosition < maxScrollExtent) {
+        print('Current scroll position: $currentScrollPosition');
+        // 在这里添加你的条件判断逻辑
+      }
+
+      // 只有当上下滚动时才拦截通知
+      if (isDownOrUp) {
+        final vm = ref.read(communityVmProvider.notifier);
+        final currentTabRouter = vm.state!.tabsRouter;
+        if(currentTabRouter!.activeIndex == 0){
+          return false;  // false 不拦截
+        }else {
+          Log.d("----news_page 滚动时---拦截了其他的");
+          return true;   // true 拦截
+        }
+      }else {
+        return false;
+      }
+    }else if (notification is ScrollEndNotification) {
+      // 检查滚动位置变化
+      double currentScrollPosition = notification.metrics.pixels;
+      double maxScrollExtent = notification.metrics.maxScrollExtent;
+
+      // 判断是否满足某个条件
+      if (currentScrollPosition > 0 && currentScrollPosition < maxScrollExtent) {
+        print('Current scroll position: $currentScrollPosition');
+        // 在这里添加你的条件判断逻辑
+      }
+
+      // 只有当上下滚动时才拦截通知
+      if (isDownOrUp) {
+        final vm = ref.read(communityVmProvider.notifier);
+        final currentTabRouter = vm.state!.tabsRouter;
+        if(currentTabRouter!.activeIndex == 0){
+          return false;  // false 不拦截
+        }else {
+          Log.d("----news_page 滚动时---拦截了其他的");
+          return true;   // true 拦截
+        }
+      }else {
+        return true;
+      }
+    }else {
+      return false;
+    }
+    // return false;
+  }
+
+
   @override
   @override
   Widget build(BuildContext context, WidgetRef ref) {
   Widget build(BuildContext context, WidgetRef ref) {
     final vm = ref.read(newsVmProvider.notifier);
     final vm = ref.read(newsVmProvider.notifier);
@@ -44,24 +105,27 @@ class NewsPage extends HookConsumerWidget {
       //   backgroundColor: context.appColors.whiteBG,
       //   backgroundColor: context.appColors.whiteBG,
       // ),
       // ),
       // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
       // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
-      body: Column(
-        children: [
-            Expanded(
-              child: EasyRefresh(
-                // 上拉加载
-                onLoad: () async{
-                  Log.d("----onLoad");
-                  vm.onLoadData();
-                },
-                // 下拉刷新
-                onRefresh: () async{
-                  Log.d("----onRefresh");
-                  vm.refreshListData();
-                },
-                child: _buildNewsFeedList(context, ref, vm),
-              ),
-            )
-        ],
+      body: NotificationListener<ScrollNotification>(
+        onNotification: (ScrollNotification notification) {
+          // 是否拦截滚动  false 表示不拦截通知
+          return _isPreventScroll(notification, ref);
+          // return false;
+        },
+        child: EasyRefresh(
+          controller: EasyRefreshController(),
+          key: UniqueKey(),
+          // 上拉加载
+          onLoad: () async{
+            Log.d("----onLoad");
+            vm.onLoadData();
+          },
+          // 下拉刷新
+          onRefresh: () async{
+            Log.d("----onRefresh");
+            vm.refreshListData();
+          },
+          child: _buildNewsFeedList(context, ref, vm),
+        ),
       )
       )
     );
     );
   }
   }

+ 1 - 3
packages/cpt_community/lib/modules/community/news/news_vm.dart

@@ -6,6 +6,7 @@ import 'package:router/ext/auto_router_extensions.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 
 
 import '../../../router/page/community_page_router.dart';
 import '../../../router/page/community_page_router.dart';
+import '../community_vm.dart';
 import '../newsfeed_detail/newsfeed_detail_page.dart';
 import '../newsfeed_detail/newsfeed_detail_page.dart';
 import 'news_respository.dart';
 import 'news_respository.dart';
 import 'news_state.dart';
 import 'news_state.dart';
@@ -157,14 +158,11 @@ class NewsVm extends _$NewsVm {
   // 下拉刷新
   // 下拉刷新
   Future refreshListData() async {
   Future refreshListData() async {
     Log.d("----property_news_vm-----refreshListData ");
     Log.d("----property_news_vm-----refreshListData ");
-
     // await Future.delayed(const Duration(seconds: 2));
     // await Future.delayed(const Duration(seconds: 2));
-
     state = state.copyWith(curPage: 1, pageSize: 10);
     state = state.copyWith(curPage: 1, pageSize: 10);
     // ref.invalidateSelf();
     // ref.invalidateSelf();
     // ref.invalidate(NewsVmProvider);
     // ref.invalidate(NewsVmProvider);
     getListData();
     getListData();
-
   }
   }
 
 
 
 

+ 79 - 30
packages/cpt_community/lib/modules/garage/for_rent/for_rent_page.dart

@@ -1,3 +1,4 @@
+import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter/rendering.dart';
@@ -6,6 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:router/ext/auto_router_extensions.dart';
 import 'package:router/ext/auto_router_extensions.dart';
 import 'package:shared/utils/color_utils.dart';
 import 'package:shared/utils/color_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/log_utils.dart';
+import 'package:widgets/my_button.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/my_text_view.dart';
@@ -13,6 +15,8 @@ import 'package:widgets/my_appbar.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:widgets/widget_export.dart';
 import 'package:widgets/widget_export.dart';
 
 
+import '../../../components/garage_card.dart';
+import '../../../components/newfeed_card_header.dart';
 import '../../../router/page/community_page_router.dart';
 import '../../../router/page/community_page_router.dart';
 import 'for_rent_vm.dart';
 import 'for_rent_vm.dart';
 
 
@@ -32,49 +36,94 @@ class ForrentPage extends HookConsumerWidget {
   @override
   @override
   Widget build(BuildContext context, WidgetRef ref) {
   Widget build(BuildContext context, WidgetRef ref) {
     final vm = ref.read(forrentVmProvider.notifier);
     final vm = ref.read(forrentVmProvider.notifier);
-    return const Scaffold(
+    return Scaffold(
       // appBar: MyAppBar.appBar(
       // appBar: MyAppBar.appBar(
       //   context,
       //   context,
-      //   "forrent",
+      //   "Forrent",
       //   backgroundColor: context.appColors.whiteBG,
       //   backgroundColor: context.appColors.whiteBG,
       // ),
       // ),
-      // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
+        backgroundColor: ColorUtils.string2Color("#F2F3F6"),
         body: Column(
         body: Column(
           children: [
           children: [
-            // Expanded(
-            //   child: EasyRefresh(
-            //     // 上拉加载
-            //     onLoad: () async{
-            //       Log.d("----onLoad");
-            //       vm.onLoadData();
-            //     },
-            //     // 下拉刷新
-            //     onRefresh: () async{
-            //       Log.d("----onRefresh");
-            //       vm.refreshListData();
-            //     },
-            //     child: _buildForrentList(context, ref, vm),
-            //   ),
-            // )
-            Text("FOR RENT PAGE"),
+            Expanded(
+              child: EasyRefresh(
+                // 上拉加载
+                onLoad: () async{
+                  Log.d("----onLoad");
+                  vm.onLoadData();
+                },
+                // 下拉刷新
+                onRefresh: () async{
+                  Log.d("----onRefresh");
+                  vm.refreshListData();
+                },
+                child: Padding(
+                  padding: const EdgeInsets.all(15.0),
+                  child: _buildForrentFeedList(context, ref, vm),
+                ),
+              ),
+            )
           ],
           ],
         )
         )
     );
     );
   }
   }
 
 
-
-  Widget _buildForrentList(BuildContext context, WidgetRef ref, ForrentVm vm) {
-
-    return ListView.builder(
-      itemCount: 3,
-      itemBuilder: (context, index) {
-        return _buildListItem(context, ref, vm, index);
-      },
+  Widget _buildForrentItem(BuildContext context, WidgetRef ref, item, vm){
+    return Container(
+      width: double.infinity,
+      child: Container(
+        decoration: BoxDecoration(
+          color: context.appColors.whiteBG,
+          borderRadius: BorderRadius.circular(8),
+          boxShadow: [
+            BoxShadow(
+              color: ColorUtils.string2Color('#E5E5E5'),
+              offset: const Offset(0, 2),
+              blurRadius: 8,
+            ),
+          ],
+        ),
+        child: Column(
+            mainAxisAlignment: MainAxisAlignment.start,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              // 卡片头部(头像 标题 时间)
+              Expanded(
+                child: GarageCard(
+                    key: UniqueKey(),
+                    itemObj: item,
+                    onClickColleciotn: (dynamic collectionValue){
+                      Log.d("点击了收藏按钮  --${item['id']}-$collectionValue");
+                      return true;
+                    }
+                ),
+              ),
+            ]
+        ),
+      ),
     );
     );
   }
   }
 
 
-  Widget _buildListItem(BuildContext context, WidgetRef ref, ForrentVm vm, int index) {
-    return Text("list-item");
+  Widget _buildForrentFeedList(BuildContext context, WidgetRef ref, vm){
+    final itemList = vm.state.list?? [];
+    if(itemList.isEmpty){
+      return const Center(child: Text('No Data'));
+    }else {
+      List itemsList = vm.state.list.toList();
+      return GridView.builder(
+        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
+          crossAxisCount: 2, // 每行显示两个项目
+          mainAxisSpacing: 15,
+          crossAxisSpacing: 15,
+          childAspectRatio: 0.78, // 宽高比
+        ),
+        key: UniqueKey(),
+        itemCount: itemsList.length,
+        itemBuilder: (context, index) {
+          return _buildForrentItem(context, ref, itemsList[index], vm);
+        },
+      );
+    }
   }
   }
-
 }
 }

+ 24 - 68
packages/cpt_community/lib/modules/garage/for_rent/for_rent_vm.dart

@@ -20,80 +20,36 @@ class ForrentVm extends _$ForrentVm {
         list: [
         list: [
           {
           {
             'id':1,
             'id':1,
-            'avator': Assets.communityCamera,
-            'title': 'William Jefferson',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': ['https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg','https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg','https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg'],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': true,
-            'likeno': 12
+            'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+            'title': 'Electronic keyboard',
+            'price': '\$66',
+            'isCollection': true,
+            'collection_num': 12,
+            'publisher': 'William Jefferson',
+            'publish_time': 'June 17,2016 at 7:23 p.m.',
+            'publisrher_avator': Assets.communityCamera
           },
           },
           {
           {
             'id':2,
             'id':2,
-            'avator': Assets.communityCamera,
-            'title': 'William fdsaf的飞洒发生的',
-            'isFollow': true,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': true,
-            'likeno': 12
+            'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+            'title': 'Electronic keyboard',
+            'price': '\$88',
+            'isCollection': false,
+            'collection_num': 12,
+            'publisher': 'William Jefferson',
+            'publish_time': 'June 17,2016 at 7:23 p.m.',
+            'publisher_avator': Assets.communityCamera
           },
           },
           {
           {
             'id':3,
             'id':3,
-            'avator': Assets.communityCamera,
-            'title': 'Fsjfkds  dfsk',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
-          },
-          {
-            'id':4,
-            'avator': Assets.communityCamera,
-            'title': 'Fsjfkds  dfsk',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
-          },
-          {
-            'id':5,
-            'avator': Assets.communityCamera,
-            'title': 'Fsjfkds  dfsk',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
-          },
-          {
-            'id':6,
-            'avator': Assets.communityCamera,
-            'title': 'Fsjfkds  dfsk',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
-          },
-          {
-            'id':7,
-            'avator': Assets.communityCamera,
-            'title': '放大发大水',
-            'isFollow': false,
-            'content': 'She said YES and our lives changed.Thank you all for coming to my propose today.We hope everyone can ……[More]',
-            'imageUrls': [],
-            'time': 'June 17,2016 at 7:23 p.m.',
-            'isLike': false,
-            'likeno': 12
+            'goods_img':  'https://img.alicdn.com/tfs/TB1h.o9O4MPMeJjy1XaXXcSsFXa-640-360.jpg',
+            'title': 'Electronic keyboard',
+            'price': '\$66',
+            'isCollection': true,
+            'collection_num': 12,
+            'publisher': 'William Jefferson',
+            'publish_time': 'June 17,2016 at 7:23 p.m.',
+            'publisher_avator': Assets.communityCamera
           },
           },
         ]
         ]
     );
     );

+ 42 - 50
packages/cpt_community/lib/modules/garage/for_sale/for_sale_page.dart

@@ -1,5 +1,3 @@
-import 'package:cpt_community/components/garage_card_content.dart';
-import 'package:cpt_community/components/garage_card_footer.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:auto_route/auto_route.dart';
@@ -17,7 +15,7 @@ import 'package:widgets/my_appbar.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:cs_resources/theme/app_colors_theme.dart';
 import 'package:widgets/widget_export.dart';
 import 'package:widgets/widget_export.dart';
 
 
-import '../../../components/garage_card_header.dart';
+import '../../../components/garage_card.dart';
 import '../../../components/newfeed_card_header.dart';
 import '../../../components/newfeed_card_header.dart';
 import '../../../router/page/community_page_router.dart';
 import '../../../router/page/community_page_router.dart';
 import 'for_sale_vm.dart';
 import 'for_sale_vm.dart';
@@ -44,7 +42,7 @@ class ForsalePage extends HookConsumerWidget {
       //   "Forsale",
       //   "Forsale",
       //   backgroundColor: context.appColors.whiteBG,
       //   backgroundColor: context.appColors.whiteBG,
       // ),
       // ),
-      // backgroundColor: ColorUtils.string2Color("#F2F3F6"),
+      backgroundColor: ColorUtils.string2Color("#F2F3F6"),
       body: Column(
       body: Column(
         children: [
         children: [
             Expanded(
             Expanded(
@@ -59,7 +57,10 @@ class ForsalePage extends HookConsumerWidget {
                   Log.d("----onRefresh");
                   Log.d("----onRefresh");
                   vm.refreshListData();
                   vm.refreshListData();
                 },
                 },
-                child: _buildForsaleFeedList(context, ref, vm),
+                child: Padding(
+                  padding: const EdgeInsets.all(15.0),
+                  child: _buildForsaleFeedList(context, ref, vm),
+                ),
               ),
               ),
             )
             )
         ],
         ],
@@ -70,51 +71,36 @@ class ForsalePage extends HookConsumerWidget {
   Widget _buildForsaleItem(BuildContext context, WidgetRef ref, item, vm){
   Widget _buildForsaleItem(BuildContext context, WidgetRef ref, item, vm){
     return Container(
     return Container(
       width: double.infinity,
       width: double.infinity,
-      //   color: Colors.yellow,
-      child: Stack(
-        children: [
-          Container(
-            margin: const EdgeInsets.only(left: 15, right: 15,top: 14,bottom: 14),
-            color: Colors.white,
-            padding: const EdgeInsets.only(left: 15, right: 15,top: 17,bottom: 17),
-            height: 280,
-            child: Column(
-                mainAxisAlignment: MainAxisAlignment.center,
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: [
-                  // 卡片头部(头像 标题 时间)
-                  GarageCardHeader(
-                    key: UniqueKey(),
-                    itemObj: item,
-                  ),
-                  const SizedBox(height: 15),
-                  // 卡片中间 (文字和图片)
-                  // Expanded(
-                  //   child: GarageCardContent(
-                  //     key: UniqueKey(),
-                  //     content: item['content'],
-                  //     imageUrls: item['imageUrls'],
-                  //   ),
-                  // ),
-                  const SizedBox(height: 26),
-                  // // 卡片底部 (点赞 评论 分享)
-                  // GarageCardFooter(
-                  //     key: UniqueKey(),
-                  //     isLike: item['isLike'],
-                  //     onLike: (){
-                  //       vm.handlerClickActionBtn('like', item);
-                  //     },
-                  //     onComment: (){
-                  //       vm.handlerClickActionBtn('comments', item);
-                  //     },
-                  //     onShare: (){
-                  //       vm.handlerClickActionBtn('share', item);
-                  //     },
-                  // ),
-                ]
+      child: Container(
+        decoration: BoxDecoration(
+          color: context.appColors.whiteBG,
+          borderRadius: BorderRadius.circular(8),
+          boxShadow: [
+            BoxShadow(
+              color: ColorUtils.string2Color('#E5E5E5'),
+              offset: const Offset(0, 2),
+              blurRadius: 8,
             ),
             ),
-          ),
-        ],
+          ],
+        ),
+        child: Column(
+            mainAxisAlignment: MainAxisAlignment.start,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            mainAxisSize: MainAxisSize.max,
+            children: [
+              // 卡片头部(头像 标题 时间)
+              Expanded(
+                child: GarageCard(
+                  key: UniqueKey(),
+                  itemObj: item,
+                  onClickColleciotn: (dynamic collectionValue){
+                    Log.d("点击了收藏按钮  --${item['id']}-$collectionValue");
+                    return true;
+                  }
+                ),
+              ),
+            ]
+        ),
       ),
       ),
     );
     );
   }
   }
@@ -125,7 +111,13 @@ class ForsalePage extends HookConsumerWidget {
       return const Center(child: Text('No Data'));
       return const Center(child: Text('No Data'));
     }else {
     }else {
       List itemsList = vm.state.list.toList();
       List itemsList = vm.state.list.toList();
-      return ListView.builder(
+      return GridView.builder(
+        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
+          crossAxisCount: 2, // 每行显示两个项目
+          mainAxisSpacing: 15,
+          crossAxisSpacing: 15,
+          childAspectRatio: 0.78, // 宽高比
+        ),
         key: UniqueKey(),
         key: UniqueKey(),
         itemCount: itemsList.length,
         itemCount: itemsList.length,
         itemBuilder: (context, index) {
         itemBuilder: (context, index) {

+ 6 - 6
packages/cpt_community/lib/modules/garage/for_sale/for_sale_vm.dart

@@ -24,7 +24,7 @@ class ForsaleVm extends _$ForsaleVm {
             'title': 'Electronic keyboard',
             'title': 'Electronic keyboard',
             'price': '\$66',
             'price': '\$66',
             'isCollection': true,
             'isCollection': true,
-            'collection_num': '12',
+            'collection_num': 12,
             'publisher': 'William Jefferson',
             'publisher': 'William Jefferson',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publisher_avator': Assets.communityCamera
             'publisher_avator': Assets.communityCamera
@@ -35,7 +35,7 @@ class ForsaleVm extends _$ForsaleVm {
             'title': 'Electronic keyboard',
             'title': 'Electronic keyboard',
             'price': '\$88',
             'price': '\$88',
             'isCollection': false,
             'isCollection': false,
-            'collection_num': '12',
+            'collection_num': 12,
             'publisher': 'William Jefferson',
             'publisher': 'William Jefferson',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publisher_avator': Assets.communityCamera
             'publisher_avator': Assets.communityCamera
@@ -46,7 +46,7 @@ class ForsaleVm extends _$ForsaleVm {
             'title': 'Electronic keyboard',
             'title': 'Electronic keyboard',
             'price': '\$66',
             'price': '\$66',
             'isCollection': true,
             'isCollection': true,
-            'collection_num': '12',
+            'collection_num': 12,
             'publisher': 'William Jefferson',
             'publisher': 'William Jefferson',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publisher_avator': Assets.communityCamera
             'publisher_avator': Assets.communityCamera
@@ -57,7 +57,7 @@ class ForsaleVm extends _$ForsaleVm {
             'title': 'Electronic keyboard',
             'title': 'Electronic keyboard',
             'price': '\$88',
             'price': '\$88',
             'isCollection': false,
             'isCollection': false,
-            'collection_num': '12',
+            'collection_num': 12,
             'publisher': 'William Jefferson',
             'publisher': 'William Jefferson',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publisher_avator': Assets.communityCamera
             'publisher_avator': Assets.communityCamera
@@ -68,7 +68,7 @@ class ForsaleVm extends _$ForsaleVm {
             'title': 'Electronic keyboard',
             'title': 'Electronic keyboard',
             'price': '\$66',
             'price': '\$66',
             'isCollection': true,
             'isCollection': true,
-            'collection_num': '12',
+            'collection_num': 12,
             'publisher': 'William Jefferson',
             'publisher': 'William Jefferson',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publisher_avator': Assets.communityCamera
             'publisher_avator': Assets.communityCamera
@@ -79,7 +79,7 @@ class ForsaleVm extends _$ForsaleVm {
             'title': 'Electronic keyboard',
             'title': 'Electronic keyboard',
             'price': '\$88',
             'price': '\$88',
             'isCollection': false,
             'isCollection': false,
-            'collection_num': '12',
+            'collection_num': 12,
             'publisher': 'William Jefferson',
             'publisher': 'William Jefferson',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publish_time': 'June 17,2016 at 7:23 p.m.',
             'publisher_avator': Assets.communityCamera
             'publisher_avator': Assets.communityCamera

+ 27 - 18
packages/cpt_community/lib/modules/garage/garage_page.dart

@@ -139,23 +139,7 @@ class GaragePage extends HookConsumerWidget {
         )
         )
     );
     );
   }
   }
-
-  Widget _buildNewsFeedList(BuildContext context, WidgetRef ref, vm){
-    final itemList = vm.state.list?? [];
-    if(itemList.isEmpty){
-      return const Center(child: Text('No Data'));
-    }else {
-      List itemsList = vm.state.list.toList();
-      return ListView.builder(
-        key: UniqueKey(),
-        itemCount: itemsList.length,
-        itemBuilder: (context, index) {
-          return _buildNewsItem(context, ref, itemsList[index], vm);
-        },
-      );
-    }
-  }
-
+  
 
 
   @override
   @override
   Widget build(BuildContext context, WidgetRef ref) {
   Widget build(BuildContext context, WidgetRef ref) {
@@ -170,6 +154,7 @@ class GaragePage extends HookConsumerWidget {
             icon: const Icon(Icons.search),
             icon: const Icon(Icons.search),
             onPressed: () {
             onPressed: () {
               // do something
               // do something
+              vm.handlerChooseCategory(context);
             },
             },
           ),
           ),
         ],
         ],
@@ -202,6 +187,7 @@ class GaragePage extends HookConsumerWidget {
             builder: (context, child, animation) {
             builder: (context, child, animation) {
               final tabsRouter = AutoTabsRouter.of(context);
               final tabsRouter = AutoTabsRouter.of(context);
               return Column(
               return Column(
+                mainAxisSize: MainAxisSize.max,
                 children: [
                 children: [
                   //  garagesale tab 分类 (For sale  For Rent)
                   //  garagesale tab 分类 (For sale  For Rent)
                   _buildTabsSection(context, ref, tabsRouter),
                   _buildTabsSection(context, ref, tabsRouter),
@@ -216,6 +202,28 @@ class GaragePage extends HookConsumerWidget {
           ),
           ),
         ),
         ),
       ),
       ),
+      // body: AutoTabsRouter.pageView(
+      //     key: UniqueKey(),
+      //     routes: const [
+      //       ForsalePageRoute(),
+      //       ForrentPageRoute(),
+      //     ],
+      //     builder: (context, child, animation) {
+      //       final tabsRouter = AutoTabsRouter.of(context);
+      //       return Column(
+      //         mainAxisSize: MainAxisSize.max,
+      //         children: [
+      //           //  garagesale tab 分类 (For sale  For Rent)
+      //           _buildTabsSection(context, ref, tabsRouter),
+      //           // 发布 garage sale 组件
+      //           _buildPostSection(context, ref, vm),
+      //           Expanded(
+      //             child: child,
+      //           )
+      //         ],
+      //       );
+      //     },
+      // )
     );
     );
   }
   }
 
 
@@ -224,9 +232,10 @@ class GaragePage extends HookConsumerWidget {
     int curTagIdx = 1;
     int curTagIdx = 1;
     return Container(
     return Container(
       color: Colors.white,
       color: Colors.white,
-      padding: const EdgeInsets.only(top: 30, bottom: 30),
+      padding: const EdgeInsets.only(top: 23, bottom: 30),
       child: Center(
       child: Center(
         child: Row(
         child: Row(
+          mainAxisSize: MainAxisSize.max,
           mainAxisAlignment: MainAxisAlignment.center,
           mainAxisAlignment: MainAxisAlignment.center,
           crossAxisAlignment: CrossAxisAlignment.center,
           crossAxisAlignment: CrossAxisAlignment.center,
           children: List.generate(topSectionsData.length, (index) {
           children: List.generate(topSectionsData.length, (index) {

+ 6 - 1
packages/cpt_community/lib/modules/garage/garage_state.dart

@@ -9,6 +9,7 @@ class GarageState {
   int? filterCount;
   int? filterCount;
   int? activeIndex = 0;
   int? activeIndex = 0;
   List tabsList = [];
   List tabsList = [];
+  List<Map<String,dynamic>> categoryList = [];
   List? list = [];
   List? list = [];
 
 
   GarageState({
   GarageState({
@@ -17,12 +18,14 @@ class GarageState {
     this.pageSize,
     this.pageSize,
     this.filterCount,
     this.filterCount,
     this.activeIndex,
     this.activeIndex,
+    List<Map<String, dynamic>>? categoryList,
     required this.tabsList,
     required this.tabsList,
     this.list,
     this.list,
-  });
+  }): categoryList = categoryList ?? [];
 
 
   GarageState copyWith({
   GarageState copyWith({
     List<Map<String, dynamic>>? topSectionsData,
     List<Map<String, dynamic>>? topSectionsData,
+    List<Map<String, dynamic>>? categoryList,
     int? curPage,
     int? curPage,
     int? pageSize,
     int? pageSize,
     int? filterCount,
     int? filterCount,
@@ -36,6 +39,7 @@ class GarageState {
       pageSize: pageSize ?? this.pageSize,
       pageSize: pageSize ?? this.pageSize,
       filterCount: filterCount ?? this.filterCount,
       filterCount: filterCount ?? this.filterCount,
       activeIndex: activeIndex ?? this.activeIndex,
       activeIndex: activeIndex ?? this.activeIndex,
+      categoryList: categoryList ?? this.categoryList,
       tabsList: tabsList ?? this.tabsList,
       tabsList: tabsList ?? this.tabsList,
       list: list ?? this.list,
       list: list ?? this.list,
     );
     );
@@ -50,6 +54,7 @@ class GarageState {
       'activeIndex': this.activeIndex,
       'activeIndex': this.activeIndex,
       'tabsList': this.tabsList,
       'tabsList': this.tabsList,
       'list': this.list,
       'list': this.list,
+      'categoryList': this.categoryList,
     };
     };
   }
   }
 
 

+ 75 - 0
packages/cpt_community/lib/modules/garage/garage_vm.dart

@@ -2,12 +2,17 @@
 import 'package:cpt_community/modules/community/community_page.dart';
 import 'package:cpt_community/modules/community/community_page.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:cs_resources/generated/assets.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
+import 'package:plugin_platform/engine/dialog/dialog_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:router/path/router_path.dart';
 import 'package:router/path/router_path.dart';
 import 'package:shared/utils/color_utils.dart';
 import 'package:shared/utils/color_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:auto_route/auto_route.dart';
+import 'package:widgets/dialog/app_default_dialog.dart';
+import 'package:widgets/dialog/app_custom_dialog.dart';
+import 'package:widgets/app_check_box.dart';
+import 'package:widgets/my_checkbox_group.dart';
 
 
 import 'garage_page.dart';
 import 'garage_page.dart';
 import 'garage_state.dart';
 import 'garage_state.dart';
@@ -54,6 +59,36 @@ class GarageVm extends _$GarageVm {
             'activeTitleBackgroundColor': ColorUtils.string2Color("#4161D0"),
             'activeTitleBackgroundColor': ColorUtils.string2Color("#4161D0"),
           },
           },
         ],
         ],
+        categoryList: [
+          {
+            'id': '1',
+            'label': 'Kids',
+          },
+          {
+            'id': '2',
+            'label': 'Homeware',
+          },
+          {
+            'id': '3',
+            'label': 'Fashion',
+          },
+          {
+            'id': '4',
+            'label': 'Electronics',
+          },
+          {
+            'id': '5',
+            'label': 'Sports',
+          },
+          {
+            'id': '6',
+            'label': 'Furniture',
+          },
+          {
+            'id': '7',
+            'label': 'Others',
+          },
+        ],
         list: [
         list: [
           {
           {
             'id':1,
             'id':1,
@@ -142,6 +177,46 @@ class GarageVm extends _$GarageVm {
 
 
   }
   }
 
 
+  // 选择 category
+  handlerChooseCategory(BuildContext context) async {
+    await DialogEngine.show(
+      tag: "choosegaragesalecategory",
+      position: DialogPosition.center,
+      widget: AppCustomDialog(
+        message: '',
+        confirmTxt: "Ok",
+        messageBuilder: (BuildContext context){
+          return Container(
+            // width: 500,
+            height: 400,
+            color: Colors.white,
+            child: Column(
+              mainAxisAlignment: MainAxisAlignment.start,
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: [
+                MyCheckboxGroup(
+                  isSingleSelect: false,
+                    labelStyle: const TextStyle(
+                    fontSize: 16,
+                    fontWeight: FontWeight.w500,
+                  ),
+                  items: state.categoryList,
+                  onChanged: (List<Map<String, dynamic>> selectedItems){
+                    Log.d("----MyCheckboxGroup onChanged  $selectedItems");
+                  }
+                )
+              ],
+            ),
+          );
+        },
+        isShowCancelBtn:false,
+        confirmAction: (){
+
+        },
+      )
+    );
+  }
+
   // 切换tab
   // 切换tab
   handlerChangeTab(int index, tabsRouter) {
   handlerChangeTab(int index, tabsRouter) {
     tabsRouter.setActiveIndex(index);
     tabsRouter.setActiveIndex(index);

+ 1 - 1
packages/cpt_property/lib/modules/ioan/property_ioan_vm.dart

@@ -91,7 +91,7 @@ class PropertyIoanVm extends _$PropertyIoanVm {
 
 
   handlerRequestQuote(BuildContext context) async {
   handlerRequestQuote(BuildContext context) async {
     Log.d("点击了请求报价");
     Log.d("点击了请求报价");
-    ToastEngine.show("暂未开放");
+    // ToastEngine.show("暂未开放");
     await DialogEngine.show(
     await DialogEngine.show(
       tag: "requestQuote",
       tag: "requestQuote",
       position: DialogPosition.bottom,
       position: DialogPosition.bottom,

+ 1 - 1
packages/cpt_property/lib/modules/ioan/property_ioan_vm.g.dart

@@ -6,7 +6,7 @@ part of 'property_ioan_vm.dart';
 // RiverpodGenerator
 // RiverpodGenerator
 // **************************************************************************
 // **************************************************************************
 
 
-String _$propertyIoanVmHash() => r'30a52b0e2e7a252f4c8bc8c8401bdafbd95a2604';
+String _$propertyIoanVmHash() => r'42f901fbd503e5b5a45c96781200412291240a37';
 
 
 /// See also [PropertyIoanVm].
 /// See also [PropertyIoanVm].
 @ProviderFor(PropertyIoanVm)
 @ProviderFor(PropertyIoanVm)

+ 15 - 2
packages/cpt_property/lib/modules/news/page/property_news_page.dart

@@ -6,6 +6,7 @@ import 'package:router/ext/auto_router_extensions.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/util.dart';
 import 'package:shared/utils/util.dart';
 import 'package:widgets/ext/ex_widget.dart';
 import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/load_state_layout.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_load_image.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/my_text_view.dart';
 import 'package:widgets/widget_export.dart';
 import 'package:widgets/widget_export.dart';
@@ -172,11 +173,14 @@ class PropertyNewsPage extends HookConsumerWidget {
   @override
   @override
   Widget build(BuildContext context, WidgetRef ref) {
   Widget build(BuildContext context, WidgetRef ref) {
     final _vm = ref.read(propertyNewsVmProvider.notifier);
     final _vm = ref.read(propertyNewsVmProvider.notifier);
-
+    final state = ref.watch(propertyNewsVmProvider);
     return Scaffold(
     return Scaffold(
       // appBar: AppBar(title: Text("资产")),
       // appBar: AppBar(title: Text("资产")),
       body: Container(
       body: Container(
+        width: double.infinity,
+        height: double.infinity,
         child: EasyRefresh(
         child: EasyRefresh(
+          controller: _vm.refreshController,
           // 上拉加载
           // 上拉加载
           onLoad: () async{
           onLoad: () async{
             Log.d("----onLoad");
             Log.d("----onLoad");
@@ -187,7 +191,16 @@ class PropertyNewsPage extends HookConsumerWidget {
             Log.d("----onRefresh");
             Log.d("----onRefresh");
             _vm.refreshListData();
             _vm.refreshListData();
           },
           },
-          child: _buildNewsList(context, ref, _vm),
+          child: LoadStateLayout(
+            state: state.loadingState,
+            errorMessage: state.errorMessage,
+            errorRetry: () {
+              _vm.retryRequest();
+            },
+            successSliverWidget: [
+              _buildNewsList(context, ref, _vm)
+            ],
+          ),
         )
         )
       ),
       ),
     );
     );

+ 42 - 23
packages/cpt_property/lib/modules/news/page/property_news_state.dart

@@ -2,48 +2,67 @@
 
 
 import 'dart:convert';
 import 'dart:convert';
 
 
-PropertyNewsState propertyNewsStateFromJson(String str) => PropertyNewsState.fromJson(json.decode(str));
-
-String propertyNewsStateToJson(PropertyNewsState data) => json.encode(data.toJson());
+import 'package:widgets/load_state_layout.dart';
 
 
 class PropertyNewsState {
 class PropertyNewsState {
+    //页面 LoadView 状态的展示
+    LoadState loadingState;
+    String? errorMessage;
+
+    int? curPage;
+    int? pageSize = 10;
+    int? filterCount = 0;
+    List<Map<String, dynamic>> list;
+
     PropertyNewsState({
     PropertyNewsState({
-        required this.curPage,
-        required this.pageSize,
+        this.loadingState = LoadState.State_Loading,
+        String? errorMessage,
+        this.curPage,
+        this.pageSize,
+        this.filterCount,
         required this.list,
         required this.list,
-        required this.filterCount,
     });
     });
 
 
-    int curPage;
-    int pageSize;
-    int filterCount;
-    List<Map<String, dynamic>> list;
 
 
-    factory PropertyNewsState.fromJson(Map<dynamic, dynamic> json) => PropertyNewsState(
-        curPage: json["curPage"],
-        pageSize: json["pageSize"],
-        list: List<Map<String, dynamic>>.from(json["list"].map((x) => x)),
-        filterCount: json["filterCount"],
-    );
 
 
-    Map<dynamic, dynamic> toJson() => {
-        "curPage": curPage,
-        "pageSize": pageSize,
-        "list": List<dynamic>.from(list.map((x) => x)),
-        "filterCount": filterCount,
+
+    Map<String, dynamic> toMap() {
+    return {
+      'loadingState': this.loadingState,
+      'errorMessage': this.errorMessage,
+      'curPage': this.curPage,
+      'pageSize': this.pageSize,
+      'filterCount': this.filterCount,
+      'list': this.list,
     };
     };
+  }
+
+  factory PropertyNewsState.fromMap(Map<String, dynamic> map) {
+    return PropertyNewsState(
+      loadingState: map['loadingState'] as LoadState,
+      errorMessage: map['errorMessage'] as String,
+      curPage: map['curPage'] as int,
+      pageSize: map['pageSize'] as int,
+      filterCount: map['filterCount'] as int,
+      list: map['list'] as List<Map<String, dynamic>>,
+    );
+  }
 
 
     PropertyNewsState copyWith({
     PropertyNewsState copyWith({
+    LoadState? loadingState,
+    String? errorMessage,
     int? curPage,
     int? curPage,
     int? pageSize,
     int? pageSize,
-    List<Map<String, dynamic>>? list,
     int? filterCount,
     int? filterCount,
+    List<Map<String, dynamic>>? list,
   }) {
   }) {
     return PropertyNewsState(
     return PropertyNewsState(
+      loadingState: loadingState ?? this.loadingState,
+      errorMessage: errorMessage ?? this.errorMessage,
       curPage: curPage ?? this.curPage,
       curPage: curPage ?? this.curPage,
       pageSize: pageSize ?? this.pageSize,
       pageSize: pageSize ?? this.pageSize,
-      list: list ?? this.list,
       filterCount: filterCount ?? this.filterCount,
       filterCount: filterCount ?? this.filterCount,
+      list: list ?? this.list,
     );
     );
   }
   }
 }
 }

+ 1 - 1
packages/cpt_property/lib/modules/news/repository/property_news_repository.dart

@@ -60,7 +60,7 @@ class PropertyNewsRepository {
     if (result.isSuccess) {
     if (result.isSuccess) {
       //重新赋值data或list
       //重新赋值data或list
       final json = result.getDataJson();
       final json = result.getDataJson();
-      var data = PropertyNewsState.fromJson(json!);
+      var data = PropertyNewsState.fromMap(json!);
       //重新赋值data或list
       //重新赋值data或list
       return result.convert<PropertyNewsState>(data: data);
       return result.convert<PropertyNewsState>(data: data);
     }
     }

+ 102 - 47
packages/cpt_property/lib/modules/news/vm/property_news_vm.dart

@@ -2,36 +2,30 @@ import 'package:plugin_platform/http/http_result.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:riverpod_annotation/riverpod_annotation.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:shared/utils/log_utils.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
 import 'package:plugin_platform/engine/toast/toast_engine.dart';
+import 'package:widgets/load_state_layout.dart';
+import 'package:widgets/widget_export.dart';
 import '../page/property_news_state.dart';
 import '../page/property_news_state.dart';
 import '../repository/property_news_repository.dart';
 import '../repository/property_news_repository.dart';
+
 part 'property_news_vm.g.dart';
 part 'property_news_vm.g.dart';
 
 
 @riverpod
 @riverpod
 class PropertyNewsVm extends _$PropertyNewsVm {
 class PropertyNewsVm extends _$PropertyNewsVm {
   late PropertyNewsRepository propertyNewsRepository;
   late PropertyNewsRepository propertyNewsRepository;
+
+  bool _needShowPlaceholder = true; //是否展示LoadingView
+
+  // Refresh 控制器
+  final EasyRefreshController refreshController = EasyRefreshController(
+    controlFinishRefresh: true,  //允许刷新
+    controlFinishLoad: true,   //允许加载
+  );
+
   PropertyNewsState initState() {
   PropertyNewsState initState() {
     return PropertyNewsState(
     return PropertyNewsState(
-      curPage: 1,
-      pageSize: 10,
       list: [
       list: [
-        {
-          "id": 1,
-          "title": "fkladsfk fldask fldsakfllfkaslsd",
-          "description": "fsklfdsk罚款乱收费上课了发送卡",
-          "time": "2024-02-15 12:00:00",
-          "isCollection": true,
-          "pic": ""
-        },
-        {
-          "id": 2,
-          "title": "JHKFDSAJKjfkdsfjkasjkjklfajfkajifwoqirujweiqofjndsaikfniasdhfiasdhfiadshfifjadslfjkdlsafjlkadsj",
-          "description": "oifosjf fjdskafj hjiwehfriohjfiash",
-          "time": "2024-10-16 12:00:00",
-          "isCollection": false,
-          "pic": ""
-        },
+
       ],
       ],
-      filterCount: 2,
     );
     );
   }
   }
 
 
@@ -45,6 +39,14 @@ class PropertyNewsVm extends _$PropertyNewsVm {
     return state;
     return state;
   }
   }
 
 
+  //刷新页面状态
+  void changeLoadingState(LoadState loadState, String? errorMsg) {
+    state = state.copyWith(
+        loadingState: loadState,
+        errorMessage: errorMsg
+    );
+  }
+
   // 初始化页面数据
   // 初始化页面数据
   initPageData() {
   initPageData() {
     Log.d("----property_news_vm-----initPageData");
     Log.d("----property_news_vm-----initPageData");
@@ -62,48 +64,101 @@ class PropertyNewsVm extends _$PropertyNewsVm {
     //   state = state.copyWith(curPage: curPage,);
     //   state = state.copyWith(curPage: curPage,);
     //   getListData();
     //   getListData();
     // }
     // }
+    // 检查 curPage 是否为 null,并初始化为 1
+    int newCurPage = state.curPage ?? 1;
+    state = state.copyWith(curPage: ++newCurPage);
     getListData();
     getListData();
   }
   }
 
 
-  // 获取list 列表数据
-  void getListData<T>() async {
-    Log.d("加载listData数据---------------start-----");
-    try {
-      //请求网络
-      Map<String, dynamic>  params = {
-        "curPage": state.curPage,
-        "pageSize": state.pageSize,
-      };
-      Log.d("请求参数------$params");
-      final result = await propertyNewsRepository.fetchPropertyNewsList(params);
-      Log.d("请求完成结果------${result.data}");
-      //校验成功失败
-      if (result.isSuccess) {
-        // state = state.copyWith(serverTime: result.data);
-        state = state;
-        ToastEngine.show("获取数据成功");
-      } else {
-        ToastEngine.show(result.errorMsg ?? "Network Load Error");
-      }
-    } catch (e) {
-      ToastEngine.show("Error: $e");
-    }
-  }
-
 
 
   // 下拉刷新
   // 下拉刷新
   Future refreshListData() async {
   Future refreshListData() async {
     Log.d("----property_news_vm-----refreshListData ");
     Log.d("----property_news_vm-----refreshListData ");
 
 
     // await Future.delayed(const Duration(seconds: 2));
     // await Future.delayed(const Duration(seconds: 2));
+    state = state.copyWith(curPage: 1);
+    getListData();
+  }
 
 
-    state = state.copyWith(curPage: 1, pageSize: 10);
-    // ref.invalidateSelf();
-    // ref.invalidate(propertyNewsVmProvider);
+  // 重试请求
+  Future retryRequest() async {
+    state = state.copyWith(curPage: 1);
+    _needShowPlaceholder = true;
     getListData();
     getListData();
+  }
+
+
+  // 获取list 列表数据
+  void getListData<T>() async {
+    if (_needShowPlaceholder) {
+      changeLoadingState(LoadState.State_Loading, null);
+    }
+
+    Log.d("加载listData数据---------------start-----");
+    //   try {
+    //     //请求网络
+    //     Map<String, dynamic>  params = {
+    //       "curPage": state.curPage,
+    //       "pageSize": state.pageSize,
+    //     };
+    //     Log.d("请求参数------$params");
+    //     final result = await propertyNewsRepository.fetchPropertyNewsList(params);
+    //     Log.d("请求完成结果------${result.data}");
+    //     //校验成功失败
+    //     if (result.isSuccess) {
+    //       // state = state.copyWith(serverTime: result.data);
+    //       state = state;
+    //       ToastEngine.show("获取数据成功");
+    //     } else {
+    //       ToastEngine.show(result.errorMsg ?? "Network Load Error");
+    //     }
+    //   } catch (e) {
+    //     ToastEngine.show("Error: $e");
+    //   }
 
 
+    await Future.delayed(const Duration(milliseconds: 1500));
+    final List<Map<String, dynamic>> listData = [
+      {
+        "id": 1,
+        "title": "fkladsfk fldask fldsakfllfkaslsd",
+        "description": "fsklfdsk罚款乱收费上课了发送卡",
+        "time": "2024-02-15 12:00:00",
+        "isCollection": true,
+        "pic": ""
+      },
+      {
+        "id": 2,
+        "title": "JHKFDSAJKjfkdsfjkasjkjklfajfkajifwoqirujweiqofjndsaikfniasdhfiasdhfiadshfifjadslfjkdlsafjlkadsj",
+        "description": "oifosjf fjdskafj hjiwehfriohjfiash",
+        "time": "2024-10-16 12:00:00",
+        "isCollection": false,
+        "pic": ""
+      },
+    ];
+
+    if (state.curPage == 1) {
+      //刷新的方式
+      state = state.copyWith(list: listData);
+      refreshController.finishRefresh();
+
+      //更新展示的状态
+      changeLoadingState(LoadState.State_Success, null);
+    } else {
+      //加载更多
+      final allList = state.list;
+      allList.addAll(listData);
+      state.list.addAll(listData);
+
+      refreshController.finishLoad();
+
+      state = state.copyWith(list: allList);
+    }
+
+    // 最后赋值
+    _needShowPlaceholder = false;
   }
   }
 
 
+
   // 去新闻详情页
   // 去新闻详情页
   void goNewsDetail(String item) {
   void goNewsDetail(String item) {
     Log.d("goNewsDetail");
     Log.d("goNewsDetail");

+ 1 - 1
packages/cpt_property/lib/modules/news/vm/property_news_vm.g.dart

@@ -6,7 +6,7 @@ part of 'property_news_vm.dart';
 // RiverpodGenerator
 // RiverpodGenerator
 // **************************************************************************
 // **************************************************************************
 
 
-String _$propertyNewsVmHash() => r'9f9fe61ce917e7f3098de28310a19171f9e8c457';
+String _$propertyNewsVmHash() => r'3a62be346ba45f73d4c4272c6b42cae5bfdfcdae';
 
 
 /// See also [PropertyNewsVm].
 /// See also [PropertyNewsVm].
 @ProviderFor(PropertyNewsVm)
 @ProviderFor(PropertyNewsVm)

+ 1 - 1
packages/cpt_property/lib/modules/property/vm/property_vm.g.dart

@@ -6,7 +6,7 @@ part of 'property_vm.dart';
 // RiverpodGenerator
 // RiverpodGenerator
 // **************************************************************************
 // **************************************************************************
 
 
-String _$propertyVmHash() => r'9b08b5e83d2b45f67b653daf60bb66bacb9c47ed';
+String _$propertyVmHash() => r'e9f36995f10e7a4a0897046c50ff9ddd047b58d6';
 
 
 /// See also [PropertyVm].
 /// See also [PropertyVm].
 @ProviderFor(PropertyVm)
 @ProviderFor(PropertyVm)

+ 5 - 4
packages/cs_widgets/lib/app_check_box.dart

@@ -4,9 +4,10 @@ import 'package:flutter/material.dart';
 class AppCheckbox extends StatefulWidget {
 class AppCheckbox extends StatefulWidget {
   final String? label;
   final String? label;
   final bool? checked;
   final bool? checked;
+  final TextStyle? labelStyle;
   final Function(bool?)? onChecked;
   final Function(bool?)? onChecked;
 
 
-  AppCheckbox({this.label, this.checked, this.onChecked});
+  AppCheckbox({this.label, this.checked, this.labelStyle, this.onChecked});
 
 
   @override
   @override
   _AppCheckboxState createState() => _AppCheckboxState();
   _AppCheckboxState createState() => _AppCheckboxState();
@@ -29,19 +30,19 @@ class _AppCheckboxState extends State<AppCheckbox> {
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return SafeArea(
     return SafeArea(
       child: Row(
       child: Row(
-        crossAxisAlignment: CrossAxisAlignment.start,
+        crossAxisAlignment: CrossAxisAlignment.center,
         children: [
         children: [
           SizedBox(
           SizedBox(
             width: 24.0,
             width: 24.0,
             height: 24.0,
             height: 24.0,
             child: Checkbox(value: _checked, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, onChanged: _onChecked),
             child: Checkbox(value: _checked, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, onChanged: _onChecked),
           ),
           ),
-          SizedBox(width: 10),
+          const SizedBox(width: 10),
           Flexible(
           Flexible(
             child: Text(
             child: Text(
               widget.label!,
               widget.label!,
               textAlign: TextAlign.left,
               textAlign: TextAlign.left,
-              style: const TextStyle(
+              style: ( widget.labelStyle!=null )? widget.labelStyle: const TextStyle(
                 fontSize: 13.0,
                 fontSize: 13.0,
                 color: Colors.white,
                 color: Colors.white,
               ),
               ),

+ 165 - 0
packages/cs_widgets/lib/dialog/app_custom_dialog.dart

@@ -0,0 +1,165 @@
+import 'package:cs_resources/generated/assets.dart';
+import 'package:cs_resources/generated/l10n.dart';
+import 'package:cs_resources/theme/app_colors_theme.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+import 'package:widgets/ext/ex_widget.dart';
+import 'package:widgets/my_load_image.dart';
+import '../my_text_view.dart';
+import 'dart:ui';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/widgets.dart';
+import 'package:widgets/widget_export.dart';
+
+import '../no_shadow_scroll_behavior.dart';
+
+/*
+ * 默认的弹窗
+ */
+class AppCustomDialog extends StatelessWidget {
+  String? title;
+  String message;
+  Widget Function(BuildContext context)? messageBuilder;
+  VoidCallback confirmAction;
+  VoidCallback? cancelAction;
+  bool isShowCancelBtn;
+  String? confirmTxt;
+  String? cancelTxt;
+
+  AppCustomDialog({
+    required this.message,
+    required this.confirmAction,
+    this.messageBuilder,
+    this.title,
+    this.cancelAction,
+    this.isShowCancelBtn = true,
+    this.confirmTxt,
+    this.cancelTxt,
+  });
+
+  @override
+
+  Widget build(BuildContext context) {
+    //使用一个 Column 为最外层容器,可以方便的视线 wrap_content 的效果
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisAlignment: MainAxisAlignment.center,
+      mainAxisSize: MainAxisSize.max,
+      children: [
+        //Title (如果使用 Container 为最外层容器则默认为 match_parent 的效果,除非我们限制宽度和最大高度最小高度)
+        Container(
+          width: double.infinity,
+          height: 55,
+          decoration: BoxDecoration(
+            color: context.appColors.btnBgDefault,
+            borderRadius: const BorderRadius.only(
+              topRight: Radius.circular(15),
+              topLeft: Radius.circular(15),
+            ),
+          ),
+          child: Row(
+            children: [
+              const SizedBox(width: 45),
+              MyTextView(
+                title ?? S.current.alert,
+                fontSize: 18,
+                textAlign: TextAlign.center,
+                isFontMedium: true,
+                textColor: Colors.white,
+              ).expanded(),
+              const MyAssetImage(Assets.baseServiceDialogDeleteIcon,width: 25,height: 25.5,).onTap((){
+                onCancel();
+              },padding: 10)
+            ],
+
+          ),
+        ),
+
+        Container(
+          width: double.infinity,
+          padding: const EdgeInsets.only(top: 30),
+          decoration: BoxDecoration(
+            color: context.appColors.whiteSecondBG,
+            borderRadius: const BorderRadius.only(
+              bottomLeft: Radius.circular(15),
+              bottomRight: Radius.circular(15),
+            ),
+          ),
+          child: Column(
+            children: [
+              Scrollbar(
+                child: ScrollConfiguration(
+                  behavior: NoShadowScrollBehavior(),
+                  child: SingleChildScrollView(
+                    child: message.isNotEmpty?MyTextView(
+                      message,
+                      fontSize: 18,
+                      textColor: context.appColors.textBlack,
+                      isFontRegular: true,
+                      textAlign: TextAlign.center,
+                      paddingLeft: 30,
+                      paddingRight: 30,
+                    ):  (messageBuilder != null ? messageBuilder!(context) : Container()),
+                  ),
+                ),
+              ).constrained(maxHeight: 210),
+              Row(
+                children: [
+                  const SizedBox(width: 18),
+                  Visibility(
+                    visible: isShowCancelBtn,
+                    child: Expanded(
+                        flex: 1,
+                        child: InkWell(
+                          onTap: () {
+                            onCancel();
+                            cancelAction?.call();
+                          },
+                          child: MyTextView(
+                            cancelTxt ?? S.current.no,
+                            fontSize: 16,
+                            isFontMedium: true,
+                            paddingTop: 13,
+                            marginRight: 15,
+                            paddingBottom: 13,
+                            textAlign: TextAlign.center,
+                            textColor: Colors.white,
+                            backgroundColor: context.appColors.orangeBG,
+                            cornerRadius: 7,
+                          ),
+                        )),
+                  ),
+                  Expanded(
+                      flex: 1,
+                      child: InkWell(
+                        onTap: () async {
+                          onCancel();
+                          confirmAction();
+                        },
+                        child: MyTextView(
+                          confirmTxt ?? S.current.yes,
+                          fontSize: 16,
+                          paddingTop: 13,
+                          paddingBottom: 13,
+                          isFontMedium: true,
+                          textAlign: TextAlign.center,
+                          textColor: Colors.white,
+                          backgroundColor: context.appColors.btnBgDefault,
+                          cornerRadius: 7,
+                        ),
+                      )),
+                  const SizedBox(width: 18),
+                ],
+              ).marginOnly(bottom: 30, top: 28),
+            ],
+          ),
+        ),
+      ],
+    ).constrained(width: 300);
+  }
+
+  //取消弹框
+  void onCancel() async {
+    SmartDialog.dismiss();
+  }
+}

+ 5 - 2
packages/cs_widgets/lib/dialog/app_default_dialog.dart

@@ -20,6 +20,7 @@ class AppDefaultDialog extends StatelessWidget {
   String? title;
   String? title;
 
 
   String message;
   String message;
+  Widget Function(BuildContext context)? messageBuilder;
   VoidCallback confirmAction;
   VoidCallback confirmAction;
   VoidCallback? cancelAction;
   VoidCallback? cancelAction;
   bool isShowCancelBtn;
   bool isShowCancelBtn;
@@ -29,6 +30,7 @@ class AppDefaultDialog extends StatelessWidget {
   AppDefaultDialog({
   AppDefaultDialog({
     required this.message,
     required this.message,
     required this.confirmAction,
     required this.confirmAction,
+    this.messageBuilder,
     this.title,
     this.title,
     this.cancelAction,
     this.cancelAction,
     this.isShowCancelBtn = true,
     this.isShowCancelBtn = true,
@@ -37,6 +39,7 @@ class AppDefaultDialog extends StatelessWidget {
   });
   });
 
 
   @override
   @override
+
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     //使用一个 Column 为最外层容器,可以方便的视线 wrap_content 的效果
     //使用一个 Column 为最外层容器,可以方便的视线 wrap_content 的效果
     return Column(
     return Column(
@@ -88,7 +91,7 @@ class AppDefaultDialog extends StatelessWidget {
                 child: ScrollConfiguration(
                 child: ScrollConfiguration(
                   behavior: NoShadowScrollBehavior(),
                   behavior: NoShadowScrollBehavior(),
                   child: SingleChildScrollView(
                   child: SingleChildScrollView(
-                    child: MyTextView(
+                    child: message.isNotEmpty?MyTextView(
                       message,
                       message,
                       fontSize: 18,
                       fontSize: 18,
                       textColor: context.appColors.textBlack,
                       textColor: context.appColors.textBlack,
@@ -96,7 +99,7 @@ class AppDefaultDialog extends StatelessWidget {
                       textAlign: TextAlign.center,
                       textAlign: TextAlign.center,
                       paddingLeft: 30,
                       paddingLeft: 30,
                       paddingRight: 30,
                       paddingRight: 30,
-                    ),
+                    ):  (messageBuilder != null ? messageBuilder!(context) : Container()),
                   ),
                   ),
                 ),
                 ),
               ).constrained(maxHeight: 210),
               ).constrained(maxHeight: 210),

+ 89 - 0
packages/cs_widgets/lib/my_checkbox_group.dart

@@ -0,0 +1,89 @@
+import 'package:flutter/material.dart';
+
+class MyCheckboxGroup extends StatefulWidget {
+  final List<Map<String, dynamic>> items;
+  final bool isSingleSelect;
+  final String nameStr;
+  final String valueStr;
+  final ValueChanged<List<Map<String, dynamic>>> onChanged;
+  final List<Map<String, dynamic>>? defaultSelectedItems;
+  final TextStyle? labelStyle;
+
+  MyCheckboxGroup({
+    required this.items,
+    this.isSingleSelect = false,
+    this.valueStr = 'id',
+    this.nameStr = 'label',
+    required this.onChanged,
+    this.defaultSelectedItems,
+    this.labelStyle = const TextStyle(
+      fontSize: 14,
+      fontWeight: FontWeight.w500,
+    ),
+  });
+
+  @override
+  _MyCheckboxGroupState createState() => _MyCheckboxGroupState();
+}
+
+class _MyCheckboxGroupState extends State<MyCheckboxGroup> {
+  Set<String> _selectedItemKeys = {};
+
+  @override
+  void initState() {
+    super.initState();
+    if (widget.defaultSelectedItems != null) {
+      _selectedItemKeys.addAll(widget.defaultSelectedItems!.map((item) => item[widget.valueStr] as String));
+      widget.onChanged(widget.items.where((item) => _selectedItemKeys.contains(item[widget.valueStr] as String)).toList());
+    }
+  }
+
+  void _toggleSelection(String key) {
+    if (widget.isSingleSelect) {
+      setState(() {
+        _selectedItemKeys.clear();
+        _selectedItemKeys.add(key);
+      });
+    } else {
+      setState(() {
+        if (_selectedItemKeys.contains(key)) {
+          _selectedItemKeys.remove(key);
+        } else {
+          _selectedItemKeys.add(key);
+        }
+      });
+    }
+    widget.onChanged(widget.items.where((item) => _selectedItemKeys.contains(item[widget.valueStr] as String)).toList());
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      children: widget.items.map((item) {
+        final key = item[widget.valueStr] as String;
+        final label = item[widget.nameStr] as String;
+        return Container(
+          child: Row(
+            children: [
+              Checkbox(
+                value: _selectedItemKeys.contains(key),
+                onChanged: (bool? checked) {
+                  if (checked != null) {
+                    _toggleSelection(key);
+                  }
+                },
+              ),
+              Text(
+                label,
+                style: widget.labelStyle ?? const TextStyle(
+                  fontSize: 14,
+                  fontWeight: FontWeight.w500,
+                ),
+              ),
+            ],
+          ),
+        );
+      }).toList(),
+    );
+  }
+}