Parcourir la source

[fit]1.修改弹窗逻辑
2.修改新人介绍动画
3.修改商店活动页展示逻辑
4.新人结果页添加遮罩

云天逵 il y a 7 mois
Parent
commit
13807ec2c1

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
assets/anim/anim_intro_second_data.json


+ 1 - 1
lib/data/consts/constants.dart

@@ -3,7 +3,7 @@ import '../../utils/mmkv_util.dart';
 class Constants {
   Constants._();
 
-  static const String env = envDev;
+  static const String env = envProd;
 
   static const String envDev = 'dev';
 

+ 8 - 7
lib/module/character/content/character_group_content_controller.dart

@@ -83,7 +83,7 @@ class CharacterGroupContentController extends BaseController {
   @override
   onReady() async {
     super.onReady();
-    await AssetLottie(Assets.anim.animSurpriseDialogData).load();
+
   }
 
   // 下拉刷新
@@ -148,13 +148,13 @@ class CharacterGroupContentController extends BaseController {
       onDismiss: () {
         if (Platform.isAndroid) {
           DailyLimiterUtil.run(
-            actionKey: 'SurpriseDialog', // 唯一标识该弹窗逻辑
+            actionKey: 'DiscountTicketDialog', // 唯一标识该弹窗逻辑
             condition:
-                characterInfo.isVip == true &&
+            characterInfo.isVip == true &&
                 characterInfo.isLock == true &&
                 !isVipUser,
             onExecute: () {
-              SurpriseDialog.show(
+              DiscountTicketDialog.show(
                 clickConfirm: () {
                   NewDiscountPage.start();
                 },
@@ -163,19 +163,20 @@ class CharacterGroupContentController extends BaseController {
           );
         }else if (Platform.isIOS) {
           DailyLimiterUtil.run(
-            actionKey: 'DiscountTicketDialog', // 唯一标识该弹窗逻辑
+            actionKey: 'SurpriseDialog', // 唯一标识该弹窗逻辑
             condition:
-                characterInfo.isVip == true &&
+            characterInfo.isVip == true &&
                 characterInfo.isLock == true &&
                 !isVipUser,
             onExecute: () {
-              DiscountTicketDialog.show(
+              SurpriseDialog.show(
                 clickConfirm: () {
                   NewDiscountPage.start();
                 },
               );
             },
           );
+
         }
       },
     );

+ 2 - 1
lib/module/main/main_controller.dart

@@ -10,6 +10,7 @@ import 'package:keyboard/data/repository/store_repository.dart';
 import 'package:keyboard/module/main/enums/main_tab.dart';
 import 'package:keyboard/module/new_user/new_user_page.dart';
 import 'package:keyboard/module/store/new_discount/new_discount_page.dart';
+import 'package:lottie/lottie.dart';
 
 import '../../base/base_controller.dart';
 import '../../data/bean/member_info.dart';
@@ -102,7 +103,7 @@ class MainController extends BaseController {
   @override
   void onInit() {
     super.onInit();
-
+    AssetLottie(Assets.anim.animSurpriseDialogData).load();
 
 
   }

+ 105 - 61
lib/module/new_user/result/new_user_result_page.dart

@@ -307,71 +307,115 @@ class NewUserResultPage extends BasePage<NewUserResultController> {
             SizedBox(height: 26.w),
             SizedBox(
               height: 100.w,
-              child: AutoScrollListView(
-                itemCount: (controller.charactersList.length / 2).ceil(),
-                scrollDirection: Axis.horizontal,
-                itemBuilder: (context, columnIndex) {
-                  int rowCount = 2;
-                  int startIndex = columnIndex * rowCount;
-                  final List<CharacterInfo> columnItems =
-                      controller.charactersList
-                          .skip(startIndex)
-                          .take(rowCount)
-                          .toList();
-                  return Column(
-                    children:
-                        columnItems.map((item) {
-                          final emoji = item.emoji ?? "";
-                          final name = item.name ?? "";
-                          return Padding(
-                            padding: EdgeInsets.symmetric(
-                              vertical: 4.w,
-                              horizontal: 4.w,
-                            ),
-                            child: Obx(() {
-                              final isSelected = controller.selectCharactersList
-                                  .any(
-                                    (selected) => selected.name == item.name,
-                                  );
-                              return SizedBox(
-                                height: 36.w,
-                                child: ChoiceChip(
-                                  label: Text(
-                                    "$emoji$name",
-                                    style: TextStyle(
-                                      color:
-                                          isSelected
-                                              ? Colors.white
-                                              : Colors.black.withAlpha(204),
-                                      fontSize: 13.sp,
-                                      fontWeight: FontWeight.w400,
+              child: Stack(
+                children: [
+                  // 滚动列表
+                  Positioned.fill(
+                    child: AutoScrollListView(
+                      itemCount: (controller.charactersList.length / 2).ceil(),
+                      scrollDirection: Axis.horizontal,
+                      itemBuilder: (context, columnIndex) {
+                        int rowCount = 2;
+                        int startIndex = columnIndex * rowCount;
+                        final List<CharacterInfo> columnItems =
+                        controller.charactersList
+                            .skip(startIndex)
+                            .take(rowCount)
+                            .toList();
+                        return Column(
+                          children: columnItems.map((item) {
+                            final emoji = item.emoji ?? "";
+                            final name = item.name ?? "";
+                            return Padding(
+                              padding: EdgeInsets.symmetric(
+                                vertical: 4.w,
+                                horizontal: 4.w,
+                              ),
+                              child: Obx(() {
+                                final isSelected = controller.selectCharactersList
+                                    .any((selected) => selected.name == item.name);
+                                return SizedBox(
+                                  height: 36.w,
+                                  child: ChoiceChip(
+                                    label: Text(
+                                      "$emoji$name",
+                                      style: TextStyle(
+                                        color: isSelected
+                                            ? Colors.white
+                                            : Colors.black.withAlpha(204),
+                                        fontSize: 13.sp,
+                                        fontWeight: FontWeight.w400,
+                                      ),
                                     ),
+                                    showCheckmark: false,
+                                    selected: isSelected,
+                                    selectedColor: const Color(0xFFB782FF),
+                                    backgroundColor: const Color(0xFFF6F5FA),
+                                    shape: RoundedRectangleBorder(
+                                      borderRadius: BorderRadius.circular(31.r),
+                                    ),
+                                    side: BorderSide.none,
+                                    onSelected: (selected) {
+                                      if (selected != isSelected) {
+                                        controller.onSelected(item);
+                                      }
+                                    },
                                   ),
-                                  showCheckmark: false,
-                                  selected: isSelected,
-                                  selectedColor: const Color(0xFFB782FF),
-                                  backgroundColor: Color(0xFFF6F5FA),
-                                  shape: RoundedRectangleBorder(
-                                    borderRadius: BorderRadius.circular(31.r),
-                                  ),
-                                  side: BorderSide(
-                                    width: 0.w,
-                                    color: Colors.transparent
-                                  ),
-                                  onSelected: (selected) {
-                                    if (selected != isSelected) {
-                                      controller.onSelected(item);
-                                    }
-                                  },
-                                ),
-                              );
-                            }),
-                          );
-                        }).toList(),
-                  );
-                },
+                                );
+                              }),
+                            );
+                          }).toList(),
+                        );
+                      },
+                    ),
+                  ),
+
+                  // 左侧渐变
+                  Positioned(
+                    left: 0,
+                    top: 0,
+                    bottom: 0,
+                    child: Container(
+                      width: 20.w,
+                      height: 94.w,
+                      decoration: BoxDecoration(
+                        gradient: LinearGradient(
+                          begin: Alignment.centerLeft,
+                          end: Alignment.centerRight,
+                          colors: [
+                            Colors.white,
+                            Colors.white.withAlpha(0),
+                          ],
+                        ),
+                      ),
+                    ),
+                  ),
+
+                  // 右侧渐变
+                  Positioned(
+                    right: 0,
+                    top: 0,
+                    bottom: 0,
+                    child: Container(
+                      width: 20.w,
+                      height: 94.w,
+                      decoration: BoxDecoration(
+                        gradient: LinearGradient(
+                          begin: Alignment.centerRight,
+                          end: Alignment.centerLeft,
+                          colors: [
+                            Colors.white,
+                            Colors.white.withAlpha(0),
+                          ],
+                        ),
+                      ),
+                    ),
+                  ),
+                ],
               ),
             ),
+
+
             SizedBox(height: 26.w),
           ],
         ),

+ 3 - 2
lib/module/store/new_discount/new_discount_controller.dart

@@ -487,7 +487,7 @@ class NewDiscountController extends BaseController
     paymentStatusManager.unregisterPaymentSuccessCallback(this);
     if (!isFirstIntoDiscount() && !accountRepository.isVipUser) {
       if (Platform.isAndroid) {
-        DiscountTicketDialog.show(
+        SurpriseDialog.show(
           clickConfirm: () {
             NewDiscountPage.start();
           },
@@ -495,12 +495,13 @@ class NewDiscountController extends BaseController
         );
       }
       if (Platform.isIOS) {
-        SurpriseDialog.show(
+        DiscountTicketDialog.show(
           clickConfirm: () {
             NewDiscountPage.start();
           },
           clickCancel: () {},
         );
+
       }
     } else {
       setFirstIntoDiscount(false);

+ 33 - 22
lib/module/store/new_discount/new_discount_page.dart

@@ -428,6 +428,7 @@ class NewDiscountPage extends BasePage<NewDiscountController> {
               ),
       child: Row(
         children: [
+
           Text(
             "¥",
             style: TextStyle(
@@ -440,7 +441,7 @@ class NewDiscountPage extends BasePage<NewDiscountController> {
             ),
           ),
           Text(
-            '${item.amountText}',
+          (item.code=="vip_permanent")? '${item.priceDescNumber}':'${item.amountText}',
             textAlign: TextAlign.center,
             style: TextStyle(
               color:
@@ -451,6 +452,15 @@ class NewDiscountPage extends BasePage<NewDiscountController> {
               fontWeight: FontWeight.w700,
             ),
           ),
+          if (item.code=="vip_permanent")
+            Text(
+                item.priceDescUnit,
+              style: TextStyle(
+                color: Colors.black.withAlpha(153),
+                fontSize: 12.sp,
+                fontWeight: FontWeight.w400,
+              ),
+            ),
           SizedBox(width: 9.w),
           Column(
             crossAxisAlignment: CrossAxisAlignment.start,
@@ -504,7 +514,8 @@ class NewDiscountPage extends BasePage<NewDiscountController> {
                 ],
               ),
               Text(
-                item.priceDesc,
+                (item.code=="vip_permanent")? '${item.description}':'${item.priceDesc}',
+
                 style: TextStyle(
                   color: Colors.black.withAlpha(153),
                   fontSize: 12.sp,
@@ -513,26 +524,26 @@ class NewDiscountPage extends BasePage<NewDiscountController> {
               ),
             ],
           ),
-          Spacer(),
-          isSelected
-              ? Assets.images.iconCustomCharacterAddDialogSelect.image(
-                width: 20.w,
-                height: 20.w,
-                fit: BoxFit.contain,
-              )
-              : Container(
-                width: 20.w,
-                height: 20.w,
-                decoration: ShapeDecoration(
-                  color: Colors.white,
-                  shape: OvalBorder(
-                    side: BorderSide(
-                      width: 2.w,
-                      color: const Color(0xFFE6E6E6),
-                    ),
-                  ),
-                ),
-              ),
+          // Spacer(),
+          // isSelected
+          //     ? Assets.images.iconCustomCharacterAddDialogSelect.image(
+          //       width: 20.w,
+          //       height: 20.w,
+          //       fit: BoxFit.contain,
+          //     )
+          //     : Container(
+          //       width: 20.w,
+          //       height: 20.w,
+          //       decoration: ShapeDecoration(
+          //         color: Colors.white,
+          //         shape: OvalBorder(
+          //           side: BorderSide(
+          //             width: 2.w,
+          //             color: const Color(0xFFE6E6E6),
+          //           ),
+          //         ),
+          //       ),
+          //     ),
         ],
       ),
     );

+ 4 - 2
lib/module/store/store_controller.dart

@@ -460,6 +460,7 @@ class StoreController extends BaseController implements PaymentStatusCallback {
   @override
   void onInit() async {
     super.onInit();
+
   }
 
   @override
@@ -471,7 +472,7 @@ class StoreController extends BaseController implements PaymentStatusCallback {
       return;
     }
     if (Platform.isAndroid) {
-      DiscountTicketDialog.show(
+      SurpriseDialog.show(
         clickConfirm: () {
           NewDiscountPage.start();
         },
@@ -479,12 +480,13 @@ class StoreController extends BaseController implements PaymentStatusCallback {
       );
     }
     if (Platform.isIOS) {
-      SurpriseDialog.show(
+      DiscountTicketDialog.show(
         clickConfirm: () {
           NewDiscountPage.start();
         },
         clickCancel: () {},
       );
+
     }
   }
 

+ 74 - 45
lib/widget/auto_scroll_list_view.dart

@@ -106,16 +106,9 @@ class _AutoScrollListViewState extends State<AutoScrollListView> {
 // 多行横向自动滚动列表
 /// 一个支持自动滚动的多行横向列表,每一行自动向右滚动(模拟跑马灯效果)
 class StaggeredAutoScrollListView extends StatefulWidget {
-  /// 子项构建器(需根据 itemIndex 构建对应组件)
   final NullableIndexedWidgetBuilder itemBuilder;
-
-  /// 实际数据项数量(不是扩展后的数量)
   final int itemCount;
-
-  /// 每行的内边距
   final EdgeInsetsGeometry? padding;
-
-  /// 是否启用自动滚动
   final bool isAutoScrolling;
 
   const StaggeredAutoScrollListView({
@@ -131,17 +124,22 @@ class StaggeredAutoScrollListView extends StatefulWidget {
 }
 
 class _StaggeredAutoScrollListViewState extends State<StaggeredAutoScrollListView> {
-  final int rowCount = 3; // 列表的总行数
-  final List<ScrollController> _controllers = []; // 每一行的滚动控制器
-  final List<Timer?> _timers = []; // 每一行对应的自动滚动定时器
-  final int loopFactor = 3; // 每行内容扩展的倍数,防止滚动过短
+  final int rowCount = 3;
+  final int loopFactor = 3;
+
+  late final List<ScrollController> _controllers;
+  late final List<Timer?> _timers;
+  late final List<Timer?> _resumeTimers;
+  late final List<bool> _isUserScrollingList;
 
   @override
   void initState() {
     super.initState();
-    for (int i = 0; i < rowCount; i++) {
-      _controllers.add(ScrollController());
-    }
+    _controllers = List.generate(rowCount, (_) => ScrollController());
+    _timers = List.generate(rowCount, (_) => null);
+    _resumeTimers = List.generate(rowCount, (_) => null);
+    _isUserScrollingList = List.generate(rowCount, (_) => false);
+
     if (widget.isAutoScrolling) {
       WidgetsBinding.instance.addPostFrameCallback((_) => _startAllScrolls());
     }
@@ -149,47 +147,68 @@ class _StaggeredAutoScrollListViewState extends State<StaggeredAutoScrollListVie
 
   @override
   void dispose() {
-    // 销毁滚动控制器
     for (final controller in _controllers) {
       controller.dispose();
     }
-
-    // 取消所有定时器
     for (final timer in _timers) {
       timer?.cancel();
     }
-
+    for (final timer in _resumeTimers) {
+      timer?.cancel();
+    }
     super.dispose();
   }
 
-  /// 启动所有行的自动滚动
   void _startAllScrolls() {
     for (int i = 0; i < rowCount; i++) {
-      final controller = _controllers[i];
-      _timers.add(Timer.periodic(const Duration(milliseconds: 50), (_) {
-        if (!controller.hasClients) return;
-
-        final maxExtent = controller.position.maxScrollExtent;
-        final current = controller.position.pixels;
-        final next = current + 1;
-
-        if (next >= maxExtent) {
-          final viewportWidth = controller.position.viewportDimension;
-          final contentWidth = maxExtent + viewportWidth;
-          final originalContentWidth = contentWidth / loopFactor;
-          final offset = next - maxExtent;
-          controller.jumpTo(originalContentWidth + offset);
-        } else {
-          controller.jumpTo(next);
-        }
-      }));
+      _startScroll(i);
     }
   }
-  @override
+
+  void _startScroll(int rowIndex) {
+    _timers[rowIndex]?.cancel();
+    _timers[rowIndex] = Timer.periodic(const Duration(milliseconds: 80), (_) {
+      if (!widget.isAutoScrolling || _isUserScrollingList[rowIndex]) return;
+
+      final controller = _controllers[rowIndex];
+      if (!controller.hasClients) return;
+
+      final maxExtent = controller.position.maxScrollExtent;
+      final current = controller.position.pixels;
+      final next = current + 1;
+
+      if (next >= maxExtent) {
+        final viewportWidth = controller.position.viewportDimension;
+        final contentWidth = maxExtent + viewportWidth;
+        final originalContentWidth = contentWidth / loopFactor;
+        final offset = next - maxExtent;
+        controller.jumpTo(originalContentWidth + offset);
+      } else {
+        controller.jumpTo(next);
+      }
+    });
+  }
+
+  void _onUserScroll(int rowIndex) {
+    if (_isUserScrollingList[rowIndex]) return;
+
+    _isUserScrollingList[rowIndex] = true;
+    _timers[rowIndex]?.cancel();
+    _timers[rowIndex] = null;
+
+    _resumeTimers[rowIndex]?.cancel();
+    _resumeTimers[rowIndex] = Timer(const Duration(seconds: 1), () {
+      _isUserScrollingList[rowIndex] = false;
+      if (widget.isAutoScrolling) {
+        _startScroll(rowIndex);
+      }
+    });
+  }
 
   @override
   Widget build(BuildContext context) {
     final actualItemsPerRow = (widget.itemCount / rowCount).ceil();
+
     return Column(
       children: List.generate(rowCount, (rowIndex) {
         final startIndex = rowIndex * actualItemsPerRow;
@@ -199,14 +218,24 @@ class _StaggeredAutoScrollListViewState extends State<StaggeredAutoScrollListVie
           rowItems.length * loopFactor,
               (i) => rowItems[i % rowItems.length],
         );
+
         return SizedBox(
-          height: 50.w,
-          child: ListView.builder(
-            controller: _controllers[rowIndex],
-            scrollDirection: Axis.horizontal,
-            padding: widget.padding,
-            itemCount: extendedItems.length,
-            itemBuilder: (context, index) => widget.itemBuilder(context, extendedItems[index]),
+          height: 50.w, // 使用你自己的高度或比例
+          child: NotificationListener<UserScrollNotification>(
+            onNotification: (notification) {
+              if (notification.direction != ScrollDirection.idle) {
+                _onUserScroll(rowIndex);
+              }
+              return false;
+            },
+            child: ListView.builder(
+              controller: _controllers[rowIndex],
+              scrollDirection: Axis.horizontal,
+              padding: widget.padding,
+              itemCount: extendedItems.length,
+              itemBuilder: (context, index) =>
+                  widget.itemBuilder(context, extendedItems[index]),
+            ),
           ),
         );
       }),