Browse Source

feat:阶梯价开发完毕

100Years 2 weeks ago
parent
commit
0e9a443621
34 changed files with 1331 additions and 254 deletions
  1. 48 0
      AIEmoji.xcodeproj/project.pbxproj
  2. 2 0
      AIEmoji/AppDelegate.swift
  3. 22 0
      AIEmoji/Assets.xcassets/VIP/countdown_bg.imageset/Contents.json
  4. BIN
      AIEmoji/Assets.xcassets/VIP/countdown_bg.imageset/countdown_bg@2x.png
  5. BIN
      AIEmoji/Assets.xcassets/VIP/countdown_bg.imageset/countdown_bg@3x.png
  6. 22 0
      AIEmoji/Assets.xcassets/VIP/countdown_small_bg.imageset/Contents.json
  7. BIN
      AIEmoji/Assets.xcassets/VIP/countdown_small_bg.imageset/countdown_small_bg@2x.png
  8. BIN
      AIEmoji/Assets.xcassets/VIP/countdown_small_bg.imageset/countdown_small_bg@3x.png
  9. 21 0
      AIEmoji/Assets.xcassets/VIP/promotional_topImage.imageset/Contents.json
  10. BIN
      AIEmoji/Assets.xcassets/VIP/promotional_topImage.imageset/promotional_topImage.png
  11. 89 0
      AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchaseCountdownView.swift
  12. 173 0
      AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalCountDownTime.swift
  13. 232 0
      AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalVC+View.swift
  14. 64 0
      AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalVC.swift
  15. 102 0
      AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVC+Promotional.swift
  16. 42 235
      AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift
  17. 231 0
      AIEmoji/Business/TSPurchaseMembershipVC/View/PurchaseView.swift
  18. 51 3
      AIEmoji/Business2/DisCover/TSDiscoverVC/TSDiscoverVC.swift
  19. 2 0
      AIEmoji/Common/Ex/UIFont+TSEx.swift
  20. 147 15
      AIEmoji/Common/Purchase/TSPurchaseManager.swift
  21. 1 0
      AIEmoji/Info.plist
  22. BIN
      AIEmoji/Res/Gift.apng
  23. BIN
      AIEmoji/Res/Poppins-Bold.otf
  24. 8 0
      AIEmoji/de.lproj/Localizable.strings
  25. 8 0
      AIEmoji/en.lproj/Localizable.strings
  26. 8 0
      AIEmoji/es.lproj/Localizable.strings
  27. 8 0
      AIEmoji/ja.lproj/Localizable.strings
  28. 8 0
      AIEmoji/ko.lproj/Localizable.strings
  29. 8 0
      AIEmoji/pt-BR.lproj/Localizable.strings
  30. 8 0
      AIEmoji/pt-PT.lproj/Localizable.strings
  31. 8 0
      AIEmoji/zh-Hans.lproj/Localizable.strings
  32. 8 0
      AIEmoji/zh-Hant.lproj/Localizable.strings
  33. 1 0
      Podfile
  34. 9 1
      Podfile.lock

+ 48 - 0
AIEmoji.xcodeproj/project.pbxproj

@@ -237,6 +237,14 @@
 		A8D638472DB21FAD00A96C0E /* TSBusinessFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638452DB21FAD00A96C0E /* TSBusinessFileManager.swift */; };
 		A8D638472DB21FAD00A96C0E /* TSBusinessFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638452DB21FAD00A96C0E /* TSBusinessFileManager.swift */; };
 		A8D638482DB21FAD00A96C0E /* TSDownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638462DB21FAD00A96C0E /* TSDownloadManager.swift */; };
 		A8D638482DB21FAD00A96C0E /* TSDownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638462DB21FAD00A96C0E /* TSDownloadManager.swift */; };
 		A8D6384A2DB252F100A96C0E /* TSAIListHistoryBaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8D638492DB252F000A96C0E /* TSAIListHistoryBaseCell.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 */; };
 		A8EEADD42D3E6C660032C5A0 /* Flower💐.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD32D3E6C610032C5A0 /* Flower💐.json */; };
 		A8EEADD42D3E6C660032C5A0 /* Flower💐.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD32D3E6C610032C5A0 /* Flower💐.json */; };
 		A8EEADD62D3E6CD80032C5A0 /* Fish🐠.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */; };
 		A8EEADD62D3E6CD80032C5A0 /* Fish🐠.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */; };
 		A8EEADD82D3E74D20032C5A0 /* Pink🩷.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */; };
 		A8EEADD82D3E74D20032C5A0 /* Pink🩷.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */; };
@@ -566,6 +574,14 @@
 		A8D638452DB21FAD00A96C0E /* TSBusinessFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBusinessFileManager.swift; sourceTree = "<group>"; };
 		A8D638452DB21FAD00A96C0E /* TSBusinessFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBusinessFileManager.swift; sourceTree = "<group>"; };
 		A8D638462DB21FAD00A96C0E /* TSDownloadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSDownloadManager.swift; sourceTree = "<group>"; };
 		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>"; };
 		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>"; };
 		A8EEADD32D3E6C610032C5A0 /* Flower💐.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Flower💐.json"; 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>"; };
 		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>"; };
 		A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Pink🩷.json"; sourceTree = "<group>"; };
@@ -863,7 +879,10 @@
 		A80E73DD2D533E5800C64288 /* TSPurchaseMembershipVC */ = {
 		A80E73DD2D533E5800C64288 /* TSPurchaseMembershipVC */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				A8EB38442E14080D002F90E9 /* TSPurchasePromotionalVC */,
+				A8EB383F2E13BB07002F90E9 /* View */,
 				A80E73D82D533E5800C64288 /* TSPurchaseVC.swift */,
 				A80E73D82D533E5800C64288 /* TSPurchaseVC.swift */,
+				A8EB38392E138058002F90E9 /* TSPurchaseVC+Promotional.swift */,
 			);
 			);
 			path = TSPurchaseMembershipVC;
 			path = TSPurchaseMembershipVC;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -1859,6 +1878,25 @@
 			path = TSAIListVideoPlayerVC;
 			path = TSAIListVideoPlayerVC;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
 		};
 		};
