ソースを参照

3.6.21(1)打包

100Years 2 週間 前
コミット
8a465f479c

+ 8 - 8
AIEmoji.xcodeproj/project.pbxproj

@@ -238,13 +238,13 @@
 		A8D638482DB21FAD00A96C0E /* TSDownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638462DB21FAD00A96C0E /* TSDownloadManager.swift */; };
 		A8D6384A2DB252F100A96C0E /* TSAIListHistoryBaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638492DB252F000A96C0E /* TSAIListHistoryBaseCell.swift */; };
 		A8EB38382E137F48002F90E9 /* TSPurchasePromotionalVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EB38372E137F47002F90E9 /* TSPurchasePromotionalVC.swift */; };
-		A8EB383A2E138061002F90E9 /* TSPurchaseVC+Promotional.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EB38392E138058002F90E9 /* TSPurchaseVC+Promotional.swift */; };
 		A8EB383C2E13AE6F002F90E9 /* TSPurchasePromotionalVC+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EB383B2E13AE67002F90E9 /* TSPurchasePromotionalVC+View.swift */; };
 		A8EB38412E13BB0E002F90E9 /* PurchaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EB38402E13BB0D002F90E9 /* PurchaseView.swift */; };
 		A8EB38432E13FEF3002F90E9 /* Gift.apng in Resources */ = {isa = PBXBuildFile; fileRef = A8EB38422E13FEF3002F90E9 /* Gift.apng */; };
 		A8EB38462E140829002F90E9 /* TSPurchasePromotionalCountDownTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EB38452E140828002F90E9 /* TSPurchasePromotionalCountDownTime.swift */; };
 		A8EB38482E140848002F90E9 /* TSPurchaseCountdownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EB38472E140844002F90E9 /* TSPurchaseCountdownView.swift */; };
 		A8EB384A2E14E220002F90E9 /* Poppins-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = A8EB38492E14E220002F90E9 /* Poppins-Bold.otf */; };
+		A8EB384C2E15117C002F90E9 /* TSPurchasePromotionalVC+Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8EB384B2E15115C002F90E9 /* TSPurchasePromotionalVC+Animation.swift */; };
 		A8EEADD42D3E6C660032C5A0 /* Flower💐.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD32D3E6C610032C5A0 /* Flower💐.json */; };
 		A8EEADD62D3E6CD80032C5A0 /* Fish🐠.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */; };
 		A8EEADD82D3E74D20032C5A0 /* Pink🩷.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */; };
@@ -575,13 +575,13 @@
 		A8D638462DB21FAD00A96C0E /* TSDownloadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSDownloadManager.swift; sourceTree = "<group>"; };
 		A8D638492DB252F000A96C0E /* TSAIListHistoryBaseCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListHistoryBaseCell.swift; sourceTree = "<group>"; };
 		A8EB38372E137F47002F90E9 /* TSPurchasePromotionalVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPurchasePromotionalVC.swift; sourceTree = "<group>"; };
-		A8EB38392E138058002F90E9 /* TSPurchaseVC+Promotional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSPurchaseVC+Promotional.swift"; sourceTree = "<group>"; };
 		A8EB383B2E13AE67002F90E9 /* TSPurchasePromotionalVC+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSPurchasePromotionalVC+View.swift"; sourceTree = "<group>"; };
 		A8EB38402E13BB0D002F90E9 /* PurchaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseView.swift; sourceTree = "<group>"; };
 		A8EB38422E13FEF3002F90E9 /* Gift.apng */ = {isa = PBXFileReference; lastKnownFileType = file; path = Gift.apng; sourceTree = "<group>"; };
 		A8EB38452E140828002F90E9 /* TSPurchasePromotionalCountDownTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPurchasePromotionalCountDownTime.swift; sourceTree = "<group>"; };
 		A8EB38472E140844002F90E9 /* TSPurchaseCountdownView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPurchaseCountdownView.swift; sourceTree = "<group>"; };
 		A8EB38492E14E220002F90E9 /* Poppins-Bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Poppins-Bold.otf"; sourceTree = "<group>"; };
+		A8EB384B2E15115C002F90E9 /* TSPurchasePromotionalVC+Animation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSPurchasePromotionalVC+Animation.swift"; sourceTree = "<group>"; };
 		A8EEADD32D3E6C610032C5A0 /* Flower💐.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Flower💐.json"; sourceTree = "<group>"; };
 		A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Fish🐠.json"; sourceTree = "<group>"; };
 		A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Pink🩷.json"; sourceTree = "<group>"; };
@@ -882,7 +882,6 @@
 				A8EB38442E14080D002F90E9 /* TSPurchasePromotionalVC */,
 				A8EB383F2E13BB07002F90E9 /* View */,
 				A80E73D82D533E5800C64288 /* TSPurchaseVC.swift */,
-				A8EB38392E138058002F90E9 /* TSPurchaseVC+Promotional.swift */,
 			);
 			path = TSPurchaseMembershipVC;
 			sourceTree = "<group>";
@@ -1893,6 +1892,7 @@
 				A8EB38452E140828002F90E9 /* TSPurchasePromotionalCountDownTime.swift */,
 				A8EB38372E137F47002F90E9 /* TSPurchasePromotionalVC.swift */,
 				A8EB383B2E13AE67002F90E9 /* TSPurchasePromotionalVC+View.swift */,
+				A8EB384B2E15115C002F90E9 /* TSPurchasePromotionalVC+Animation.swift */,
 			);
 			path = TSPurchasePromotionalVC;
 			sourceTree = "<group>";
@@ -2596,6 +2596,7 @@
 				A80EDD4C2D6C3F82003CD332 /* Typealias.swift in Sources */,
 				A8BA76632DA64A84000B6707 /* TSAILIstCell.swift in Sources */,
 				A80EDD4D2D6C3F82003CD332 /* MarkdownStrikethrough.swift in Sources */,
