Browse Source

[fix]修复bug

Destiny 6 months ago
parent
commit
1089d5434b

+ 1 - 0
ios/AiKeyboard/KeyboardViewController.swift

@@ -585,6 +585,7 @@ extension KeyboardViewController: KeyboardMenuViewDelegate, KeyboardExchangeView
         if responder != nil {
             let selectorOpenURL = sel_registerName("openURL:")
             if responder!.responds(to: selectorOpenURL) {
+                self.dismissKeyboard()
                 responder?.perform(selectorOpenURL, with: url)
             }
         }

+ 66 - 0
lib/data/api/atmob_api.g.dart

@@ -1512,6 +1512,72 @@ class _AtmobApi implements AtmobApi {
   }
 
   @override
+  Future<BaseResponse<dynamic>> subscribeCheck(
+    SubscribeCheckRequest request,
+  ) async {
+    final _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _headers = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    _data.addAll(request.toJson());
+    final _options = _setStreamType<BaseResponse<dynamic>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/member/subscribe/check',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<dynamic> _value;
+    try {
+      _value = BaseResponse<dynamic>.fromJson(
+        _result.data!,
+        (json) => json as dynamic,
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  @override
+  Future<BaseResponse<dynamic>> subscribeResume(
+    SubscribeResumeRequest request,
+  ) async {
+    final _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _headers = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    _data.addAll(request.toJson());
+    final _options = _setStreamType<BaseResponse<dynamic>>(
+      Options(method: 'POST', headers: _headers, extra: _extra)
+          .compose(
+            _dio.options,
+            '/project/keyboard/v1/member/subscribe/resume',
+            queryParameters: queryParameters,
+            data: _data,
+          )
+          .copyWith(baseUrl: _combineBaseUrls(_dio.options.baseUrl, baseUrl)),
+    );
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<dynamic> _value;
+    try {
+      _value = BaseResponse<dynamic>.fromJson(
+        _result.data!,
+        (json) => json as dynamic,
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  @override
   Future<BaseResponse<ZodiacLoveIntimacyLoveInfoResponse>>
   getZodiacLoveIntimacyLoveInfo(AppBaseRequest request) async {
     final _extra = <String, dynamic>{};

+ 9 - 12
lib/di/get_it.config.dart

@@ -149,9 +149,6 @@ extension GetItInjectableX on _i174.GetIt {
     gh.factory<_i248.KeyboardGuidePageController>(
       () => _i248.KeyboardGuidePageController(),
     );
-    gh.factory<_i1060.ZodiacLoveIntimacyController>(
-      () => _i1060.ZodiacLoveIntimacyController(),
-    );
     gh.factory<_i101.KeyboardTutorialVideoController>(
       () => _i101.KeyboardTutorialVideoController(),
     );
@@ -352,24 +349,24 @@ extension GetItInjectableX on _i174.GetIt {
         gh<_i274.KeyboardRepository>(),
       ),
     );
-    gh.factory<_i109.ZodiacLoveFutureWeekController>(
-      () => _i109.ZodiacLoveFutureWeekController(
-        gh<_i779.ZodiacLoveIntimacyRepository>(),
+    gh.factory<_i344.StoreController>(
+      () => _i344.StoreController(
+        gh<_i987.StoreRepository>(),
         gh<_i83.AccountRepository>(),
+        gh<_i779.PaymentStatusManager>(),
+        gh<_i442.StoreGoodsCountdownManager>(),
       ),
     );
     gh.factory<_i630.ZodiacLoveTodayController>(
       () => _i630.ZodiacLoveTodayController(
         gh<_i779.ZodiacLoveIntimacyRepository>(),
         gh<_i83.AccountRepository>(),
- 		),
+      ),
     );
-    gh.factory<_i344.StoreController>(
-      () => _i344.StoreController(
-        gh<_i987.StoreRepository>(),
+    gh.factory<_i109.ZodiacLoveFutureWeekController>(
+      () => _i109.ZodiacLoveFutureWeekController(
+        gh<_i779.ZodiacLoveIntimacyRepository>(),
         gh<_i83.AccountRepository>(),
-        gh<_i779.PaymentStatusManager>(),
-        gh<_i442.StoreGoodsCountdownManager>(),
       ),
     );
     gh.factoryParam<

+ 9 - 2
lib/module/character/character_controller.dart

@@ -58,7 +58,7 @@ class CharacterController extends BaseController
     }
     if (keyboardInfoList.isNotEmpty) {
       currentKeyboardInfo.value = keyboardInfoList.firstWhere(
-        (element) => element.isChoose == true,
+            (element) => element.isChoose == true,
         orElse: () => keyboardInfoList.first,
       );
     }
@@ -96,7 +96,14 @@ class CharacterController extends BaseController
     ever(keyboardInfoList, (value) {
       AtmobLog.d(tag, "keyboardInfoList1 changed ${keyboardInfoList.length}");
       if (value.isNotEmpty) {
-        currentKeyboardInfo.value = keyboardInfoList.first;
+        // currentKeyboardInfo.value = keyboardInfoList.first;
+
+        // 修改这里,选择isChoose为true的键盘,如果没有则选择第一个
+        currentKeyboardInfo.value = keyboardInfoList.firstWhere(
+              (element) => element.isChoose == true,
+          orElse: () => keyboardInfoList.first,
+        );
+
         print("currentKeyboardInfo.value: ${currentKeyboardInfo.value}");
       }
     });

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

@@ -144,7 +144,7 @@ class CharacterCustomPage extends BasePage<CharacterCustomController> {
             crossAxisAlignment: CrossAxisAlignment.start,
             children: [
               Padding(
-                padding: EdgeInsets.only(left: 16.w, bottom: 48.h),
+                padding: EdgeInsets.only(left: 16.w),
                 child: GestureDetector(
                   onTap: () {
                     controller.clickBack();
@@ -157,8 +157,7 @@ class CharacterCustomPage extends BasePage<CharacterCustomController> {
               ),
 
               Expanded(
-                child: SingleChildScrollView(
-                  child: Column(
+                child: Column(
                     mainAxisAlignment: MainAxisAlignment.center,
                     crossAxisAlignment: CrossAxisAlignment.center,
                     children: [
@@ -266,7 +265,6 @@ class CharacterCustomPage extends BasePage<CharacterCustomController> {
                     ],
                   ),
                 ),
-              ),
             ],
           ),
         ),
@@ -396,7 +394,7 @@ class CharacterCustomPage extends BasePage<CharacterCustomController> {
           SizedBox(height: 18.h),
           _buildCurrentSelectedLabels(selectedLabels, onSelected),
           Container(
-            margin: EdgeInsets.only(top: 107.h, bottom: 32.h),
+            margin: EdgeInsets.only(top: 44.h, bottom: 32.h),
             child: _buildNextButton(
               isEnable: selectedLabels.isNotEmpty,
               onTap: nextClick,

+ 7 - 0
lib/module/feedback/feedback_page.dart

@@ -25,6 +25,13 @@ class FeedbackPage extends BasePage<FeedbackController> {
   }
 
   @override
+  void backgroundOnTapEvent() {
+    // TODO: implement backgroundOnTapEvent
+    super.backgroundOnTapEvent();
+    FocusManager.instance.primaryFocus?.unfocus();
+  }
+
+  @override
   Color backgroundColor() => Color(0xFFF6F5FA);
 
   @override

+ 77 - 71
lib/module/keyboard/keyboard_view.dart

@@ -21,60 +21,64 @@ class KeyBoardView extends BaseView<KeyBoardController> {
 
   @override
   Widget buildBody(BuildContext context) {
-    return Stack(
-      children: [
-        IgnorePointer(
-          child: Assets.images.bgKeyboard.image(width: 360.w, fit: BoxFit.fill),
-        ),
-        SafeArea(
-          child: Stack(
-            children: [
-              Column(
-                children: [
-                  Expanded(
-                    child: SingleChildScrollView(
-                      child: Column(
-                        children: [
-                          _buildTitle(),
-                          _buildAvatarCard(),
-                          Container(height: 10.h, color: Colors.transparent),
-                          _buildLoveIndexCard(),
-                          SizedBox(height: 10.h),
-                          Container(
-                            padding: EdgeInsets.only(top: 16.h),
-                            decoration: BoxDecoration(
-                              color: Colors.white,
-                              borderRadius: BorderRadius.only(
-                                topLeft: Radius.circular(16.r),
-                                topRight: Radius.circular(16.r),
+    return Container(
+      // decoration: BoxDecoration(color: Colors.white),
+      child: Stack(
+        children: [
+          IgnorePointer(
+            child: Assets.images.bgKeyboard.image(width: 360.w, fit: BoxFit.fill),
+          ),
+          SafeArea(
+            child: Stack(
+              children: [
+                Column(
+                  children: [
+                    Expanded(
+                      child: SingleChildScrollView(
+                        physics: ClampingScrollPhysics(),
+                        child: Column(
+                          children: [
+                            _buildTitle(),
+                            _buildAvatarCard(),
+                            Container(height: 10.h, color: Colors.transparent),
+                            _buildLoveIndexCard(),
+                            SizedBox(height: 10.h),
+                            Container(
+                              padding: EdgeInsets.only(top: 16.h),
+                              decoration: BoxDecoration(
+                                color: Colors.white,
+                                borderRadius: BorderRadius.only(
+                                  topLeft: Radius.circular(16.r),
+                                  topRight: Radius.circular(16.r),
+                                ),
+                              ),
+                              child: Column(
+                                children: [
+                                  _buildHitCard(),
+                                  SizedBox(height: 10.h),
+                                  _buildKeyboardSettings(),
+                                  SizedBox(height: 90.h),
+                                ],
                               ),
                             ),
-                            child: Column(
-                              children: [
-                                _buildHitCard(),
-                                SizedBox(height: 10.h),
-                                _buildKeyboardSettings(),
-                                SizedBox(height: 90.h),
-                              ],
-                            ),
-                          ),
-                        ],
+                          ],
+                        ),
                       ),
                     ),
-                  ),
-                ],
-              ),
+                  ],
+                ),
 
-              Positioned(
-                bottom: 0,
-                left: 16.w,
-                right: 16.w,
-                child: _buildBanner(),
-              ),
-            ],
+                Positioned(
+                  bottom: 0,
+                  left: 16.w,
+                  right: 16.w,
+                  child: _buildBanner(),
+                ),
+              ],
+            ),
           ),
-        ),
-      ],
+        ],
+      ),
     );
   }
 
@@ -471,17 +475,15 @@ class KeyBoardView extends BaseView<KeyBoardController> {
                   imageProvider = Assets.images.bgKeyboardStartUsing.provider();
                 } else {
                   // 未选择为默认键盘,显示体验键盘
-                  imageProvider = Assets.images.bgKeyboardTryExperience.provider();
+                  imageProvider =
+                      Assets.images.bgKeyboardTryExperience.provider();
                 }
                 return GestureDetector(
                   onTap: controller.clickEasyReply,
                   child: SizedBox(
                     width: 170.w,
                     height: 155.85.w,
-                    child: Image(
-                      image: imageProvider,
-                      fit: BoxFit.contain,
-                    ),
+                    child: Image(image: imageProvider, fit: BoxFit.contain),
                   ),
                 );
               }),
@@ -644,30 +646,34 @@ class KeyBoardView extends BaseView<KeyBoardController> {
             children: [
               Positioned(
                 top: 20.h,
-                child: Visibility( visible: isNotHWChannel(),replacement:Assets.images.iconKeyboardBannerNoCountdown.image(
-                  width: 328.w,
-                  height: 64.h,
-                ) ,child: Assets.images.iconKeyboardBanner.image(
-                  width: 328.w,
-                  height: 64.h,
-                ),)
+                child: Visibility(
+                  visible: isNotHWChannel(),
+                  replacement: Assets.images.iconKeyboardBannerNoCountdown
+                      .image(width: 328.w, height: 64.h),
+                  child: Assets.images.iconKeyboardBanner.image(
+                    width: 328.w,
+                    height: 64.h,
+                  ),
+                ),
               ),
               Visibility(
                 visible: isNotHWChannel(),
-                child:   Positioned(
-                right: 53.w,
-                bottom: 18.h,
-                child: Obx(
-                      () => Text(
-                    controller.formattedTime,
-                    style: TextStyle(
-                      color: Colors.white,
-                      fontSize: 12.sp,
-                      fontWeight: FontWeight.w500,
+                child: Positioned(
+                  width: 60.w,
+                  right: 43.w,
+                  bottom: 18.h,
+                  child: Obx(
+                    () => Text(
+                      controller.formattedTime,
+                      style: TextStyle(
+                        color: Colors.white,
+                        fontSize: 12.sp,
+                        fontWeight: FontWeight.w500,
+                      ),
                     ),
                   ),
                 ),
-              ),),
+              ),
 
               Positioned(
                 right: 6.w,

+ 4 - 7
lib/module/new_user/result/new_user_result_page.dart

@@ -63,12 +63,11 @@ class NewUserResultPage extends BasePage<NewUserResultController> {
                 ),
               ),
               Expanded(
-                child: SingleChildScrollView(
-                  child: Column(
-                    mainAxisAlignment: MainAxisAlignment.center,
+                child: Column(
+                    mainAxisAlignment: MainAxisAlignment.end,
                     crossAxisAlignment: CrossAxisAlignment.center,
                     children: [
-                      SizedBox(height: 30.w),
+                      // SizedBox(height: 30.w),
                       Center(
                         child: Assets.images.iconNewUserResultTitle.image(
                           width: 246.w,
@@ -82,13 +81,11 @@ class NewUserResultPage extends BasePage<NewUserResultController> {
                       _buildZodiacDesc(),
                       SizedBox(height: 20.w),
                       buildCharacterList(),
-                      SizedBox(height: 70.w),
+                      SizedBox(height: 30.w),
                       buildOpenNowButton(),
-
                     ],
                   ),
                 ),
-              ),
             ],
           ),
         ),

+ 0 - 136
lib/module/store/new_discount/new_discount_controller.dart

@@ -659,140 +659,4 @@ class NewDiscountController extends BaseController
     //   ToastUtil.show("Restore fail");
     // }
   }
-
-  /// 恢复订阅
-  Future<void> clickRestore() async {
-    PayWayInfo? paymentWay = _selectedPayWay.value;
-    if (paymentWay == null) {
-      return;
-    }
-    int payPlatform = paymentWay.payPlatform;
-    int payMethod = paymentWay.payMethod;
-
-    CustomLoadingDialog.show();
-
-    Future.delayed(const Duration(seconds: 20), () {
-      CustomLoadingDialog.hide();
-      ToastUtil.show("Restore record not found");
-    });
-
-    final result = await ApplePay().restore();
-    if (result["success"] == true) {
-      // CustomLoadingDialog.hide();
-      var receipt = result['receipt'];
-      print('查找恢复记录成功: ${result['receipt']}');
-      checkRestoreStatus(receipt);
-    } else {
-      CustomLoadingDialog.hide();
-      ToastUtil.show("Pay Error");
-      print('恢复失败: ${result['error']}');
-    }
-
-    // 显示恢复订阅弹窗
-    // RecoverSubscribeDialog.show("周会员2025年3月6日到期。", () {
-    //   AtmobLog.d(tag, "恢复订阅弹窗 => 点击确认");
-    // });
-  }
-
-  /// 检查恢复订阅结果
-  Future<void> checkRestoreStatus(String? receiptData) async {
-    PayWayInfo? paymentWay = _selectedPayWay.value;
-    if (paymentWay == null) {
-      // ToastUtil.showToast(StringName.storeChoicePayment.tr);
-      return;
-    }
-    if (receiptData == null) {
-      return;
-    }
-    int payPlatform = paymentWay.payPlatform;
-    int payMethod = paymentWay.payMethod;
-    // var code = await storeRepository.resume(payPlatform, payMethod, receiptData);
-    storeRepository.subscribeResume(payPlatform, payMethod, receiptData).then((data) {
-      CustomLoadingDialog.hide();
-      ToastUtil.show("Restore success");
-      accountRepository.getUserInfo();
-      Get.back();
-    }).catchError((error) {
-      CustomLoadingDialog.hide();
-      ToastUtil.show("Restore fail");
-    });
-
-    // if (code == 0) {
-    //   CustomLoadingDialog.hide();
-    //   ToastUtil.show("Restore success");
-    //   userRepository.getUserInfo();
-    //   Get.back();
-    // } else {
-    //   CustomLoadingDialog.hide();
-    //   ToastUtil.show("Restore fail");
-    // }
-  }
-
-  /// 恢复订阅
-  Future<void> clickRestore() async {
-    PayWayInfo? paymentWay = _selectedPayWay.value;
-    if (paymentWay == null) {
-      return;
-    }
-    int payPlatform = paymentWay.payPlatform;
-    int payMethod = paymentWay.payMethod;
-
-    CustomLoadingDialog.show();
-
-    Future.delayed(const Duration(seconds: 20), () {
-      CustomLoadingDialog.hide();
-      ToastUtil.show("Restore record not found");
-    });
-
-    final result = await ApplePay().restore();
-    if (result["success"] == true) {
-      // CustomLoadingDialog.hide();
-      var receipt = result['receipt'];
-      print('查找恢复记录成功: ${result['receipt']}');
-      checkRestoreStatus(receipt);
-    } else {
-      CustomLoadingDialog.hide();
-      ToastUtil.show("Pay Error");
-      print('恢复失败: ${result['error']}');
-    }
-
-    // 显示恢复订阅弹窗
-    // RecoverSubscribeDialog.show("周会员2025年3月6日到期。", () {
-    //   AtmobLog.d(tag, "恢复订阅弹窗 => 点击确认");
-    // });
-  }
-
-  /// 检查恢复订阅结果
-  Future<void> checkRestoreStatus(String? receiptData) async {
-    PayWayInfo? paymentWay = _selectedPayWay.value;
-    if (paymentWay == null) {
-      // ToastUtil.showToast(StringName.storeChoicePayment.tr);
-      return;
-    }
-    if (receiptData == null) {
-      return;
-    }
-    int payPlatform = paymentWay.payPlatform;
-    int payMethod = paymentWay.payMethod;
-    // var code = await storeRepository.resume(payPlatform, payMethod, receiptData);
-    storeRepository.subscribeResume(payPlatform, payMethod, receiptData).then((data) {
-      CustomLoadingDialog.hide();
-      ToastUtil.show("Restore success");
-      accountRepository.getUserInfo();
-      Get.back();
-    }).catchError((error) {
-      CustomLoadingDialog.hide();
-      ToastUtil.show("Restore fail");
-    });
-
-    // if (code == 0) {
-    //   CustomLoadingDialog.hide();
-    //   ToastUtil.show("Restore success");
-    //   userRepository.getUserInfo();
-    //   Get.back();
-    // } else {
-    //   CustomLoadingDialog.hide();
-    //   ToastUtil.show("Restore fail");
-    // }
-  }
 }

+ 1 - 1
lib/module/store/new_discount/new_discount_page.dart

@@ -748,7 +748,7 @@ class NewDiscountPage extends BasePage<NewDiscountController> {
                     ),
                   ),
                   ClickTextSpan(
-                    text: StringName.textSpanMemberAgreement,
+                    text: StringName.textSpanMembershipAgreement,
                     url: WebUrl.subscribeAgreement,
                   ),
                 ],

+ 1 - 67
lib/module/store/store_page.dart

@@ -1035,72 +1035,6 @@ class StorePage extends BasePage<StoreController> {
     );
   }
 
-  /// 恢复订阅
-  Widget _buildRecoverSubscribe() {
-    return Container(
-      margin: EdgeInsets.only(left: 16.w, top: 8.h, right: 16.w),
-      child: Row(
-        children: [
-          Text(
-            "⚠️  订阅未生效?点此试试",
-            style: TextStyle(
-              color: Color(0xFF666355),
-              fontSize: 13.sp,
-              fontWeight: FontWeight.w400,
-            ),
-          ),
-          GestureDetector(
-            onTap: () {
-              // 恢复订阅
-              controller.clickRecoverSubscribe();
-            },
-            child: Text(
-              "  恢复订阅>",
-              style: TextStyle(
-                color: Color(0xFF479DF7),
-                fontSize: 13.sp,
-                fontWeight: FontWeight.w400,
-              ),
-            ),
-          ),
-        ],
-      ),
-    );
-  }
-
-  /// 恢复订阅
-  Widget _buildRecoverSubscribe() {
-    return Container(
-      margin: EdgeInsets.only(left: 16.w, top: 8.h, right: 16.w),
-      child: Row(
-        children: [
-          Text(
-            "⚠️  订阅未生效?点此试试",
-            style: TextStyle(
-              color: Color(0xFF666355),
-              fontSize: 13.sp,
-              fontWeight: FontWeight.w400,
-            ),
-          ),
-          GestureDetector(
-            onTap: () {
-              // 恢复订阅
-              controller.clickRecoverSubscribe();
-            },
-            child: Text(
-              "  恢复订阅>",
-              style: TextStyle(
-                color: Color(0xFF479DF7),
-                fontSize: 13.sp,
-                fontWeight: FontWeight.w400,
-              ),
-            ),
-          ),
-        ],
-      ),
-    );
-  }
-
   Widget _buildBuyButtonCard() {
     return Container(
       width: 360.w,
@@ -1232,7 +1166,7 @@ class StorePage extends BasePage<StoreController> {
                       ),
                     ),
                     ClickTextSpan(
-                      text: StringName.textSpanMemberAgreement,
+                      text: StringName.textSpanMembershipAgreement,
                       url: WebUrl.subscribeAgreement,
                       color: privacyColor,
                     ),

+ 2 - 4
lib/resource/string.gen.dart

@@ -133,11 +133,10 @@ class StringName {
   static final String textSpanPrivacyPolicy = 'text_span_privacy_policy'.tr; // 《隐私政策》
   static final String textSpanServiceTerms = 'text_span_service_terms'.tr; // 《服务条款》
   static final String textSpanUserAgreement = 'text_span_user_agreement'.tr; // 《用户协议》
-  static final String textSpanMemberAgreement = 'text_span_member_agreement'.tr; // 《会员服务协议》
+  static final String textSpanMembershipAgreement = 'text_span_membership_agreement'.tr; // 《会员服务协议》
   static final String recoverSubscribe = 'recover_subscribe'.tr; // 恢复订阅
   static final String recoverSubscribeTitle = 'recover_subscribe_title'.tr; // 已恢复订阅
   static final String recoverSubscribeConfirm = 'recover_subscribe_confirm'.tr; // 知道了
-  static final String textSpanMembershipAgreement = 'text_span_membership_agreement'.tr; // 《会员服务协议》
   static final String memberContinuePay = 'member_continue_pay'.tr; // 继续支付
   static final String memberPleaseChoiceGoods = 'member_please_choice_goods'.tr; // 请选择支付商品
   static final String memberPleaseChoicePayment = 'member_please_choice_payment'.tr; // 请选择支付方式
@@ -496,11 +495,10 @@ class StringMultiSource {
       'text_span_privacy_policy': '《隐私政策》',
       'text_span_service_terms': '《服务条款》',
       'text_span_user_agreement': '《用户协议》',
-      'text_span_member_agreement': '《会员服务协议》',
+      'text_span_membership_agreement': '《会员服务协议》',
       'recover_subscribe': '恢复订阅',
       'recover_subscribe_title': '已恢复订阅',
       'recover_subscribe_confirm': '知道了',
-      'text_span_membership_agreement': '《会员服务协议》',
       'member_continue_pay': '继续支付',
       'member_please_choice_goods': '请选择支付商品',
       'member_please_choice_payment': '请选择支付方式',

+ 1 - 1
lib/utils/count_down_timer.dart

@@ -89,7 +89,7 @@ class CountdownTimer {
   /// 格式化时间,格式:分:秒:毫秒
   static String format(Duration duration) {
     String twoDigits(int n) => n.toString().padLeft(2, '0');
-    String threeDigits(int n) => n.toString().padLeft(3, '0');
+    String threeDigits(int n) => n.toString().padLeft(2, '0').substring(0, 2);
 
     return "${twoDigits(duration.inMinutes)}:"
         "${twoDigits(duration.inSeconds % 60)}:"