Browse Source

fix: 首页增加刷新操作

lilu 3 tháng trước cách đây
mục cha
commit
21f2ffc191

+ 10 - 15
lib/app/app.dart

@@ -33,26 +33,21 @@ class App extends StatelessWidget {
       rebuildFactor: (old, data) => true,
       builder: (context, widget) => RefreshConfiguration(
         headerBuilder: () =>
-            GradientCircleHeader(), // Configure the default header indicator. If you have the same header indicator for each page, you need to set this
-        footerBuilder: () =>
-            ClassicFooter(), // Configure default bottom indicator
-        headerTriggerDistance: 100.0, // header trigger refresh trigger distance
+            GradientCircleHeader(), // 配置默认页眉指示器。如果您每个页面都有相同的页眉指示器,您需要设置此
+        footerBuilder: () => ClassicFooter(), // 配置默认底部指示器
+        headerTriggerDistance: 80.0, // 标题触发刷新触发距离
         springDescription: SpringDescription(
           mass: 1,
           stiffness: 1000,
           damping: 100,
-        ), // custom spring back animate,the props meaning see the flutter api
-        maxOverScrollExtent:
-            100, //The maximum dragging range of the head. Set this property if a rush out of the view area occurs
-        maxUnderScrollExtent: 0, // Maximum dragging range at the bottom
+        ), // 自定义弹簧回弹动画,属性含义请参阅Flutter API
+        maxOverScrollExtent: 40, //头部最大拖动范围。如果发生超出视图区域的情况,请设置此属性
+        maxUnderScrollExtent: 0, // 底部最大拖动范围
         enableScrollWhenRefreshCompleted:
-            true, //This property is incompatible with PageView and TabBarView. If you need TabBarView to slide left and right, you need to set it to true.
-        enableLoadingWhenFailed:
-            true, //In the case of load failure, users can still trigger more loads by gesture pull-up.
-        hideFooterWhenNotFull:
-            false, // Disable pull-up to load more functionality when Viewport is less than one screen
-        enableBallisticLoad:
-            true, // trigger load more by BallisticScrollActivity
+            true, //此属性与PageView和TabBarView不兼容。如果您需要TabBarView左右滑动,则需要将其设置为true。
+        enableLoadingWhenFailed: true, //在负载失败的情况下,用户仍然可以通过手势下拉触发更多负载。
+        hideFooterWhenNotFull: false, //禁用上拉加载更多功能,当视口小于一屏时
+        enableBallisticLoad: true, //触发通过BallisticScrollActivity加载更多
         child: _buildMaterialApp(),
       ),
     );

+ 9 - 0
lib/app/modules/home/controllers/home_controller.dart

@@ -1,4 +1,5 @@
 import 'package:get/get.dart';
+import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
 import '../../../../utils/log/logger.dart';
 import '../../../../utils/permission_manager.dart';
 import '../../../base/base_controller.dart';
@@ -11,6 +12,9 @@ class HomeController extends BaseController {
   final coreController = Get.find<CoreController>();
   final TAG = 'HomeController';
 
+  final _refreshController = RefreshController(initialRefresh: false);
+  RefreshController get refreshController => _refreshController;
+
   final _isOn = false.obs;
   bool get isOn => _isOn.value;
   set isOn(bool value) => _isOn.value = value;
@@ -167,4 +171,9 @@ class HomeController extends BaseController {
       log(TAG, 'Error saving locations to storage: $e');
     }
   }
+
+  void onRefresh() async {
+    await Future.delayed(Duration(milliseconds: 2000));
+    refreshController.refreshCompleted();
+  }
 }

+ 114 - 98
lib/app/modules/home/views/home_view.dart

@@ -5,6 +5,7 @@ import 'package:flutter/material.dart' hide ConnectionState;
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:get/get.dart';
 import 'package:nomo/app/constants/iconfont/iconfont.dart';
+import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
 import '../../../../config/theme/theme_extensions/theme_extension.dart';
 import '../../../../config/translations/strings_enum.dart';
 import '../../../base/base_view.dart';