+				A8EB384C2E15117C002F90E9 /* TSPurchasePromotionalVC+Animation.swift in Sources */,
 				A80EDD4E2D6C3F82003CD332 /* MarkdownUnescaping.swift in Sources */,
 				A80EDD4F2D6C3F82003CD332 /* MarkdownParser+UIKit.swift in Sources */,
 				A8990EEC2DEE8EED00DD55FE /* TSPredictBabyStyleView.swift in Sources */,
@@ -2783,7 +2784,6 @@
 				A8708A472E0BFD1E00601686 /* TSTextToastView.swift in Sources */,
 				A83405202DA3ADA900C140E4 /* TSPhotoSizeHelper.swift in Sources */,
 				A8F775382D390C3C00AA6E93 /* TSNetworkManager.swift in Sources */,
-				A8EB383A2E138061002F90E9 /* TSPurchaseVC+Promotional.swift in Sources */,
 				A80EDDE72D6EBFC1003CD332 /* TSPTPGeneratorVM.swift in Sources */,
 				A8BA76682DA6567E000B6707 /* TSAIListHintBaseVC.swift in Sources */,
 				A8708A432E0B93EF00601686 /* TSAIGenerateBaseVC+Video.swift in Sources */,
@@ -2872,7 +2872,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 7;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -2888,7 +2888,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 3.6.20;
+				MARKETING_VERSION = 3.6.21;
 				PRODUCT_BUNDLE_IDENTIFIER = com.girl.music.wallpaper;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
@@ -2911,7 +2911,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 7;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -2927,7 +2927,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 3.6.20;
+				MARKETING_VERSION = 3.6.21;
 				PRODUCT_BUNDLE_IDENTIFIER = com.girl.music.wallpaper;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";

+ 4 - 0
AIEmoji/Business/General/Ex/Notification+Ex.swift

@@ -26,4 +26,8 @@ extension Notification.Name {
     static let kGenerateBasePhotoOperation = Notification.Name("TSGenerateBasePhotoOperation") //生成图生图任务发生变化
     static let kAIPhotoDataChanged = Notification.Name("kGenerateBasePhotoChanged") //生成图片数据发生改变
     static let kAIComeInBackstage = Notification.Name("kAIComeInBackstage") //进入了后台生成
+    
+    
+    static let kCloseTSPurchaseVC = Notification.Name("kCloseTSPurchaseVC")   //关闭了订阅页
+    static let kCloseTSPurchasePromotionalVC = Notification.Name("kCloseTSPurchasePromotionalVC")   //关闭了优惠订阅页
 }

+ 10 - 3
AIEmoji/Business/TSAILIstVC/TSAIUploadPhotoBaseVC/TSAIUploadPhotoBaseVC.swift

