소스 검색

[feat]完成挽回页UI和修复部分问题

Destiny 1 년 전
부모
커밋
4b880d679b

BIN
assets/images/icon_discount_percent.webp


BIN
assets/images/icon_discount_title.webp


+ 21 - 16
lib/data/bean/store_item.dart

@@ -1,5 +1,3 @@
-
-
 import 'package:clean/utils/expand.dart';
 import 'package:json_annotation/json_annotation.dart';
 
@@ -26,22 +24,29 @@ class StoreItem {
   @JsonKey(name: "subscriptionMillis")
   late int subscriptionMillis;
   @JsonKey(name: "priceDesc")
-  late String priceDesc;
+  late String? priceDesc;
+  @JsonKey(name: "freeTrialPriceDesc")
+  late String? freeTrialPriceDesc;
+  @JsonKey(name: "freeTrialName")
+  late String? freeTrialName;
   @JsonKey(name: "coefficient")
   late int coefficient;
 
-  StoreItem(
-      {required this.id,
-        required this.sort,
-        required this.name,
-        required this.appleGoodsId,
-        required this.subscribable,
-        required this.amount,
-        required this.originalAmount,
-        required this.auth,
-        required this.subscriptionMillis,
-        required this.priceDesc,
-        required this.coefficient});
+  StoreItem({
+    required this.id,
+    required this.sort,
+    required this.name,
+    required this.appleGoodsId,
+    required this.subscribable,
+    required this.amount,
+    required this.originalAmount,
+    required this.auth,
+    required this.subscriptionMillis,
+    required this.priceDesc,
+    required this.coefficient,
+    this.freeTrialName,
+    this.freeTrialPriceDesc,
+  });
 
   get amountText => (amount / 100).toFormattedString(2);
 
@@ -49,4 +54,4 @@ class StoreItem {
 
   factory StoreItem.fromJson(Map<String, dynamic> json) =>
       _$StoreItemFromJson(json);
-}
+}

+ 74 - 73
lib/dialog/privacy_dialog.dart