+		A8EB383F2E13BB07002F90E9 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				A8EB38402E13BB0D002F90E9 /* PurchaseView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
+		A8EB38442E14080D002F90E9 /* TSPurchasePromotionalVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8EB38472E140844002F90E9 /* TSPurchaseCountdownView.swift */,
+				A8EB38452E140828002F90E9 /* TSPurchasePromotionalCountDownTime.swift */,
+				A8EB38372E137F47002F90E9 /* TSPurchasePromotionalVC.swift */,
+				A8EB383B2E13AE67002F90E9 /* TSPurchasePromotionalVC+View.swift */,
+			);
+			path = TSPurchasePromotionalVC;
+			sourceTree = "<group>";
+		};
 		A8F413492DA75863001E715A /* TSUploadPhotoPrivacyAlertVC */ = {
 		A8F413492DA75863001E715A /* TSUploadPhotoPrivacyAlertVC */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -2281,10 +2319,12 @@
 		A8FB02AE2D3E38FA0031A396 /* Res */ = {
 		A8FB02AE2D3E38FA0031A396 /* Res */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				A8EB38422E13FEF3002F90E9 /* Gift.apng */,
 				A8708A522E0D4FA000601686 /* discover_0_AnimatePhoto.gif */,
 				A8708A522E0D4FA000601686 /* discover_0_AnimatePhoto.gif */,
 				A83404D62D9D34ED00C140E4 /* Kelsi-fill.otf */,
 				A83404D62D9D34ED00C140E4 /* Kelsi-fill.otf */,
 				A83404D72D9D34ED00C140E4 /* Kelsi-Regular.otf */,
 				A83404D72D9D34ED00C140E4 /* Kelsi-Regular.otf */,
 				A81BECB02DD4AE9A005D06A2 /* Poppins-BoldItalic.otf */,
 				A81BECB02DD4AE9A005D06A2 /* Poppins-BoldItalic.otf */,
+				A8EB38492E14E220002F90E9 /* Poppins-Bold.otf */,
 				A83404CB2D9BEED800C140E4 /* Poppins-BlackItalic.ttf */,
 				A83404CB2D9BEED800C140E4 /* Poppins-BlackItalic.ttf */,
 				A83404DA2D9D382200C140E4 /* AccentURW-Reg.ttf */,
 				A83404DA2D9D382200C140E4 /* AccentURW-Reg.ttf */,
 				A8F7D33D2DF18A1800DDBECE /* arrow.gif */,
 				A8F7D33D2DF18A1800DDBECE /* arrow.gif */,
@@ -2422,6 +2462,8 @@
 				A87587162D81734300286A66 /* text_to_photo_style.json in Resources */,
 				A87587162D81734300286A66 /* text_to_photo_style.json in Resources */,
 				A8FDB1812DCC8C5600E9919B /* catPaw_left.gif in Resources */,
 				A8FDB1812DCC8C5600E9919B /* catPaw_left.gif in Resources */,
 				A8F7D33E2DF18A1800DDBECE /* arrow.gif in Resources */,
 				A8F7D33E2DF18A1800DDBECE /* arrow.gif in Resources */,
+				A8EB384A2E14E220002F90E9 /* Poppins-Bold.otf in Resources */,
+				A8EB38432E13FEF3002F90E9 /* Gift.apng in Resources */,
 				A8FDB1822DCC8C5600E9919B /* catPaw_right.gif in Resources */,
 				A8FDB1822DCC8C5600E9919B /* catPaw_right.gif in Resources */,
 				A8EEADD42D3E6C660032C5A0 /* Flower💐.json in Resources */,
 				A8EEADD42D3E6C660032C5A0 /* Flower💐.json in Resources */,
 				A82D60812DB7A1E600596190 /* activePhoto.gif in Resources */,
 				A82D60812DB7A1E600596190 /* activePhoto.gif in Resources */,
@@ -2535,6 +2577,7 @@
 				A80E721A2D3F393A00C64288 /* DiyStickerModel.swift in Sources */,
 				A80E721A2D3F393A00C64288 /* DiyStickerModel.swift in Sources */,
 				A80EDDEB2D6EC014003CD332 /* TSPhotoToPhotoVC.swift in Sources */,
 				A80EDDEB2D6EC014003CD332 /* TSPhotoToPhotoVC.swift in Sources */,
 				A80E726F2D40DE2B00C64288 /* TSWallpaperPreviewVC.swift in Sources */,
 				A80E726F2D40DE2B00C64288 /* TSWallpaperPreviewVC.swift in Sources */,
+				A8EB38382E137F48002F90E9 /* TSPurchasePromotionalVC.swift in Sources */,
 				A8F775492D3935D600AA6E93 /* TSBusinessWebVC.swift in Sources */,
 				A8F775492D3935D600AA6E93 /* TSBusinessWebVC.swift in Sources */,
 				A8F776392D3B38E600AA6E93 /* TSGenmojiGennerateVC.swift in Sources */,
 				A8F776392D3B38E600AA6E93 /* TSGenmojiGennerateVC.swift in Sources */,
 				A85E47C02D6961BB0018D62D /* TSChatMessageUIModel.swift in Sources */,
 				A85E47C02D6961BB0018D62D /* TSChatMessageUIModel.swift in Sources */,
@@ -2576,6 +2619,7 @@
 				A8D6384A2DB252F100A96C0E /* TSAIListHistoryBaseCell.swift in Sources */,
 				A8D6384A2DB252F100A96C0E /* TSAIListHistoryBaseCell.swift in Sources */,
 				A80EDD5A2D6C3F82003CD332 /* MarkdownParser.swift in Sources */,
 				A80EDD5A2D6C3F82003CD332 /* MarkdownParser.swift in Sources */,
 				A80EDD5B2D6C3F82003CD332 /* MarkdownCommonElement.swift in Sources */,
 				A80EDD5B2D6C3F82003CD332 /* MarkdownCommonElement.swift in Sources */,
+				A8EB38482E140848002F90E9 /* TSPurchaseCountdownView.swift in Sources */,
 				A82D60792DB7703D00596190 /* TSAIExpandImageVC.swift in Sources */,
 				A82D60792DB7703D00596190 /* TSAIExpandImageVC.swift in Sources */,
 				A8990EE82DEE8CC200DD55FE /* TSFutureBabyVC.swift in Sources */,
 				A8990EE82DEE8CC200DD55FE /* TSFutureBabyVC.swift in Sources */,
 				A8708A1F2E095A8800601686 /* TSDiscoverFullCardCell.swift in Sources */,
 				A8708A1F2E095A8800601686 /* TSDiscoverFullCardCell.swift in Sources */,
@@ -2663,6 +2707,7 @@
 				A80E72222D3F3A9200C64288 /* DiyStickerElement.swift in Sources */,
 				A80E72222D3F3A9200C64288 /* DiyStickerElement.swift in Sources */,
 				A85E47C32D6964A50018D62D /* TSMSGAIDefaultHeaderView.swift in Sources */,
 				A85E47C32D6964A50018D62D /* TSMSGAIDefaultHeaderView.swift in Sources */,
 				A80EDD032D6C282B003CD332 /* TSMarkDownTool.swift in Sources */,
 				A80EDD032D6C282B003CD332 /* TSMarkDownTool.swift in Sources */,
+				A8EB383C2E13AE6F002F90E9 /* TSPurchasePromotionalVC+View.swift in Sources */,
 				A8F775002D38EA8C00AA6E93 /* WindowHelper.swift in Sources */,
 				A8F775002D38EA8C00AA6E93 /* WindowHelper.swift in Sources */,
 				A8F7764B2D3E008500AA6E93 /* TSEmojisChildColViewModel.swift in Sources */,
 				A8F7764B2D3E008500AA6E93 /* TSEmojisChildColViewModel.swift in Sources */,
 				A80E72772D41EFF900C64288 /* TSEmojisTutorialsVC.swift in Sources */,
 				A80E72772D41EFF900C64288 /* TSEmojisTutorialsVC.swift in Sources */,
@@ -2692,10 +2737,12 @@
 				A85E47BE2D68999B0018D62D /* ShareActivityItemProvider.swift in Sources */,
 				A85E47BE2D68999B0018D62D /* ShareActivityItemProvider.swift in Sources */,
 				A81BECA82DD1F075005D06A2 /* TSGeneratoringAnimationView.swift in Sources */,
 				A81BECA82DD1F075005D06A2 /* TSGeneratoringAnimationView.swift in Sources */,
 				A8F7763C2D3B429B00AA6E93 /* TSCommonloadingView.swift in Sources */,
 				A8F7763C2D3B429B00AA6E93 /* TSCommonloadingView.swift in Sources */,
+				A8EB38412E13BB0E002F90E9 /* PurchaseView.swift in Sources */,
 				A8BA76752DA67E66000B6707 /* TSAIListHistoryBaseVC.swift in Sources */,
 				A8BA76752DA67E66000B6707 /* TSAIListHistoryBaseVC.swift in Sources */,
 				A8F776322D3A771400AA6E93 /* TSGenmojiCollectionViewModel.swift in Sources */,
 				A8F776322D3A771400AA6E93 /* TSGenmojiCollectionViewModel.swift in Sources */,
 				A80E721E2D3F3A7500C64288 /* DiyElement.swift in Sources */,
 				A80E721E2D3F3A7500C64288 /* DiyElement.swift in Sources */,
 				A8708A132E0958F200601686 /* TSDiscoverVC.swift in Sources */,
 				A8708A132E0958F200601686 /* TSDiscoverVC.swift in Sources */,
+				A8EB38462E140829002F90E9 /* TSPurchasePromotionalCountDownTime.swift in Sources */,
 				A83404D32D9D23FA00C140E4 /* TSGeneratorloadingView.swift in Sources */,
 				A83404D32D9D23FA00C140E4 /* TSGeneratorloadingView.swift in Sources */,
 				A8F776372D3A806E00AA6E93 /* TSGenmojiItemCell.swift in Sources */,
 				A8F776372D3A806E00AA6E93 /* TSGenmojiItemCell.swift in Sources */,
 				A89EA6692D59AA31000EB181 /* CameraInputBarAccessoryView.swift in Sources */,
 				A89EA6692D59AA31000EB181 /* CameraInputBarAccessoryView.swift in Sources */,
@@ -2736,6 +2783,7 @@
 				A8708A472E0BFD1E00601686 /* TSTextToastView.swift in Sources */,
 				A8708A472E0BFD1E00601686 /* TSTextToastView.swift in Sources */,
 				A83405202DA3ADA900C140E4 /* TSPhotoSizeHelper.swift in Sources */,
 				A83405202DA3ADA900C140E4 /* TSPhotoSizeHelper.swift in Sources */,
 				A8F775382D390C3C00AA6E93 /* TSNetworkManager.swift in Sources */,
 				A8F775382D390C3C00AA6E93 /* TSNetworkManager.swift in Sources */,
+				A8EB383A2E138061002F90E9 /* TSPurchaseVC+Promotional.swift in Sources */,
 				A80EDDE72D6EBFC1003CD332 /* TSPTPGeneratorVM.swift in Sources */,
 				A80EDDE72D6EBFC1003CD332 /* TSPTPGeneratorVM.swift in Sources */,
 				A8BA76682DA6567E000B6707 /* TSAIListHintBaseVC.swift in Sources */,
 				A8BA76682DA6567E000B6707 /* TSAIListHintBaseVC.swift in Sources */,
 				A8708A432E0B93EF00601686 /* TSAIGenerateBaseVC+Video.swift in Sources */,
 				A8708A432E0B93EF00601686 /* TSAIGenerateBaseVC+Video.swift in Sources */,

+ 2 - 0
AIEmoji/AppDelegate.swift

@@ -58,6 +58,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
         checkAppConfig()
         checkAppConfig()
 
 
         kHandleDBHistoryOperation()
         kHandleDBHistoryOperation()
+        
+        kPurchaseCountDownTime.autoStart()
     }
     }
 }
 }
 
 

+ 22 - 0
AIEmoji/Assets.xcassets/VIP/countdown_bg.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "countdown_bg@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "countdown_bg@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AIEmoji/Assets.xcassets/VIP/countdown_bg.imageset/countdown_bg@2x.png


BIN
AIEmoji/Assets.xcassets/VIP/countdown_bg.imageset/countdown_bg@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/VIP/countdown_small_bg.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "countdown_small_bg@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "countdown_small_bg@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AIEmoji/Assets.xcassets/VIP/countdown_small_bg.imageset/countdown_small_bg@2x.png


BIN
AIEmoji/Assets.xcassets/VIP/countdown_small_bg.imageset/countdown_small_bg@3x.png


+ 21 - 0
AIEmoji/Assets.xcassets/VIP/promotional_topImage.imageset/Contents.json

@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "filename" : "promotional_topImage.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
AIEmoji/Assets.xcassets/VIP/promotional_topImage.imageset/promotional_topImage.png


+ 89 - 0
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchaseCountdownView.swift

@@ -0,0 +1,89 @@
+//
+//  TSPurchaseCountdownView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/7/1.
+//
+class TSPurchaseCountdownView: TSBaseView {
+    
+    let minLabel:UILabel = UILabel()
+    let secLabel:UILabel = UILabel()
+    
+    var clickBlock:(()->Void)?
+    
+    override func creatUI() {
+        
+        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickView)))
+        let countdownView = creatCountdownView()
+        contentView.addSubview(countdownView)
+        countdownView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+    
+    @objc func clickView(){
+        clickBlock?()
+    }
+    
+    func creatCountdownView() -> UIView {
+        let countdownView = UIView()
+        
+        let min = creatItem(label: minLabel, unit: "min".localized)
+        let sec = creatItem(label: secLabel, unit: "sec".localized)
+        countdownView.addSubview(min)
+        countdownView.addSubview(sec)
+        
+        let label = UILabel.createLabel(text: ":",font: .font(size: 10,weight: .semibold),textColor: .white,textAlignment: .center)
+        countdownView.addSubview(label)
+        
+        label.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.equalTo(5)
+            make.height.equalTo(24)
+        }
+        
+        min.snp.makeConstraints { make in
+            make.leading.equalToSuperview()
+            make.trailing.equalTo(label.snp.leading).offset(-2)
+            make.height.equalToSuperview()
+        }
+        
+        sec.snp.makeConstraints { make in
+            make.trailing.equalToSuperview()
+            make.leading.equalTo(label.snp.trailing).offset(2)
+            make.height.equalToSuperview()
+        }
+        
+        return countdownView
+    }
+    
+    
+    func creatItem(label:UILabel,unit:String) -> UIView {
+        
+        let bgView = UIView()
+        let bgImageView:UIImageView = UIImageView(image: .countdownSmallBg)
+//        bgImageView.backgroundColor = .black.withAlphaComponent(0.3)
+//        bgImageView.cornerRadius = 6
+        bgView.addSubview(bgImageView)
+        
+        label.setUpLabel(font:.font(size: 12,weight: .medium),textColor: .white,textAlignment: .center)
+        bgImageView.addSubview(label)
+        
+        bgImageView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+            make.width.height.equalTo(24)
+        }
+        
+        label.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+
+        
+        kMainAsync {
+            label.applyGradient(colors: ["#FA794F".uiColor,"#F8C32A".uiColor,"#FEFBF4".uiColor])
+        }
+        
+        return bgView
+    }
+}
+