@@ -217,9 +217,17 @@ class TSAIUploadPhotoBaseVC: TSBaseVC {
     
     @objc func updateVipView() {
         kMainAsync{
-            kSetBtnVipIcon(btn: self.submitBtn, show: kPurchaseDefault.generateVipShow(type: .aiGenerate))
+            kSetBtnVipIcon(btn: self.submitBtn, show: self.isNeedVip)
         }
     }
+    
+    
+    var isNeedVip:Bool{
+        if generatorStyle == .photoLive {
+            return true
+        }
+        return kPurchaseDefault.generateVipShow(type: .aiGenerate)
+    }
 }
 
 extension TSAIUploadPhotoBaseVC {
@@ -318,7 +326,7 @@ extension TSAIUploadPhotoBaseVC {
 extension TSAIUploadPhotoBaseVC {
 
     func generateImage() {
-        if kJudgeVip(externalBool: kPurchaseDefault.freeNumAvailable(type: .aiGenerate) == false, vc: self) { return }
+        if kJudgeVip(externalBool: isNeedVip, vc: self) { return }
         guard let upLoadImage = upLoadImage else { return }
         if generatorStyle != .catTohuman {
             additionalPrompt = ""
@@ -411,7 +419,6 @@ extension TSAIUploadPhotoBaseVC{
     }
     
     func pickSinglePhoto(maxBitSize:Int,complete: @escaping (UIImage)->Void)  {
-//        photoPickerManager.pickSinglePhoto(maxBitSize: maxBitSize) { [weak self] image, errorString in
         photoPickerManager.pickCustomSinglePhoto() { [weak self] image, errorString in
             guard let self = self else { return }
             if let errorString = errorString {

+ 29 - 5
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalCountDownTime.swift

@@ -28,10 +28,13 @@ class TSPurchasePromotionalTimeModel: TSBaseModel {
 let kPurchaseCountDownTime = TSPurchasePromotionalCountDownTime()
 class TSPurchasePromotionalCountDownTime {
  
+    var isNeedCheck:Bool = false
+    
+    
     let timer:TSGCDTimer = TSGCDTimer()
-    var countDownTime:Int = 300//30分钟 = 1800
+    var countDownTime:Int = 1800//30分钟 = 1800
     private var countDownInt:Int = 0
-    init(countDownTime: Int = 300) {
+    init(countDownTime: Int = 1800) {
         self.countDownTime = countDownTime
         
         // 监听应用生命周期事件
@@ -48,6 +51,15 @@ class TSPurchasePromotionalCountDownTime {
             name: UIApplication.willEnterForegroundNotification,
             object: nil
         )
+        
+        NotificationCenter.default.addObserver(self, selector: #selector(updateVipView), name: .kPurchaseDidChanged, object: nil)
+    }
+    
+    @objc func updateVipView() {
+        if kPurchaseDefault.isVip == true {
+            endCountDown()
+            NotificationCenter.default.post(name: .kCloseTSPurchasePromotionalVC, object: nil)
+        }
     }
     
     @objc private func handleAppDidEnterBackground() {
@@ -148,15 +160,27 @@ class TSPurchasePromotionalCountDownTime {
         if self.countDownInt >= 0 {
              let minutes = self.countDownInt / 60
              let seconds = self.countDownInt % 60
+            dePrint("\(minutes):\(seconds)")
              self.complete?(String(format: "%02d", minutes),String(format: "%02d", seconds),false)
          } else {
-             self.timer.stop()
-             self.complete?("00","00",true)
+             endCountDown()
          }
     }
     
-    func start(){
+    
+    func endCountDown(){
+        self.timer.stop()
+        self.complete?("00","00",true)
+    }
+    
+    var isNeedNewCountDown:Bool{
         if isHaveTime == false && isTodayAvailable == true {
+            return true
+        }
+        return false
+    }
+    func start(){
+        if isNeedNewCountDown {
             let currentTimestampInt = Date.timestampInt
             let timeModel = TSPurchasePromotionalTimeModel()
             timeModel.startTimestampInt = currentTimestampInt

+ 20 - 49
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVC+Promotional.swift → AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalVC+Animation.swift

@@ -1,16 +1,14 @@
 //
-//  TSPurchaseVC+Promotional.swift
+//  TSPurchasePromotionalVC+Animation.swift
 //  AIEmoji
 //
-//  Created by 100Years on 2025/6/30.
+//  Created by 100Years on 2025/7/2.
 //
 
 import APNGKit
 import Delegate
-extension TSPurchaseVC {
+extension TSPurchasePromotionalVC {
 
-
-    
     func creatApngImageView() -> APNGImageView {
         let image = try! APNGImage(named: "Gift")
         image.numberOfPlays = 1
@@ -18,12 +16,9 @@ extension TSPurchaseVC {
         apngImageView.autoStartAnimationWhenSetImage = false
         apngImageView.onAllPlaysDone.delegate(on: self) { (self, _) in
        
-            self.addPromotionalVC()
-            self.promotionalVC.view.alpha = 0
-            
             UIView.animate(withDuration: 0.5, animations: {
                 self.animationView.alpha = 0
-                self.promotionalVC.view.alpha = 1
+                self.contentView.alpha = 1
               }, completion: { finished in
                   dePrint("kPurchaseCountDownTime.start")
                   kPurchaseCountDownTime.start()
@@ -34,47 +29,18 @@ extension TSPurchaseVC {
         return apngImageView
     }
     
-    func creatPromotionalVC() -> TSPurchasePromotionalVC {
-        let promotionalVC = TSPurchasePromotionalVC()
-        
-        promotionalVC.clickPromotionalBlock = { [weak self]  in
-            guard let self = self else { return }
-            isHandlePurchaseStateChanged = true
-            PurchaseManager.default.pay(for: .week(.weekPromotional1))
-        }
-        
-        promotionalVC.clickRestoreBlock = { [weak self]  in
-            guard let self = self else { return }
-            restorePremium()
-        }
-        
-        promotionalVC.closePageBlock = { [weak self]  in
-            guard let self = self else { return }
-            closePage()
-        }
-        return promotionalVC
-    }
-    
-    var showGift:Bool{
-        
+    static var showGift:Bool{
         if kPurchaseDefault.isVip == false,
            kPurchaseDefault.checkLocalReceiptForIntroOffer(type: .week(.weekPromotional1)) == false,
-           kPurchaseCountDownTime.isShowGift,
-           promotionalVC.view.superview == nil {
+           kPurchaseCountDownTime.isShowGift{
             return true
         }
         return false
     }
-    
-    func addPromotionalVC(){
-        self.addChild(promotionalVC)
-        self.view.addSubview(promotionalVC.view)
-        self.view.insertSubview(promotionalVC.view, belowSubview: navBarContentView)
-    }
-    
+
     func addApngImageView(){
-      
-        animationView.backgroundColor = .black.withAlphaComponent(0.5)
+        
+        animationView.backgroundColor = .black.withAlphaComponent(0.8)
         self.view.addSubview(animationView)
         animationView.snp.makeConstraints { make in
             make.edges.equalToSuperview()
@@ -90,12 +56,17 @@ extension TSPurchaseVC {
             make.centerY.equalToSuperview()
             make.width.height.equalTo(k_ScreenWidth)
         }
- 
-        kMainAfter(0.5) {
-            self.apngImageView.startAnimating()
-            UIView.animate(withDuration: 0.8) {
-                self.animationLab.transform = CGAffineTransform(translationX: 0, y: -150)
-                self.animationLab.alpha = 1
+
+        kMainShort(){
+            self.animationLab.setNeedsLayout()
+            self.animationLab.applyGradient(colors: ["#FA794F".uiColor,"#F8C32A".uiColor,"#FEFBF4".uiColor])
+            
+            kMainAfter(0.5) {
+                self.apngImageView.startAnimating()
+                UIView.animate(withDuration: 0.8) {
+                    self.animationLab.transform = CGAffineTransform(translationX: 0, y: -150)
+                    self.animationLab.alpha = 1
+                }
             }
         }
     }

+ 65 - 7
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalVC+View.swift

@@ -18,6 +18,21 @@ extension TSPurchasePromotionalVC {
             make.leading.trailing.equalToSuperview()
             make.height.equalTo(82)
         }
+        
+        kMainShort {
+            UIView.animate(
+                 withDuration: 1.2,
+                 delay: 0,
+                 usingSpringWithDamping: 0.3,
+                 initialSpringVelocity: 0.5,
+                 options: [.autoreverse, .repeat],
+                 animations: {
+                     priceLabel.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
+                 },
+                 completion: nil
+             )
+        }
+        
         //ONLY TODAY
         let label1 = UILabel.createLabel(text:"ONLY TODAY".localized,font: .font(size: 18,weight: .medium),textColor: .themeColor,textAlignment: .center)
         frontCtnView.addSubview(label1)
@@ -69,13 +84,15 @@ extension TSPurchasePromotionalVC {
             make.height.equalTo(27)
         }
         
-        
+
         //提交按钮
-        let submitBtn = kCreateNormalSubmitBtn(title:"Start Trial".localized) { [weak self]  in
-            guard let self = self else { return }
-            clickPromotionalBlock?()
-        }
-        submitBtn.cornerRadius = 24.0
+//        let submitBtn = kCreateNormalSubmitBtn(title:"Start Trial".localized) { [weak self]  in
+//            guard let self = self else { return }
+//            isHandlePurchaseStateChanged = true
+//            PurchaseManager.default.pay(for: .week(.weekPromotional1))
+//        }
+//        submitBtn.cornerRadius = 24.0
+        let submitBtn = creatSubmitBtn()
         frontCtnView.addSubview(submitBtn)
         submitBtn.snp.makeConstraints { make in
             make.top.equalTo(label4.snp.bottom).offset(14)
@@ -84,6 +101,8 @@ extension TSPurchasePromotionalVC {
             make.height.equalTo(48)
         }
         
+
+        
         //底部按钮组
         frontCtnView.addSubview(bottomBtnsView)
         bottomBtnsView.snp.makeConstraints { make in
@@ -97,7 +116,45 @@ extension TSPurchasePromotionalVC {
     }
     
     
+    @objc func clickSubmitBtn(){
+        isHandlePurchaseStateChanged = true
+        PurchaseManager.default.pay(for: .week(.weekPromotional1))
+    }
     
+    func creatSubmitBtn() -> UIView{
+        let bgView = UIView()
+        bgView.cornerRadius = 24.0
+        bgView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickSubmitBtn)))
+
+        var buttonBgImage = UIImage(named: "submit_btn_bg")!
+        buttonBgImage = buttonBgImage.resizableImage(withCapInsets: UIEdgeInsets(top:24, left: 24, bottom: 24, right: 24), resizingMode: .stretch)
+        let imageView = UIImageView.createImageView(image: buttonBgImage)
+        bgView.addSubview(imageView)
+        
+        let titleLab = UILabel.createLabel(text: "Start Trial".localized,font: .font(size: 14,weight: .medium),textColor: "#111111".uiColor)
+        bgView.addSubview(titleLab)
+    
+        let title1Lab = UILabel.createLabel(text: "Auto renew. Cancel anytime".localized,font: .font(size: 9,weight: .medium),textColor: "#111111".uiColor.withAlphaComponent(0.6),textAlignment: .center)
+        bgView.addSubview(title1Lab)
+        
+        imageView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        titleLab.snp.makeConstraints { make in
+            make.top.equalTo(8)
+            make.centerX.equalToSuperview()
+            make.height.equalTo(18)
+        }
+        
+        title1Lab.snp.makeConstraints { make in
+            make.top.equalTo(30)
+            make.leading.equalTo(24)
+            make.trailing.equalTo(-24)
+        }
+        
+        return bgView
+    }
     
     
     func creatBottomBtnsView() -> UIView {
@@ -124,7 +181,8 @@ extension TSPurchasePromotionalVC {
         
         let restoreBtn = UIButton.createButton(title: "Restore".localized,font: font,titleColor: titleColor){ [weak self]  in
             guard let self = self else { return }
-            clickRestoreBlock?()
+            isHandlePurchaseStateChanged = true
+            PurchaseManager.default.restorePremium()
         }
         bottomBtnsView.addSubview(restoreBtn)
         

+ 140 - 8
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalVC.swift

@@ -5,14 +5,12 @@
 //  Created by 100Years on 2025/6/30.
 //
 
-
+import APNGKit
+import Delegate
 class TSPurchasePromotionalVC: TSBaseVC {
     
     var isHandlePurchaseStateChanged = true //是否处理购买状态变化
     
-    
-    var clickPromotionalBlock:(()->Void)?
-    var clickRestoreBlock:(()->Void)?
     var closePageBlock:(()->Void)?
     
     lazy var topImageView: UIImageView = UIImageView.createImageView(imageName: "promotional_topImage",contentMode: .scaleAspectFill)
@@ -26,15 +24,45 @@ class TSPurchasePromotionalVC: TSBaseVC {
     let minLabel:UILabel = UILabel()
     let secLabel:UILabel = UILabel()
 
-    var countDownTime:Int = 1800 //30 分钟
+    lazy var apngImageView: APNGImageView = creatApngImageView()
+
+
+    var isAnimation:Bool = false
+    init(isAnimation: Bool, closePageBlock: ( () -> Void)? = nil) {
+        self.closePageBlock = closePageBlock
+        self.isAnimation = isAnimation
+        super.init()
+    }
+    
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    let animationView:UIView = UIView()
+    lazy var animationLab: UILabel = {
+        let animationLab = UILabel.createLabel(text: "LUCKY GIFT\nFOR YOU!".localized,font:.font(name: .PoppinsBold, size: 38),textAlignment: .center)
+        animationLab.alpha = 0.0
+        return animationLab
+    }()
+    
+    
+    lazy var closeBtn:TSUIExpandedTouchButton = {
+        let closeBtn = TSUIExpandedTouchButton()
+        closeBtn.setUpButton(image:.closeGray){ [weak self]  in
+            guard let self = self else { return }
+            closePage()
+        }
+        return closeBtn
+    }()
+    
     
     override func createView() {
         setNavBarViewHidden(true)
-        
+        self.view.backgroundColor = .clear
         contentView.addSubview(topImageView)
         contentView.addSubview(shaowImageView)
         contentView.addSubview(frontCtnView)
-        
+        contentView.addSubview(closeBtn)
         topImageView.snp.makeConstraints { make in
             make.leading.trailing.top.equalToSuperview()
             make.height.equalTo(532*kDesignScale)
@@ -48,17 +76,121 @@ class TSPurchasePromotionalVC: TSBaseVC {
             make.leading.trailing.bottom.top.equalToSuperview()
         }
         
+        closeBtn.snp.makeConstraints { make in
+            make.leading.equalTo(16)
+            make.top.equalTo(4+k_Height_statusBar())
+            make.width.height.equalTo(36)
+        }
+        
+        if isAnimation {
+            self.contentView.alpha = 0.0
+            addApngImageView()
+        }
     }
     
     override func dealThings() {
         kPurchaseCountDownTime.complete = { [weak self] minutes, seconds, end in
             guard let self = self else { return }
             if end {
-                self.closePageBlock?()
+                self.closePage()
             }else{
                 self.minLabel.text = minutes
                 self.secLabel.text = seconds
             }
         }
+
+        onPurchaseStateChanged()
+    }
+    
+    @objc func closePage(){
+        TSToastShared.hideLoading()
+        closePageBlock?()
+        self.dismiss(animated: true)
+        NotificationCenter.default.post(name: .kCloseTSPurchasePromotionalVC, object: nil)
+    }
+    
+    func onPurchaseStateChanged(){
+        PurchaseManager.default.onPurchaseStateChanged = { [weak self] manager,state,object in
+            guard let self = self else { return }
+        
+            if isHandlePurchaseStateChanged == false {
+                debugPrint("purchaseManager.onPurchaseStateChanged 不处理")
+                return
+            }
+            
+            DispatchQueue.main.async {
+                switch state {
+                case .none:
+                    break
+                case .loading:
+                    TSToastShared.showLoading(text: "Getting price".localized,containerView: self.view)
+                case .loadSuccess:
+                    TSToastShared.hideLoading()
+                case .loadFail:
+                    TSToastShared.hideLoading()
+                    let message = "Failed to get the price, will automatically retry in 5 seconds".localized
+                    TSToastShared.showToast(text: message)
+                    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
+                        PurchaseManager.default.requestProducts()
+                    }
+                case .paying:
+                    TSToastShared.showLoading(text: "Purchasing now".localized,containerView: self.view)
+                case .paySuccess:
+                    TSToastShared.hideLoading()
+                 
+                    var loadingText = "Finish".localized
+                    if manager.isVip {
+                        loadingText = manager.vipType == .year ? "Congratulations on being VIP of the Year!".localized : "Congratulation you have become VIP".localized
+                    }
+                    
+                    TSToastShared.showToast(text:loadingText)
+                    if manager.isVip {
+                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
+                            self.closePage()
+                        }
+                    }
+
+                case .payFail:
+                    TSToastShared.hideLoading()
+                    if let str = object as? String {
+                        TSToastShared.showToast(text: str)
+                    }
+                    
+                case .restoreing:
+                    TSToastShared.showLoading(text: "Restoring now".localized,containerView: self.view)
+                case .restoreSuccess:
+                    TSToastShared.hideLoading()
+                    let loadingText = manager.isVip ? "Congratulation you have become VIP".localized : "Couldn't Restore Subscription".localized
+                    debugPrint(loadingText)
+                    TSToastShared.showToast(text:loadingText)
+                    if manager.isVip {
+                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
+                            self.closePage()
+                        }
+                    }
+
+                case .restoreFail:
+                    TSToastShared.hideLoading()
+                    let loadingText = (object as? String) ?? "Failed to restore subscribe, please try again".localized
+                    debugPrint(loadingText)
+                    TSToastShared.showToast(text: loadingText)
+                case .verifying:
+                    #if DEBUG
+                    TSToastShared.showLoading(text: "Verifying receipt...".localized,containerView: self.view)
+                    #endif
+                case .verifySuccess:
+                    break
+                case .verifyFail:
+                #if DEBUG
+                    TSToastShared.hideLoading()
+                    let message = (object as? String) ?? "Failed to validate receipt".localized
+                    TSToastShared.showToast(text:message)
+
+                #endif
+                }
+            }
+            debugPrint("PurchaseManager onPurchaseStateChanged=\(String(describing: state))")
+        }
     }
+
 }

+ 7 - 27
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift

@@ -8,8 +8,7 @@
 import Combine
 import SwiftUI
 import SwiftUIX
-import APNGKit
-import Delegate
+
 
 class PurchaseViewModel : ObservableObject{
     
@@ -90,18 +89,6 @@ class TSPurchaseVC: TSBaseVC {
         return vc
     }()
     
-    lazy var apngImageView: APNGImageView = creatApngImageView()
-    lazy var promotionalVC: TSPurchasePromotionalVC = creatPromotionalVC()
-    let animationView:UIView = UIView()
-    lazy var animationLab: UILabel = {
-        let animationLab = UILabel.createLabel(text: "LUCKY GIFT\nFOR YOU!".localized,font:.font(name: .PoppinsBold, size: 38),textAlignment: .center)
-        animationLab.alpha = 0.0
-        kMainAsync {
-            animationLab.applyGradient(colors: ["#FA794F".uiColor,"#F8C32A".uiColor,"#FEFBF4".uiColor])
-        }
-        return animationLab
-    }()
-    
     override func createView() {
         addNormalNavBarView()
         _ = setNavigationItem("", imageName: "close_gray", direction: .left, action: #selector(closePage))
@@ -119,23 +106,15 @@ class TSPurchaseVC: TSBaseVC {
         hostVc.view.snp.makeConstraints { make in
             make.leading.trailing.bottom.top.equalToSuperview()
         }
-
-        if kPurchaseCountDownTime.isCountDown {
-           addPromotionalVC()
-        }
     }
     
     @objc func closePage(){
         TSToastShared.hideLoading()
-        
-        if showGift {
-//        if promotionalVC.view.superview == nil {
-            addApngImageView()
-            return
-        }
-        
         closePageBlock?()
         self.dismiss(animated: true)
+        kPurchaseCountDownTime.isNeedCheck = true
+        NotificationCenter.default.post(name: .kCloseTSPurchaseVC, object: nil)
+
     }
     
     override func dealThings() {
@@ -249,7 +228,8 @@ class TSPurchaseVC: TSBaseVC {
                     TSToastShared.showLoading(text: "Restoring now".localized,containerView: self.view)
                 case .restoreSuccess:
                     TSToastShared.hideLoading()
-                    let loadingText = manager.isVip ? "Congratulation you have become VIP".localized : "Couldn't Restore Subscription".localized
+//                    let loadingText = manager.isVip ? "Congratulation you have become VIP".localized : "Couldn't Restore Subscription".localized
+                    let loadingText = manager.vipType == .year ? "Congratulations on being VIP of the Year!".localized : "Congratulation you have become VIP".localized
                     debugPrint(loadingText)
                     TSToastShared.showToast(text:loadingText)
                     if manager.isVip {
@@ -326,7 +306,7 @@ func kJudgeVip(externalBool:Bool,
 
 extension TSPurchaseVC{
     
-    static func show(target:UIViewController,closePageBlock:(()->Void)?){
+    static func show(target:UIViewController,closePageBlock:(()->Void)? = nil){
         kDelayMainShort {
             let vc = TSPurchaseVC()
             vc.closePageBlock = closePageBlock

+ 7 - 5
AIEmoji/Business/TSPurchaseMembershipVC/View/PurchaseView.swift

@@ -111,11 +111,13 @@ struct PurchaseView :View {
                         .onTapGesture {
                             viewModel.privacyPublisher.send(true)
                         }
-                    Text("|")
-                    Text("Restore".localized)
-                        .onTapGesture {
-                            viewModel.restorePublisher.send(true)
-                        }
+                    if vipType == .none {
+                        Text("|")
+                        Text("Restore".localized)
+                            .onTapGesture {
+                                viewModel.restorePublisher.send(true)
+                            }
+                    }
                 }.font(.system(size: 12)).foregroundColor(.hex("#999999"))
             }.padding(.horizontal)
             

+ 43 - 16
AIEmoji/Business/TSTabBarController/TSTabBarController.swift

@@ -93,35 +93,28 @@ class TSTabBarController: UITabBarController {
         tabBarItem.image = image?.withRenderingMode(.alwaysOriginal)
         tabBarItem.title = title
         tabBarItem.selectedImage = selectedImage?.withRenderingMode(.alwaysOriginal)
-//        tabBarItem.imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: -8, right: 0) // 向下移动图标
         return tabBarItem
     }
     func monitorEvent(){
+        
+        //后台生成后,跳转到历史页面
         NotificationCenter.default.addObserver(forName: .kAIComeInBackstage, object: nil, queue: .main) { _ in
             if let nav = self.viewControllers?.safeObj(At: self.selectedIndex) as? UINavigationController {
                 nav.popToRootViewController(animated: false)
             }
             TSGenerateHistoryVC.showPosition()
         }
-        
-        refreshView()
-        NotificationCenter.default.addObserver(self, selector: #selector(refreshView), name: .kAppUpdateNotification, object: nil)
-    }
     
-    let updateAlertVC = TSAppUpdateAlertVC()
-    @objc func refreshView() {
-        if TSAppUpdateManager.isNeedUpdate,TSAppUpdateManager.isDisplayedUpdateAlert == false{
+        //升级弹窗
+        refreshUpdateView()
+        NotificationCenter.default.addObserver(self, selector: #selector(refreshUpdateView), name: .kAppUpdateNotification, object: nil)
         
-            kMainAfter(1.0) {
-                self.updateAlertVC.modalPresentationStyle = .overFullScreen
-                self.updateAlertVC.modalTransitionStyle = .crossDissolve
-                self.present(self.updateAlertVC, animated: true,completion: {
-                    TSAppUpdateManager.isDisplayedUpdateAlert = true
-                })
-            }
-        }
+        //关闭订阅页面,弹出优惠订阅
+        refreshPurchasePromotional()
+        NotificationCenter.default.addObserver(self, selector: #selector(refreshPurchasePromotional), name: .kCloseTSPurchaseVC, object: nil)
     }
     
+
     deinit {
         debugPrint("TSTabBarController deinit")
         NotificationCenter.default.removeObserver(self)
@@ -135,6 +128,40 @@ extension TSTabBarController {
     }
 }
 
+
+//升级弹窗
+extension TSTabBarController {
+    @objc func refreshUpdateView() {
+        if TSAppUpdateManager.isNeedUpdate,TSAppUpdateManager.isDisplayedUpdateAlert == false{
+            kMainAfter(1.0) {
+                let updateAlertVC = TSAppUpdateAlertVC()
+                updateAlertVC.modalPresentationStyle = .overFullScreen
+                updateAlertVC.modalTransitionStyle = .crossDissolve
+                self.present(updateAlertVC, animated: true,completion: {
+                    TSAppUpdateManager.isDisplayedUpdateAlert = true
+                })
+            }
+        }
+    }
+
+}
+
+//关闭订阅页面,弹出优惠订阅
+extension TSTabBarController {
+    @objc func refreshPurchasePromotional() {
+        if TSPurchasePromotionalVC.showGift,kPurchaseCountDownTime.isNeedCheck == true{
+            kMainAfter(1.0) {
+                let updateAlertVC = TSPurchasePromotionalVC(isAnimation: true)
+                updateAlertVC.modalPresentationStyle = .overFullScreen
+                updateAlertVC.modalTransitionStyle = .crossDissolve
+                self.present(updateAlertVC, animated: true,completion: {
+                    kPurchaseCountDownTime.isNeedCheck = false
+                })
+            }
+        }
+    }
+
+}
 //private let animatedIndex = 1
 //extension TSTabBarController {
 //    func addAnimatedImageView(){

+ 15 - 14
AIEmoji/Business2/DisCover/TSDiscoverVC/TSDiscoverVC.swift

@@ -9,16 +9,17 @@ class TSDiscoverVC: TSBaseVC {
     
     let viewModel = kTSDiscoverVM
     var hintBaseVC:TSAIListHintBaseVC = TSAIListHintBaseVC(config: .defaultConfig)
-    lazy var photoPickerManager: TSPhotoPickerManager =  TSPhotoPickerManager(viewController: self)
+    lazy var photoPickerManager: TSPhotoPickerManager = TSPhotoPickerManager(viewController: self)
     
     lazy var vipBtn: UIButton = {
-       let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self]  in
-           guard let self = self else { return }
-           TSPurchaseVC.show(target: self) { [weak self]  in
-               guard let self = self else { return }
-               checkkPurchaseCountDownTime()
-           }
-       }
+        let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self]  in
+            guard let self = self else { return }
+            if kPurchaseCountDownTime.isCountDown {
+                kPresentModalVC(target: self, modelVC: TSPurchasePromotionalVC(isAnimation: false))
+            }else{
+                TSPurchaseVC.show(target: self)
+            }
+        }
        return vipBtn
    }()
     
@@ -26,10 +27,7 @@ class TSDiscoverVC: TSBaseVC {
        let purchaseCountdownView = TSPurchaseCountdownView()
         purchaseCountdownView.clickBlock = { [weak self]  in
             guard let self = self else { return }
-            TSPurchaseVC.show(target: self) { [weak self]  in
-                guard let self = self else { return }
-                checkkPurchaseCountDownTime()
-            }
+            kPresentModalVC(target: self, modelVC: TSPurchasePromotionalVC(isAnimation: false))
         }
        return purchaseCountdownView
    }()
@@ -55,7 +53,7 @@ class TSDiscoverVC: TSBaseVC {
             make.trailing.equalTo(-16)
         }
         vipBtn.snp.makeConstraints { make in
-            make.width.height.equalTo(32)
+            make.width.height.equalTo(24)
         }
         
         purchaseCountdownView.snp.makeConstraints { make in
@@ -100,15 +98,18 @@ class TSDiscoverVC: TSBaseVC {
     override func dealThings() {
         NotificationCenter.default.addObserver(self, selector: #selector(updateVipView), name: .kPurchaseDidChanged, object: nil)
         updateVipView()
+        NotificationCenter.default.addObserver(self, selector: #selector(checkkPurchaseCountDownTime), name: .kCloseTSPurchasePromotionalVC, object: nil)
+        checkkPurchaseCountDownTime()
     }
     
     @objc func updateVipView() {
         kMainAsync{
             self.vipBtn.isHidden = PurchaseManager.default.isVip
+            self.checkkPurchaseCountDownTime()
         }
     }
     
-    func checkkPurchaseCountDownTime(){
+    @objc func checkkPurchaseCountDownTime(){
         if kPurchaseCountDownTime.isCountDown {
             self.purchaseCountdownView.isHidden = false
             kPurchaseCountDownTime.complete = { [weak self] minutes, seconds, end in

+ 62 - 7
AIEmoji/Business2/DisCover/TSGenerateHistoryVC/TSGenerateHistoryVC.swift

@@ -14,11 +14,24 @@ class TSGenerateHistoryVC: TSBaseVC {
     lazy var vipBtn: UIButton = {
        let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self]  in
            guard let self = self else { return }
-           TSPurchaseVC.show(target: self) {}
+           if kPurchaseCountDownTime.isCountDown {
+               kPresentModalVC(target: self, modelVC: TSPurchasePromotionalVC(isAnimation: false))
+           }else{
+               TSPurchaseVC.show(target: self)
+           }
        }
        return vipBtn
    }()
     
+    lazy var purchaseCountdownView : TSPurchaseCountdownView = {
+       let purchaseCountdownView = TSPurchaseCountdownView()
+        purchaseCountdownView.clickBlock = { [weak self]  in
+            guard let self = self else { return }
+            kPresentModalVC(target: self, modelVC: TSPurchasePromotionalVC(isAnimation: false))
+        }
+       return purchaseCountdownView
+   }()
+    
     lazy var navBarView: TSBaseNavContentBarView = {
         let navBarView = TSBaseNavContentBarView()
 
@@ -33,18 +46,35 @@ class TSGenerateHistoryVC: TSBaseVC {
             guard let self = self else { return }
             clickNavRight()
         }
-        navBarView.barView.addSubview(deleteBtn)
-        deleteBtn.snp.makeConstraints { make in
+        
+        let clearView = UIView()
+        
+
+        let stackView:UIStackView = UIStackView()
+        stackView.spacing = 8
+        navBarView.barView.addSubview(stackView)
+        stackView.addArrangedSubview(vipBtn)
+        stackView.addArrangedSubview(purchaseCountdownView)
+        stackView.addArrangedSubview(clearView)
+        stackView.addArrangedSubview(deleteBtn)
+        
+        stackView.snp.makeConstraints { make in
             make.centerY.equalToSuperview()
             make.trailing.equalTo(-16)
+        }
+        vipBtn.snp.makeConstraints { make in
             make.width.height.equalTo(24)
         }
         
+        purchaseCountdownView.snp.makeConstraints { make in
+            make.height.equalTo(24)
+        }
         
-        navBarView.barView.addSubview(vipBtn)
-        vipBtn.snp.makeConstraints { make in
-            make.centerY.equalToSuperview()
-            make.trailing.equalTo(-64)
+        clearView.snp.makeConstraints { make in
+            make.width.equalTo(0.1)
+        }
+        
+        deleteBtn.snp.makeConstraints { make in
             make.width.height.equalTo(24)
         }
         
@@ -110,6 +140,30 @@ class TSGenerateHistoryVC: TSBaseVC {
         NotificationCenter.default.addObserver(self, selector: #selector(updateDataView), name: .kAIPhotoDataChanged, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(updateVipView), name: .kPurchaseDidChanged, object: nil)
         updateVipView()
+        NotificationCenter.default.addObserver(self, selector: #selector(checkkPurchaseCountDownTime), name: .kCloseTSPurchasePromotionalVC, object: nil)
+        checkkPurchaseCountDownTime()
+    }
+    
+    @objc func checkkPurchaseCountDownTime(){
+        
+        kMainAsync {
+            if kPurchaseCountDownTime.isCountDown {
+                self.purchaseCountdownView.isHidden = false
+                kPurchaseCountDownTime.complete = { [weak self] minutes, seconds, end in
+                    guard let self = self else { return }
+                    kMainAsync {
+                        if end {
+                            self.purchaseCountdownView.isHidden = true
+                        }else{
+                            self.purchaseCountdownView.minLabel.text = minutes
+                            self.purchaseCountdownView.secLabel.text = seconds
+                        }
+                    }
+                }
+            }else{
+                self.purchaseCountdownView.isHidden = true
+            }
+        }
     }
     
     @objc func operationChanged(_ notification: Notification) {
@@ -141,6 +195,7 @@ class TSGenerateHistoryVC: TSBaseVC {
     
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
+        checkkPurchaseCountDownTime()
     }
     
     @objc func clickNavRight() {

+ 1 - 0
AIEmoji/de.lproj/Localizable.strings

@@ -487,3 +487,4 @@
 "sec" = "sec";
 "First week %@ Then total %@/week" = "Erste Woche %@ Dann insgesamt %@/Woche";
 "Start Trial" = "Testversion starten";
+"Auto renew. Cancel anytime" = "Automatische Verlängerung. Jederzeit kündbar.";

+ 2 - 1
AIEmoji/en.lproj/Localizable.strings

@@ -83,7 +83,7 @@
 "How to add emojis to iMessages?" = "How to add emojis to iMessages?";
 "Update Version" = "Update Version";
 "Share us" = "Share us";
-"Rate us" = "Rate us";
+"Rate us" = "Like us? Rate us!";
 "Terms of Service" = "Terms of Service";
 "Privacy Policy" = "Privacy Policy";
 "Allow us to access Photos in order to save emoji to your device." = "Allow us to access Photos in order to save emoji to your device.";
@@ -484,4 +484,5 @@
 "sec" = "sec";
 "First week %@ Then total %@/week" = "First week %@ Then total %@/week";
 "Start Trial" = "Start Trial";
+"Auto renew. Cancel anytime" = "Auto renew. Cancel anytime";
 

+ 1 - 0
AIEmoji/es.lproj/Localizable.strings

@@ -485,3 +485,4 @@
 "sec" = "seg";
 "First week %@ Then total %@/week" = "Primera semana %@ Luego total %@/semana";
 "Start Trial" = "Comienza la prueba";
+"Auto renew. Cancel anytime" = "Renovación automática. Cancela en cualquier momento";

+ 1 - 0
AIEmoji/ja.lproj/Localizable.strings

@@ -484,3 +484,4 @@
 "sec" = "秒";
 "First week %@ Then total %@/week" = "最初の週 %@ その後、週あたり %@";
 "Start Trial" = "トライアルを開始";
+"Auto renew. Cancel anytime" = "自動更新。いつでもキャンセル可能";

+ 1 - 0
AIEmoji/ko.lproj/Localizable.strings

@@ -489,3 +489,4 @@
 "sec" = "초";
 "First week %@ Then total %@/week" = "첫 주 %@ 그 다음 주당 %@";
 "Start Trial" = "무료 체험 시작";
+"Auto renew. Cancel anytime" = "자동 갱신. 언제든지 취소 가능";

+ 1 - 0
AIEmoji/pt-BR.lproj/Localizable.strings

@@ -484,3 +484,4 @@
 "sec" = "seg";
 "First week %@ Then total %@/week" = "Primeira semana %@ Depois, total %@/semana";
 "Start Trial" = "Comece o teste";
+"Auto renew. Cancel anytime" = "Renovação automática. Cancele a qualquer momento.";

+ 1 - 0
AIEmoji/pt-PT.lproj/Localizable.strings

@@ -483,3 +483,4 @@
 "sec" = "seg";
 "First week %@ Then total %@/week" = "Primeira semana %@ Depois, total %@/semana";
 "Start Trial" = "Comece o teste";
+"Auto renew. Cancel anytime" = "Renovação automática. Cancele a qualquer momento.";

+ 1 - 0
AIEmoji/zh-Hans.lproj/Localizable.strings

@@ -485,3 +485,4 @@
 "sec" = "秒";
 "First week %@ Then total %@/week" = "首周 %@ 随后每周总计 %@";
 "Start Trial" = "立即试用";
+"Auto renew. Cancel anytime" = "自动续订。随时取消";

+ 1 - 0
AIEmoji/zh-Hant.lproj/Localizable.strings

@@ -474,3 +474,4 @@
 "sec" = "秒";
 "First week %@ Then total %@/week" = "首周%@隨後每週總計%@";
 "Start Trial" = "立即試用";
+"Auto renew. Cancel anytime" = "自動續訂。隨時取消";