Selaa lähdekoodia

增加会员月升级年

100Years 2 viikkoa sitten
vanhempi
commit
152092cfd6

+ 13 - 9
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift

@@ -74,6 +74,10 @@ class TSPurchaseVC: TSBaseVC {
     }()
     }()
     
     
     lazy var hostVc: UIHostingController<PurchaseView> = {
     lazy var hostVc: UIHostingController<PurchaseView> = {
+        if PurchaseManager.default.vipType == .none {
+            viewModel.selectedType = .month
+        }
+        
         let vc = UIHostingController(rootView: PurchaseView(viewModel: viewModel))
         let vc = UIHostingController(rootView: PurchaseView(viewModel: viewModel))
         vc.view.backgroundColor = .clear
         vc.view.backgroundColor = .clear
         return vc
         return vc
@@ -100,8 +104,9 @@ class TSPurchaseVC: TSBaseVC {
     
     
     override func dealThings() {
     override func dealThings() {
         
         
-        //周会员不自动处理变化,必须点击购买后才处理
-        if purchaseManager.vipType == .week {
+        //周会员和月会员不自动处理变化,必须点击购买后才处理
+        let vipType = purchaseManager.vipType
+        if vipType == .week || vipType == .month {
             isHandlePurchaseStateChanged = false
             isHandlePurchaseStateChanged = false
         }
         }
 
 
@@ -313,9 +318,7 @@ struct PurchaseView :View {
         
         
         VStack {
         VStack {
             Spacer()
             Spacer()
-#if DEBUG
-//    let vipType = PremiumPeriod.week
-#endif
+            
             VStack {
             VStack {
                 let text = vipType == .none ? "Get PRO Access".localized : "Super Offer for Yearly Pro".localized
                 let text = vipType == .none ? "Get PRO Access".localized : "Super Offer for Yearly Pro".localized
                 Text(text)
                 Text(text)
@@ -346,10 +349,10 @@ struct PurchaseView :View {
                 
                 
                 if vipType == .none {
                 if vipType == .none {
                     ZStack(alignment: .topTrailing) {
                     ZStack(alignment: .topTrailing) {
-                        PurchaseItemView(title: "One Year".localized, type: .year, selectedType: $viewModel.selectedType).onTapGesture {
-                            viewModel.selectedType = .year
+                        PurchaseItemView(title: "One Month".localized, type: .month, selectedType: $viewModel.selectedType).onTapGesture {
+                            viewModel.selectedType = .month
                         }
                         }
-                        TSVipRecView()
+                        TSVipRecView(save: vipType.saveString)
                             .offset(x:-30,y:-14)
                             .offset(x:-30,y:-14)
                     }
                     }
                     
                     
@@ -499,11 +502,12 @@ struct PurchaseItemTypeOneView: View {
 
 
 //推荐选择view
 //推荐选择view
 struct TSVipRecView: View {
 struct TSVipRecView: View {
+    var save:String //年 80%,月 30%
     var body: some View {
     var body: some View {
     
     
         HStack(spacing: 4) {
         HStack(spacing: 4) {
             Image("upvote_black").resizable().frame(width: 16, height: 16)
             Image("upvote_black").resizable().frame(width: 16, height: 16)
-            Text("Save-Vip".localized + " 80%").font(.font(size: 12,weight: .medium)).foregroundColor(.hex("#111111"))
+            Text("Save-Vip".localized + " " + save).font(.font(size: 12,weight: .medium)).foregroundColor(.hex("#111111"))
         }
         }
         .padding(EdgeInsets(top: 6, leading: 6, bottom: 6, trailing: 6))
         .padding(EdgeInsets(top: 6, leading: 6, bottom: 6, trailing: 6))
         .background(Color.hex("#FECB34"))
         .background(Color.hex("#FECB34"))

+ 4 - 6
AIEmoji/Business/TSSetingVC/SetingVC/View/SettingPurchaseTopView.swift

@@ -9,14 +9,12 @@ struct SettingPurchaseTopView: View {
     var eventPublisher: ListEventPublisher
     var eventPublisher: ListEventPublisher
     @Binding var vipType: PremiumPeriod
     @Binding var vipType: PremiumPeriod
     var body: some View {
     var body: some View {
-#if DEBUG
-//        let vipType = PremiumPeriod.year
-#endif
+
         let topW = k_ScreenWidth-32
         let topW = k_ScreenWidth-32
         let topH = 134.0    //kGetScaleHeight(originalSize: CGSize(width: 343, height: 130), width: topW)
         let topH = 134.0    //kGetScaleHeight(originalSize: CGSize(width: 343, height: 130), width: topW)
-        let updateText = vipType == .week ? "Upgrade Yearly Pro".localized : "Upgrade to PRO".localized
+        let updateText = vipType == .none ? "Upgrade to PRO".localized : "Upgrade Yearly Pro".localized
         let timeString = "Due Date:".localized + " \(PurchaseManager.default.expiredDateString)"
         let timeString = "Due Date:".localized + " \(PurchaseManager.default.expiredDateString)"
-        let timeText = vipType == .week ? timeString : "Limited Time Discount".localized
+        let timeText = vipType == .none ? "Limited Time Discount".localized : timeString
         ZStack {
         ZStack {
             Image(.settingVipBj).resizable().cornerRadius(16.0)
             Image(.settingVipBj).resizable().cornerRadius(16.0)
             if vipType == .year {
             if vipType == .year {
@@ -44,7 +42,7 @@ struct SettingPurchaseTopView: View {
                         
                         
                         Spacer()
                         Spacer()
                  
                  
-                        Text("Save-Vip".localized + " 80%")
+                        Text("Save-Vip".localized + " " + vipType.saveString)
                             .lineLimit(1)
                             .lineLimit(1)
                             .foregroundColor(Color.white)
                             .foregroundColor(Color.white)
                             .font(.font(size: 12,weight: .semibold))
                             .font(.font(size: 12,weight: .semibold))

+ 99 - 14
AIEmoji/Common/Purchase/TSPurchaseManager.swift

@@ -20,6 +20,8 @@ public enum PremiumPeriod: String, CaseIterable {
         switch self {
         switch self {
         case .week:
         case .week:
             return 30
             return 30
+        case .month:
+            return 30
         case .year:
         case .year:
             return 60
             return 60
         case .none:
         case .none:
@@ -28,6 +30,38 @@ public enum PremiumPeriod: String, CaseIterable {
             return 30
             return 30
         }
         }
     }
     }
+    
+    /// 对应vip类型,可以免费使用次数
+    var saveString: String {
+        switch self {
+        case .none:
+            return "30%"
+        default:
+            return "80%"
+        }
+    }
+    /*
+    1. 一年(非闰年)
+    ​365 天​ = 365 × 24 × 60 × 60 × 1000 = ​31,536,000,000 毫秒
+    (若闰年 366 天 = 31,622,400,000 毫秒)
+    ​2. 一个月(平均)
+    ​30.44 天​(按 365 天/12 个月计算)≈ 30.44 × 24 × 60 × 60 × 1000 ≈ ​2,629,746,000 毫秒
+    (实际月份天数不同,如 28/30/31 天需单独计算)
+    ​3. 一周
+    ​7 天​ = 7 × 24 × 60 × 60 × 1000 = ​604,800,000 毫秒
+    */
+    var milliseconds:Int {
+        switch self {
+        case .year:
+            return  365 * 24 * 60 * 60 * 1000
+        case .month:
+            return 30 * 24 * 60 * 60 * 1000
+        case .week:
+            return 7 * 24 * 60 * 60 * 1000
+        default:
+            return 0
+        }
+    }
 }
 }
 
 
 public enum VipFreeNumType: String, CaseIterable {
 public enum VipFreeNumType: String, CaseIterable {
@@ -89,10 +123,9 @@ public class PurchaseManager: NSObject {
     // 商品信息
     // 商品信息
     public lazy var purchaseProducts: [PurchaseProduct] = {
     public lazy var purchaseProducts: [PurchaseProduct] = {
         [
         [
-//            PurchaseProduct(productId: "101", period:.month),
+            PurchaseProduct(productId: "101", period: .month),
             PurchaseProduct(productId: "102", period: .year),
             PurchaseProduct(productId: "102", period: .year),
-            PurchaseProduct(productId: "103", period: .week),
-            // PurchaseProduct(productId: "003", period: .lifetime),
+            PurchaseProduct(productId: "103", period: .week)
         ]
         ]
     }()
     }()
 
 
@@ -167,9 +200,9 @@ public class PurchaseManager: NSObject {
     }
     }
 
 
     @objc public var isVip: Bool {
     @objc public var isVip: Bool {
-//        #if DEBUG
-//            return true
-//        #endif
+//#if DEBUG
+//        return vipType != .none
+//#endif
         guard let expiresDate = expiredDate else {
         guard let expiresDate = expiredDate else {
             return false
             return false
         }
         }
@@ -181,9 +214,13 @@ public class PurchaseManager: NSObject {
     }
     }
 
 
     public var vipType: PremiumPeriod {
     public var vipType: PremiumPeriod {
+//#if DEBUG
+//        return PremiumPeriod.week
+//#endif
         guard isVip, let type = vipInformation["type"] as? String else {
         guard isVip, let type = vipInformation["type"] as? String else {
             return .none
             return .none
         }
         }
+        debugPrint("PurchaseManager get vipType = \(type)")
         return PremiumPeriod(rawValue: type) ?? .none
         return PremiumPeriod(rawValue: type) ?? .none
     }
     }
 
 
@@ -194,10 +231,9 @@ public class PurchaseManager: NSObject {
         vipInformation["expireTime"] = timeInterval
         vipInformation["expireTime"] = timeInterval
         vipInformation["productId"] = productId
         vipInformation["productId"] = productId
         vipInformation["type"] = period(for: productId).rawValue
         vipInformation["type"] = period(for: productId).rawValue
-
+        dePrint("vipInformation = \(vipInformation)")
         UserDefaults.standard.set(vipInformation, forKey: kPremiumExpiredInfoKey)
         UserDefaults.standard.set(vipInformation, forKey: kPremiumExpiredInfoKey)
         UserDefaults.standard.synchronize()
         UserDefaults.standard.synchronize()
-
         NotificationCenter.default.post(name: .kPurchaseDidChanged, object: nil)
         NotificationCenter.default.post(name: .kPurchaseDidChanged, object: nil)
     }
     }
 
 
@@ -315,7 +351,7 @@ extension PurchaseManager {
     public func restorePremium() {
     public func restorePremium() {
         purchase(self, didChaged: .restoreing, object: nil)
         purchase(self, didChaged: .restoreing, object: nil)
         SKPaymentQueue.default().restoreCompletedTransactions()
         SKPaymentQueue.default().restoreCompletedTransactions()
-        debugPrint("PurchaseManager restoreCompletedTransactions")
+        debugPrint("PurchaseManager restoreCompletedTransactions restorePremium")
 
 
         subscriptionApple(type: .created, jsonString: "Payment restore")
         subscriptionApple(type: .created, jsonString: "Payment restore")
     }
     }
@@ -329,12 +365,14 @@ extension PurchaseManager {
 
 
         guard SKPaymentQueue.default().transactions.count <= 0 else {
         guard SKPaymentQueue.default().transactions.count <= 0 else {
             purchase(self, didChaged: .payFail, object: "You have outstanding orders that must be paid for before a new subscription can be placed.")
             purchase(self, didChaged: .payFail, object: "You have outstanding orders that must be paid for before a new subscription can be placed.")
+            debugPrint("PurchaseManager pay period restorePremium = \(period)")
             restorePremium()
             restorePremium()
             return
             return
         }
         }
         if let product = product(for: period) {
         if let product = product(for: period) {
             purchase(self, didChaged: .paying, object: nil)
             purchase(self, didChaged: .paying, object: nil)
             let payment = SKPayment(product: product)
             let payment = SKPayment(product: product)
+            debugPrint("PurchaseManager pay product = \(product.localizedDescription)")
             SKPaymentQueue.default().add(payment)
             SKPaymentQueue.default().add(payment)
             debugPrint("PurchaseManager pay period = \(period)")
             debugPrint("PurchaseManager pay period = \(period)")
 
 
@@ -536,11 +574,13 @@ extension PurchaseManager {
         }
         }
 
 
         if !isLifetime {
         if !isLifetime {
-            let info = resp["latest_receipt_info"] as? [[String: Any]]
-            if let firstItem = info?.first,
-               let expires_date_ms = firstItem["expires_date_ms"] as? String,
-               let productId = firstItem["product_id"] as? String {
-                updateExpireTime(expires_date_ms, for: productId)
+            if upgradePendingRenewalInfo(resp) == false {
+                let info = resp["latest_receipt_info"] as? [[String: Any]]
+                if let firstItem = info?.first,
+                   let expires_date_ms = firstItem["expires_date_ms"] as? String,
+                   let productId = firstItem["product_id"] as? String {
+                    updateExpireTime(expires_date_ms, for: productId)
+                }
             }
             }
         }
         }
 
 
@@ -554,6 +594,51 @@ extension PurchaseManager {
 
 
         subscriptionApple(type: .result, jsonString: simplifyVerifyPayResult(resp: resp))
         subscriptionApple(type: .result, jsonString: simplifyVerifyPayResult(resp: resp))
     }
     }
+    
+    
+    func upgradePendingRenewalInfo(_ resp: [String: Any]) -> Bool {
+        guard !resp.isEmpty else {
+            return false
+        }
+        /*
+        pending_renewal_info={
+            "auto_renew_product_id" = 102;
+            "auto_renew_status" = 1;
+            "original_transaction_id" = 2000000929272571;
+            "product_id" = 101;
+        }*/
+        let info = resp["pending_renewal_info"] as? [[String: Any]]
+        if let firstItem = info?.first,
+           let auto_renew_product_id = firstItem["auto_renew_product_id"] as? String,
+           let auto_product_id = firstItem["product_id"] as? String {
+            if auto_renew_product_id != auto_product_id {//拿到待生效的和当前的对比不一样,以待生效的为主
+                
+                //取当前的过期时间+加上待生效的会员过期时长
+                let info = resp["latest_receipt_info"] as? [[String: Any]]
+                if let firstItem = info?.first,
+                   let expires_date_ms = firstItem["expires_date_ms"] as? String {
+                    let expiresms = Int(expires_date_ms) ?? 0 + period(for: auto_renew_product_id).milliseconds
+                    updateExpireTime(String(expiresms), for: auto_renew_product_id)
+                    return true
+                }
+            }
+        }
+        return false
+    }
+//    func findLatestSubscription(_ receipts: [[String: Any]]?) -> [String: Any]? {
+//        guard let receiptInfo = receipts , !receiptInfo.isEmpty else {
+//            return nil
+//        }
+//        
+//        // 使用 max(by:) 找出 expires_date_ms 最大的对象
+//        let latestSubscription = receiptInfo.max { (first, second) -> Bool in
+//            let firstExpiry = Int(first["expires_date_ms"] as? String ?? "0") ?? 0
+//            let secondExpiry = Int(second["expires_date_ms"] as? String ?? "0") ?? 0
+//            return firstExpiry < secondExpiry
+//        }
+//        
+//        return latestSubscription
+//    }
 
 
     // 终生会员过期时间:100年
     // 终生会员过期时间:100年
     var lifetimeExpireTime: String {
     var lifetimeExpireTime: String {