+ 173 - 0
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalCountDownTime.swift

@@ -0,0 +1,173 @@
+//
+//  TSPurchasePromotionalCountDownTime.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/7/1.
+//
+
+import ObjectMapper
+
+class TSPurchasePromotionalTimeModel: TSBaseModel {
+    var startTimestampInt:Int = 0
+    var endTimestampInt:Int = 0
+    var startDayString:String = ""
+    override func mapping(map: ObjectMapper.Map) {
+        startTimestampInt  <- map["startTimestampInt"]
+        endTimestampInt    <- map["endTimestampInt"]
+        startDayString    <- map["startDayString"]
+    }
+}
+
+
+
+/**
+ 1.一天只开启一次倒计时
+ 2.第二次开启倒计时,直接进去
+ */
+
+let kPurchaseCountDownTime = TSPurchasePromotionalCountDownTime()
+class TSPurchasePromotionalCountDownTime {
+ 
+    let timer:TSGCDTimer = TSGCDTimer()
+    var countDownTime:Int = 300//30分钟 = 1800
+    private var countDownInt:Int = 0
+    init(countDownTime: Int = 300) {
+        self.countDownTime = countDownTime
+        
+        // 监听应用生命周期事件
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(handleAppDidEnterBackground),
+            name: UIApplication.didEnterBackgroundNotification,
+            object: nil
+        )
+        
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(handleAppWillEnterForeground),
+            name: UIApplication.willEnterForegroundNotification,
+            object: nil
+        )
+    }
+    
+    @objc private func handleAppDidEnterBackground() {
+        timer.stop()
+    }
+
+    @objc private func handleAppWillEnterForeground() {
+        autoStart()
+    }
+    
+    var complete:((String,String,Bool)->Void)?{
+        didSet{
+            if timer.isRunning {
+                handleCountDownTime()
+            }
+        }
+    }
+    
+    var isHaveTime:Bool{
+        guard let timeModel = timeModel else { return false }
+        let dis:Int = timeModel.endTimestampInt - Date.timestampInt
+        
+        if dis > 0 && dis <= 1800 {
+            return true
+        }
+        return false
+    }
+    
+    var isTodayAvailable:Bool{
+        guard let timeModel = timeModel else { return true }
+        return timeModel.startDayString != dateFormatter.string(from: Date())
+    }
+    
+    var isShowGift:Bool{
+        if isTodayAvailable == true , isHaveTime == false {
+            return true
+        }
+        return false
+    }
+    
+    var isShowCountDownTime:Bool{
+        if isHaveTime {
+            return true
+        }
+        return false
+    }
+    
+    var isCreatNewTimeModel:Bool{
+        if isHaveTime {
+            return true
+        }
+        return false
+    }
+    lazy var dateFormatter: DateFormatter = {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "yyyyMMdd"
+        return dateFormatter
+    }()
+    
+    
+    var timeModel: TSPurchasePromotionalTimeModel?{
+        if let dictionary = userDefaults.string(forKey: key),let timeModel = TSPurchasePromotionalTimeModel(JSONString: dictionary) {
+            return timeModel
+        }
+        return nil
+    }
+    
+    var key:String{
+        return "kTSPurchasePromotionalTimeModel"
+    }
+    
+    lazy var userDefaults: UserDefaults = {
+        let userDefaults = UserDefaults.standard
+        return userDefaults
+    }()
+    
+    var isCountDown:Bool{
+        timer.isRunning
+    }
+    
+    func autoStart(){
+        if isHaveTime == false { return }
+        guard let timeModel = self.timeModel else { return }
+        let currentTimestampInt = Date.timestampInt
+        self.countDownInt = timeModel.endTimestampInt - currentTimestampInt
+    
+        handleCountDownTime()
+
+        if timer.isRunning { return }
+        timer.start(interval: 1.0) {[weak self]  in
+            guard let self = self else { return }
+            self.countDownInt -= 1
+            handleCountDownTime()
+        }
+    }
+    
+    func handleCountDownTime(){
+        if self.countDownInt >= 0 {
+             let minutes = self.countDownInt / 60
+             let seconds = self.countDownInt % 60
+             self.complete?(String(format: "%02d", minutes),String(format: "%02d", seconds),false)
+         } else {
+             self.timer.stop()
+             self.complete?("00","00",true)
+         }
+    }
+    
+    func start(){
+        if isHaveTime == false && isTodayAvailable == true {
+            let currentTimestampInt = Date.timestampInt
+            let timeModel = TSPurchasePromotionalTimeModel()
+            timeModel.startTimestampInt = currentTimestampInt
+            timeModel.endTimestampInt = currentTimestampInt + countDownTime
+            timeModel.startDayString = dateFormatter.string(from: Date())
+         
+            if let string = timeModel.toJSONString()  {
+                userDefaults.setValue(string, forKey: key)
+                userDefaults.synchronize()
+            }
+        }
+        autoStart()
+    }
+}

+ 232 - 0
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalVC+View.swift

@@ -0,0 +1,232 @@
+//
+//  TSPurchasePromotionalVC+View.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/6/30.
+//
+
+extension TSPurchasePromotionalVC {
+    
+    
+    func creatFrontCtnView() -> UIView {
+        let frontCtnView = UIView()
+    
+        //原始价格
+        let priceLabel = UILabel.createLabel(text:promotionalPrice,font: .font(size: 82,weight: .bold),textColor: .white,textAlignment: .center)
+        frontCtnView.addSubview(priceLabel)
+        priceLabel.snp.makeConstraints { make in
+            make.leading.trailing.equalToSuperview()
+            make.height.equalTo(82)
+        }
+        //ONLY TODAY
+        let label1 = UILabel.createLabel(text:"ONLY TODAY".localized,font: .font(size: 18,weight: .medium),textColor: .themeColor,textAlignment: .center)
+        frontCtnView.addSubview(label1)
+        label1.snp.makeConstraints { make in
+            make.top.equalTo(priceLabel.snp.bottom).offset(13)
+            make.leading.trailing.equalToSuperview()
+            make.height.equalTo(27)
+        }
+        
+        //$4.99/Week
+        let label2 = UILabel.createLabel(text:originalPrice + "/" + "Week".localized,font: .font(size: 18,weight: .medium),textColor: "#CDCDCD".uiColor,textAlignment: .center)
+        frontCtnView.addSubview(label2)
+        label2.snp.makeConstraints { make in
+            make.top.equalTo(label1.snp.bottom).offset(4)
+            make.height.equalTo(14)
+            make.centerX.equalToSuperview()
+        }
+  
+        let line2 = UIView.creatColor(color: label2.textColor)
+        label2.addSubview(line2)
+        line2.snp.makeConstraints { make in
+            make.leading.trailing.centerY.equalToSuperview()
+            make.height.equalTo(0.6)
+        }
+        
+        //Limited Time Offer
+        let label3 = UILabel.createLabel(text:"Limited Time Offer".localized,font: .font(size: 18,weight: .medium),textColor: .white.withAlphaComponent(0.6),textAlignment: .center)
+        frontCtnView.addSubview(label3)
+        label3.snp.makeConstraints { make in
+            make.top.equalTo(label2.snp.bottom).offset(30)
+            make.leading.trailing.equalToSuperview()
+            make.height.equalTo(27)
+        }
+        
+        //倒计时
+        frontCtnView.addSubview(countdownView)
+        countdownView.snp.makeConstraints { make in
+            make.top.equalTo(label3.snp.bottom).offset(28)
+            make.centerX.equalToSuperview()
+            make.height.equalTo(68)
+        }
+        
+        //First week $2.99  Then total $4.99/week
+        let label4 = UILabel.createLabel(text:String(format: "First week %@ Then total %@/week".localized, promotionalPrice,originalPrice) ,font: .font(size: 14,weight: .regular),textColor: .white.withAlphaComponent(0.4),textAlignment: .center)
+        frontCtnView.addSubview(label4)
+        label4.snp.makeConstraints { make in
+            make.top.equalTo(countdownView.snp.bottom).offset(38)
+            make.leading.trailing.equalToSuperview()
+            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
+        frontCtnView.addSubview(submitBtn)
+        submitBtn.snp.makeConstraints { make in
+            make.top.equalTo(label4.snp.bottom).offset(14)
+            make.leading.equalTo(16.0)
+            make.trailing.equalTo(-16.0)
+            make.height.equalTo(48)
+        }
+        
+        //底部按钮组
+        frontCtnView.addSubview(bottomBtnsView)
+        bottomBtnsView.snp.makeConstraints { make in
+            make.top.equalTo(submitBtn.snp.bottom).offset(18)
+            make.centerX.equalToSuperview()
+            make.height.equalTo(17)
+            make.bottom.equalTo(-9-k_Height_safeAreaInsetsBottom())
+        }
+        
+        return frontCtnView
+    }
+    
+    
+    
+    
+    
+    func creatBottomBtnsView() -> UIView {
+        let bottomBtnsView = UIView()
+        
+        let titleColor:UIColor = .white.withAlphaComponent(0.4)
+        let font:UIFont = .font(size: 12)
+        //Terms of us  |  Privacy Policy  |  Restore
+        let termsBtn = UIButton.createButton(title: "Terms of us".localized,font: font,titleColor: titleColor){ [weak self]  in
+            guard let self = self else { return }
+            let vc = TSBusinessWebVC(urlType: .terms)
+            vc.hidesBottomBarWhenPushed = true
+            kPresentModalVC(target: self, modelVC: vc)
+        }
+        bottomBtnsView.addSubview(termsBtn)
+        
+        let privacyBtn = UIButton.createButton(title: "Privacy Policy".localized,font: font,titleColor: titleColor){ [weak self]  in
+            guard let self = self else { return }
+            let vc = TSBusinessWebVC(urlType: .privacy)
+            vc.hidesBottomBarWhenPushed = true
+            kPresentModalVC(target: self, modelVC: vc)
+        }
+        bottomBtnsView.addSubview(privacyBtn)
+        
+        let restoreBtn = UIButton.createButton(title: "Restore".localized,font: font,titleColor: titleColor){ [weak self]  in
+            guard let self = self else { return }
+            clickRestoreBlock?()
+        }
+        bottomBtnsView.addSubview(restoreBtn)
+        
+        let label1 = UILabel.createLabel(text: "|",font: font,textColor: titleColor)
+        bottomBtnsView.addSubview(label1)
+        
+        
+        let label2 = UILabel.createLabel(text: "|",font: font,textColor: titleColor)
+        bottomBtnsView.addSubview(label2)
+        
+        
+        privacyBtn.snp.makeConstraints { make in
+            make.height.equalTo(17)
+            make.centerY.equalToSuperview()
+        }
+        
+        label1.snp.makeConstraints { make in
+            make.trailing.equalTo(privacyBtn.snp.leading).offset(-8)
+            make.centerY.equalToSuperview()
+        }
+        
+        termsBtn.snp.makeConstraints { make in
+            make.trailing.equalTo(label1.snp.leading).offset(-8)
+            make.leading.centerY.equalToSuperview()
+        }
+        
+        label2.snp.makeConstraints { make in
+            make.leading.equalTo(privacyBtn.snp.trailing).offset(8)
+            make.centerY.equalToSuperview()
+        }
+        
+        restoreBtn.snp.makeConstraints { make in
+            make.leading.equalTo(label2.snp.trailing).offset(8)
+            make.trailing.centerY.equalToSuperview()
+        }
+        
+        return bottomBtnsView
+    }
+}
+extension TSPurchasePromotionalVC {
+    func creatCountdownView() -> UIView {
+        let countdownView = UIView()
+        
+        let min = creatItem(label: minLabel, unit: "min".localized)
+        let sec = creatItem(label: secLabel, unit: "sec".localized)
+        countdownView.addSubview(min)
+        countdownView.addSubview(sec)
+        
+        let label = UILabel.createLabel(text: ":",font: .font(size: 22,weight: .semibold),textColor: .white)
+        countdownView.addSubview(label)
+        
+        label.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.equalTo(12)
+            make.height.equalTo(64)
+        }
+        
+        min.snp.makeConstraints { make in
+            make.leading.centerY.equalToSuperview()
+            make.width.height.equalTo(68)
+            make.trailing.equalTo(label.snp.leading).offset(-16)
+        }
+        
+        sec.snp.makeConstraints { make in
+            make.trailing.centerY.equalToSuperview()
+            make.width.height.equalTo(68)
+            make.leading.equalTo(label.snp.trailing).offset(14)
+        }
+        
+        return countdownView
+    }
+    
+    
+    func creatItem(label:UILabel,unit:String) -> UIView {
+        
+        let bgView = UIView()
+
+        let bgImageView:UIImageView = UIImageView.createImageView(image: .countdownBg)
+        bgView.addSubview(bgImageView)
+        
+        label.setUpLabel(font:.font(size: 24,weight: .medium),textColor: .white)
+        bgImageView.addSubview(label)
+        
+        let label2 = UILabel.createLabel(text: unit,font: .font(size: 11,weight: .regular),textColor: .white.withAlphaComponent(0.4))
+        bgImageView.addSubview(label2)
+        
+        bgImageView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        label.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(14.0)
+            make.height.equalTo(24)
+        }
+
+        label2.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(label.snp.bottom).offset(5)
+            make.height.equalTo(11)
+        }
+        return bgView
+    }
+    
+}