@@ -26,114 +27,129 @@ class HomeView extends BaseView<HomeController> {
 
   @override
   Widget buildContent(BuildContext context) {
-    return Container(
-      width: double.maxFinite,
-      margin: EdgeInsets.symmetric(horizontal: 14.w),
-      child: SafeArea(
-        child: Column(
-          crossAxisAlignment: CrossAxisAlignment.start,
+    return SafeArea(
+      child: Container(
+        margin: EdgeInsets.symmetric(horizontal: 14.w),
+        child: Stack(
           children: [
-            Row(
-              mainAxisAlignment: MainAxisAlignment.spaceBetween,
+            Column(
               children: [
-                Obx(
-                  () => ClickOpacity(
-                    onTap: () => Get.toNamed(Routes.SUBSCRIPTION),
-                    child: IXImage(
-                      source: controller.isPremium
-                          ? Assets.premium
-                          : Assets.free,
-                      width: controller.isPremium ? 92.w : 64.w,
-                      height: 28.w,
-                      sourceType: ImageSourceType.asset,
-                    ),
-                  ),
-                ),
-                ClickOpacity(
-                  child: Padding(
-                    padding: EdgeInsets.only(
-                      left: 10.w,
-                      right: 0.w,
-                      top: 10.w,
-                      bottom: 10.w,
+                Row(
+                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                  children: [
+                    Obx(
+                      () => ClickOpacity(
+                        onTap: () => Get.toNamed(Routes.SUBSCRIPTION),
+                        child: IXImage(
+                          source: controller.isPremium
+                              ? Assets.premium
+                              : Assets.free,
+                          width: controller.isPremium ? 92.w : 64.w,
+                          height: 28.w,
+                          sourceType: ImageSourceType.asset,
+                        ),
+                      ),
                     ),
-                    child: Icon(
-                      IconFont.icon09,
-                      size: 26.w,
-                      color: Get.reactiveTheme.hintColor,
+                    ClickOpacity(
+                      child: Padding(
+                        padding: EdgeInsets.only(
+                          left: 10.w,
+                          right: 0.w,
+                          top: 10.w,
+                          bottom: 10.w,
+                        ),
+                        child: Icon(
+                          IconFont.icon09,
+                          size: 26.w,
+                          color: Get.reactiveTheme.hintColor,
+                        ),
+                      ),
+                      onTap: () {
+                        Get.toNamed(Routes.SETTING);
+                        // ErrorDialog.show(
+                        //   message:
+                        //       "The VPN was disconnected unexpectedly. Would you like to reconnect now to stay protected?",
+                        // );
+                      },
                     ),
-                  ),
-                  onTap: () {
-                    Get.toNamed(Routes.SETTING);
-                    // ErrorDialog.show(
-                    //   message:
-                    //       "The VPN was disconnected unexpectedly. Would you like to reconnect now to stay protected?",
-                    // );
-                  },
+                  ],
                 ),
-              ],
-            ),
 
-            // 80.verticalSpaceFromWidth,
-            Padding(
-              padding: EdgeInsets.symmetric(vertical: 20.w),
-              child: CarouselSlider(
-                options: CarouselOptions(height: 80.w, viewportFraction: 1.0),
-                items: [1, 2, 3, 4, 5].map((i) {
-                  return Builder(
-                    builder: (BuildContext context) {
-                      return IXImage(
-                        source: Assets.bannerTest,
-                        width: double.infinity,
-                        height: 80.w,
-                        sourceType: ImageSourceType.asset,
-                        borderRadius: 14.r,
-                      );
-                    },
-                  );
-                }).toList(),
-              ),
-            ),
-            Text(
-              Strings.activeTime.tr,
-              style: TextStyle(
-                fontSize: 18.sp,
-                height: 1.3,
-                color: Get.reactiveTheme.hintColor,
-              ),
-            ),
-            2.verticalSpaceFromWidth,
-            Obx(
-              () => Text(
-                controller.coreController.timer,
-                style: TextStyle(
-                  fontSize: 28.sp,
-                  height: 1.2,
-                  color: Get.reactiveTheme.primaryColor,
-                ),
-              ),
-            ),
+                Expanded(
+                  child: SmartRefresher(
+                    enablePullDown: true,
+                    enablePullUp: false,
+                    controller: controller.refreshController,
+                    onRefresh: controller.onRefresh,
+                    child: Column(
+                      crossAxisAlignment: CrossAxisAlignment.start,
+                      children: [
+                        // 80.verticalSpaceFromWidth,
+                        Padding(
+                          padding: EdgeInsets.symmetric(vertical: 20.w),
+                          child: CarouselSlider(
+                            options: CarouselOptions(
+                              height: 80.w,
+                              viewportFraction: 1.0,
+                            ),
+                            items: [1, 2, 3, 4, 5].map((i) {
+                              return Builder(
+                                builder: (BuildContext context) {
+                                  return IXImage(
+                                    source: Assets.bannerTest,
+                                    width: double.infinity,
+                                    height: 80.w,
+                                    sourceType: ImageSourceType.asset,
+                                    borderRadius: 14.r,
+                                  );
+                                },
+                              );
+                            }).toList(),
+                          ),
+                        ),
+                        Text(
+                          Strings.activeTime.tr,
+                          style: TextStyle(
+                            fontSize: 18.sp,
+                            height: 1.3,
+                            color: Get.reactiveTheme.hintColor,
+                          ),
+                        ),
+                        2.verticalSpaceFromWidth,
+                        Obx(
+                          () => Text(
+                            controller.coreController.timer,
+                            style: TextStyle(
+                              fontSize: 28.sp,
+                              height: 1.2,
+                              color: Get.reactiveTheme.primaryColor,
+                            ),
+                          ),
+                        ),
 
-            20.verticalSpaceFromWidth,
-            // 位置选择按钮和最近位置(叠在一起的效果)
-            Stack(
-              children: [
-                Container(
-                  alignment: Alignment.center,
-                  margin: EdgeInsets.only(top: 138.w),
-                  child: _buildConnectionButton(),
+                        20.verticalSpaceFromWidth,
+                        // 位置选择按钮和最近位置(叠在一起的效果)
+                        Stack(
+                          children: [
+                            Container(
+                              alignment: Alignment.center,
+                              margin: EdgeInsets.only(top: 138.w),
+                              child: _buildConnectionButton(),
+                            ),
+                            _buildLocationStack(),
+                          ],
+                        ),
+                      ],
+                    ),
+                  ),
                 ),
-                _buildLocationStack(),
               ],
             ),
-            Expanded(
-              child: Column(
-                mainAxisAlignment: MainAxisAlignment.end,
-                children: [
-                  MenuList(),
-                  if (Platform.isAndroid) 10.verticalSpaceFromWidth,
-                ],
-              ),
+            Positioned(
+              bottom: Platform.isAndroid ? 10.w : 0,
+              left: 0,
+              right: 0,
+              child: MenuList(),
             ),
           ],
         ),

+ 1 - 29
lib/app/modules/node/widgets/node_list.dart

@@ -1,4 +1,3 @@
-import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_screenutil/flutter_screenutil.dart';
 import 'package:flutter_sticky_header/flutter_sticky_header.dart';
@@ -11,7 +10,6 @@ import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
 import '../../../constants/iconfont/iconfont.dart';
 import '../../../data/models/launch/groups.dart';
 import '../../../widgets/country_icon.dart';
-import '../../../widgets/gradient_circle_header.dart';
 import '../../home/controllers/home_controller.dart';
 import '../controllers/node_controller.dart';
 
@@ -55,11 +53,6 @@ class _NodeListState extends State<NodeList>
     _refreshController.refreshCompleted();
   }
 
-  void _onLoading() async {
-    await Future.delayed(Duration(milliseconds: 1000));
-    _refreshController.loadComplete();
-  }
-
   @override
   Widget build(BuildContext context) {
     super.build(context);
@@ -98,31 +91,10 @@ class _NodeListState extends State<NodeList>
 
     return SmartRefresher(
       enablePullDown: true,
-      enablePullUp: true,
-      header: GradientCircleHeader(),
-      physics: const ClampingScrollPhysics(),
-      footer: CustomFooter(
-        builder: (BuildContext context, LoadStatus? mode) {
-          Widget body;
-          if (mode == LoadStatus.idle) {
-            body = Text("pull up load");
-          } else if (mode == LoadStatus.loading) {
-            body = CupertinoActivityIndicator();
-          } else if (mode == LoadStatus.failed) {
-            body = Text("Load Failed!Click retry!");
-          } else if (mode == LoadStatus.canLoading) {
-            body = Text("release to load more");
-          } else {
-            body = Text("No more Data");
-          }
-          return SizedBox(height: 55.0, child: Center(child: body));
-        },
-      ),
+      enablePullUp: false,
       controller: _refreshController,
       onRefresh: _onRefresh,
-      onLoading: _onLoading,
       child: CustomScrollView(
-        physics: const ClampingScrollPhysics(),
         slivers: [
           for (var tag in sortedTags)
             if (groupedData.containsKey(tag.id) &&