Kaynağa Gözat

[feat]1.修改惊喜买断价弹窗逻辑,每日3次
2.修改人设定制历史生成逻辑

云天逵 7 ay önce
ebeveyn
işleme
a418c86846

+ 5 - 0
lib/data/repository/account_repository.dart

@@ -13,6 +13,7 @@ import '../../base/app_base_request.dart';
 import '../../di/get_it.dart';
 import '../../utils/async_util.dart';
 import '../../utils/atmob_log.dart';
+import '../../utils/daily_limiter_util.dart';
 import '../../utils/http_handler.dart';
 import '../../utils/mmkv_util.dart';
 import '../api/request/complaint_submit_request.dart';
@@ -39,6 +40,9 @@ class AccountRepository {
 
   Rxn<MemberInfo> memberStatusInfo = Rxn<MemberInfo>();
 
+  bool get isVipUser =>
+      memberStatusInfo.value != null && memberStatusInfo.value!.isMember && isLogin.value;
+
   int? _lastRequestCodeTime;
   int _errorCodeTimes = 0;
 
@@ -220,6 +224,7 @@ class AccountRepository {
     isLogin.value = false;
     keyboardRepository.refreshData();
     KVUtil.putString(Constants.keyboardSelect, null);
+    DailyLimiterUtil.clearDailyLimitData("SurpriseDialog");
   }
 
   // 意见反馈

+ 2 - 0
lib/dialog/character_details_dialog.dart

@@ -15,6 +15,7 @@ class CharacterDetailsDialog {
   static void show({
     required CharacterInfo characterInfo,
     required VoidCallback clickCallback,
+    VoidCallback ? onDismiss,
   }) {
     SmartDialog.show(
       tag: tag,
@@ -211,6 +212,7 @@ class CharacterDetailsDialog {
                 child: GestureDetector(
                   onTap: () {
                     SmartDialog.dismiss(tag: tag);
+                    onDismiss?.call();
                   },
                   child: Assets.images.iconCharacterDialogClose.image(
                     width: 40.r,

+ 3 - 0
lib/dialog/custom_character/custom_character_add_controller.dart

@@ -7,6 +7,7 @@ import '../../data/api/response/character_custom_update_response.dart';
 import '../../data/bean/character_info.dart';
 import '../../data/bean/keyboard_info.dart';
 import '../../data/repository/keyboard_repository.dart';
+import '../../module/character_custom/character_custom_page.dart';
 import '../../utils/atmob_log.dart';
 import '../../utils/http_handler.dart';
 import '../../utils/toast_util.dart';
@@ -123,4 +124,6 @@ class CustomCharacterAddController extends BaseController {
       }
     }
   }
+
+
 }

+ 88 - 60
lib/dialog/custom_character/custom_character_add_view.dart

@@ -17,10 +17,8 @@ import '../../resource/string.gen.dart';
 import '../../utils/styles.dart';
 
 class CustomCharacterAddView extends BaseView<CustomCharacterAddController> {
-
   final KeyboardInfo currentKeyboardInfo;
 
-
   @override
   String? get tag => "CustomCharacterAddController${currentKeyboardInfo.id}";
 
@@ -32,50 +30,49 @@ class CustomCharacterAddView extends BaseView<CustomCharacterAddController> {
   @override
   Widget buildBody(BuildContext context) {
     Get.delete<CustomCharacterAddController>(tag: tag);
-    Get.put(CustomCharacterAddController(
+    Get.put(
+      CustomCharacterAddController(
         getIt.get<CharactersRepository>(),
         getIt.get<KeyboardRepository>(),
-        currentKeyboardInfo: currentKeyboardInfo),
-        tag: tag);
-    return Column(
-      children: [
-
-        Expanded(
-          child: Obx(() {
-            return EasyRefresh(
-              controller: controller.refreshController,
-              header: const ClassicHeader(),
-              footer: ClassicFooter(
-                showMessage: false,
-                noMoreText: StringName.noMoreData,
-                failedText: StringName.loadFailed,
-                processedText: StringName.loadCompleted,
-                processingText: StringName.loading,
-              ),
+        currentKeyboardInfo: currentKeyboardInfo,
+      ),
+      tag: tag,
+    );
+    return Obx(() {
+      if (controller.characterList.isEmpty) {
+        return _buildCustomListEmpty();
+      }
+      return EasyRefresh(
+        controller: controller.refreshController,
+        header: const ClassicHeader(),
+        footer: ClassicFooter(
+          showMessage: false,
+          noMoreText: StringName.noMoreData,
+          failedText: StringName.loadFailed,
+          processedText: StringName.loadCompleted,
+          processingText: StringName.loading,
+        ),
 
-              // onRefresh: controller.refreshData,
-              onLoad: controller.loadMoreData,
-              child: ListView.separated(
-                padding: EdgeInsets.zero,
-                itemCount: controller.characterList.length,
-                itemBuilder: (context, index) {
-                  return _buildListItem(
-                    characterInfo: controller.characterList[index],
-                  );
-                },
-                separatorBuilder: (BuildContext context, int index) {
-                  return SizedBox(
-                    width: double.infinity,
-                    height: 10.h,
-                    child: Container(color: const Color(0xFFF4F2FB)),
-                  );
-                },
-              ),
+        // onRefresh: controller.refreshData,
+        onLoad: controller.loadMoreData,
+        child: ListView.separated(
+          padding: EdgeInsets.zero,
+          itemCount: controller.characterList.length,
+          itemBuilder: (context, index) {
+            return _buildListItem(
+              characterInfo: controller.characterList[index],
+            );
+          },
+          separatorBuilder: (BuildContext context, int index) {
+            return SizedBox(
+              width: double.infinity,
+              height: 10.h,
+              child: Container(color: const Color(0xFFF4F2FB)),
             );
-          }),
+          },
         ),
-      ],
-    );
+      );
+    });
   }
 
   Widget _buildListItem({required CharacterInfo characterInfo}) {
@@ -104,7 +101,6 @@ class CustomCharacterAddView extends BaseView<CustomCharacterAddController> {
     );
   }
 
-
   /// 角色头像
   Widget _buildAvatar({required String? imageUrl}) {
     return Container(
@@ -118,11 +114,20 @@ class CustomCharacterAddView extends BaseView<CustomCharacterAddController> {
           colors: [Color(0xffebe6ff), Color(0xffffe6fe)],
         ),
       ),
-      child: CachedNetworkImage(
-        imageUrl: imageUrl ?? "",
-        width: 60.r,
-        height: 60.r,
-        fit: BoxFit.cover,
+      child: ClipRRect(
+        borderRadius: BorderRadius.circular(8.r),
+        child: CachedNetworkImage(
+          imageUrl: imageUrl ?? "",
+          width: 60.r,
+          height: 60.r,
+          fit: BoxFit.contain,
+          errorWidget:
+              (_, __, ___) => Assets.images.iconSystemKeyboard.image(
+            width: 60.r,
+            height: 60.r,
+            fit: BoxFit.contain,
+          ),
+        ),
       ),
     );
   }
@@ -147,9 +152,9 @@ class CustomCharacterAddView extends BaseView<CustomCharacterAddController> {
               SizedBox(width: 4.w),
               characterInfo.isVip == true
                   ? Assets.images.iconCharacterVip.image(
-                width: 38.w,
-                height: 16.h,
-              )
+                    width: 38.w,
+                    height: 16.h,
+                  )
                   : Container(),
             ],
           ),
@@ -180,13 +185,13 @@ class CustomCharacterAddView extends BaseView<CustomCharacterAddController> {
         decoration: BoxDecoration(
           borderRadius: BorderRadius.circular(50.r),
           gradient:
-          characterInfo.isAdd == true
-              ? null
-              : const LinearGradient(
-            colors: [Color(0xFF7D46FC), Color(0xFFBC87FF)],
-            begin: Alignment.topLeft,
-            end: Alignment.bottomRight,
-          ),
+              characterInfo.isAdd == true
+                  ? null
+                  : const LinearGradient(
+                    colors: [Color(0xFF7D46FC), Color(0xFFBC87FF)],
+                    begin: Alignment.topLeft,
+                    end: Alignment.bottomRight,
+                  ),
           color: characterInfo.isAdd == true ? const Color(0xFFEDE8FF) : null,
         ),
         child: Row(
@@ -208,9 +213,9 @@ class CustomCharacterAddView extends BaseView<CustomCharacterAddController> {
                   : StringName.characterAdd,
               style: TextStyle(
                 color:
-                characterInfo.isAdd == true
-                    ? const Color(0xFF7D46FC)
-                    : Colors.white,
+                    characterInfo.isAdd == true
+                        ? const Color(0xFF7D46FC)
+                        : Colors.white,
                 fontSize: 14.sp,
                 fontWeight: FontWeight.w500,
               ),
@@ -220,4 +225,27 @@ class CustomCharacterAddView extends BaseView<CustomCharacterAddController> {
       ),
     );
   }
+
+  Widget _buildCustomListEmpty() {
+    return Container(
+      alignment: Alignment.center,
+        child: Column(
+      children: [
+        SizedBox(height: 100.w),
+        Assets.images.iconCharacterCustomListEmpty.image(
+          width: 161.w,
+          height: 139.w,
+        ),
+        Text(
+          StringName.characterCustomListEmpty,
+          style: TextStyle(
+            color: Colors.black.withAlpha(178),
+            fontSize: 14.sp,
+            fontWeight: FontWeight.w400,
+          ),
+        ),
+
+      ],
+    ));
+  }
 }

+ 1 - 0
lib/module/change/nickname/change_nickname_page.dart

@@ -108,6 +108,7 @@ class ChangeNicknamePage extends BasePage<ChangeNicknameController> {
               style: Styles.getTextStyleBlack204W500(18.sp),
               textAlignVertical: TextAlignVertical.center,
               decoration: InputDecoration(
+                isDense: true,
                 counterText: "",
                 hintText: "请输入你的昵称",
                 hintStyle: TextStyle(

+ 32 - 5
lib/module/character/content/character_group_content_controller.dart

@@ -11,14 +11,19 @@ import 'package:keyboard/dialog/login/login_dialog.dart';
 import 'package:keyboard/module/character/character_controller.dart';
 import 'package:keyboard/module/store/store_page.dart';
 import 'package:keyboard/utils/atmob_log.dart';
+import 'package:keyboard/utils/daily_limiter_util.dart';
 import 'package:keyboard/utils/http_handler.dart';
 import 'package:keyboard/utils/toast_util.dart';
+import 'package:lottie/lottie.dart';
 
 import '../../../data/bean/character_group_info.dart';
 import '../../../data/bean/character_info.dart';
 import '../../../data/bean/keyboard_info.dart';
 import '../../../data/bean/member_info.dart';
+import '../../../resource/assets.gen.dart';
 import '../../../utils/error_handler.dart';
+import '../../store/new_discount/new_discount_page.dart';
+import '../../store/suprise/surprise_dialog.dart';
 
 @injectable
 class CharacterGroupContentController extends BaseController {
@@ -33,6 +38,8 @@ class CharacterGroupContentController extends BaseController {
 
   final AccountRepository accountRepository;
 
+  bool get isVipUser => accountRepository.isVipUser;
+
   bool get isLogin => accountRepository.isLogin.value;
 
   bool get isVip =>
@@ -40,9 +47,7 @@ class CharacterGroupContentController extends BaseController {
 
   MemberInfo? get memberStatusInfo => accountRepository.memberStatusInfo.value;
 
-
-  UserInfoResponse? get userInfo =>
-      accountRepository.userInfo.value;
+  UserInfoResponse? get userInfo => accountRepository.userInfo.value;
 
   CharacterGroupContentController(
     this.charactersRepository,
@@ -56,8 +61,9 @@ class CharacterGroupContentController extends BaseController {
   late EasyRefreshController refreshController;
 
   @override
-  void onInit() async {
+  void onInit()  {
     super.onInit();
+
     refreshController = EasyRefreshController(
       controlFinishLoad: true,
       controlFinishRefresh: true,
@@ -69,11 +75,15 @@ class CharacterGroupContentController extends BaseController {
     everAll([currentCharacterGroupInfo, currentKeyboardInfo], (_) async {
       await refreshData();
     });
+
+
   }
 
   @override
-  onReady() {
+  onReady() async {
+
     super.onReady();
+    await AssetLottie(Assets.anim.animSurpriseDialogData).load();
   }
 
   // 下拉刷新
@@ -136,6 +146,23 @@ class CharacterGroupContentController extends BaseController {
           addCharacter(characterInfo);
         }
       },
+      onDismiss: () {
+        DailyLimiterUtil.run(
+          actionKey: 'SurpriseDialog', // 唯一标识该弹窗逻辑
+          condition:
+              characterInfo.isVip == true &&
+              characterInfo.isLock == true &&
+              !isVipUser,
+          onExecute: () {
+            SurpriseDialog.show(
+              clickConfirm: () {
+                NewDiscountPage.start();
+              },
+            );
+          },
+        );
+        DailyLimiterUtil.printSavedData('SurpriseDialog');
+      },
     );
   }
 

+ 23 - 4
lib/module/character_custom/character_custom_controller.dart

@@ -46,6 +46,9 @@ class CharacterCustomController extends BaseController {
 
   CharacterCustomController(this.configRepository);
 
+  // 是否从定制历史跳过来的
+  final RxBool isSkipFromHistory = false.obs;
+
   @override
   void onInit() {
     super.onInit();
@@ -98,6 +101,12 @@ class CharacterCustomController extends BaseController {
     } else if (currentStep.value == StepType.inputName) {
       currentStep.value = StepType.characters;
     } else {
+      if (isSkipFromHistory.value) {
+        // 跳到定制历史
+        clickHistory();
+        isSkipFromHistory.value = false;
+        return;
+      }
       Get.back();
     }
   }
@@ -143,7 +152,7 @@ class CharacterCustomController extends BaseController {
   }
 
   // 名字页的下一步
-  void clickInputNameNext() {
+  Future<void> clickInputNameNext() async {
     if (currentNameValue.value.isEmpty) {
       ToastUtil.show("请输入名字");
       return;
@@ -153,11 +162,16 @@ class CharacterCustomController extends BaseController {
       return;
     }
 
-    CharacterCustomDetailPage.start(
+ await CharacterCustomDetailPage.start(
       hobbiesSelectLabels: hobbiesSelectLabels,
       characterSelectLabels: characterSelectLabels,
       characterCustomName: currentNameValue.value,
     );
+    if (isSkipFromHistory.value) {
+    //  跳到定制历史
+      clickHistory();
+      isSkipFromHistory.value = false;
+    }
   }
 
   // 处理下一步
@@ -198,9 +212,14 @@ class CharacterCustomController extends BaseController {
     );
   }
 
-  void clickHistory() {
+  Future<void> clickHistory() async {
     AtmobLog.d(tag, "clickHistory");
-    CharacterCustomListPage.start();
+    var result = await CharacterCustomListPage.start();
+    if (result != null) {
+      AtmobLog.d(tag, "clickHistory");
+      currentStep.value = result;
+      isSkipFromHistory.value = true;
+    }
   }
 
   ///标签选择处理

+ 3 - 2
lib/module/character_custom/character_custom_page.dart

@@ -14,8 +14,8 @@ import '../../widget/auto_scroll_list_view.dart';
 class CharacterCustomPage extends BasePage<CharacterCustomController> {
   const CharacterCustomPage({super.key});
 
-  static start() {
-    return Get.to(() => CharacterCustomPage());
+  static Future<void > start({StepType? step}) async {
+    return  Get.to(() => CharacterCustomPage());
   }
 
   @override
@@ -537,6 +537,7 @@ class CharacterCustomPage extends BasePage<CharacterCustomController> {
                   controller.currentNameValue.value = value;
                 },
                 decoration: InputDecoration(
+                  isDense: true,
                   counterText: "",
                   hintText: StringName.characterCustomNameHint,
                   hintStyle: TextStyle(color: Colors.black.withAlpha(66)),

+ 1 - 0
lib/module/character_custom/detail/character_custom_detail_controller.dart

@@ -316,6 +316,7 @@ class CharacterCustomDetailController extends BaseController {
       final characterCustomController = Get.find<CharacterCustomController>();
       characterCustomController.clearData();
 
+
       ToastUtil.show("生成成功");
     } catch (error) {
       if (error is ServerErrorException) {

+ 6 - 0
lib/module/character_custom/list/character_custom_list_controller.dart

@@ -6,6 +6,7 @@ import 'package:get/get.dart';
 import 'package:keyboard/data/repository/characters_repository.dart';
 import 'package:keyboard/data/repository/keyboard_repository.dart';
 import 'package:keyboard/dialog/login/login_dialog.dart';
+import 'package:keyboard/module/character_custom/character_custom_page.dart';
 import 'package:keyboard/utils/toast_util.dart';
 
 import '../../../data/bean/character_info.dart';
@@ -17,6 +18,7 @@ import '../../../resource/string.gen.dart';
 import '../../../utils/atmob_log.dart';
 import '../../../utils/error_handler.dart';
 import '../../../utils/http_handler.dart';
+import '../character_custom_controller.dart';
 import '../detail/character_custom_detail_page.dart';
 
 @injectable
@@ -177,4 +179,8 @@ class CharacterCustomListController extends BaseController {
   void clickBack() {
     Get.back();
   }
+
+  void clickStartCustom(){
+    Get.back(result: StepType.hobbies);
+  }
 }

+ 8 - 3
lib/module/character_custom/list/character_custom_list_page.dart

@@ -12,12 +12,17 @@ import 'package:keyboard/utils/styles.dart';
 import '../../../data/bean/character_info.dart';
 import '../../../resource/assets.gen.dart';
 import '../../../router/app_pages.dart';
+import '../character_custom_controller.dart';
 
 class CharacterCustomListPage extends BasePage<CharacterCustomListController> {
   const CharacterCustomListPage({super.key});
 
-  static start() {
-    Get.toNamed(RoutePath.characterCustomList);
+  static Future<StepType?> start() async {
+    final result = await Get.toNamed(RoutePath.characterCustomList);
+    if (result is StepType) {
+      return result;
+    }
+    return null;
   }
 
   @override
@@ -331,7 +336,7 @@ class CharacterCustomListPage extends BasePage<CharacterCustomListController> {
         SizedBox(height: 47.w),
         InkWell(
           onTap: () {
-            controller.clickBack();
+            controller.clickStartCustom();
           },
           child: Container(
             width: 162.w,

+ 4 - 1
lib/module/intimacy_scale/intimacy_scale_page.dart

@@ -65,7 +65,8 @@ class IntimacyScalePage extends BasePage<IntimacyScaleController> {
                                 text: controller.currentCustomIntimacy.value.toString(),
                                 style: TextStyle(
                                   color: Colors.white,
-                                  fontSize: 82.72.sp,
+                                  fontSize: 70.sp,
+                                  wordSpacing: 0,
                                   height: 0,
                                   fontWeight: FontWeight.w700,
                                   shadows: [
@@ -81,7 +82,9 @@ class IntimacyScalePage extends BasePage<IntimacyScaleController> {
                               ),
                               TextSpan(
                                 text: "%",
+
                                 style: TextStyle(
+                                  wordSpacing: 0,
                                   color: Colors.white,
                                   fontSize: 35.15.sp,
                                   fontWeight: FontWeight.w700,

+ 1 - 0
lib/module/new_user/step/nickname/step_nickname_view.dart

@@ -70,6 +70,7 @@ class StepNicknameView extends BaseView<NewUserController>{
           textAlign: TextAlign.center,
           textAlignVertical: TextAlignVertical.center,
           decoration: InputDecoration(
+            isDense: true,
             counterText: "",
             hintText: "请输入你的昵称",
             hintStyle: TextStyle(

+ 1 - 0
lib/module/new_user/step/partner/step_partner_view.dart

@@ -218,6 +218,7 @@ class StepPartnerView extends BaseView<NewUserController> {
               maxLines: 1,
               textAlignVertical: TextAlignVertical.center,
               decoration: InputDecoration(
+                isDense: true,
                 hintText: StringName.newUserNicknameTitle,
                 counterText: "",
                 hintStyle: TextStyle(

+ 1 - 0
lib/module/profile/profile_page.dart

@@ -375,6 +375,7 @@ class ProfilePage extends BasePage<ProfileController> {
               imageUrl: imageUrl,
               size: 78.w,
               borderWidth: 0.r,
+                borderColor: Colors.transparent,
               placeholder: (_, __) {
                 return const CupertinoActivityIndicator();
               },

+ 1 - 6
lib/module/store/store_controller.dart

@@ -466,7 +466,6 @@ class StoreController extends BaseController implements PaymentStatusCallback {
     super.onClose();
     _storeDataFuture?.cancel();
     paymentStatusManager.unregisterPaymentSuccessCallback(this);
-    await AssetLottie(Assets.anim.animSurpriseDialogData).load();
     if (memberStatusInfo != null && memberStatusInfo!.isMember&&isLogin) {
       return;
     }
@@ -475,11 +474,7 @@ class StoreController extends BaseController implements PaymentStatusCallback {
         NewDiscountPage.start();
       },
       clickCancel: () {
-        SurpriseDialog.show(
-          clickConfirm: () {
-            NewDiscountPage.start();
-          },
-        );
+
       },
     );
   }

+ 1 - 1
lib/module/store/suprise/surprise_dialog.dart

@@ -12,7 +12,7 @@ import '../../../widget/horizontal_dashed_line.dart';
 import '../../../widget/vertical_dots.dart';
 import 'goods_surprise_controller.dart';
 
-// 惊喜买断价弹窗
+// 限时活动 惊喜买断价弹窗
 class SurpriseDialog {
   static const String tag = 'SurpriseDialog';
 

+ 9 - 2
lib/plugins/keyboard_method_handler.dart

@@ -99,8 +99,14 @@ class KeyboardMethodHandler {
         .firstWhereOrNull((element) => element.id == keyboardId);
     if (selectedKeyboard != null) {
       if(selectedKeyboard.type == KeyboardType.custom.name) {
-        await KeyboardRepository.getInstance().keyboardChoose(keyboardId:keyboardId);
-        KeyboardRepository.getInstance().refreshData();
+        try {
+          await KeyboardRepository.getInstance().keyboardChoose(keyboardId:keyboardId);
+          KeyboardRepository.getInstance().refreshData();
+
+        } catch (error) {
+         return handleError(error);
+        }
+
       }
       KVUtil.putString(Constants.keyboardSelect, jsonEncode(selectedKeyboard.toJson()));
     }
@@ -235,6 +241,7 @@ class KeyboardMethodHandler {
       throw PlatformException(
         code: error.code.toString(),
         message: error.message,
+
         details: {'code': error.code, 'message': error.message},
       );
     } else {

+ 56 - 0
lib/utils/daily_limiter_util.dart

@@ -0,0 +1,56 @@
+
+import 'package:intl/intl.dart';
+
+import 'mmkv_util.dart';
+
+typedef LimitedAction = void Function();
+
+class DailyLimiterUtil {
+  static Future<void> run({
+    required String actionKey,
+    required bool condition,
+    required LimitedAction onExecute,
+    int maxPerDay = 3,
+  }) async {
+    if (!condition) return;
+
+    final today = DateFormat('yyyy-MM-dd').format(DateTime.now());
+    final dateKey = '${actionKey}_date';
+    final countKey = '${actionKey}_count';
+
+    final savedDate = KVUtil.getString(dateKey, '');
+    int execCount = KVUtil.getInt(countKey, 0);
+
+    if (savedDate != today) {
+      execCount = 0;
+      KVUtil.putString(dateKey, today);
+      KVUtil.putInt(countKey, execCount);
+    }
+
+    if (execCount < maxPerDay) {
+      onExecute();
+      KVUtil.putInt(countKey, execCount + 1);
+    }
+  }
+
+  static void printSavedData(String actionKey) {
+    final dateKey = '${actionKey}_date';
+    final countKey = '${actionKey}_count';
+    final savedDate = KVUtil.getString(dateKey, '');
+    final execCount = KVUtil.getInt(countKey, 0);
+
+    print("保存的日期: $savedDate");
+    print("保存的执行次数: $execCount");
+  }
+
+  // 清除指定 actionKey 的日期和执行次数数据
+  static void clearDailyLimitData(String actionKey) {
+    final dateKey = '${actionKey}_date';
+    final countKey = '${actionKey}_count';
+
+    KVUtil.putString(dateKey, null);
+    KVUtil.putInt(countKey, 0);
+
+    print("已清除 $actionKey 的日期和执行次数数据");
+  }
+}