+ 64 - 0
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchasePromotionalVC/TSPurchasePromotionalVC.swift

@@ -0,0 +1,64 @@
+//
+//  TSPurchasePromotionalVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/6/30.
+//
+
+
+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)
+    lazy var shaowImageView: UIImageView = UIImageView.createImageView(imageName: "purchase_bj",contentMode: .scaleAspectFill)
+    lazy var promotionalPrice: String = PurchaseManager.default.introductoryPrice(for: .week(.weekPromotional1)) ?? "--"
+    lazy var originalPrice: String = PurchaseManager.default.price(for: .week(.weekPromotional1)) ?? "--"
+    lazy var frontCtnView: UIView = creatFrontCtnView()
+    lazy var bottomBtnsView: UIView = creatBottomBtnsView()
+    lazy var countdownView: UIView = creatCountdownView()
+    
+    let minLabel:UILabel = UILabel()
+    let secLabel:UILabel = UILabel()
+
+    var countDownTime:Int = 1800 //30 分钟
+    
+    override func createView() {
+        setNavBarViewHidden(true)
+        
+        contentView.addSubview(topImageView)
+        contentView.addSubview(shaowImageView)
+        contentView.addSubview(frontCtnView)
+        
+        topImageView.snp.makeConstraints { make in
+            make.leading.trailing.top.equalToSuperview()
+            make.height.equalTo(532*kDesignScale)
+        }
+        
+        shaowImageView.snp.makeConstraints { make in
+            make.leading.trailing.bottom.top.equalToSuperview()
+        }
+        
+        frontCtnView.snp.makeConstraints { make in
+            make.leading.trailing.bottom.top.equalToSuperview()
+        }
+        
+    }
+    
+    override func dealThings() {
+        kPurchaseCountDownTime.complete = { [weak self] minutes, seconds, end in
+            guard let self = self else { return }
+            if end {
+                self.closePageBlock?()
+            }else{
+                self.minLabel.text = minutes
+                self.secLabel.text = seconds
+            }
+        }
+    }
+}

+ 102 - 0
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVC+Promotional.swift

@@ -0,0 +1,102 @@
+//
+//  TSPurchaseVC+Promotional.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/6/30.
+//
+
+import APNGKit
+import Delegate
+extension TSPurchaseVC {
+
+
+    
+    func creatApngImageView() -> APNGImageView {
+        let image = try! APNGImage(named: "Gift")
+        image.numberOfPlays = 1
+        let apngImageView = APNGImageView(image: image)
+        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
+              }, completion: { finished in
+                  dePrint("kPurchaseCountDownTime.start")
+                  kPurchaseCountDownTime.start()
+                  self.animationView.removeFromSuperview()
+              })
+
+        }
+        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{
+        
+        if kPurchaseDefault.isVip == false,
+           kPurchaseDefault.checkLocalReceiptForIntroOffer(type: .week(.weekPromotional1)) == false,
+           kPurchaseCountDownTime.isShowGift,
+           promotionalVC.view.superview == nil {
+            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)
+        self.view.addSubview(animationView)
+        animationView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        animationView.addSubview(animationLab)
+        animationLab.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+        }
+        
+        animationView.addSubview(apngImageView)
+        apngImageView.snp.makeConstraints { make in
+            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
+            }
+        }
+    }
+}

+ 42 - 235
AIEmoji/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift

@@ -8,6 +8,9 @@
 import Combine
 import Combine
 import SwiftUI
 import SwiftUI
 import SwiftUIX
 import SwiftUIX