@@ -31,7 +31,7 @@ void privacyDialog({required Function onAgree, required Function onDisagree}) {
                           SmartDialog.dismiss(tag: tag);
                         },
                         child: Container(
-                          margin: EdgeInsets.only(left: 16.w, top: 16.h),
+                          margin: EdgeInsets.only(left: 16.w),
                           width: 28.w,
                           height: 28.w,
                           decoration: ShapeDecoration(
@@ -47,82 +47,82 @@ void privacyDialog({required Function onAgree, required Function onDisagree}) {
                     SizedBox(
                       height: 45.h,
                     ),
-                    Column(
-                      crossAxisAlignment: CrossAxisAlignment.center,
-                      mainAxisAlignment: MainAxisAlignment.center,
-                      children: [
-                        SizedBox(
-                          width: 245.w,
-                          child: Text(
-                            'Clean up your iphone and free up storage',
-                            textAlign: TextAlign.center,
-                            style: TextStyle(
-                              color: Colors.white,
-                              fontSize: 24.sp,
-                              fontWeight: FontWeight.w500,
-                              height: 1.25.h,
+                    Expanded(
+                      child: Column(
+                        crossAxisAlignment: CrossAxisAlignment.center,
+                        mainAxisAlignment: MainAxisAlignment.center,
+                        children: [
+                          SizedBox(
+                            width: 245.w,
+                            child: Text(
+                              'Clean up your iphone and free up storage',
+                              textAlign: TextAlign.center,
+                              style: TextStyle(
+                                color: Colors.white,
+                                fontSize: 24.sp,
+                                fontWeight: FontWeight.w500,
+                                height: 1.25.h,
+                              ),
                             ),
                           ),
-                        ),
-                        // SizedBox(
-                        //     child: Lottie.asset(
-                        //   Assets.anim.animPrivacy,
-                        //   height: 412.w,
-                        //   repeat: true,
-                        // )),
-                        SizedBox(
-                          height: 8,
-                        ),
-                        Text(
-                          'CleanPro values your privacy. By starting, you agree to ',
-                          style: TextStyle(
-                            color: Colors.white.withValues(alpha: 0.8),
-                            fontSize: 12.sp,
-                            fontWeight: FontWeight.w400,
-                            height: 1.50.h,
+                          SizedBox(
+                            child: Lottie.asset(
+                              Assets.anim.animPrivacy,
+                              height: 412.h,
+                              repeat: true,
+                            ),
+                          ),
+                          SizedBox(
+                            height: 8,
+                          ),
+                          Text(
+                            'CleanPro values your privacy. By starting, you agree to ',
+                            style: TextStyle(
+                              color: Colors.white.withValues(alpha: 0.8),
+                              fontSize: 12.sp,
+                              fontWeight: FontWeight.w400,
+                              height: 1.50.h,
+                            ),
                           ),
-                        ),
-                        Text.rich(
-                          TextSpan(
-                            children: [
-                              TextSpan(
-                                text: 'our ',
-                                style: TextStyle(
-                                  color: Colors.white.withValues(alpha: 0.8),
-                                  fontSize: 12.sp,
-                                  fontWeight: FontWeight.w400,
-                                  height: 2.50.h,
+                          Text.rich(
+                            TextSpan(
+                              children: [
+                                TextSpan(
+                                  text: 'our ',
+                                  style: TextStyle(
+                                    color: Colors.white.withValues(alpha: 0.8),
+                                    fontSize: 12.sp,
+                                    fontWeight: FontWeight.w400,
+                                    height: 2.50.h,
+                                  ),
                                 ),
-                              ),
-                              buildLinkText(
-                                  'Privacy Policy', Constants.privacyPolicy),
-                              TextSpan(
-                                text: ' and ',
-                                style: TextStyle(
-                                  color: Colors.white.withValues(alpha: 0.8),
-                                  fontSize: 12.sp,
-                                  fontWeight: FontWeight.w400,
-                                  height: 2.50.h,
+                                buildLinkText(
+                                    'Privacy Policy', Constants.privacyPolicy),
+                                TextSpan(
+                                  text: ' and ',
+                                  style: TextStyle(
+                                    color: Colors.white.withValues(alpha: 0.8),
+                                    fontSize: 12.sp,
+                                    fontWeight: FontWeight.w400,
+                                    height: 2.50.h,
+                                  ),
                                 ),
-                              ),
-                              buildLinkText(
-                                  'Terms of Service', Constants.userAgreement),
-                              TextSpan(
-                                text: '.',
-                                style: TextStyle(
-                                  color: Colors.white,
-                                  fontSize: 12.sp,
-                                  fontWeight: FontWeight.w400,
-                                  height: 2.50.h,
+                                buildLinkText('Terms of Service',
+                                    Constants.userAgreement),
+                                TextSpan(
+                                  text: '.',
+                                  style: TextStyle(
+                                    color: Colors.white,
+                                    fontSize: 12.sp,
+                                    fontWeight: FontWeight.w400,
+                                    height: 2.50.h,
+                                  ),
                                 ),
-                              ),
-                            ],
+                              ],
+                            ),
                           ),
-                        ),
-                        SizedBox(
-                          height: 8.h,
-                        ),
-                        GestureDetector(
+                          Spacer(),
+                          GestureDetector(
                             onTap: () {
                               onAgree();
                               SmartDialog.dismiss(tag: tag);
@@ -146,8 +146,10 @@ void privacyDialog({required Function onAgree, required Function onDisagree}) {
                                   ),
                                 ),
                               ),
-                            )),
-                      ],
+                            ),
+                          ),
+                        ],
+                      ),
                     ),
                   ],
                 ),
@@ -155,7 +157,6 @@ void privacyDialog({required Function onAgree, required Function onDisagree}) {
               IgnorePointer(
                 child: Assets.images.bgPhotoSelectedPreviewFinish.image(
                   width: 360.w,
-                  height: 335.h,
                 ),
               ),
             ],

+ 1 - 1
lib/module/home/home_view.dart

@@ -72,7 +72,7 @@ class HomePage extends BaseView<HomeController> {
           ),
           GestureDetector(
             onTap: () {
-              Get.toNamed(RoutePath.store);
+              Get.toNamed(RoutePath.discount);
             },
             child: Assets.images.iconHomeTitleVip
                 .image(width: 60.8.w, height: 20.h),

+ 107 - 0
lib/module/store/discount/count_down_timer.dart

@@ -0,0 +1,107 @@
+import 'dart:async';
+
+import 'package:clean/utils/expand.dart';
+import 'package:flutter/Material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+
+class CountdownTimer extends StatefulWidget {
+  final Duration duration;
+
+  const CountdownTimer({super.key, required this.duration});
+
+  @override
+  State<CountdownTimer> createState() => _CountdownTimerState();
+}
+
+class _CountdownTimerState extends State<CountdownTimer> {
+  late Timer _timer;
+  late Duration _remainingTime;
+
+  @override
+  void initState() {
+    super.initState();
+    _remainingTime = widget.duration;
+    _startTimer();
+  }
+
+  void _startTimer() {
+    // 使用16毫秒的间隔来更新UI,确保毫秒的显示更流畅
+    _timer = Timer.periodic(const Duration(milliseconds: 16), (timer) {
+      setState(() {
+        if (_remainingTime.inMilliseconds <= 0) {
+          _timer.cancel();
+        } else {
+          _remainingTime = _remainingTime - const Duration(milliseconds: 16);
+        }
+      });
+    });
+  }
+
+  @override
+  void dispose() {
+    _timer.cancel();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    // 计算分、秒、毫秒
+    int minutes = _remainingTime.inMinutes;
+    int seconds = (_remainingTime.inSeconds % 60);
+    int milliseconds = (_remainingTime.inMilliseconds % 1000) ~/ 10; // 取前两位
+
+    return Row(
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        _buildTimeBox(minutes.toString().padLeft(2, '0')),
+        SizedBox(width: 10.w),
+        _buildSeparator(),
+        SizedBox(width: 10.w),
+        _buildTimeBox(seconds.toString().padLeft(2, '0')),
+        SizedBox(width: 10.w),
+        _buildSeparator(),
+        SizedBox(width: 10.w),
+        _buildTimeBox(milliseconds.toString().padLeft(2, '0')),
+      ],
+    );
+  }
+
+  Widget _buildTimeBox(String value) {
+    return Container(
+      width: 60.w,
+      height: 60.w,
+      decoration: BoxDecoration(
+        color: Colors.black,
+        borderRadius: BorderRadius.circular(12.r),
+        border: Border.all(
+          color: "#343947".color,
+          width: 1.w,
+        ),
+      ),
+      child: Center(
+        child: Text(
+          value,
+          style: TextStyle(
+            color: Colors.white,
+            fontSize: 32.sp,
+            fontWeight: FontWeight.bold,
+          ),
+        ),
+      ),
+    );
+  }
+
+  Widget _buildSeparator() {
+    return Padding(
+      padding: EdgeInsets.symmetric(horizontal: 8),
+      child: Text(
+        ':',
+        style: TextStyle(
+          color: "#343947".color,
+          fontSize: 32.sp,
+          fontWeight: FontWeight.bold,
+        ),
+      ),
+    );
+  }
+}

+ 5 - 0
lib/module/store/discount/discount_controller.dart

@@ -0,0 +1,5 @@
+import 'package:clean/base/base_controller.dart';
+
+class DiscountController extends BaseController {
+
+}

+ 162 - 0
lib/module/store/discount/discount_view.dart

@@ -0,0 +1,162 @@
+import 'dart:async';
+
+import 'package:clean/base/base_page.dart';
+import 'package:clean/module/store/discount/discount_controller.dart';
+import 'package:clean/utils/expand.dart';
+import 'package:flutter/Material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+
+import '../../../resource/assets.gen.dart';
+import 'count_down_timer.dart';
+
+class DiscountPage extends BasePage<DiscountController> {
+  const DiscountPage({super.key});
+
+  @override
+  bool immersive() {
+    return true;
+  }
+
+  @override
+  bool statusBarDarkFont() => false;
+
+  @override
+  Widget buildBody(BuildContext context) {
+    return Scaffold(
+      backgroundColor: "#05050D".color,
+      body: Stack(
+        children: [
+          // IgnorePointer(
+          //   child: Assets.images.bgStore.image(
+          //     width: 360.w,
+          //   ),
+          // ),
+          SafeArea(
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                Row(
+                  children: [
+                    Container(
+                      margin: EdgeInsets.only(left: 16.w, top: 14.h),
+                      child: GestureDetector(
+                        onTap: () {
+                          Get.back();
+                        },
+                        child: Assets.images.iconStoreClose
+                            .image(width: 28.w, height: 28.w),
+                      ),
+                    ),
+                  ],
+                ),
+                Assets.images.iconDiscountTitle
+                    .image(width: 259.w, height: 55.h),
+                SizedBox(
+                  height: 20.h,
+                ),
+                Assets.images.iconDiscountPercent
+                    .image(width: 195.w, height: 86.h),
+                SizedBox(
+                  height: 13.h,
+                ),
+                Container(
+                  width: 197.w,
+                  height: 32.h,
+                  padding: EdgeInsets.all(1.w),
+                  decoration: BoxDecoration(
+                    gradient: LinearGradient(
+                      begin: Alignment.topCenter,
+                      end: Alignment.bottomCenter,
+                      colors: [
+                        '#CF9EFD'.color,
+                        '#4DCFFF'.color.withOpacity(0.5),
+                      ],
+                    ),
+                    borderRadius: BorderRadius.all(Radius.circular(18.r)),
+                  ),
+                  child: Container(
+                    decoration: BoxDecoration(
+                      color: "#05050D".color,
+                      borderRadius: BorderRadius.all(Radius.circular(18.r)),
+                    ),
+                    child: Center(
+                      child: Text(
+                        "Get CleanPro Premium",
+                        style: TextStyle(
+                          color: Colors.white,
+                          fontSize: 15.sp,
+                          fontWeight: FontWeight.w700,
+                        ),
+                      ),
+                    ),
+                  ),
+                ),
+                SizedBox(
+                  height: 26.h,
+                ),
+                // 创建一个1分钟的倒计时
+                CountdownTimer(duration: const Duration(minutes: 1)),
+                Spacer(),
+                Text(
+                  "3-Day Free Trial",
+                  style: TextStyle(
+                    color: Colors.white,
+                    fontSize: 16.sp,
+                    fontWeight: FontWeight.w500,
+                  ),
+                ),
+                Text(
+                  "Then \$69.99",
+                  style: TextStyle(
+                    color: Colors.white,
+                    fontSize: 13.sp,
+                  ),
+                ),
+                SizedBox(
+                  height: 14.h,
+                ),
+                GestureDetector(
+                  onTap: () {
+                    // controller.onBuyClick();
+                  },
+                  child: Container(
+                    width: 312.w,
+                    height: 48.h,
+                    decoration: BoxDecoration(
+                      color: "#0279FB".color,
+                      borderRadius: BorderRadius.all(
+                        Radius.circular(24.r),
+                      ),
+                    ),
+                    child: Center(
+                      child: Text(
+                        "START FREE TRIAL",
+                        style: TextStyle(
+                          color: Colors.white,
+                          fontWeight: FontWeight.w700,
+                          fontSize: 16.sp,
+                        ),
+                      ),
+                    ),
+                  ),
+                ),
+                SizedBox(
+                  height: 5.h,
+                ),
+                Text(
+                  "No payment now!",
+                  style: TextStyle(
+                    color: "#57C87A".color,
+                    fontSize: 12.sp,
+                    fontWeight: FontWeight.w500,
+                  ),
+                ),
+              ],
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 13 - 5
lib/module/store/store_controller.dart

@@ -30,19 +30,18 @@ class StoreController extends BaseController implements PaymentStatusCallback {
 
   final Rxn<PaymentWay> currentSelectedPaymentWay = Rxn<PaymentWay>();
 
-  RxBool isUseFree = false.obs;
+  var freeAppleId = "";
+
+  RxBool isFree = false.obs;
 
   @override
   Future<void> onInit() async {
 
     initStoreIndexData();
-    isUseFree.value = await ClassifyPhoto().checkTrialEligibility();
-
-    ApplePay().check();
   }
 
   void initStoreIndexData() {
-    storeRepository.storeIndex().then((indexData) {
+    storeRepository.storeIndex().then((indexData) async {
       storeItems.clear();
       storeItems.addAll(indexData.items);
       currentSelectedStoreItem.value =
@@ -52,6 +51,15 @@ class StoreController extends BaseController implements PaymentStatusCallback {
       paymentWays.addAll(indexData.paymentWays);
       currentSelectedPaymentWay.value =
       paymentWays.isNotEmpty ? paymentWays.first : null;
+
+      var freeAppleId = "";
+      for (var item in storeItems) {
+        if (item.freeTrialName != null) {
+          freeAppleId = item.appleGoodsId;
+        }
+      }
+
+      isFree.value = await ApplePay().check(freeAppleId);
     });
   }
 

+ 33 - 29
lib/module/store/store_view.dart

@@ -47,7 +47,7 @@ class StorePage extends BasePage<StoreController> {
                         onTap: () {
                           Get.back();
                         },
-                        child: Assets.images.iconCommonBack
+                        child: Assets.images.iconStoreClose
                             .image(width: 28.w, height: 28.w),
                       ),
                     ),
@@ -179,19 +179,19 @@ class StorePage extends BasePage<StoreController> {
                   height: 5.h,
                 ),
                 Center(
-                  child: Container(
-                    width: 312.w,
-                    height: 48.h,
-                    decoration: BoxDecoration(
-                      color: "#0279FB".color,
-                      borderRadius: BorderRadius.all(
-                        Radius.circular(24.r),
+                  child: GestureDetector(
+                    onTap: () {
+                      controller.onBuyClick();
+                    },
+                    child: Container(
+                      width: 312.w,
+                      height: 48.h,
+                      decoration: BoxDecoration(
+                        color: "#0279FB".color,
+                        borderRadius: BorderRadius.all(
+                          Radius.circular(24.r),
+                        ),
                       ),
-                    ),
-                    child: GestureDetector(
-                      onTap: () {
-                        controller.onBuyClick();
-                      },
                       child: Center(
                         child: Text(
                           "CONTINUE",
@@ -278,17 +278,14 @@ class StorePage extends BasePage<StoreController> {
     required StoreItem item,
   }) {
     bool isSelected = controller.currentSelectedStoreItem.value?.id == item.id;
+    bool isFreeItem = (item.freeTrialName != null);
     final formatter = NumberFormat.currency(
       symbol: '\$',
       decimalDigits: 2,
     );
     var amount = formatter.format(item.amount / 100);
-
-    var content = "{totalPrice}, only {dailyPrice} per day";
-    content = content.replaceAll("{totalPrice}", "\$${item.amount / 100}");
-    content = content.replaceAll("{dailyPrice}",
-        "\$${(item.amount / 100 / item.coefficient).toStringAsFixed(2)}");
     return Obx(() {
+      bool isShowFree = isFreeItem && controller.isFree.value;
       return Container(
         height: 80.h,
         margin: EdgeInsets.symmetric(horizontal: 20.w),
@@ -338,7 +335,7 @@ class StorePage extends BasePage<StoreController> {
                       children: [
                         Padding(
                           padding: EdgeInsets.only(
-                              left: 12.w, top: 10.h, bottom: 12.h, right: 20.w),
+                              left: 12.w, top: 10.h, bottom: 12.h, right: 12.w),
                           child: Row(
                             mainAxisAlignment: MainAxisAlignment.spaceBetween,
                             children: [
@@ -348,7 +345,9 @@ class StorePage extends BasePage<StoreController> {
                                 crossAxisAlignment: CrossAxisAlignment.start,
                                 children: [
                                   Text(
-                                    item.name,
+                                    isShowFree
+                                        ? item.freeTrialName ?? ""
+                                        : item.name,
                                     style: TextStyle(
                                       color: Colors.white,
                                       fontSize: 16.sp,
@@ -356,7 +355,9 @@ class StorePage extends BasePage<StoreController> {
                                     ),
                                   ),
                                   Text(
-                                    content,
+                                    isShowFree
+                                        ? item.freeTrialPriceDesc ?? ""
+                                        : item.priceDesc ?? "",
                                     style: TextStyle(
                                       color: Colors.white60,
                                       fontSize: 12.sp,
@@ -364,12 +365,15 @@ class StorePage extends BasePage<StoreController> {
                                   ),
                                 ],
                               ),
-                              Text(
-                                amount,
-                                style: TextStyle(
-                                  color: Colors.white,
-                                  fontSize: 16.sp,
-                                  fontWeight: FontWeight.bold,
+                              Visibility(
+                                visible: !isShowFree,
+                                child: Text(
+                                  amount,
+                                  style: TextStyle(
+                                    color: Colors.white,
+                                    fontSize: 16.sp,
+                                    fontWeight: FontWeight.bold,
+                                  ),
                                 ),
                               ),
                             ],
@@ -414,9 +418,9 @@ class StorePage extends BasePage<StoreController> {
                 ),
               ),
             ),
-            if (false)
+            if (isShowFree)
               Positioned(
-                right: 120.w,
+                right: 110.w,
                 top: 0.h,
                 child: Assets.images.iconStoreFree
                     .image(width: 30.w, height: 28.h),

+ 14 - 9
lib/router/app_pages.dart

@@ -22,6 +22,8 @@ import 'package:clean/module/similar_photo/similar_photo_controller.dart';
 import 'package:clean/module/similar_photo/similar_photo_view.dart';
 import 'package:clean/module/splash/intro/intro_controller.dart';
 import 'package:clean/module/splash/intro/intro_view.dart';
+import 'package:clean/module/store/discount/discount_controller.dart';
+import 'package:clean/module/store/discount/discount_view.dart';
 import 'package:clean/module/store/store_controller.dart';
 import 'package:clean/module/store/store_view.dart';
 import 'package:clean/module/splash/splash_controller.dart';
@@ -44,7 +46,6 @@ abstract class AppPage {
 }
 
 abstract class RoutePath {
-
   static const browser = '/browser';
   static const mainTab = '/mainTab';
   static const privacy = '/privacy';
@@ -54,6 +55,7 @@ abstract class RoutePath {
   static const screenshots = '/screenshots';
   static const photoInfo = '/photoInfo';
   static const store = '/store';
+  static const discount = '/discount';
   static const photoPreview = '/photoPreview';
   static const locationsSinglePhoto = '/locationsSinglePhoto';
   static const setting = '/setting';
@@ -79,21 +81,19 @@ class AppBinding extends Bindings {
 
     lazyPut(() => PhotoInfoController());
     lazyPut(() => StoreController());
+    lazyPut(() => DiscountController());
     lazyPut(() => LocationsSinglePhotoController());
     lazyPut(() => SettingController());
     lazyPut(() => AnalysisController());
     lazyPut(() => PhotoSelectedPreviewController());
-    lazyPut(()=>SplashController());
-    lazyPut(()=>WallPaperController());
-    lazyPut(()=>IntroController());
+    lazyPut(() => SplashController());
+    lazyPut(() => WallPaperController());
+    lazyPut(() => IntroController());
   }
 
   void lazyPut<S>(InstanceBuilderCallback<S> builder) {
     Get.lazyPut(builder, fenix: true);
   }
-
-
-
 }
 
 final generalPages = [
@@ -107,8 +107,13 @@ final generalPages = [
   GetPage(name: RoutePath.photoPreview, page: () => PhotoPreviewPage()),
   GetPage(name: RoutePath.photoInfo, page: () => PhotoInfoPage()),
   GetPage(name: RoutePath.store, page: () => StorePage()),
-  GetPage(name: RoutePath.locationsSinglePhoto, page: () => LocationsSinglePhotoPage()),
-  GetPage(name: RoutePath.photoSelectedPreview, page: () => PhotoSelectedPreviewPage()),
+  GetPage(name: RoutePath.discount, page: () => DiscountPage()),
+  GetPage(
+      name: RoutePath.locationsSinglePhoto,
+      page: () => LocationsSinglePhotoPage()),
+  GetPage(
+      name: RoutePath.photoSelectedPreview,
+      page: () => PhotoSelectedPreviewPage()),
   GetPage(name: RoutePath.setting, page: () => SettingPage()),
   GetPage(name: RoutePath.analysis, page: () => AnalysisPage()),
   GetPage(name: RoutePath.splash, page: () => SplashPage()),

+ 19 - 3
plugins/apple_pay/ios/Classes/ApplePayManager.swift

@@ -34,10 +34,26 @@ class ApplePayManager: NSObject {
 }
 
 extension ApplePayManager {
-    
-    func check() {
-        print("检查自动续费订单")
+
+    @available(iOS 15.0.0, *)
+    func check(appleId: String) async -> Bool {
+        print("检查自动续费订单及是否存在试用资格")
         self.isCheck = true
+
+        do {
+            // 获取产品信息
+            let productIds = [appleId]
+            let products = try await Product.products(for: Set(productIds))
+
+            // 检查第一个产品的试用资格
+            if let product = products.first {
+                return await product.subscription?.isEligibleForIntroOffer ?? false
+            }
+            return false
+        } catch {
+            print("Error checking trial eligibility: \(error)")
+            return false
+        }
     }
     
     // 开始支付

+ 17 - 1
plugins/apple_pay/ios/Classes/ApplePayPlugin.swift

@@ -34,7 +34,23 @@ public class ApplePayPlugin: NSObject, FlutterPlugin {
             ])
         }
     case "check":
-        result(nil)
+        
+        guard let args = call.arguments as? [String: Any],
+              let appleId = args["appleId"] as? String else {
+            result(false)
+            return
+        }
+        
+        if #available(iOS 15.0.0, *) {
+            Task {
+                let isEligible = await ApplePayManager.shared.check(appleId: appleId)
+                DispatchQueue.main.async {
+                   result(isEligible)
+               }
+            }
+        } else {
+            result(false)
+        }
     case "getPlatformVersion":
       result("iOS " + UIDevice.current.systemVersion)
     default:

+ 2 - 2
plugins/apple_pay/lib/apple_pay.dart

@@ -20,7 +20,7 @@ class ApplePay {
     return ApplePayPlatform.instance.restore();
   }
 
-  Future<void> check() {
-    return ApplePayPlatform.instance.check();
+  Future<bool> check(String appleId) {
+    return ApplePayPlatform.instance.check(appleId);
   }
 }

+ 14 - 4
plugins/apple_pay/lib/apple_pay_method_channel.dart

@@ -61,9 +61,19 @@ class MethodChannelApplePay extends ApplePayPlatform {
   }
 
   @override
-  Future<void> check() async {
-    await methodChannel.invokeMethod<void>(
-      'check',
-    );
+  Future<bool> check(String appleId) async {
+    try {
+      // 调用原生方法并处理可能的空值
+      final result = await methodChannel.invokeMethod<bool>('check',
+        {'appleId': appleId},
+      );
+      return result ?? false; // 如果结果为 null,返回 false
+    } on PlatformException catch (e) {
+      print('检查试用资格失败: ${e.message}');
+      return false; // 发生错误时返回 false
+    } catch (e) {
+      print('未知错误: $e');
+      return false;
+    }
   }
 }

+ 1 - 1
plugins/apple_pay/lib/apple_pay_platform_interface.dart

@@ -41,7 +41,7 @@ abstract class ApplePayPlatform extends PlatformInterface {
   }
 
   /// 检查订单
-  Future<void> check() async {
+  Future<bool> check(String appleId) async {
     throw UnimplementedError('check() has not been implemented.');
   }
 }

+ 10 - 26
plugins/classify_photo/ios/Classes/ClassifyPhotoPlugin.swift

@@ -20,16 +20,16 @@ public class ClassifyPhotoPlugin: NSObject, FlutterPlugin {
         self.getPhoto(flutterResult: result)
     case "getStorageInfo":
         getStorageInfo(result: result)
-    case "checkTrialEligibility":
-        if #available(iOS 15.0, *) {
-            Task {
-                let handler = SubscriptionHandler()
-                let isEligible = await handler.checkTrialEligibility()
-                DispatchQueue.main.async {
-                    result(isEligible)
-                }
-            }
-        }
+//    case "checkTrialEligibility":
+//        if #available(iOS 15.0, *) {
+//            Task {
+//                let handler = SubscriptionHandler()
+//                let isEligible = await handler.checkTrialEligibility()
+//                DispatchQueue.main.async {
+//                    result(isEligible)
+//                }
+//            }
+//        }
     case "getExifInfo":
         guard let args = call.arguments as? [String: Any],
               let filePath = args["filePath"] as? String else {
@@ -41,10 +41,6 @@ public class ClassifyPhotoPlugin: NSObject, FlutterPlugin {
             return
         }
         getExifInfo(filePath: filePath, completion: result)
-    case "finishTran":
-        let handler = SubscriptionHandler()
-        handler.finishTransaction()
-        result(nil)
     case "getPlatformVersion":
         result("iOS " + UIDevice.current.systemVersion)
     default:
@@ -331,16 +327,4 @@ class SubscriptionHandler: NSObject {
             return false
         }
     }
-    
-    // 支付前查询自动续费的订单,将订单置为支付状态
-    func finishTransaction() {
-        let transactions = SKPaymentQueue.default().transactions
-        if transactions.count > 0 {
-            for tran in transactions {
-                if tran.transactionState == .purchased {
-                    SKPaymentQueue.default().finishTransaction(tran)
-                }
-            }
-        }
-    }
 }

+ 2 - 2
plugins/classify_photo/lib/classify_photo.dart

@@ -16,8 +16,8 @@ class ClassifyPhoto {
     return ClassifyPhotoPlatform.instance.getStorageInfo();
   }
 
-  Future<bool> checkTrialEligibility() {
-    return ClassifyPhotoPlatform.instance.checkTrialEligibility();
+  Future<bool> checkTrialEligibility(String appleId) {
+    return ClassifyPhotoPlatform.instance.checkTrialEligibility(appleId);
   }
 
   Future<Map<String, dynamic>> getPhotoExif(String filePath) async {

+ 4 - 2
plugins/classify_photo/lib/classify_photo_method_channel.dart

@@ -18,10 +18,12 @@ class MethodChannelClassifyPhoto extends ClassifyPhotoPlatform {
   }
 
   @override
-  Future<bool> checkTrialEligibility() async {
+  Future<bool> checkTrialEligibility(String appleId) async {
     try {
       // 调用原生方法并处理可能的空值
-      final result = await methodChannel.invokeMethod<bool>('checkTrialEligibility');
+      final result = await methodChannel.invokeMethod<bool>('checkTrialEligibility',
+        {'appleId': appleId},
+      );
       return result ?? false; // 如果结果为 null,返回 false
     } on PlatformException catch (e) {
       print('检查试用资格失败: ${e.message}');

+ 1 - 1
plugins/classify_photo/lib/classify_photo_platform_interface.dart

@@ -39,7 +39,7 @@ abstract class ClassifyPhotoPlatform extends PlatformInterface {
   }
 
   // 检查是否试用
-  Future<bool> checkTrialEligibility() {
+  Future<bool> checkTrialEligibility(String appleId) {
     throw UnimplementedError('checkTrialEligibility() has not been implemented.');
   }