+import APNGKit
+import Delegate
+
 class PurchaseViewModel : ObservableObject{
 class PurchaseViewModel : ObservableObject{
     
     
     @Published var selectedType: PremiumPeriod = .year
     @Published var selectedType: PremiumPeriod = .year
@@ -35,7 +38,7 @@ class TSPurchaseVC: TSBaseVC {
         return purchaseManager
         return purchaseManager
     }()
     }()
     
     
-    private var isHandlePurchaseStateChanged = true //是否处理购买状态变化
+    var isHandlePurchaseStateChanged = true //是否处理购买状态变化
     
     
     func createImageScroll(imageName:String,direction:ImagesAnimateScrollView.`Direction`)->ImagesAnimateScrollView{
     func createImageScroll(imageName:String,direction:ImagesAnimateScrollView.`Direction`)->ImagesAnimateScrollView{
         let imageScroll1: ImagesAnimateScrollView = ImagesAnimateScrollView()
         let imageScroll1: ImagesAnimateScrollView = ImagesAnimateScrollView()
@@ -80,13 +83,25 @@ class TSPurchaseVC: TSBaseVC {
 //        }
 //        }
         
         
         if PurchaseManager.default.vipType == .none {
         if PurchaseManager.default.vipType == .none {
-            viewModel.selectedType = .week
+            viewModel.selectedType = .week(.week)
         }
         }
         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
     }()
     }()
     
     
+    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() {
     override func createView() {
         addNormalNavBarView()
         addNormalNavBarView()
         _ = setNavigationItem("", imageName: "close_gray", direction: .left, action: #selector(closePage))
         _ = setNavigationItem("", imageName: "close_gray", direction: .left, action: #selector(closePage))
@@ -104,16 +119,33 @@ class TSPurchaseVC: TSBaseVC {
         hostVc.view.snp.makeConstraints { make in
         hostVc.view.snp.makeConstraints { make in
             make.leading.trailing.bottom.top.equalToSuperview()
             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)
     }
     }
     
     
     override func dealThings() {
     override func dealThings() {
         
         
         //周会员和月会员不自动处理变化,必须点击购买后才处理
         //周会员和月会员不自动处理变化,必须点击购买后才处理
         let vipType = purchaseManager.vipType
         let vipType = purchaseManager.vipType
-        if vipType == .week || vipType == .month {
+        if vipType.isWeekType || vipType == .month {
             isHandlePurchaseStateChanged = false
             isHandlePurchaseStateChanged = false
         }
         }
-
+        
         addNotifaction()
         addNotifaction()
         onPurchaseStateChanged()
         onPurchaseStateChanged()
         NotificationCenter.default.addObserver(forName: .kPurchasePrepared, object: nil, queue: OperationQueue.main) { [weak self] _ in
         NotificationCenter.default.addObserver(forName: .kPurchasePrepared, object: nil, queue: OperationQueue.main) { [weak self] _ in
@@ -157,11 +189,14 @@ class TSPurchaseVC: TSBaseVC {
 
 
         viewModel.restorePublisher.receive(on: DispatchQueue.main).sink { [weak self] _ in
         viewModel.restorePublisher.receive(on: DispatchQueue.main).sink { [weak self] _ in
             guard let self = self else { return }
             guard let self = self else { return }
-            isHandlePurchaseStateChanged = true
-            PurchaseManager.default.restorePremium()
+            restorePremium()
         }.store(in: &cancellabel)
         }.store(in: &cancellabel)
     }
     }
     
     
+    func restorePremium(){
+        isHandlePurchaseStateChanged = true
+        PurchaseManager.default.restorePremium()
+    }
     
     
     func onPurchaseStateChanged(){
     func onPurchaseStateChanged(){
         purchaseManager.onPurchaseStateChanged = { [weak self] manager,state,object in
         purchaseManager.onPurchaseStateChanged = { [weak self] manager,state,object in
@@ -246,13 +281,7 @@ class TSPurchaseVC: TSBaseVC {
             debugPrint("PurchaseManager onPurchaseStateChanged=\(String(describing: state))")
             debugPrint("PurchaseManager onPurchaseStateChanged=\(String(describing: state))")
         }
         }
     }
     }
-    
-    @objc func closePage(){
-        closePageBlock?()
-        TSToastShared.hideLoading()
-        self.dismiss(animated: true)
-    }
-    
+ 
     override func viewWillAppear(_ animated: Bool) {
     override func viewWillAppear(_ animated: Bool) {
          super.viewWillAppear(animated)
          super.viewWillAppear(animated)
          // 禁用右滑返回手势
          // 禁用右滑返回手势
@@ -310,225 +339,3 @@ extension TSPurchaseVC{
 }
 }
 
 
 
 
-struct PurchaseView :View {
-    
-    @ObservedObject var viewModel: PurchaseViewModel
-    
-    
-    var body: some View {
-        
-
-        let vipType = PurchaseManager.default.vipType
-        
-        VStack {
-            Spacer()
-            
-            VStack {
-                let text = vipType == .none ? "Get PRO Access".localized : "Super Offer for Yearly Pro".localized
-                Text(text)
-                    .multilineTextAlignment(.center)
-                    .font(.font(name: .PoppinsBoldItalic,size: 26))
-                    .foregroundColor(UIColor.white.color)
-                    .frame(width: k_ScreenWidth - 32, alignment: .center)
-                
-                if vipType == .none {
-                    Spacer().frame(height: 12)
-                    HStack {
-                        Text("Unlimited")
-                            .foregroundColor("#FECB34".uiColor.color)
-                        
-                        Text("Generation")
-                            .foregroundColor(UIColor.white.color)
-                        
-                    }
-                    .multilineTextAlignment(.center)
-                    .font(.font(name: .PoppinsBoldItalic,size: 26))
-                    .frame(height: 26*kDesignScale)
-                }
-            }
-            
-            Spacer().frame(height: 32)
-            
-            VStack(spacing: 12) {
-                
-                if vipType == .none {
-                    ZStack(alignment: .topTrailing) {
-//                    //增加月付费
-//                        PurchaseItemView(title: "One Month".localized, type: .month, selectedType: $viewModel.selectedType).onTapGesture {
-//                            viewModel.selectedType = .month
-                    PurchaseItemView(title: "One Year".localized, type: .year, selectedType: $viewModel.selectedType).onTapGesture {
-                        viewModel.selectedType = .year
-
-                            viewModel.buyPublisher.send(true)
-                        }
-                        TSVipRecView(save: vipType.saveString)
-                            .offset(x:-30,y:-14)
-                    }
-                    
-                    PurchaseItemView(title: "One Week".localized, type: .week, selectedType: $viewModel.selectedType).onTapGesture {
-                        viewModel.selectedType = .week
-                        viewModel.buyPublisher.send(true)
-                    }
-                }else{
-                    PurchaseItemTypeOneView(title: "One Year".localized, type: .year, selectedType: $viewModel.selectedType).onTapGesture {
-                        viewModel.selectedType = .year
-                        viewModel.buyPublisher.send(true)
-                    }
-                }
-                
-                Spacer().frame(height: 4)
-                
-                Button {
-                    viewModel.buyPublisher.send(true)
-                } label: {
-                    ZStack {
-                        UIColor.themeColor.color
-                        Text("Continue")
-                            .font(.font(size: 16,weight: .medium))
-                            .foregroundColor(.hex("#111111"))
-                        
-                    }.frame(maxWidth: .infinity ,minHeight: 48.0,maxHeight: 48.0)
-                        .cornerRadius(24.0)
-                }
-                
-                HStack {
-                    Text("Recurring billing, cancel anytime".localized)
-                        .foregroundColor(Color.hex("#FFBD59")) +
-                    Text(",Payment will be charged to your iTunes account at confirmation of purchase. Subscriptions automatically renew for the same applicable term and price, unless auto-renew is turned off at least 24 hours before the end of the current period.".localized)
-                        .foregroundColor(UIColor.lesserText.color)
-                }
-                .multilineTextAlignment(.center).font(.font(size: 8))
-                .onTapGesture {
-                    viewModel.privacyPublisher.send(true)
-                }
-                
-                Spacer().frame(height: 6.0)
-                
-                HStack(spacing: 8) {
-                    Text("Terms of us".localized)
-                        .onTapGesture {
-                            viewModel.termPublisher.send(true)
-                        }
-                    Text("|")
-                    Text("Privacy Policy".localized)
-                        .onTapGesture {
-                            viewModel.privacyPublisher.send(true)
-                        }
-                    Text("|")
-                    Text("Restore".localized)
-                        .onTapGesture {
-                            viewModel.restorePublisher.send(true)
-                        }
-                }.font(.system(size: 12)).foregroundColor(.hex("#999999"))
-            }.padding(.horizontal)
-            
-            Spacer().frame(height:9+k_Height_safeAreaInsetsBottom())
-        }
-    }
-    
-    // 定义一个返回 View 的方法
-    func customText(text:String,fontName:FontName,color:Color) -> some View {
-        let gorgeousColor = color //UIColor.themeColor.color
-        return Text(text)
-            .font(.font(name: fontName,size: 48))
-        
-            .gradientForeground(
-                colors: [.hex("#FA794F"),.hex("#F8C32A"),.hex("#FEFBF4")],
-                startPoint: UnitPoint.leading,
-                endPoint: UnitPoint.trailing
-            )
-
-            .foregroundColor(gorgeousColor)
-            .frame(height: 20)
-    }
-}
-
-
-struct PurchaseItemView: View {
-    var title: String
-    var type: PremiumPeriod
-    @Binding var selectedType: PremiumPeriod
-
-    var body: some View {
-        ZStack {
-            Color.white.opacity(0.1)
-            HStack {
-                //左边加个
-                VStack(alignment: .leading, spacing: 14) {
-                    Text(title).font(.font(size: 14)).foregroundColor(UIColor.white.color)
-                    
-                    HStack {
-                        Text(PurchaseManager.default.price(for: type) ?? "--").font(.font(size: 18,weight: .medium)).foregroundColor(UIColor.mainText.color)
-                        if type == .year { //.month {//增加月付费
-                            Text(" (≈\(PurchaseManager.default.averageWeekly(for:type) ?? "--")/\("Per week".localized))").font(.font(size: 12,weight: .medium)).foregroundColor(UIColor.mainText.withAlphaComponent(0.6).color)
-                        }
-                    }
-                }
-
-                Spacer()
-//                
-//                //右边每周的💰
-//                VStack(alignment: .trailing, spacing: 2) {
-//                    Text("\(PurchaseManager.default.averageWeekly(for:type) ?? "--")")
-//                    Text("Per week".localized)
-//             
-//                }.font(.font(size: 16,weight: .regular)).foregroundColor(Color.white.opacity(0.6))
-
-            }.padding(.horizontal)
-        }
-        .frame(height: 74) // 设置高度
-        .cornerRadius(16.0) // 圆角
-        .overlay(
-            RoundedRectangle(cornerRadius: 16)
-                .stroke(Color.hex("#FECB34"), lineWidth: type == selectedType ? 1 : 0) // 边框
-        )
-    }
-}
-
-struct PurchaseItemTypeOneView: View {
-    var title: String
-    var type: PremiumPeriod
-    @Binding var selectedType: PremiumPeriod
-
-    var body: some View {
-        ZStack {
-            Color.white.opacity(0.1)
-            HStack {
-                //左边加个
-                VStack(alignment: .leading, spacing: 8) {
-                    Text(title).font(.font(size: 14,weight: .medium)).foregroundColor(UIColor.white.color)
-                    Text(String(format:"Only %@ per day".localized,"\(PurchaseManager.default.averageDay(for:type) ?? "--")"))
-                        .font(.font(size: 12,weight: .medium))
-                        . foregroundColor(UIColor.white.color).opacity(0.7)
-                }
-
-                Spacer()
-                
-                Text(PurchaseManager.default.price(for: type) ?? "--").font(.font(size: 18,weight: .medium)).foregroundColor(UIColor.mainText.color)
-
-            }.padding(.horizontal)
-        }
-        .frame(height: 74) // 设置高度
-        .cornerRadius(16.0) // 圆角
-        .overlay(
-            RoundedRectangle(cornerRadius: 16)
-                .stroke(Color.hex("#FECB34"), lineWidth: type == selectedType ? 1 : 0) // 边框
-        )
-    }
-}
-
-//推荐选择view
-struct TSVipRecView: View {
-    var save:String //年 80%,月 30%
-    var body: some View {
-    
-        HStack(spacing: 4) {
-            Image("upvote_black").resizable().frame(width: 16, height: 16)
-            Text("Save-Vip".localized + " " + save).font(.font(size: 12,weight: .medium)).foregroundColor(.hex("#111111"))
-        }
-        .padding(EdgeInsets(top: 6, leading: 6, bottom: 6, trailing: 6))
-        .background(Color.hex("#FECB34"))
-        .frame(height: 28) // 设置高度
-        .cornerRadius([.topLeading, .topTrailing, .bottomLeading, .bottomTrailing], 16.0)
-    }
-}

+ 231 - 0
AIEmoji/Business/TSPurchaseMembershipVC/View/PurchaseView.swift

@@ -0,0 +1,231 @@
+//
+//  PurchaseView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/6/30.
+//
+
+import SwiftUI
+import SwiftUIX
+struct PurchaseView :View {
+    
+    @ObservedObject var viewModel: PurchaseViewModel
+    
+    
+    var body: some View {
+        
+
+        let vipType = PurchaseManager.default.vipType
+        
+        VStack {
+            Spacer()
+            
+            VStack {
+                let text = vipType == .none ? "Get PRO Access".localized : "Super Offer for Yearly Pro".localized
+                Text(text)
+                    .multilineTextAlignment(.center)
+                    .font(.font(name: .PoppinsBoldItalic,size: 26))
+                    .foregroundColor(UIColor.white.color)
+                    .frame(width: k_ScreenWidth - 32, alignment: .center)
+                
+                if vipType == .none {
+                    Spacer().frame(height: 12)
+                    HStack {
+                        Text("Unlimited")
+                            .foregroundColor("#FECB34".uiColor.color)
+                        
+                        Text("Generation")
+                            .foregroundColor(UIColor.white.color)
+                        
+                    }
+                    .multilineTextAlignment(.center)
+                    .font(.font(name: .PoppinsBoldItalic,size: 26))
+                    .frame(height: 26*kDesignScale)
+                }
+            }
+            
+            Spacer().frame(height: 32)
+            
+            VStack(spacing: 12) {
+                
+                if vipType == .none {
+                    ZStack(alignment: .topTrailing) {
+//                    //增加月付费
+//                        PurchaseItemView(title: "One Month".localized, type: .month, selectedType: $viewModel.selectedType).onTapGesture {
+//                            viewModel.selectedType = .month
+                    PurchaseItemView(title: "One Year".localized, type: .year, selectedType: $viewModel.selectedType).onTapGesture {
+                        viewModel.selectedType = .year
+
+                            viewModel.buyPublisher.send(true)
+                        }
+                        TSVipRecView(save: vipType.saveString)
+                            .offset(x:-30,y:-14)
+                    }
+                    
+                    PurchaseItemView(title: "One Week".localized, type: .week(.week), selectedType: $viewModel.selectedType).onTapGesture {
+                        viewModel.selectedType = .week(.week)
+                        viewModel.buyPublisher.send(true)
+                    }
+                }else{
+                    PurchaseItemTypeOneView(title: "One Year".localized, type: .year, selectedType: $viewModel.selectedType).onTapGesture {
+                        viewModel.selectedType = .year
+                        viewModel.buyPublisher.send(true)
+                    }
+                }
+                
+                Spacer().frame(height: 4)
+                
+                Button {
+                    viewModel.buyPublisher.send(true)
+                } label: {
+                    ZStack {
+                        UIColor.themeColor.color
+                        Text("Continue")
+                            .font(.font(size: 16,weight: .medium))
+                            .foregroundColor(.hex("#111111"))
+                        
+                    }.frame(maxWidth: .infinity ,minHeight: 48.0,maxHeight: 48.0)
+                        .cornerRadius(24.0)
+                }
+                
+                HStack {
+                    Text("Recurring billing, cancel anytime".localized)
+                        .foregroundColor(Color.hex("#FFBD59")) +
+                    Text(",Payment will be charged to your iTunes account at confirmation of purchase. Subscriptions automatically renew for the same applicable term and price, unless auto-renew is turned off at least 24 hours before the end of the current period.".localized)
+                        .foregroundColor(UIColor.lesserText.color)
+                }
+                .multilineTextAlignment(.center).font(.font(size: 8))
+                .onTapGesture {
+                    viewModel.privacyPublisher.send(true)
+                }
+                
+                Spacer().frame(height: 6.0)
+                
+                HStack(spacing: 8) {
+                    Text("Terms of us".localized)
+                        .onTapGesture {
+                            viewModel.termPublisher.send(true)
+                        }
+                    Text("|")
+                    Text("Privacy Policy".localized)
+                        .onTapGesture {
+                            viewModel.privacyPublisher.send(true)
+                        }
+                    Text("|")
+                    Text("Restore".localized)
+                        .onTapGesture {
+                            viewModel.restorePublisher.send(true)
+                        }
+                }.font(.system(size: 12)).foregroundColor(.hex("#999999"))
+            }.padding(.horizontal)
+            
+            Spacer().frame(height:9+k_Height_safeAreaInsetsBottom())
+        }
+    }
+    
+    // 定义一个返回 View 的方法
+    func customText(text:String,fontName:FontName,color:Color) -> some View {
+        let gorgeousColor = color //UIColor.themeColor.color
+        return Text(text)
+            .font(.font(name: fontName,size: 48))
+        
+            .gradientForeground(
+                colors: [.hex("#FA794F"),.hex("#F8C32A"),.hex("#FEFBF4")],
+                startPoint: UnitPoint.leading,
+                endPoint: UnitPoint.trailing
+            )
+
+            .foregroundColor(gorgeousColor)
+            .frame(height: 20)
+    }
+}
+
+
+struct PurchaseItemView: View {
+    var title: String
+    var type: PremiumPeriod
+    @Binding var selectedType: PremiumPeriod
+
+    var body: some View {
+        ZStack {
+            Color.white.opacity(0.1)
+            HStack {
+                //左边加个
+                VStack(alignment: .leading, spacing: 14) {
+                    Text(title).font(.font(size: 14)).foregroundColor(UIColor.white.color)
+                    
+                    HStack {
+                        Text(PurchaseManager.default.price(for: type) ?? "--").font(.font(size: 18,weight: .medium)).foregroundColor(UIColor.mainText.color)
+                        if type == .year { //.month {//增加月付费
+                            Text(" (≈\(PurchaseManager.default.averageWeekly(for:type) ?? "--")/\("Per week".localized))").font(.font(size: 12,weight: .medium)).foregroundColor(UIColor.mainText.withAlphaComponent(0.6).color)
+                        }
+                    }
+                }
+
+                Spacer()
+//
+//                //右边每周的💰
+//                VStack(alignment: .trailing, spacing: 2) {
+//                    Text("\(PurchaseManager.default.averageWeekly(for:type) ?? "--")")
+//                    Text("Per week".localized)
+//
+//                }.font(.font(size: 16,weight: .regular)).foregroundColor(Color.white.opacity(0.6))
+
+            }.padding(.horizontal)
+        }
+        .frame(height: 74) // 设置高度
+        .cornerRadius(16.0) // 圆角
+        .overlay(
+            RoundedRectangle(cornerRadius: 16)
+                .stroke(Color.hex("#FECB34"), lineWidth: type == selectedType ? 1 : 0) // 边框
+        )
+    }
+}
+
+struct PurchaseItemTypeOneView: View {
+    var title: String
+    var type: PremiumPeriod
+    @Binding var selectedType: PremiumPeriod
+
+    var body: some View {
+        ZStack {
+            Color.white.opacity(0.1)
+            HStack {
+                //左边加个
+                VStack(alignment: .leading, spacing: 8) {
+                    Text(title).font(.font(size: 14,weight: .medium)).foregroundColor(UIColor.white.color)
+                    Text(String(format:"Only %@ per day".localized,"\(PurchaseManager.default.averageDay(for:type) ?? "--")"))
+                        .font(.font(size: 12,weight: .medium))
+                        . foregroundColor(UIColor.white.color).opacity(0.7)
+                }
+
+                Spacer()
+                
+                Text(PurchaseManager.default.price(for: type) ?? "--").font(.font(size: 18,weight: .medium)).foregroundColor(UIColor.mainText.color)
+
+            }.padding(.horizontal)
+        }
+        .frame(height: 74) // 设置高度
+        .cornerRadius(16.0) // 圆角
+        .overlay(
+            RoundedRectangle(cornerRadius: 16)
+                .stroke(Color.hex("#FECB34"), lineWidth: type == selectedType ? 1 : 0) // 边框
+        )
+    }
+}
+
+//推荐选择view
+struct TSVipRecView: View {
+    var save:String //年 80%,月 30%
+    var body: some View {
+    
+        HStack(spacing: 4) {
+            Image("upvote_black").resizable().frame(width: 16, height: 16)
+            Text("Save-Vip".localized + " " + save).font(.font(size: 12,weight: .medium)).foregroundColor(.hex("#111111"))
+        }
+        .padding(EdgeInsets(top: 6, leading: 6, bottom: 6, trailing: 6))
+        .background(Color.hex("#FECB34"))
+        .frame(height: 28) // 设置高度
+        .cornerRadius([.topLeading, .topTrailing, .bottomLeading, .bottomTrailing], 16.0)
+    }
+}

+ 51 - 3
AIEmoji/Business2/DisCover/TSDiscoverVC/TSDiscoverVC.swift

@@ -14,11 +14,26 @@ class TSDiscoverVC: TSBaseVC {
     lazy var vipBtn: UIButton = {
     lazy var vipBtn: UIButton = {
        let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self]  in
        let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self]  in
            guard let self = self else { return }
            guard let self = self else { return }
-           TSPurchaseVC.show(target: self) {}
+           TSPurchaseVC.show(target: self) { [weak self]  in
+               guard let self = self else { return }
+               checkkPurchaseCountDownTime()
+           }
        }
        }
        return vipBtn
        return vipBtn
    }()
    }()
     
     
+    lazy var purchaseCountdownView : TSPurchaseCountdownView = {
+       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()
+            }
+        }
+       return purchaseCountdownView
+   }()
+    
     lazy var navBarView: TSBaseNavContentBarView = {
     lazy var navBarView: TSBaseNavContentBarView = {
         let navBarView = TSBaseNavContentBarView()
         let navBarView = TSBaseNavContentBarView()
 
 
@@ -29,13 +44,24 @@ class TSDiscoverVC: TSBaseVC {
             make.leading.equalTo(17.0)
             make.leading.equalTo(17.0)
         }
         }
         
         
-        navBarView.barView.addSubview(vipBtn)
-        vipBtn.snp.makeConstraints { make in
+
+        let stackView:UIStackView = UIStackView()
+        stackView.spacing = 8
+        navBarView.barView.addSubview(stackView)
+        stackView.addArrangedSubview(vipBtn)
+        stackView.addArrangedSubview(purchaseCountdownView)
+        stackView.snp.makeConstraints { make in
             make.centerY.equalToSuperview()
             make.centerY.equalToSuperview()
             make.trailing.equalTo(-16)
             make.trailing.equalTo(-16)
+        }
+        vipBtn.snp.makeConstraints { make in
             make.width.height.equalTo(32)
             make.width.height.equalTo(32)
         }
         }
         
         
+        purchaseCountdownView.snp.makeConstraints { make in
+            make.height.equalTo(24)
+        }
+        
         kMainAsync {
         kMainAsync {
             label.applyGradient(colors: ["#FA794F".uiColor,"#F8C32A".uiColor,"#FEFBF4".uiColor])
             label.applyGradient(colors: ["#FA794F".uiColor,"#F8C32A".uiColor,"#FEFBF4".uiColor])
         }
         }
@@ -81,6 +107,28 @@ class TSDiscoverVC: TSBaseVC {
             self.vipBtn.isHidden = PurchaseManager.default.isVip
             self.vipBtn.isHidden = PurchaseManager.default.isVip
         }
         }
     }
     }
+    
+    func checkkPurchaseCountDownTime(){
+        if kPurchaseCountDownTime.isCountDown {
+            self.purchaseCountdownView.isHidden = false
+            kPurchaseCountDownTime.complete = { [weak self] minutes, seconds, end in
+                guard let self = self else { return }
+                if end {
+                    self.purchaseCountdownView.isHidden = true
+                }else{
+                    self.purchaseCountdownView.minLabel.text = minutes
+                    self.purchaseCountdownView.secLabel.text = seconds
+                }
+            }
+        }else{
+            self.purchaseCountdownView.isHidden = true
+        }
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        super.viewWillAppear(animated)
+        checkkPurchaseCountDownTime()
+    }
 }
 }
 
 
 extension TSDiscoverVC: UICollectionViewDataSource ,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{
 extension TSDiscoverVC: UICollectionViewDataSource ,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{

+ 2 - 0
AIEmoji/Common/Ex/UIFont+TSEx.swift

@@ -9,6 +9,8 @@ public extension FontName {
     static let AccentURW   = "AccentURWReg"
     static let AccentURW   = "AccentURWReg"
     static let PoppinsBlackItalic   = "Poppins-BlackItalic"
     static let PoppinsBlackItalic   = "Poppins-BlackItalic"
     static let PoppinsBoldItalic   = "Poppins-BoldItalic"
     static let PoppinsBoldItalic   = "Poppins-BoldItalic"
+    static let PoppinsBold   = "Poppins-Bold"
+    
     
     
     static let KelsiFill   = "Kelsi 1"
     static let KelsiFill   = "Kelsi 1"
     static let KelsiRegular   = "Kelsi"
     static let KelsiRegular   = "Kelsi"

+ 147 - 15
AIEmoji/Common/Purchase/TSPurchaseManager.swift

@@ -8,17 +8,77 @@
 import Foundation
 import Foundation
 import StoreKit
 import StoreKit
 
 
-public enum PremiumPeriod: String, CaseIterable {
-    case none = ""
-    case week = "Week"
-    case month = "Monthly"
-    case year = "Yearly"
-    case lifetime = "Lifetime"
+public enum PremiumPeriod{
+    case none
+    case month
+    case year
+    case lifetime
+    case week(WeekType)
+
+    public enum WeekType:String, CaseIterable{
+        case week = "week"
+        case week1 = "week1"
+        case weekPromotional1 = "weekPromotional1"
+    }
+}
+
+extension PremiumPeriod:CaseIterable ,RawRepresentable {
+    /// 所有可迭代的 case(包括 week 的所有子类型)
+    public static var allCases: [PremiumPeriod] {
+        var cases: [PremiumPeriod] = [.none, .month, .year, .lifetime]
+        cases.append(contentsOf: WeekType.allCases.map { .week($0) })
+        return cases
+    }
+    
+    public var rawValue: String{
+        switch self {
+        case .week(let type):
+            type.rawValue
+        case .month:
+            "Monthly"
+        case .year:
+            "Yearly"
+        case .lifetime:
+            "Lifetime"
+        default:
+            ""
+        }
+    }
+    
+    public init?(rawValue: String) {
+         // 先尝试匹配基础类型
+         switch rawValue {
+         case "Monthly":
+             self = .month
+         case "Yearly":
+             self = .year
+         case "Lifetime":
+             self = .lifetime
+         default:
+             if let weekType = WeekType(rawValue: rawValue){
+                 self = .week(weekType)
+             }else{
+                 self = .none
+             }
+         }
+     }
+    
+    var isWeekType:Bool {
+        switch self {
+        case .week(_):
+            return true
+        default:
+            return false
+        }
+    }
+}
+
+extension PremiumPeriod {
 
 
     /// 对应vip类型,可以免费使用次数
     /// 对应vip类型,可以免费使用次数
     var freeNumber: Int {
     var freeNumber: Int {
         switch self {
         switch self {
-        case .week:
+        case .week(_):
             return 30
             return 30
         case .month:
         case .month:
             return 30
             return 30
@@ -56,7 +116,7 @@ public enum PremiumPeriod: String, CaseIterable {
             return  365 * 24 * 60 * 60 * 1000
             return  365 * 24 * 60 * 60 * 1000
         case .month:
         case .month:
             return 30 * 24 * 60 * 60 * 1000
             return 30 * 24 * 60 * 60 * 1000
-        case .week:
+        case .week(_):
             return 7 * 24 * 60 * 60 * 1000
             return 7 * 24 * 60 * 60 * 1000
         default:
         default:
             return 0
             return 0
@@ -126,7 +186,9 @@ public class PurchaseManager: NSObject {
         [
         [
             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: "103", period: .week(.week)),
+            PurchaseProduct(productId: "104", period: .week(.weekPromotional1)),
+//            PurchaseProduct(productId: "301", period: .week(.weekPromotional1)),
         ]
         ]
     }()
     }()
 
 
@@ -204,9 +266,9 @@ public class PurchaseManager: NSObject {
     }
     }
 
 
     @objc public var isVip: Bool {
     @objc public var isVip: Bool {
-#if DEBUG
-        return vipType != .none
-#endif
+//#if DEBUG
+//        return vipType != .none
+//#endif
         guard let expiresDate = expiredDate else {
         guard let expiresDate = expiredDate else {
             return false
             return false
         }
         }
@@ -218,9 +280,9 @@ public class PurchaseManager: NSObject {
     }
     }
 
 
     public var vipType: PremiumPeriod {
     public var vipType: PremiumPeriod {
-#if DEBUG
-        return PremiumPeriod.none
-#endif
+//#if DEBUG
+//        return PremiumPeriod.none
+//#endif
         guard isVip, let type = vipInformation["type"] as? String else {
         guard isVip, let type = vipInformation["type"] as? String else {
             return .none
             return .none
         }
         }
@@ -270,6 +332,22 @@ extension PurchaseManager {
         formatter.locale = product.priceLocale
         formatter.locale = product.priceLocale
         return formatter.string(from: product.price)
         return formatter.string(from: product.price)
     }
     }
+    
+    // 商品价格
+    public func introductoryPrice(for period: PremiumPeriod) -> String? {
+        guard let product = product(for: period) else {
+            return nil
+        }
+        guard let introductoryPrice = product.introductoryPrice else {
+            return nil
+        }
+        
+        let formatter = NumberFormatter()
+        formatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
+        formatter.numberStyle = .currency
+        formatter.locale = product.priceLocale
+        return formatter.string(from: introductoryPrice.price)
+    }
 
 
     // 平局每周的金额
     // 平局每周的金额
     public func averageWeekly(for period: PremiumPeriod) -> String? {
     public func averageWeekly(for period: PremiumPeriod) -> String? {
@@ -396,6 +474,22 @@ extension PurchaseManager: SKProductsRequestDelegate {
         purchase(self, didChaged: .loadSuccess, object: nil)
         purchase(self, didChaged: .loadSuccess, object: nil)
         NotificationCenter.default.post(name: .kPurchasePrepared, object: nil)
         NotificationCenter.default.post(name: .kPurchasePrepared, object: nil)
         debugPrint("PurchaseManager productsRequest didReceive = \(products)")
         debugPrint("PurchaseManager productsRequest didReceive = \(products)")
+        
+        for product in products {
+            print("商品ID: \(product.productIdentifier)")
+            // 获取促销价格
+            if let introductoryPrice = product.introductoryPrice {
+                print("新用户促销价格: \(introductoryPrice.price) \(introductoryPrice.priceLocale.currencySymbol ?? "")")
+                print("新用户促销周期: \(introductoryPrice.subscriptionPeriod.numberOfUnits) \(introductoryPrice.subscriptionPeriod.unit)")
+            }
+            
+            // 获取促销价格
+            for discounts in product.discounts {
+                print("老用户促销价格: \(discounts.price) \(discounts.priceLocale.currencySymbol ?? "")")
+                print("老用户促销周期: \(discounts.subscriptionPeriod.numberOfUnits)")
+            }
+
+        }
     }
     }
 
 
     public func request(_ request: SKRequest, didFailWithError error: Error) {
     public func request(_ request: SKRequest, didFailWithError error: Error) {
@@ -782,6 +876,44 @@ extension PurchaseManager {
     }
     }
 }
 }
 
 
+
+extension PurchaseManager {
+    func checkLocalReceiptForIntroOffer(type:PremiumPeriod) -> Bool {
+        
+        guard let productId = productId(for: type) else { return false }
+        guard let receiptURL = Bundle.main.appStoreReceiptURL,
+              FileManager.default.fileExists(atPath: receiptURL.path) else {
+            return false // 无收据,用户未订阅过
+        }
+        
+        // 如果有收据,进一步解析(需实现收据解析逻辑)
+        if let receiptData = try? Data(contentsOf: receiptURL) {
+            let receiptString = receiptData.base64EncodedString()
+            return parseReceiptForIntroOffer(receiptString: receiptString,productId:productId)
+        }
+        return false
+    }
+    
+    func parseReceiptForIntroOffer(receiptString: String,productId:String) -> Bool {
+        // 这里需要解析收据的 JSON 数据(实际开发建议使用开源库如 SwiftyStoreKit)
+        guard let receiptData = Data(base64Encoded: receiptString),
+              let receiptJSON = try? JSONSerialization.jsonObject(with: receiptData, options: []) as? [String: Any],
+              let latestReceiptInfo = receiptJSON["latest_receipt_info"] as? [[String: Any]] else {
+            return false
+        }
+        
+        // 检查是否有购买过首月优惠商品(例如 product_id = "monthly_intro")
+        for receipt in latestReceiptInfo {
+            if let productID = receipt["product_id"] as? String,
+               productID == "productId" {
+                return true // 用户已订阅过首月优惠
+            }
+        }
+        return false
+    }
+}
+
+
 /*
 /*
 
 
  首先,创建SKProductsRequest对象并使用init(productIdentifiers:)初始化,传入要查询的产品标识符。
  首先,创建SKProductsRequest对象并使用init(productIdentifiers:)初始化,传入要查询的产品标识符。

+ 1 - 0
AIEmoji/Info.plist

@@ -25,6 +25,7 @@
 	<key>UIAppFonts</key>
 	<key>UIAppFonts</key>
 	<array>
 	<array>
 		<string>Poppins-BoldItalic.otf</string>
 		<string>Poppins-BoldItalic.otf</string>
+		<string>Poppins-Bold.otf</string>
 		<string>Poppins-BlackItalic.ttf</string>
 		<string>Poppins-BlackItalic.ttf</string>
 		<string>AccentURW-Reg.ttf</string>
 		<string>AccentURW-Reg.ttf</string>
 		<string>Kelsi-fill.otf</string>
 		<string>Kelsi-fill.otf</string>

BIN
AIEmoji/Res/Gift.apng


BIN
AIEmoji/Res/Poppins-Bold.otf


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

@@ -479,3 +479,11 @@
 "Update now to unlock the best experience" = "Jetzt aktualisieren, um das beste Erlebnis freizuschalten";
 "Update now to unlock the best experience" = "Jetzt aktualisieren, um das beste Erlebnis freizuschalten";
 "Update" = "Aktualisieren";
 "Update" = "Aktualisieren";
 "More AI Tools" = "Weitere KI-Tools";
 "More AI Tools" = "Weitere KI-Tools";
+
+"LUCKY GIFT\nFOR YOU!" = "GLÜCKSGESCHENK \n FÜR SIE!";
+"ONLY TODAY" = "NUR HEUTE";
+"Limited Time Offer" = "Zeitlich begrenztes Angebot";
+"min" = "min";
+"sec" = "sec";
+"First week %@ Then total %@/week" = "Erste Woche %@ Dann insgesamt %@/Woche";
+"Start Trial" = "Testversion starten";

+ 8 - 0
AIEmoji/en.lproj/Localizable.strings

@@ -477,3 +477,11 @@
 "Update" = "Update";
 "Update" = "Update";
 "More AI Tools" = "More AI Tools";
 "More AI Tools" = "More AI Tools";
 
 
+"LUCKY GIFT\nFOR YOU!" = "LUCKY GIFT\nFOR YOU!";
+"ONLY TODAY" = "ONLY TODAY";
+"Limited Time Offer" = "Limited Time Offer";
+"min" = "min";
+"sec" = "sec";
+"First week %@ Then total %@/week" = "First week %@ Then total %@/week";
+"Start Trial" = "Start Trial";
+

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

@@ -477,3 +477,11 @@
 "Update now to unlock the best experience" = "Actualiza ahora para disfrutar de la mejor experiencia";
 "Update now to unlock the best experience" = "Actualiza ahora para disfrutar de la mejor experiencia";
 "Update" = "Actualizar";
 "Update" = "Actualizar";
 "More AI Tools" = "Más herramientas de IA";
 "More AI Tools" = "Más herramientas de IA";
+
+"LUCKY GIFT\nFOR YOU!" = "¡REGALO DE SUERTE \n PARA TI!";
+"ONLY TODAY" = "SOLO HOY";
+"Limited Time Offer" = "Oferta por tiempo limitado";
+"min" = "min";
+"sec" = "seg";
+"First week %@ Then total %@/week" = "Primera semana %@ Luego total %@/semana";
+"Start Trial" = "Comienza la prueba";

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

@@ -476,3 +476,11 @@
 "Update now to unlock the best experience" = "今すぐアップデートして最高の体験を解錠";
 "Update now to unlock the best experience" = "今すぐアップデートして最高の体験を解錠";
 "Update" = "アップデート";
 "Update" = "アップデート";
 "More AI Tools" = "その他のAIツール";
 "More AI Tools" = "その他のAIツール";
+
+"LUCKY GIFT\nFOR YOU!" = "ラッキーギフト \n あなたへ!";
+"ONLY TODAY" = "本日限定";
+"Limited Time Offer" = "期間限定オファー";
+"min" = "分";
+"sec" = "秒";
+"First week %@ Then total %@/week" = "最初の週 %@ その後、週あたり %@";
+"Start Trial" = "トライアルを開始";

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

@@ -481,3 +481,11 @@
 "Update now to unlock the best experience" = "지금 업데이트하여 최고의 경험을 경험하세요";
 "Update now to unlock the best experience" = "지금 업데이트하여 최고의 경험을 경험하세요";
 "Update" = "업데이트";
 "Update" = "업데이트";
 "More AI Tools" = "더 많은 AI 도구";
 "More AI Tools" = "더 많은 AI 도구";
+
+"LUCKY GIFT\nFOR YOU!" = "행운의 선물 \n 당신을 위해!";
+"ONLY TODAY" = "오늘만";
+"Limited Time Offer" = "한정 시간 프로모션";
+"min" = "분";
+"sec" = "초";
+"First week %@ Then total %@/week" = "첫 주 %@ 그 다음 주당 %@";
+"Start Trial" = "무료 체험 시작";

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

@@ -476,3 +476,11 @@
 "Update now to unlock the best experience" = "Atualize agora para desbloquear a melhor experiência";
 "Update now to unlock the best experience" = "Atualize agora para desbloquear a melhor experiência";
 "Update" = "Atualizar";
 "Update" = "Atualizar";
 "More AI Tools" = "Mais ferramentas de IA";
 "More AI Tools" = "Mais ferramentas de IA";
+
+"LUCKY GIFT\nFOR YOU!" = "PRESENTE DE SORTE \n PARA VOCÊ!";
+"ONLY TODAY" = "SÓ HOJE";
+"Limited Time Offer" = "Oferta por tempo limitado";
+"min" = "min";
+"sec" = "seg";
+"First week %@ Then total %@/week" = "Primeira semana %@ Depois, total %@/semana";
+"Start Trial" = "Comece o teste";

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

@@ -475,3 +475,11 @@
 "Update now to unlock the best experience" = "Atualize agora para desbloquear a melhor experiência";
 "Update now to unlock the best experience" = "Atualize agora para desbloquear a melhor experiência";
 "Update" = "Atualizar";
 "Update" = "Atualizar";
 "More AI Tools" = "Mais ferramentas de IA";
 "More AI Tools" = "Mais ferramentas de IA";
+
+"LUCKY GIFT\nFOR YOU!" = "PRESENTE DE SORTE \n PARA VOCÊ!";
+"ONLY TODAY" = "SÓ HOJE";
+"Limited Time Offer" = "Oferta por tempo limitado";
+"min" = "min";
+"sec" = "seg";
+"First week %@ Then total %@/week" = "Primeira semana %@ Depois, total %@/semana";
+"Start Trial" = "Comece o teste";

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

@@ -477,3 +477,11 @@
 "Update now to unlock the best experience" = "立即更新,解锁最佳体验";
 "Update now to unlock the best experience" = "立即更新,解锁最佳体验";
 "Update" = "更新";
 "Update" = "更新";
 "More AI Tools" = "更多 AI 工具";
 "More AI Tools" = "更多 AI 工具";
+
+"LUCKY GIFT\nFOR YOU!" = "幸运礼物\n专为您准备!";
+"ONLY TODAY" = "仅限今日";
+"Limited Time Offer" = "限时优惠";
+"min" = "分钟";
+"sec" = "秒";
+"First week %@ Then total %@/week" = "首周 %@ 随后每周总计 %@";
+"Start Trial" = "立即试用";

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

@@ -466,3 +466,11 @@
 "Update now to unlock the best experience" = "立即更新,解鎖最佳體驗";
 "Update now to unlock the best experience" = "立即更新,解鎖最佳體驗";
 "Update" = "更新";
 "Update" = "更新";
 "More AI Tools" = "更多 AI 工具";
 "More AI Tools" = "更多 AI 工具";
+
+"LUCKY GIFT\nFOR YOU!" = "幸運禮物\n專為您準備!";
+"ONLY TODAY" = "僅限今日";
+"Limited Time Offer" = "限時優惠";
+"min" = "分鐘";
+"sec" = "秒";
+"First week %@ Then total %@/week" = "首周%@隨後每週總計%@";
+"Start Trial" = "立即試用";

+ 1 - 0
Podfile

@@ -25,6 +25,7 @@ target 'AIEmoji' do
   pod 'BetterSegmentedControl', '~> 2.0'
   pod 'BetterSegmentedControl', '~> 2.0'
   pod 'TYCyclePagerView'
   pod 'TYCyclePagerView'
   pod 'Shimmer'
   pod 'Shimmer'
+  pod 'APNGKit', '~> 2.0'
 end
 end
 
 
 
 

+ 9 - 1
Podfile.lock

@@ -1,6 +1,9 @@
 PODS:
 PODS:
   - Alamofire (5.10.2)
   - Alamofire (5.10.2)
+  - APNGKit (2.3.0):
+    - Delegate (~> 1.3)
   - BetterSegmentedControl (2.0.1)
   - BetterSegmentedControl (2.0.1)
+  - Delegate (1.3.0)
   - DynamicBlurView (5.0.3)
   - DynamicBlurView (5.0.3)
   - IQKeyboardCore (1.0.5)
   - IQKeyboardCore (1.0.5)
   - IQKeyboardManagerSwift (8.0.0):
   - IQKeyboardManagerSwift (8.0.0):
@@ -74,6 +77,7 @@ PODS:
 
 
 DEPENDENCIES:
 DEPENDENCIES:
   - Alamofire
   - Alamofire
+  - APNGKit (~> 2.0)
   - BetterSegmentedControl (~> 2.0)
   - BetterSegmentedControl (~> 2.0)
   - DynamicBlurView
   - DynamicBlurView
   - IQKeyboardManagerSwift
   - IQKeyboardManagerSwift
@@ -94,7 +98,9 @@ DEPENDENCIES:
 SPEC REPOS:
 SPEC REPOS:
   trunk:
   trunk:
     - Alamofire
     - Alamofire
+    - APNGKit
     - BetterSegmentedControl
     - BetterSegmentedControl
+    - Delegate
     - DynamicBlurView
     - DynamicBlurView
     - IQKeyboardCore
     - IQKeyboardCore
     - IQKeyboardManagerSwift
     - IQKeyboardManagerSwift
@@ -125,7 +131,9 @@ EXTERNAL SOURCES:
 
 
 SPEC CHECKSUMS:
 SPEC CHECKSUMS:
   Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
   Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
+  APNGKit: eb7e111277527cfd47636f797c9c8e7aab5d9601
   BetterSegmentedControl: 09607b27861d49cbce48b7673b74f9150a3d371a
   BetterSegmentedControl: 09607b27861d49cbce48b7673b74f9150a3d371a
+  Delegate: 0ff4467868095239ff578ab531efd8af46e62881
   DynamicBlurView: b57e2f6aa33f85b2bcca272265162a3c7c5cc499
   DynamicBlurView: b57e2f6aa33f85b2bcca272265162a3c7c5cc499
   IQKeyboardCore: 28c8bf3bcd8ba5aa1570b318cbc4da94b861711e
   IQKeyboardCore: 28c8bf3bcd8ba5aa1570b318cbc4da94b861711e
   IQKeyboardManagerSwift: 0c6fbbaa2e60739e48d7cf59f25661471a7a3a65
   IQKeyboardManagerSwift: 0c6fbbaa2e60739e48d7cf59f25661471a7a3a65
@@ -151,6 +159,6 @@ SPEC CHECKSUMS:
   TSSmalCoacopods: 6aa97167f0c76b16fc7d1fd1eb198bb6aece4f68
   TSSmalCoacopods: 6aa97167f0c76b16fc7d1fd1eb198bb6aece4f68
   TYCyclePagerView: 2b051dade0615c70784aa34f40c646feeddb7344
   TYCyclePagerView: 2b051dade0615c70784aa34f40c646feeddb7344
 
 
-PODFILE CHECKSUM: a3c8fcf2d7ce56c8dc3fd11eebfc9bc5b5d65559
+PODFILE CHECKSUM: f423f1e8807aaf798447596ea4e32bcbbee64c98
 
 
 COCOAPODS: 1.16.2
 COCOAPODS: 1.16.2