Răsfoiți Sursa

feat: 历史记录整改完毕

100Years 3 săptămâni în urmă
părinte
comite
84dd5b05c9
39 a modificat fișierele cu 1564 adăugiri și 394 ștergeri
  1. 64 4
      AIEmoji.xcodeproj/project.pbxproj
  2. 3 1
      AIEmoji/AppDelegate.swift
  3. 116 38
      AIEmoji/Business/Data/TSDBHistoryManager.swift
  4. 1 1
      AIEmoji/Business/Data/TSUserDefaultData.swift
  5. 4 0
      AIEmoji/Business/General/Ex/Notification+Ex.swift
  6. 2 2
      AIEmoji/Business/General/TSBigIconBrowseVC/TSBigIconBrowseVC.swift
  7. 1 1
      AIEmoji/Business/TSAILIstVC/TSAIExpandImageVC/TSAIExpandImageVC.swift
  8. 1 1
      AIEmoji/Business/TSAILIstVC/TSAIListHistoryBaseVC/TSAIListHistoryBaseCell.swift
  9. 13 9
      AIEmoji/Business/TSAILIstVC/TSAIListHistoryBaseVC/TSAIListHistoryBaseVC.swift
  10. 12 2
      AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIListPhotoGeneratorBaseVC.swift
  11. 4 2
      AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIPhotoGeneratorBaseVM/TSAIListPhotoGeneratorBaseVM.swift
  12. 20 2
      AIEmoji/Business/TSAILIstVC/TSAIUploadPhotoBaseVC/TSAIUploadPhotoBaseVC.swift
  13. 1 1
      AIEmoji/Business/TSAILIstVC/TSPredictBabyVC/TSFutureBabyVC.swift
  14. 44 10
      AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/Model/TSActionInfoModel.swift
  15. 44 7
      AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/Model/TSDBActionInfoModel.swift
  16. 1 1
      AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/View/TSGenmojiItemCell.swift
  17. 24 25
      AIEmoji/Business/TSPTPGeneratorVC/TSAIPhotoGeneratorBaseVC/TSAIPhotoBrowseVC.swift
  18. 2 2
      AIEmoji/Business/TSPTPGeneratorVC/TSAbnormalPopUpAlertVC/TSAbnormalPopUpAlertVC.swift
  19. 1 1
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPBrowseVC/TSPTPBrowseVC.swift
  20. 2 2
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPGeneratorVC/TSPTPGeneratorVC.swift
  21. 12 4
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPHistoryVC/TSPTPHistoryVC.swift
  22. 14 9
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC.swift
  23. 1 1
      AIEmoji/Business/TSPTPGeneratorVC/TSPhotoToPhotoVC/TSPhotoToPhotoVC.swift
  24. 1 1
      AIEmoji/Business/TSPTPGeneratorVC/TSPhotoToPhotoVC/VM/TSPhotoToPhotoVM.swift
  25. 6 2
      AIEmoji/Business/TSTabBarController/TSTabBarController.swift
  26. 6 5
      AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/TSTTPInputVC+Col.swift
  27. 1 1
      AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/TSTTPInputVC.swift
  28. 2 1
      AIEmoji/Business/TSTextGeneralPictureVC/TSTextGeneralPictureVC/TSTextGeneralPictureVC.swift
  29. 27 0
      AIEmoji/Business2/Data/TSDiscoverViewModel.swift
  30. 239 0
      AIEmoji/Business2/TSGenerateHistoryVC/TSGenerateHistoryVC.swift
  31. 193 0
      AIEmoji/Business2/TSGenerateHistoryVC/View/TSGenerateHistoryCell.swift
  32. 124 0
      AIEmoji/Business2/TSGenerateHistoryVC/View/TSGennerateCellView.swift
  33. 6 6
      AIEmoji/Common/Purchase/TSPurchaseManager.swift
  34. 7 4
      AIEmoji/Common/TSRealmManager/TSRealmManager.swift
  35. 0 208
      AIEmoji/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGenerateBaseOperation.swift
  36. 9 12
      AIEmoji/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGeneratePosterOperation.swift
  37. 283 0
      AIEmoji/Common/Tool/OperationQueue/V2/TSGenerateBaseOperation.swift
  38. 273 0
      AIEmoji/Common/Tool/OperationQueue/V2/TSGenerateBasePhotoOperation.swift
  39. 0 28
      AIEmoji/Common/Tool/TSCommonTool/TSCommonTool.swift

+ 64 - 4
AIEmoji.xcodeproj/project.pbxproj

@@ -109,7 +109,6 @@
 		A82D60812DB7A1E600596190 /* activePhoto.gif in Resources */ = {isa = PBXBuildFile; fileRef = A82D60802DB7A1E600596190 /* activePhoto.gif */; };
 		A82D60832DB87D1A00596190 /* TSAIExpandChangeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82D60822DB87D1900596190 /* TSAIExpandChangeView.swift */; };
 		A82D608B2DB9CE7E00596190 /* MXParallaxHeader+Ex.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82D608A2DB9CE7A00596190 /* MXParallaxHeader+Ex.swift */; };
-		A82D60942DB9D45900596190 /* TSGenerateBaseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82D608C2DB9D45900596190 /* TSGenerateBaseOperation.swift */; };
 		A82D60952DB9D45900596190 /* TSGeneratePosterOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82D608D2DB9D45900596190 /* TSGeneratePosterOperation.swift */; };
 		A82D60972DB9D45900596190 /* TSBaseOperationQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82D60912DB9D45900596190 /* TSBaseOperationQueue.swift */; };
 		A82D60982DB9D45900596190 /* TSBaseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82D60922DB9D45900596190 /* TSBaseOperation.swift */; };
@@ -140,6 +139,7 @@
 		A85E47C02D6961BB0018D62D /* TSChatMessageUIModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85E47BF2D6961B90018D62D /* TSChatMessageUIModel.swift */; };
 		A85E47C32D6964A50018D62D /* TSMSGAIDefaultHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85E47C22D69646D0018D62D /* TSMSGAIDefaultHeaderView.swift */; };
 		A85E47C62D697E750018D62D /* SwiftUIX in Frameworks */ = {isa = PBXBuildFile; productRef = A85E47C52D697E750018D62D /* SwiftUIX */; };
+		A8708A0C2E08F5C600601686 /* TSGennerateCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8708A0B2E08F5C600601686 /* TSGennerateCellView.swift */; };
 		A875870F2D81689A00286A66 /* TSPTPEnterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A875870E2D81689600286A66 /* TSPTPEnterView.swift */; };
 		A87587122D81702700286A66 /* TSUserDefaultData.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87587102D81702700286A66 /* TSUserDefaultData.swift */; };
 		A87587162D81734300286A66 /* text_to_photo_style.json in Resources */ = {isa = PBXBuildFile; fileRef = A87587152D81733C00286A66 /* text_to_photo_style.json */; };
@@ -183,6 +183,11 @@
 		A89EA6CA2D642C0A000EB181 /* TSChatViewController+SendMsg.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6C92D642C03000EB181 /* TSChatViewController+SendMsg.swift */; };
 		A89EA6CC2D642CE2000EB181 /* TSChatViewController+NaviBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6CB2D642CD4000EB181 /* TSChatViewController+NaviBar.swift */; };
 		A89EA6CF2D6430F3000EB181 /* TSChatViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6CE2D6430EE000EB181 /* TSChatViewController+Keyboard.swift */; };
+		A8B70BC62E06B9D7003177FA /* TSDiscoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B70BC52E06B9C7003177FA /* TSDiscoverViewModel.swift */; };
+		A8B70BC92E08E416003177FA /* TSGenerateHistoryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B70BC82E08E416003177FA /* TSGenerateHistoryVC.swift */; };
+		A8B70BCB2E08F28F003177FA /* TSGenerateHistoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B70BCA2E08F28B003177FA /* TSGenerateHistoryCell.swift */; };
+		A8B70BD22E08F2F4003177FA /* TSGenerateBaseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B70BCD2E08F2F4003177FA /* TSGenerateBaseOperation.swift */; };
+		A8B70BD42E08F2F4003177FA /* TSGenerateBasePhotoOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8B70BCE2E08F2F4003177FA /* TSGenerateBasePhotoOperation.swift */; };
 		A8BA763C2DA4C225000B6707 /* SwiftUIX in Frameworks */ = {isa = PBXBuildFile; productRef = A8BA763B2DA4C225000B6707 /* SwiftUIX */; };
 		A8BA763F2DA4C908000B6707 /* TSPTPInputVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA763E2DA4C906000B6707 /* TSPTPInputVC.swift */; };
 		A8BA76422DA4C924000B6707 /* TSPTPInputVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76412DA4C920000B6707 /* TSPTPInputVM.swift */; };
@@ -385,7 +390,6 @@
 		A82D60802DB7A1E600596190 /* activePhoto.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = activePhoto.gif; sourceTree = "<group>"; };
 		A82D60822DB87D1900596190 /* TSAIExpandChangeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIExpandChangeView.swift; sourceTree = "<group>"; };
 		A82D608A2DB9CE7A00596190 /* MXParallaxHeader+Ex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MXParallaxHeader+Ex.swift"; sourceTree = "<group>"; };
-		A82D608C2DB9D45900596190 /* TSGenerateBaseOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGenerateBaseOperation.swift; sourceTree = "<group>"; };
 		A82D608D2DB9D45900596190 /* TSGeneratePosterOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGeneratePosterOperation.swift; sourceTree = "<group>"; };
 		A82D60912DB9D45900596190 /* TSBaseOperationQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBaseOperationQueue.swift; sourceTree = "<group>"; };
 		A82D60922DB9D45900596190 /* TSBaseOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBaseOperation.swift; sourceTree = "<group>"; };
@@ -436,6 +440,7 @@
 		A85E47BD2D68999B0018D62D /* ShareActivityItemProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareActivityItemProvider.swift; sourceTree = "<group>"; };
 		A85E47BF2D6961B90018D62D /* TSChatMessageUIModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSChatMessageUIModel.swift; sourceTree = "<group>"; };
 		A85E47C22D69646D0018D62D /* TSMSGAIDefaultHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSMSGAIDefaultHeaderView.swift; sourceTree = "<group>"; };
+		A8708A0B2E08F5C600601686 /* TSGennerateCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGennerateCellView.swift; sourceTree = "<group>"; };
 		A875870E2D81689600286A66 /* TSPTPEnterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPEnterView.swift; sourceTree = "<group>"; };
 		A87587102D81702700286A66 /* TSUserDefaultData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSUserDefaultData.swift; sourceTree = "<group>"; };
 		A87587152D81733C00286A66 /* text_to_photo_style.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = text_to_photo_style.json; sourceTree = "<group>"; };
@@ -478,6 +483,11 @@
 		A89EA6C92D642C03000EB181 /* TSChatViewController+SendMsg.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSChatViewController+SendMsg.swift"; sourceTree = "<group>"; };
 		A89EA6CB2D642CD4000EB181 /* TSChatViewController+NaviBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSChatViewController+NaviBar.swift"; sourceTree = "<group>"; };
 		A89EA6CE2D6430EE000EB181 /* TSChatViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSChatViewController+Keyboard.swift"; sourceTree = "<group>"; };
+		A8B70BC52E06B9C7003177FA /* TSDiscoverViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSDiscoverViewModel.swift; sourceTree = "<group>"; };
+		A8B70BC82E08E416003177FA /* TSGenerateHistoryVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGenerateHistoryVC.swift; sourceTree = "<group>"; };
+		A8B70BCA2E08F28B003177FA /* TSGenerateHistoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGenerateHistoryCell.swift; sourceTree = "<group>"; };
+		A8B70BCD2E08F2F4003177FA /* TSGenerateBaseOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGenerateBaseOperation.swift; sourceTree = "<group>"; };
+		A8B70BCE2E08F2F4003177FA /* TSGenerateBasePhotoOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGenerateBasePhotoOperation.swift; sourceTree = "<group>"; };
 		A8BA763E2DA4C906000B6707 /* TSPTPInputVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPInputVC.swift; sourceTree = "<group>"; };
 		A8BA76412DA4C920000B6707 /* TSPTPInputVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPInputVM.swift; sourceTree = "<group>"; };
 		A8BA76442DA4CB99000B6707 /* TSPTPUploadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPUploadView.swift; sourceTree = "<group>"; };
@@ -1231,7 +1241,6 @@
 		A82D60902DB9D45900596190 /* TSGenerateBaseOperation */ = {
 			isa = PBXGroup;
 			children = (
-				A82D608C2DB9D45900596190 /* TSGenerateBaseOperation.swift */,
 				A82D608D2DB9D45900596190 /* TSGeneratePosterOperation.swift */,
 			);
 			path = TSGenerateBaseOperation;
@@ -1240,6 +1249,7 @@
 		A82D60932DB9D45900596190 /* OperationQueue */ = {
 			isa = PBXGroup;
 			children = (
+				A8708A092E08F34800601686 /* V2 */,
 				A82D60902DB9D45900596190 /* TSGenerateBaseOperation */,
 				A82D60912DB9D45900596190 /* TSBaseOperationQueue.swift */,
 				A82D60922DB9D45900596190 /* TSBaseOperation.swift */,
@@ -1330,6 +1340,24 @@
 			path = TSChatMsgBaseView;
 			sourceTree = "<group>";
 		};
+		A8708A092E08F34800601686 /* V2 */ = {
+			isa = PBXGroup;
+			children = (
+				A8B70BCD2E08F2F4003177FA /* TSGenerateBaseOperation.swift */,
+				A8B70BCE2E08F2F4003177FA /* TSGenerateBasePhotoOperation.swift */,
+			);
+			path = V2;
+			sourceTree = "<group>";
+		};
+		A8708A0A2E08F5B700601686 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				A8708A0B2E08F5C600601686 /* TSGennerateCellView.swift */,
+				A8B70BCA2E08F28B003177FA /* TSGenerateHistoryCell.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		A87587112D81702700286A66 /* Data */ = {
 			isa = PBXGroup;
 			children = (
@@ -1511,6 +1539,32 @@
 			path = TSChatViewController;
 			sourceTree = "<group>";
 		};
+		A8B70BC32E06B9AE003177FA /* Business2 */ = {
+			isa = PBXGroup;
+			children = (
+				A8B70BC72E08E408003177FA /* TSGenerateHistoryVC */,
+				A8B70BC42E06B9C1003177FA /* Data */,
+			);
+			path = Business2;
+			sourceTree = "<group>";
+		};
+		A8B70BC42E06B9C1003177FA /* Data */ = {
+			isa = PBXGroup;
+			children = (
+				A8B70BC52E06B9C7003177FA /* TSDiscoverViewModel.swift */,
+			);
+			path = Data;
+			sourceTree = "<group>";
+		};
+		A8B70BC72E08E408003177FA /* TSGenerateHistoryVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8708A0A2E08F5B700601686 /* View */,
+				A8B70BC82E08E416003177FA /* TSGenerateHistoryVC.swift */,
+			);
+			path = TSGenerateHistoryVC;
+			sourceTree = "<group>";
+		};
 		A8BA763D2DA4C8F9000B6707 /* TSPTPInputVC */ = {
 			isa = PBXGroup;
 			children = (
@@ -1682,6 +1736,7 @@
 				A8FDB1702DCC4B1100E9919B /* Enums */,
 				A8FB02AE2D3E38FA0031A396 /* Res */,
 				A8F7751E2D38ED4500AA6E93 /* DataManger */,
+				A8B70BC32E06B9AE003177FA /* Business2 */,
 				A8F774922D38EA8C00AA6E93 /* Business */,
 				A8F774D82D38EA8C00AA6E93 /* Common */,
 				A8F774812D38E8B700AA6E93 /* AppDelegate.swift */,
@@ -2267,6 +2322,7 @@
 				A80EDE002D6EFD22003CD332 /* TSPhotoPickerManager.swift in Sources */,
 				A89EA6B42D5C9D43000EB181 /* TSAIChatHistoryVM.swift in Sources */,
 				A81BECA32DD1EA1E005D06A2 /* TSGeneratorErrorView.swift in Sources */,
+				A8B70BCB2E08F28F003177FA /* TSGenerateHistoryCell.swift in Sources */,
 				A8BA766F2DA65824000B6707 /* TSAIListPhotoGeneratorBaseVM.swift in Sources */,
 				A80E72532D3F985E00C64288 /* TSWallpaperVC.swift in Sources */,
 				A8FB02B32D3E39A40031A396 /* TSEmojisModel.swift in Sources */,
@@ -2382,10 +2438,12 @@
 				A82D609E2DBA0FEA00596190 /* TSAppBtnView.swift in Sources */,
 				A82D608B2DB9CE7E00596190 /* MXParallaxHeader+Ex.swift in Sources */,
 				A89EA6AC2D5B3EFB000EB181 /* TSRealmManager.swift in Sources */,
+				A8B70BC92E08E416003177FA /* TSGenerateHistoryVC.swift in Sources */,
 				A8BA76772DA68619000B6707 /* TSAIListHistoryBaseVM.swift in Sources */,
 				A80EDDE42D6EB8FA003CD332 /* TSPTPSelectStyleCell.swift in Sources */,
 				A8F775172D38EB7400AA6E93 /* TSTabBarController.swift in Sources */,
 				A80E73E12D533E5800C64288 /* TSPurchaseVC.swift in Sources */,
+				A8708A0C2E08F5C600601686 /* TSGennerateCellView.swift in Sources */,
 				A80EDDE02D6EB1B9003CD332 /* TSPTPGeneratorCell.swift in Sources */,
 				A81BECA62DD1EFAF005D06A2 /* TSGeneratorloadingContentView.swift in Sources */,
 				A8F776352D3A7C2B00AA6E93 /* TSGenmojiColSectionView.swift in Sources */,
@@ -2413,7 +2471,6 @@
 				A83404D12D9D16FA00C140E4 /* TSAIPhotoGeneratorBaseVC.swift in Sources */,
 				A80327BF2D81578900AF7878 /* TSPromptTextView.swift in Sources */,
 				A80EDE022D6F1CCD003CD332 /* TSPTPGeneratorVC.swift in Sources */,
-				A82D60942DB9D45900596190 /* TSGenerateBaseOperation.swift in Sources */,
 				A82D60952DB9D45900596190 /* TSGeneratePosterOperation.swift in Sources */,
 				A82D60972DB9D45900596190 /* TSBaseOperationQueue.swift in Sources */,
 				A82D60982DB9D45900596190 /* TSBaseOperation.swift in Sources */,
@@ -2439,8 +2496,11 @@
 				A83404D32D9D23FA00C140E4 /* TSGeneratorloadingView.swift in Sources */,
 				A8F776372D3A806E00AA6E93 /* TSGenmojiItemCell.swift in Sources */,
 				A89EA6692D59AA31000EB181 /* CameraInputBarAccessoryView.swift in Sources */,
+				A8B70BC62E06B9D7003177FA /* TSDiscoverViewModel.swift in Sources */,
 				A89EA66B2D59AA31000EB181 /* TSTextMessageContentCell.swift in Sources */,
 				605E205B2DCCB8D20069F4B6 /* TSCustomAlertController+Ext.swift in Sources */,
+				A8B70BD22E08F2F4003177FA /* TSGenerateBaseOperation.swift in Sources */,
+				A8B70BD42E08F2F4003177FA /* TSGenerateBasePhotoOperation.swift in Sources */,
 				A804B98F2DC0F0F700C494C7 /* TSTTPRatioView.swift in Sources */,
 				A8FDB17C2DCC5A1000E9919B /* TSTTPInputVC+Col.swift in Sources */,
 				A83404D52D9D28D700C140E4 /* TSAIPhotoBrowseVC.swift in Sources */,

+ 3 - 1
AIEmoji/AppDelegate.swift

@@ -9,6 +9,7 @@ import UIKit
 var kAppNewVerison = ""
 @main
 class AppDelegate: UIResponder, UIApplicationDelegate {
+    static var tabbar:TSTabBarController?
     var window: UIWindow?
     var backgroundTaskIdentifier: UIBackgroundTaskIdentifier = .invalid
 
@@ -31,7 +32,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
     }
 
     func goToTab() {
-        window?.rootViewController = TSTabBarController()
+        Self.tabbar = TSTabBarController()
+        window?.rootViewController = Self.tabbar
     }
 
     func JudgmentSkipPage() {

+ 116 - 38
AIEmoji/Business/Data/TSDBHistoryManager.swift

@@ -27,13 +27,17 @@ enum TSDBHistoryType: String,CaseIterable {
     case motherDay = "kTSAIMotherDayHistoryListString"   //母亲节
     case catTohuman = "kTSAICatTohumanHistoryListString"   //猫变人
     case futureBaby = "kTSAIFutureBabyHistoryListString"   //预测宝宝
+    
+    
+    
+    case aiGenerate = "kTSAiGenerateHistoryListString"  //通用的 AI 生成
 }
 
 
 //MARK: TSDBAIChatList - 用于存储会话及消息列表
 class TSDBHistory: Object {
     @Persisted(primaryKey: true) var primaryKey: String = ""
-    @Persisted var listModels = List<TSDBActionInfoModel>()
+    @Persisted var listModels = List<TSDBActionInfoModel>()//惰性加载特性
     
     var type: TSDBHistoryType {
         get { TSDBHistoryType(rawValue: primaryKey) ?? .ptp }
@@ -45,7 +49,7 @@ class TSDBHistory: Object {
         self.primaryKey = type.rawValue
     }
     
-
+    
     func getModelList() -> [TSActionInfoModel] {
         var msgModel:[TSActionInfoModel] = []
         for msgDBModel in listModels {
@@ -90,35 +94,52 @@ class TSDBHistory: Object {
         }
     }
     
-    static func deleteAll() {
-        do {
-            let realm = try Realm()
-            try realm.write {
-                let allPersons = realm.objects(TSDBHistory.self)
-                realm.delete(allPersons)
+    func deleteListModel(uuid:String) {
+        TSRMShared.writeThread {
+            if let index = listModels.firstIndex(where: { $0.uuid == uuid }) {
+                listModels.remove(at: index)
+                debugPrint("listModels.remove(at: \(index))")
             }
-        } catch {
-            debugPrint("删除 TSDBPTPHistory 模型数据时出错: \(error)")
+        }
+    }
+
+    func deleteListModel(index:Int) {
+        TSRMShared.writeThread {
+            deleteResources(index:index)
+            listModels.remove(at: index)
+            debugPrint("listModels.remove(at: \(index))")
         }
     }
     
-    func updateData(_ actionInfoModel:TSActionInfoModel,id:Int? = nil){
-            let dbModel = TSDBActionInfoModel.createDBModel(actionInfoModel: actionInfoModel)
-            var replaceID = dbModel.id
-            if let id = id {
-                replaceID = id
-            }
-            
+    func deleteResources(index:Int) {
+        if let model = listModels[safe: index] {
+            model.deleteResources()
+        }
+    }
+    
+    
+    func deleteAll() {
+        for index in listModels.indices {
+            deleteResources(index: index)
+        }
+        TSRMShared.writeThread {
+            listModels.removeAll()
+        }
+    }
+    
+    func updateData(_ actionInfoModel:TSActionInfoModel,uuid:String? = nil){
+        let dbModel = TSDBActionInfoModel.createDBModel(actionInfoModel: actionInfoModel)
+            let replaceUUID = uuid ?? dbModel.uuid
             let frozenList = self.listModels.freeze()
-            if let index = frozenList.firstIndex(where: { $0.id == replaceID }) {
+            if let index = frozenList.firstIndex(where: { $0.uuid == replaceUUID }) {
+                dePrint("updateData 替换 \(dbModel)")
                 TSRMShared.writeThread {
                     listModels[index] = dbModel// 如果找到,替换该元素
                 }
             } else {
-                print("Thread.current insert1=\(Thread.current)")
                 TSRMShared.writeThread {
+                    dePrint("updateData 插入 \(dbModel)")
                     listModels.insert(dbModel, at: 0)// 如果没有找到,添加到末尾
-                    print("Thread.current insert2=\(Thread.current)")
                 }
             }
     }
@@ -175,6 +196,80 @@ extension TSDBHistory {
 }
 
 
+//从App 大改版本后,基本就用这两个,其他的历史记录不再使用
+extension TSRealmManager {
+    
+    var aiGenerateDB:TSDBHistory {
+        let history = getDBHistory(type: TSDBHistoryType.aiGenerate)
+        let forKey = "insertAIGenerateExampleData1"
+        if history.listModels.count == 0,UserDefaults.standard.string(forKey: forKey) == nil {
+            
+//            mergeAllDataToAIGenerateDB(history: history)
+            
+            let id = Date.timestampInt
+            history.updateDatas([
+                createExampleModel(id:id, imageName: "ttp_example_image0"),
+                createExampleModel(id:id+1, imageName: "ttp_example_image1")
+            ])
+            UserDefaults.standard.set("1", forKey: forKey)
+            UserDefaults.standard.synchronize()
+    
+        }
+        
+        mergeAllDataToAIGenerateDB(history: history)
+        
+        return history
+    }
+    //文生图
+    var ttpDBHistory:TSDBHistory {
+        
+        let history = getDBHistory(type: TSDBHistoryType.ttp)
+        
+        if history.listModels.count == 0,UserDefaults.standard.string(forKey: "insertTTPExampleData") == nil {
+            let id = Date.timestampInt
+            history.updateDatas([
+                createExampleModel(id:id, imageName: "ttp_example_image0"),
+                createExampleModel(id:id+1, imageName: "ttp_example_image1")
+            ])
+            UserDefaults.standard.set("1", forKey: "insertTTPExampleData")
+            UserDefaults.standard.synchronize()
+        }
+        
+        return history
+    }
+    
+    
+    
+    //同时这里提供数据合并后的获取方式
+    
+    func mergeAllDataToAIGenerateDB(history:TSDBHistory){
+        let predicate = NSPredicate(format: "actionType != %@ AND modelType != %d",
+                                  "image_create", 1)
+        let results = realm.objects(TSDBActionInfoModel.self)
+            .filter(predicate)
+            .sorted(byKeyPath: "createdTimestamp", ascending: false)
+//        let sortedArray = Array(results)
+//        for model in sortedArray {
+//            print("Model: \(model), Timestamp: \(model.createdTimestamp)")
+//        }
+        
+        let combinedList = List<TSDBActionInfoModel>()
+        combinedList.append(objectsIn: results)
+        TSRMShared.writeThread {
+            history.listModels = combinedList
+        }
+        
+//        let combinedList = List<TSDBActionInfoModel>()
+//        combinedList.append(objectsIn: results)
+//        combinedList.append(objectsIn: history.listModels)
+//        TSRMShared.writeThread {
+//            history.listModels = combinedList
+//        }
+    }
+    
+    
+}
+
 extension TSRealmManager {
     func getDBHistory(type:TSDBHistoryType) -> TSDBHistory {
         let predicate = NSPredicate(format: "primaryKey == %@",type.rawValue)
@@ -193,7 +288,7 @@ extension TSRealmManager {
         model.id = id
         model.modelType = .example
         model.request.prompt = "Example"
-        model.request.promptSort = "Example"
+        model.request.inputText = "Example"
         model.request.width = 330
         model.request.height = 440
         model.response.resultUrl = imageName
@@ -239,24 +334,7 @@ extension TSRealmManager {
         return ptpHistory
     }
     
-    //文生图
-    var ttpDBHistory:TSDBHistory {
 
-        let history = getDBHistory(type: TSDBHistoryType.ttp)
-        
-        if history.listModels.count == 0,UserDefaults.standard.string(forKey: "insertTTPExampleData") == nil {
-            let id = Date.timestampInt
-            history.updateDatas([
-                createExampleModel(id:id, imageName: "ttp_example_image0"),
-                createExampleModel(id:id+1, imageName: "ttp_example_image1")
-            ])
-            UserDefaults.standard.set("1", forKey: "insertTTPExampleData")
-            UserDefaults.standard.synchronize()
-        }
-        
-        return history
-        
-    }
 
     //文生表情
     var ttEnmojiDBHistory:TSDBHistory {

+ 1 - 1
AIEmoji/Business/Data/TSUserDefaultData.swift

@@ -12,7 +12,7 @@ func kHandleDBHistoryOperation(){
         if model.modelType != 1 {
             if model.isResult == false,model.id > 0 {
                 let generatePTPOperation = TSGeneratePTPOperationQueue.shared.creatOperation(uuid: model.uuid)
-                generatePTPOperation.isSaveDB = true
+                generatePTPOperation.isSaveProcessToDB = true
                 generatePTPOperation.getActionInfo(oldModel: model.getModel())
             }
         }

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

@@ -21,4 +21,8 @@ extension Notification.Name {
     
     static let kOpenMotherDayVC = Notification.Name("kOpenMotherDayVC") //打开母亲节 vc
     static let kOpenCatTohumanVC = Notification.Name("kOpenCatTohumanVC") //打开猫咪变人 vc
+    
+    
+    static let kGenerateBasePhotoOperation = Notification.Name("TSGenerateBasePhotoOperation") //生成图生图任务发生变化
+    static let kAIPhotoDataChanged = Notification.Name("kGenerateBasePhotoChanged") //生成图片数据发生改变
 }

+ 2 - 2
AIEmoji/Business/General/TSBigIconBrowseVC/TSBigIconBrowseVC.swift

@@ -201,8 +201,8 @@ extension TSBigIconBrowseVC:UICollectionViewDataSource,UICollectionViewDelegate
             cell.netWorkImageView.setAsyncImage(urlString: model.response.resultUrl,placeholder: kPlaceholderImage,contentMode: .scaleAspectFill)
             cell.vipImageView.isHidden = !model.response.vip
             
-            if model.request.promptSort.count > 0 {
-                cell.textLabel.text = model.request.promptSort
+            if model.request.inputText.count > 0 {
+                cell.textLabel.text = model.request.inputText
             }else{
                 cell.textLabel.text = model.request.prompt
             }

+ 1 - 1
AIEmoji/Business/TSAILIstVC/TSAIExpandImageVC/TSAIExpandImageVC.swift

@@ -233,7 +233,7 @@ extension TSAIExpandImageVC {
         if kJudgeVip(externalBool: true, vc: self){ return } //判断 vip
         
         guard let upLoadImage = upLoadImage else { return }
-        let model = TSAIListPhotoGeneratorModel(
+        let model = TSAIGeneratorModel(
             upLoadImage: upLoadImage,
             generatorStyle: .photoExpand,
             expandEdge: photoExpand,

+ 1 - 1
AIEmoji/Business/TSAILIstVC/TSAIListHistoryBaseVC/TSAIListHistoryBaseCell.swift

@@ -21,7 +21,7 @@ class TSAIListHistoryBaseCell: TSBaseCollectionCell,TSSimpleConfigurableView {
                 }else{
                     if dataModel.isVideo {
                         videoIconImageView.isHidden = false
-                        self.showImageView.image = UIImage(contentsOfFile: dataModel.videoThumbnailURL.path)
+                        self.showImageView.image = UIImage(contentsOfFile: dataModel.videoPreviewUrlString)
                     }else {
                         showImageView.setAsyncImage(urlString: dataModel.response.resultUrl,contentMode: .scaleAspectFill,backgroundColor: .white.withAlphaComponent(0.1))
                     }

+ 13 - 9
AIEmoji/Business/TSAILIstVC/TSAIListHistoryBaseVC/TSAIListHistoryBaseVC.swift

@@ -4,7 +4,7 @@
 //
 //  Created by 100Years on 2025/4/9.
 //
-
+import RealmSwift
 class TSAIListHistoryBaseVC: TSBaseVC {
     var generatorStyle:TSGeneratorImageStyle
     var titleString:String?
@@ -16,8 +16,7 @@ class TSAIListHistoryBaseVC: TSBaseVC {
     @MainActor required init?(coder: NSCoder) {
         fatalError("init(coder:) has not been implemented")
     }
-    
-    var listModelArray: [TSActionInfoModel] = []
+    var listModelArray = List<TSDBActionInfoModel>()//惰性加载特性
     //###################################### 集合视图 ######################################
     let collectionViewBtootm:CGFloat = 80
     lazy var collectionView: TSSimpleCollectionView = {
@@ -75,15 +74,18 @@ class TSAIListHistoryBaseVC: TSBaseVC {
     }
     
     func updateDataView(){
-        dbHistory.getModelList { [weak self] array in
-            guard let self = self else { return }
-            listModelArray = array
-            updateView()
-        }
+//        dbHistory.getModelList { [weak self] array in
+//            guard let self = self else { return }
+//            listModelArray = array
+//            updateView()
+//        }
+        
+        listModelArray = dbHistory.listModels
+        updateView()
     }
     
     func updateView() {
-        collectionView.reload(with:[TSSimpleSectionData(items: listModelArray)])
+//        collectionView.reload(with:[TSSimpleSectionData(items: listModelArray)])
         
         navRightBtn.isHidden = listModelArray.count <= 0
         pageNullView.isHidden = listModelArray.count > 0
@@ -149,6 +151,8 @@ extension TSAIListHistoryBaseVC{
             TSRMShared.catTohumanDBHistory
         case .futureBaby:
             TSRMShared.futureBabyDBHistory
+        default:
+            TSRMShared.futureBabyDBHistory
         }
     }
     

+ 12 - 2
AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIListPhotoGeneratorBaseVC.swift

@@ -5,7 +5,10 @@
 //  Created by 100Years on 2025/4/9.
 //
 import Kingfisher
-struct TSAIListPhotoGeneratorModel {
+
+
+
+class TSAIGeneratorModel {
     var upLoadImage:UIImage
     var generatorStyle:TSGeneratorImageStyle
     var expandEdge:UIEdgeInsets
@@ -30,11 +33,18 @@ struct TSAIListPhotoGeneratorModel {
         self.additionalPrompt = additionalPrompt
         self.upLoadImages = upLoadImages
     }
+    
+    
+    var prompt:String = ""
+    var inputText:String = ""
+    var upLoadImageUrl:String?
+    var model:String = ""   //决定生图的模型
+    
 }
 
 class TSAIListPhotoGeneratorBaseVC: TSAIPhotoGeneratorBaseVC {
 
-    init(generatorModel:TSAIListPhotoGeneratorModel,complete:@escaping ((TSActionInfoModel)->Void)) {
+    init(generatorModel:TSAIGeneratorModel,complete:@escaping ((TSActionInfoModel)->Void)) {
         self.complete = complete
         self.viewModel = TSAIListPhotoGeneratorBaseVM(generatorModel: generatorModel)
         super.init()

+ 4 - 2
AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIPhotoGeneratorBaseVM/TSAIListPhotoGeneratorBaseVM.swift

@@ -33,8 +33,8 @@ class TSAIListPhotoGeneratorBaseVM {
     
     var imageUrl:String?
     var imageUrls:[String]?
-    var generatorModel:TSAIListPhotoGeneratorModel
-    init(generatorModel:TSAIListPhotoGeneratorModel) {
+    var generatorModel:TSAIGeneratorModel
+    init(generatorModel:TSAIGeneratorModel) {
         self.generatorModel = generatorModel
     }
     
@@ -199,6 +199,8 @@ class TSAIListPhotoGeneratorBaseVM {
                         "imageUrls":imageUrls
                         ]
             postDict.removeValue(forKey: "imageUrl")
+        default:
+            break;
         }
         postDict["device"] = getUserInfoJsonString()
         postDict["imageUrl"] = imageUrl

+ 20 - 2
AIEmoji/Business/TSAILIstVC/TSAIUploadPhotoBaseVC/TSAIUploadPhotoBaseVC.swift

@@ -19,7 +19,7 @@ enum TSGeneratorImageStyle {
     case motherDay    //母亲节
     case catTohuman    //猫变人
     case futureBaby    //预测宝宝
-    
+    case ptp            //通用的图生图
     
     var imageMaxKb:Int{
         switch self {
@@ -45,6 +45,8 @@ enum TSGeneratorImageStyle {
             return 10*1024
         case .futureBaby:
             return 10*1024
+        default:
+            return 10*1024
         }
     }
     
@@ -72,6 +74,8 @@ enum TSGeneratorImageStyle {
             return kUploadImageMaxBit10Size
         case .futureBaby:
             return kUploadImageMaxBit10Size
+        default:
+            return kUploadImageMaxBit10Size
         }
     }
     
@@ -99,6 +103,8 @@ enum TSGeneratorImageStyle {
             return "isFirstAICatTohuman"
         case .futureBaby:
             return "isFirstAIFutureBaby"
+        default:
+            return ""
         }
     }
     
@@ -126,6 +132,9 @@ enum TSGeneratorImageStyle {
             return .catTohumanConfig
         case .futureBaby:
             return .futureBabyConfig
+            
+        default:
+            return .futureBabyConfig
         }
     }
     
@@ -137,6 +146,13 @@ enum TSGeneratorImageStyle {
             return false
         }
     }
+    
+    var isVideo:Bool{
+        if self == .photoLive {
+            return true
+        }
+        return false
+    }
 }
 
 class TSAIUploadPhotoBaseVC: TSBaseVC {
@@ -455,7 +471,7 @@ extension TSAIUploadPhotoBaseVC {
         if generatorStyle != .catTohuman {
             additionalPrompt = ""
         }
-        let gennerateVC = TSAIListPhotoGeneratorBaseVC(generatorModel: TSAIListPhotoGeneratorModel(upLoadImage: upLoadImage, generatorStyle: generatorStyle,additionalPrompt: additionalPrompt)){ [weak self] model in
+        let gennerateVC = TSAIListPhotoGeneratorBaseVC(generatorModel: TSAIGeneratorModel(upLoadImage: upLoadImage, generatorStyle: generatorStyle,additionalPrompt: additionalPrompt)){ [weak self] model in
             guard let self = self else { return }
             saveModel(model: model)
         }
@@ -485,6 +501,8 @@ extension TSAIUploadPhotoBaseVC {
             TSRMShared.motherDayDBHistory.updateData(model)
         case .catTohuman:
             TSRMShared.catTohumanDBHistory.updateData(model)
+        default:
+            break;
         }
     }
 

+ 1 - 1
AIEmoji/Business/TSAILIstVC/TSPredictBabyVC/TSFutureBabyVC.swift

@@ -145,7 +145,7 @@ extension TSFutureBabyVC {
         }
         
         let gennerateVC = TSAIListPhotoGeneratorBaseVC(generatorModel:
-            TSAIListPhotoGeneratorModel(
+            TSAIGeneratorModel(
                 upLoadImage: upLoadImage1,
                 generatorStyle: .futureBaby,
                 additionalPrompt: additionalPrompt,

+ 44 - 10
AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/Model/TSActionInfoModel.swift

@@ -35,8 +35,7 @@ class TSActionInfoModel: TSBaseModel {
     var percent:Float = 0.0
     var actionStatus:ActionStatus = .failed
     
-    var videoThumbnailPath:String = ""
-    var videoPath:String = ""
+
     
     var uuid:String = UUID().uuidString
     override func mapping(map: ObjectMapper.Map) {
@@ -57,19 +56,31 @@ class TSActionInfoModel: TSBaseModel {
         
         uuid      <- map["uuid"]
     }
+    
+    
+
+    
+    var videoThumbnailPath:String = ""
+    var videoPath:String = ""
 }
 
 extension TSActionInfoModel {
     var isVideo:Bool{
-        return videoThumbnailPath.count > 0
+        return videoThumbnailPath.count > 0 || response.videoDocument.count > 0
     }
     
-    var videoThumbnailURL: URL {
-        return videoThumbnailPath.fillDocumentURL
+    var videoPreviewUrlString: String {
+        if videoThumbnailPath.count > 0 {
+            return videoThumbnailPath.fillDocumentPath
+        }
+        return response.previewUrl
     }
     
     var videoURL: URL {
-        return videoPath.fillDocumentURL
+        if videoPath.count > 0 {
+            return videoPath.fillDocumentURL
+        }
+        return response.videoDocument.fillDocumentURL
     }
     
     
@@ -92,19 +103,20 @@ extension TSActionInfoModel {
 
 class TSActionRequestModel : TSBaseModel {
     var prompt:String = ""
-    var promptSort:String = ""  //用户自己输入的内容
+    var inputText:String = ""  //用户自己输入的内容
     var width:Int = 0
     var height:Int = 0
     
     var imageUrl:String = ""
     var imageUrlTimestamp:Int = 0
-    var style:String = ""
-    var advance:Bool = false//决定生图的模型
+
+    
     var model:String = ""   //决定生图的模型
+    var generatorStyle:TSGeneratorImageStyle = .ptp
     
     override func mapping(map: ObjectMapper.Map) {
         prompt              <- map["prompt"]
-        promptSort          <- map["promptSort"]
+        inputText           <- map["inputText"]
         width               <- map["width"]
         height              <- map["height"]
         
@@ -113,15 +125,33 @@ class TSActionRequestModel : TSBaseModel {
         style               <- map["style"]
         advance             <- map["advance"]
         model               <- map["model"]
+        generatorStyle      <- map["generatorStyle"]
     }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    var style:String = ""
+    var advance:Bool = false//决定生图的模型
 }
 
 class TSActionResponseModel : TSBaseModel {
     var resultUrl:String = ""
+    var previewUrl:String = ""
+    var videoDocument:String = ""
+    
     var code:Int = 0
     var vip:Bool = false
     override func mapping(map: ObjectMapper.Map) {
         resultUrl           <- map["resultUrl"]
+        previewUrl           <- map["previewUrl"]
+        videoDocument           <- map["videoDocument"]
+        
         vip                 <- map["vip"]
         code                <- map["code"]
     }
@@ -134,5 +164,9 @@ class TSActionResponseModel : TSBaseModel {
     var sensitiveError:Bool {
         return TSNetWorkCode.sensitiveError(code: code)
     }
+    
+    var videoURL: URL {
+        return videoDocument.fillDocumentURL
+    }
 }
 

+ 44 - 7
AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/Model/TSDBActionInfoModel.swift

@@ -12,7 +12,7 @@ class TSDBActionInfoModel: Object {
     @Persisted(primaryKey: true) var primaryKey: String = UUID().uuidString
     @Persisted var createdAt: Date = Date()
     
-    @Persisted var modelType:Int = 0
+    @Persisted var modelType:Int = 0 //0普通 1 示例
     @Persisted var id:Int = 0
     @Persisted var actionType:String = ""
     @Persisted var comments:String = ""
@@ -23,8 +23,10 @@ class TSDBActionInfoModel: Object {
     @Persisted var costTime:Int = 0
     @Persisted var percent:Float = 0.0
     
+    //活照片用到的,后续慢慢废弃
     @Persisted var videoThumbnailPath:String = ""
     @Persisted var videoPath:String = ""
+    
     @Persisted var uuid:String = UUID().uuidString
     
     static func createDBModel(actionInfoModel:TSActionInfoModel) -> TSDBActionInfoModel{
@@ -81,6 +83,19 @@ class TSDBActionInfoModel: Object {
     }
     
     
+
+}
+
+
+extension TSDBActionInfoModel {
+    
+    var isVideo:Bool{
+        if let response = response,!response.videoDocument.isEmpty {
+            return true
+        }
+        return !videoThumbnailPath.isEmpty
+    }
+    
     var isResult:Bool {
         if status.count > 0 {
             if status == "pending" ||
@@ -92,17 +107,32 @@ class TSDBActionInfoModel: Object {
         return true
     }
 
+    
+    func deleteResources() {
+        if let response = response {
+            TSImageStoreTool.removeImage(urlString:response.resultUrl)
+            TSImageStoreTool.removeImage(urlString:response.previewUrl)
+            if !response.videoDocument.isEmpty {
+                TSFileManagerTool.removeItem(from: response.videoDocument.fillDocumentURL)
+            }
+            
+        }
+        
+        if !videoPath.isEmpty {
+            TSFileManagerTool.removeItem(from: videoPath.fillDocumentURL)
+        }
+        if !videoThumbnailPath.isEmpty {
+            TSFileManagerTool.removeItem(from: videoThumbnailPath.fillDocumentURL)
+        }
+    }
 }
-
-
-
 class TSDBActionRequestModel : Object {
     
     @Persisted(primaryKey: true) var primaryKey: String = UUID().uuidString
     @Persisted var createdAt: Date = Date()
     
     @Persisted var prompt:String = ""
-    @Persisted var promptSort:String = ""  //用户自己输入的内容
+    @Persisted var inputText:String = ""  //用户自己输入的内容
     @Persisted var width:Int = 0
     @Persisted var height:Int = 0
     
@@ -119,7 +149,7 @@ class TSDBActionRequestModel : Object {
     
     func saveData(requestModel:TSActionRequestModel) {
         self.prompt = requestModel.prompt
-        self.promptSort = requestModel.promptSort
+        self.inputText = requestModel.inputText
         self.width = requestModel.width
         self.height = requestModel.height
         
@@ -133,7 +163,7 @@ class TSDBActionRequestModel : Object {
     func getModel()->TSActionRequestModel{
         let model = TSActionRequestModel()
         model.prompt = self.prompt
-        model.promptSort = self.promptSort
+        model.inputText = self.inputText
         model.width = self.width
         model.height = self.height
         
@@ -152,6 +182,9 @@ class TSDBActionResponseModel : Object {
     @Persisted var createdAt: Date = Date()
     
     @Persisted var resultUrl:String = ""
+    @Persisted var previewUrl:String = ""
+    @Persisted var videoDocument:String = ""
+    
     @Persisted var code:Int = 0
     @Persisted var vip:Bool = false
     
@@ -163,6 +196,8 @@ class TSDBActionResponseModel : Object {
     
     func saveData(responseModel:TSActionResponseModel) {
         self.resultUrl = responseModel.resultUrl
+        self.previewUrl = responseModel.previewUrl
+        self.videoDocument = responseModel.videoDocument
         self.code = responseModel.code
         self.vip = responseModel.vip
     }
@@ -171,6 +206,8 @@ class TSDBActionResponseModel : Object {
     func getModel()->TSActionResponseModel{
         let model = TSActionResponseModel()
         model.resultUrl = self.resultUrl
+        model.previewUrl = self.previewUrl
+        model.videoDocument = self.videoDocument
         model.code = self.code
         model.vip = self.vip
         return model

+ 1 - 1
AIEmoji/Business/TSGenmojiVC/TSGenmojiVC/View/TSGenmojiItemCell.swift

@@ -83,7 +83,7 @@ class TSGenmojiItemCell: TSBaseCollectionCell ,TSSimpleConfigurableView {
                 if kJudgeVipFreeType(vipFreeNumType: .picToPic){ return }
                 if TSGeneratePTPOperationQueue.shared.isAvailability {
                     let generatePTPOperation = TSGeneratePTPOperationQueue.shared.creatOperation(uuid: dataModel.uuid)
-                    generatePTPOperation.isSaveDB = true
+                    generatePTPOperation.isSaveProcessToDB = true
                     generatePTPOperation.creatImage(oldModel: dataModel)
                     generateView.setProgress(progress: 0)
                 }

+ 24 - 25
AIEmoji/Business/TSPTPGeneratorVC/TSAIPhotoGeneratorBaseVC/TSAIPhotoBrowseVC.swift

@@ -7,9 +7,10 @@
 
 private let cellId = "TSAIPhotoBrowseCell"
 private let videoCellId = "TSAIVideoBrowseCell"
+import RealmSwift
 class TSAIPhotoBrowseVC: TSBaseVC {
-    var deleteComplete:((TSActionInfoModel)->Void)?
-    var dataModelArray = [TSActionInfoModel]()
+    var deleteComplete:((TSDBActionInfoModel)->Void)?
+    var dataModelArray = List<TSDBActionInfoModel>()//惰性加载特性
     var currentImage:UIImage?{
         let cell = collectionView.cellForItem(at: IndexPath(item: currentIndex, section: 0)) as? TSAIPhotoBrowseCell
         var image = cell?.netWorkImageView.image
@@ -17,8 +18,8 @@ class TSAIPhotoBrowseVC: TSBaseVC {
         return image
     }
 
-    var currentModel:TSActionInfoModel?{
-        if let model = dataModelArray.safeObj(At: currentIndex){
+    var currentModel:TSDBActionInfoModel?{
+        if let model = dataModelArray[safe:currentIndex]{
             return model
         }
         return nil
@@ -209,13 +210,10 @@ class TSAIPhotoBrowseVC: TSBaseVC {
         addPullDownClosePage()
     }
     @objc func clickSubmitBtn(){
-        
-        if JudgeVip(){
-            return
-        }
-        
+
         guard let currentModel = currentModel else { return }
-        let urlString = currentModel.response.resultUrl
+        guard let response = currentModel.response else { return }
+        let urlString = response.resultUrl
         if currentModel.isVideo {
             TSDownloadManager.getDownLoadVideo(urlString: urlString) { url, _ in
                 if let url = url {
@@ -256,9 +254,9 @@ class TSAIPhotoBrowseVC: TSBaseVC {
     }
     
     
-    func JudgeVip() -> Bool {
-        return kJudgeVip(externalBool: currentModel?.response.vip ?? false , vc: self, closePageBlock: nil)
-    }
+//    func JudgeVip() -> Bool {
+//        return kJudgeVip(externalBool: currentModel?.response.vip ?? false , vc: self, closePageBlock: nil)
+//    }
     
     @objc func clickXBtn(){
         pop()
@@ -269,7 +267,8 @@ class TSAIPhotoBrowseVC: TSBaseVC {
 //        kShareContent(target: self, anyData: image)
         
         guard let currentModel = currentModel else { return }
-        let urlString = currentModel.response.resultUrl
+        guard let response = currentModel.response else { return }
+        let urlString = response.resultUrl
         if currentModel.isVideo {
             TSDownloadManager.getDownLoadVideo(urlString: urlString) { url, _ in
                 if let url = url {
@@ -318,29 +317,29 @@ extension TSAIPhotoBrowseVC:UICollectionViewDataSource,UICollectionViewDelegate
     }
     
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
-        if let model = dataModelArray.safeObj(At: indexPath.item){
+        if let model = dataModelArray[safe:indexPath.item]{
             if model.isVideo {
                 let cell = collectionView.dequeueReusableCell(withReuseIdentifier: videoCellId, for: indexPath) as! TSAIVideoBrowseCell
-                cell.model = model
+                cell.model = model.getModel()
+                return cell
+            }else{
+                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! TSAIPhotoBrowseCell
+                cell.model = model.getModel()
                 return cell
             }
         }
         
-        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! TSAIPhotoBrowseCell
-        if let model = dataModelArray.safeObj(At: indexPath.item){
-            cell.model = model
-        }
-        return cell
+        return UICollectionViewCell()
     }
     
     func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
-        if let model = dataModelArray.safeObj(At: indexPath.item){
+        if let model = dataModelArray[safe:indexPath.item]{
             if model.isVideo {
                 guard let cell = cell as? TSAIVideoBrowseCell else { return }
-                cell.model = model
+                cell.model = model.getModel()
             }else{
                 guard let cell = cell as? TSAIPhotoBrowseCell else { return }
-                cell.model = model
+                cell.model = model.getModel()
             }
         }
     }
@@ -349,7 +348,7 @@ extension TSAIPhotoBrowseVC:UICollectionViewDataSource,UICollectionViewDelegate
                       didEndDisplaying cell: UICollectionViewCell,
                       forItemAt indexPath: IndexPath) {
 
-        if let model = dataModelArray.safeObj(At: indexPath.item){
+        if let model = dataModelArray[safe:indexPath.item]{
             if model.isVideo {
                 guard let cell = cell as? TSAIVideoBrowseCell else { return }
                 cell.videoPlayerVC?.playPause()

+ 2 - 2
AIEmoji/Business/TSPTPGeneratorVC/TSAbnormalPopUpAlertVC/TSAbnormalPopUpAlertVC.swift

@@ -12,7 +12,7 @@ class TSAbnormalPopUpAlertVC: TSBaseVC {
     var text:String = "" {
         didSet{
             textLab.text = text
-            textLab.setLineSpacing(6.0, alignment: .center)
+            textLab.setLineSpacing(6.0)
         }
     }
     var isAddView:Bool = false
@@ -38,7 +38,7 @@ class TSAbnormalPopUpAlertVC: TSBaseVC {
     
     lazy var textLab: UILabel = {
         let textLab = UILabel.createLabel(text: text,font: .font(size: 16),textColor: .white,textAlignment: .center,numberOfLines: 0)
-        textLab.setLineSpacing(6.0, alignment: .center)
+        textLab.setLineSpacing(6.0)
         return textLab
     }()
     lazy var submitBtn: UIButton = {

+ 1 - 1
AIEmoji/Business/TSPTPGeneratorVC/TSPTPBrowseVC/TSPTPBrowseVC.swift

@@ -196,7 +196,7 @@ extension TSPTPBrowseVC:UICollectionViewDataSource,UICollectionViewDelegate {
             }
 
             cell.vipImageView.isHidden = !model.response.vip
-            cell.textLabel.text = model.request.promptSort
+            cell.textLabel.text = model.request.inputText
         }
         return cell
     }

+ 2 - 2
AIEmoji/Business/TSPTPGeneratorVC/TSPTPGeneratorVC/TSPTPGeneratorVC.swift

@@ -142,7 +142,7 @@ class TSPTPGeneratorVC: TSAIPhotoGeneratorBaseVC {
     
     //后台生成
     @objc func clickBackstageBtn() {
-        self.operation.isSaveDB = true //后台生成,让数据库保存数据
+        self.operation.isSaveProcessToDB = true //后台生成,让数据库保存数据
         if let model = infoModel {
             TSRMShared.ptpDBHistory.updateData(model)
             debugPrint("图生图进入后台,保存数据listModels.first=\(TSRMShared.ptpDBHistory.listModels.first)")
@@ -340,7 +340,7 @@ extension TSPTPGeneratorVC {
         self.netWorkImageView.setAsyncImage(urlString: model.response.resultUrl,placeholder:kPlaceholderImage,backgroundColor:netWorkImageView.backgroundColor!)
         
         if let model = infoModel {
-            model.request.promptSort = viewModel.generateStyleModel.inputText
+            model.request.inputText = viewModel.generateStyleModel.inputText
             complete(model)
         }
     }

+ 12 - 4
AIEmoji/Business/TSPTPGeneratorVC/TSPTPHistoryVC/TSPTPHistoryVC.swift

@@ -111,17 +111,25 @@ class TSPTPHistoryVC: TSBaseVC {
         })
     }
 }
-
+import RealmSwift
 extension TSPTPHistoryVC: TSSimpleCollectionViewDelegate {
     
     func collectionView(didTrigger event: TSSmalCoacopods.TSSimpleCellEvent) {
         switch event.action {
         case .tap:
             guard let selectedModel = listModelArray.safeObj(At: event.indexPath.item) else { return }
-            let dataModelArray = listModelArray.filter{$0.status == "success" || $0.modelType == .example}
+//            let dataModelArray = listModelArray.filter{$0.status == "success" || $0.modelType == .example}
+            
+            
+            let filteredResults = TSRMShared.ptpDBHistory.listModels.filter("status == %@", "success")//直接过滤List(返回Results类型)
+            let filteredList = List<TSDBActionInfoModel>()
+            filteredList.append(objectsIn: filteredResults)
+            
+            
             let browseVC = TSAIPhotoBrowseVC()
-            browseVC.dataModelArray = dataModelArray
-            browseVC.currentIndex = dataModelArray.firstIndex(of: selectedModel) ?? 0
+//            browseVC.dataModelArray = dataModelArray
+            browseVC.dataModelArray = filteredList
+            browseVC.currentIndex = filteredList.firstIndex(where: { $0.id == selectedModel.id }) ?? 0
             browseVC.deleteComplete = { [weak self]  deleteModel in
                 guard let self = self else { return }
                 dbHistory.deleteListModel(id: deleteModel.id)

+ 14 - 9
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC.swift

@@ -4,7 +4,7 @@
 //
 //  Created by 100Years on 2025/4/7.
 //
-
+import RealmSwift
 import PhotosUI
 class TSPTPInputVC: TSBaseVC {
     lazy var viewModel: TSPTPInputVM = {
@@ -230,16 +230,21 @@ class TSPTPInputVC: TSBaseVC {
             guard let self = self else { return }
             if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel,
                let dataModel = sections.items.safeObj(At: indexPath.item)?.dataModel {
-                var dataModelArray: [TSActionInfoModel] = []
-                for itemModel in sections.items {
-                    if itemModel.dataModel.status == "success" || itemModel.dataModel.modelType == .example {
-                        dataModelArray.append(itemModel.dataModel)
-                    }
-                }
+//                var dataModelArray: [TSActionInfoModel] = []
+//                for itemModel in sections.items {
+//                    if itemModel.dataModel.status == "success" || itemModel.dataModel.modelType == .example {
+//                        dataModelArray.append(itemModel.dataModel)
+//                    }
+//                }
+                
+                
+                let filteredResults = TSRMShared.ptpDBHistory.listModels.filter("status == %@", "success")//直接过滤List(返回Results类型)
+                let filteredList = List<TSDBActionInfoModel>()
+                filteredList.append(objectsIn: filteredResults)
 
                 let browseVC = TSAIPhotoBrowseVC()
-                browseVC.dataModelArray = dataModelArray
-                browseVC.currentIndex = dataModelArray.firstIndex(of: dataModel) ?? 0
+                browseVC.dataModelArray = filteredList
+                browseVC.currentIndex = filteredList.firstIndex(where: { $0.id == dataModel.id }) ?? 0
                 browseVC.deleteComplete = { [weak self]  deleteModel in
                     guard let self = self else { return }
                     TSRMShared.ptpDBHistory.deleteListModel(id: deleteModel.id)

+ 1 - 1
AIEmoji/Business/TSPTPGeneratorVC/TSPhotoToPhotoVC/TSPhotoToPhotoVC.swift

@@ -336,7 +336,7 @@ extension TSPhotoToPhotoVC {
         guard let selectedPTPStyleModel = viewModel.selectedPTPStyleModel else { return }
         guard let upLoadImage = viewModel.upLoadImage else { return }
 
-        let gennerateVC = TSPTPGeneratorVC(prompt: selectedPTPStyleModel.prompt,promptSort: selectedPTPStyleModel.imageText , imageUrl: "",upLoadImage: upLoadImage,style: selectedPTPStyleModel.style) { [weak self] model in
+        let gennerateVC = TSPTPGeneratorVC(prompt: selectedPTPStyleModel.prompt,inputText: selectedPTPStyleModel.imageText , imageUrl: "",upLoadImage: upLoadImage,style: selectedPTPStyleModel.style) { [weak self] model in
             guard let self = self else { return }
             if viewModel.saveModel(model:model) {
                 collectionComponent.clear()

+ 1 - 1
AIEmoji/Business/TSPTPGeneratorVC/TSPhotoToPhotoVC/VM/TSPhotoToPhotoVM.swift

@@ -132,7 +132,7 @@ class TSPhotoToPhotoVM {
         let model = TSActionInfoModel()
         model.modelType = .example
         model.request.prompt = "Example"
-        model.request.promptSort = "Example"
+        model.request.inputText = "Example"
         model.request.width = 330
         model.request.height = 440
         model.response.resultUrl = imageName

+ 6 - 2
AIEmoji/Business/TSTabBarController/TSTabBarController.swift

@@ -43,8 +43,8 @@ class TSTabBarController: UITabBarController {
 
     @objc private func setUpData() {
 
-        viewControllerArray = ["TSPTPInputVC","TSAILIstVC","TSTTPInputVC","TSChatViewController","TSSetingVC"]
-        titleArray = ["Photo","AI Store","Text","Chat","Setting"]
+        viewControllerArray = ["TSPTPInputVC","TSAILIstVC","TSTTPInputVC","TSGenerateHistoryVC","TSSetingVC"]
+        titleArray = ["Photo","AI Store","Text","Creations","Setting"]
         selectedImageArray = [
             "tabbar_select_pic",
             "tabbar_select_ailist",
@@ -135,6 +135,10 @@ extension TSTabBarController {
             }
         }
     }
+    
+    func changeSelectedIndex(index:Int){
+        self.selectedIndex = index
+    }
 }
 
 extension TSTabBarController:UITabBarControllerDelegate {

+ 6 - 5
AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/TSTTPInputVC+Col.swift

@@ -32,13 +32,14 @@ extension TSTTPInputVC {
             guard let self = self else { return }
             if indexPath.section == 0{
                 if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel{
-                    var dataModelArray:[TSActionInfoModel] = []
-                    for itemModel in sections.items {
-                        dataModelArray.append(itemModel.dataModel)
-                    }
+//                    var dataModelArray:[TSActionInfoModel] = []
+//                    for itemModel in sections.items {
+//                        dataModelArray.append(itemModel.dataModel)
+//                    }
                     
                     let browseVC = TSAIPhotoBrowseVC()
-                    browseVC.dataModelArray = dataModelArray
+//                    browseVC.dataModelArray = dataModelArray
+                    browseVC.dataModelArray = TSRMShared.ttpDBHistory.listModels
                     browseVC.currentIndex = indexPath.item
                     browseVC.deleteComplete = { [weak self]  deleteModel in
                         guard let self = self else { return }

+ 1 - 1
AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/TSTTPInputVC.swift

@@ -216,7 +216,7 @@ extension TSTTPInputVC {
         if kJudgeVip(externalBool: isVip, vc: self) { return } //判断 vip
         let gennerateVC = TSTextPicGennerateVC(generateStyleModel: viewModel.generateStyleModel) {[weak self] model in
             guard let self = self else { return }
-            model.request.promptSort = viewModel.promptText
+            model.request.inputText = viewModel.promptText
             viewModel.saveModel(model: model)
             updateVipView()
             reloadUIBlock?()

+ 2 - 1
AIEmoji/Business/TSTextGeneralPictureVC/TSTextGeneralPictureVC/TSTextGeneralPictureVC.swift

@@ -63,7 +63,8 @@ class TSTextGeneralPictureVC: TSBaseVC {
                     }
                     
                     let browseVC = TSAIPhotoBrowseVC()
-                    browseVC.dataModelArray = dataModelArray
+//                    browseVC.dataModelArray = dataModelArray
+                    browseVC.dataModelArray = TSRMShared.ttpDBHistory.listModels
                     browseVC.currentIndex = indexPath.item
                     browseVC.deleteComplete = { [weak self]  deleteModel in
                         guard let self = self else { return }

+ 27 - 0
AIEmoji/Business2/Data/TSDiscoverViewModel.swift

@@ -0,0 +1,27 @@
+//
+//  TSHomeViewModel.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/6/21.
+//
+
+
+
+
+class aaa {
+    
+}
+
+class TSDiscoverViewModel {
+    
+    
+    
+    
+    //顶部功能 1
+    lazy var topFunc0: [Int] = {
+        
+        return []
+    }()
+    
+    
+}

+ 239 - 0
AIEmoji/Business2/TSGenerateHistoryVC/TSGenerateHistoryVC.swift

@@ -0,0 +1,239 @@
+//
+//  TSGenerateHistoryVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/6/22.
+//
+
+import RealmSwift
+
+class TSGenerateHistoryVC: TSBaseVC {
+
+    var listModelArray = List<TSDBActionInfoModel>()//惰性加载特性
+    //###################################### 导航栏 view ######################################
+    lazy var vipBtn: UIButton = {
+       let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self]  in
+           guard let self = self else { return }
+           TSPurchaseVC.show(target: self) {}
+       }
+       return vipBtn
+   }()
+    
+    lazy var navBarView: TSBaseNavContentBarView = {
+        let navBarView = TSBaseNavContentBarView()
+
+        let label = UILabel.createLabel(text: "Creations".localized,font: .font(name: .KelsiFill,size: 28))
+        navBarView.barView.addSubview(label)
+        label.snp.makeConstraints { make in
+            make.centerY.equalToSuperview()
+            make.leading.equalTo(17.0)
+        }
+        
+        navBarView.barView.addSubview(vipBtn)
+        vipBtn.snp.makeConstraints { make in
+            make.centerY.equalToSuperview()
+            make.trailing.equalTo(-16)
+            make.width.height.equalTo(32)
+        }
+        
+        kMainAsync {
+            label.applyGradient(colors: ["#FA794F".uiColor,"#F8C32A".uiColor,"#FEFBF4".uiColor])
+        }
+        
+       return navBarView
+    }()
+    
+    //###################################### 集合视图 ######################################
+    let collectionViewBtootm:CGFloat = 80
+
+    let identifier = "TSAIListHistoryCell"
+    lazy var collectionView: UICollectionView = {
+        let layout = UICollectionViewFlowLayout()
+        layout.scrollDirection = .vertical
+        
+        let itemW = (k_ScreenWidth-32.0-13.0-2.0)/2.0
+        let itemH = kGetScaleHeight(originalSize: CGSize(width: 165.0, height: 220.0), width: itemW)
+
+        layout.itemSize = CGSize(width: itemW, height: itemH)
+        layout.minimumInteritemSpacing = 13
+        layout.minimumLineSpacing = 16
+        layout.sectionInset = UIEdgeInsets(top: 10, left: 16, bottom: k_Height_TabBar+20, right: 16)
+        
+        let collectionView = TSBaseCollectionView(frame: .zero, collectionViewLayout: layout)
+        collectionView.delegate = self
+        collectionView.dataSource = self
+        collectionView.register(TSGenerateHistoryCell.self, forCellWithReuseIdentifier: identifier)
+        return collectionView
+    }()
+    
+    lazy var pageNullView: TSPageNullView = {
+        let pageNullView = TSPageNullView()
+        pageNullView.isHidden = true
+        return pageNullView
+    }()
+    
+    override func createData() {
+        
+    }
+    
+    var navRightBtn = UIButton()
+    override func createView() {
+        addNormalNavBarView()
+
+        navBarContentView.addSubview(navBarView)
+        navBarView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        contentView.addSubview(pageNullView)
+        contentView.addSubview(collectionView)
+        collectionView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+    
+    override func dealThings() {
+        updateDataView()
+        NotificationCenter.default.addObserver(self, selector: #selector(operationChanged(_:)), name: .kGenerateBasePhotoOperation, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(updateDataView), name: .kAIPhotoDataChanged, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(updateVipView), name: .kPurchaseDidChanged, object: nil)
+        updateVipView()
+    }
+    
+    @objc func operationChanged(_ notification: Notification) {
+        if let userInfo = notification.userInfo as? [String: Any],let state = userInfo["state"] as? TSProgressState {
+            if state.reloadNewData {
+                self.updateDataView()
+            }
+        }
+    }
+    
+    @objc func updateVipView() {
+        kMainAsync{
+            self.vipBtn.isHidden = PurchaseManager.default.isVip
+        }
+    }
+    
+    @objc func updateDataView(){
+//        dbHistory.getModelList { [weak self] array in
+//            guard let self = self else { return }
+//            listModelArray = array
+//            updateView()
+//        }
+        listModelArray = dbHistory.listModels//惰性加载特性
+        updateView()
+    }
+    
+
+    func updateView() {
+        collectionView.reloadData()
+        
+        navRightBtn.isHidden = listModelArray.count <= 0
+        pageNullView.isHidden = listModelArray.count > 0
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        print("viewWillAppear")
+    }
+    
+    @objc func clickNavRight() {
+        TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
+            message: "Are you sure to delete all histories?".localized,
+            cancelTitle: "Delete All".localized,
+            cancelColor: .red,
+            confirmTitle: "Retain".localized,
+            confirmColor: .white,
+            cancelAction: { [weak self]  in
+                guard let self = self else { return }
+                self.removeAllHistoryList()
+                self.updateDataView()
+            }
+        ))
+    }
+}
+
+extension TSGenerateHistoryVC: UICollectionViewDataSource ,UICollectionViewDelegate {
+    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return listModelArray.count
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        
+        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
+        if let cell = cell as? TSGenerateHistoryCell ,let dbModel = listModelArray[safe:indexPath.row]{
+            cell.dataModel = dbModel.getModel()
+            cell.buttonTapped = { [weak self] cmd in
+                self?.handelCellCmd(cmd: cmd,indexPath: indexPath)
+            }
+        }
+        
+        return cell
+    }
+
+    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        guard let selectedModel = listModelArray[safe:indexPath.row] else { return }
+        let filteredResults = listModelArray.filter("status == %@", "success")//直接过滤List(返回Results类型)
+        let filteredList = List<TSDBActionInfoModel>()
+        filteredList.append(objectsIn: filteredResults)
+        
+        let browseVC = TSAIPhotoBrowseVC()
+        browseVC.dataModelArray = filteredList
+        browseVC.currentIndex = filteredList.firstIndex(of: selectedModel) ?? 0
+        browseVC.deleteComplete = { [weak self]  deleteModel in
+            guard let self = self else { return }
+            dbHistory.deleteListModel(uuid: deleteModel.uuid)
+            updateDataView()
+        }
+        kPresentModalVC(target: self, modelVC: browseVC,transitionStyle: .crossDissolve)
+    }
+}
+
+extension TSGenerateHistoryVC{
+    func handelCellCmd(cmd:String,indexPath: IndexPath){
+        if let currentActionInfoModel = listModelArray[safe:indexPath.row]{
+            if cmd == "delete_task_expired" {
+                dbHistory.deleteListModel(id: currentActionInfoModel.id)
+                updateDataView()
+            }else if cmd == "delete_task_sensitive" {
+                showDeleteErrorAlert(message: "Delete this error history?".localized, deleteHandler:  { [weak self]  in
+                    guard let self = self else { return }
+                    dbHistory.deleteListModel(id: currentActionInfoModel.id)
+                    updateDataView()
+                })
+            }else if cmd == "delete" {
+                TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
+                    message: "Are you sure to delete?".localized,
+                    cancelTitle: "Delete".localized,
+                    cancelColor: .red,
+                    confirmTitle: "Retain".localized,
+                    confirmColor: .white,
+                    cancelAction: { [weak self]  in
+                        guard let self = self else { return }
+                        removeDelete(index: indexPath.row)
+                    }
+                ))
+            }
+        }
+    }
+    
+    func removeDelete(index:Int){
+        dbHistory.deleteListModel(index: index)
+        updateDataView()
+    }
+    
+    func removeAllHistoryList(){
+        dbHistory.deleteAll()
+        updateDataView()
+    }
+    
+    var dbHistory:TSDBHistory{
+        TSRMShared.aiGenerateDB
+    }
+}
+extension TSGenerateHistoryVC{
+
+    static func showPosition(){
+        AppDelegate.tabbar?.changeSelectedIndex(index: 1)
+    }
+    
+}

+ 193 - 0
AIEmoji/Business2/TSGenerateHistoryVC/View/TSGenerateHistoryCell.swift

@@ -0,0 +1,193 @@
+//
+//  TSGenerateHistoryCell.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/6/22.
+//
+
+import RealmSwift
+class TSGenerateHistoryCell: TSBaseCollectionCell {
+    var buttonTapped:((String)->Void)?
+    var operation:TSGenerateBasePhotoOperation?
+    var dataModel:TSActionInfoModel = TSActionInfoModel(){
+        didSet {
+            self.updataActionInfoModelView(model: dataModel)
+            if let operation = TSGenerateBasePhotoOperationQueue.shared.findOperation(uuid: dataModel.uuid) as? TSGenerateBasePhotoOperation {
+                DispatchQueue.main.async {
+                    operation.currentActionInfoModelChanged = { [weak self] actionInfoModel in
+                        guard let self = self else { return }
+                        DispatchQueue.main.async {
+//                            print("actionInfoModel.toJSONString()=\(actionInfoModel.toJSONString())")
+                            self.updataActionInfoModelView(model: actionInfoModel)
+                        }
+                    }
+                    self.operation = operation
+                }
+            }else{
+                self.operation?.currentActionInfoModelChanged = nil
+                self.operation = nil
+            }
+        }
+    }
+    
+
+    lazy var generateView: TSGennerateCellView = {
+        let generateView = TSGennerateCellView()
+        generateView.isHidden = true
+        generateView.refreshHandel = { [weak self]  in
+            guard let self = self else { return }
+            if dataModel.upImageURLExpired { //任务已经过期了
+                buttonTapped?("delete_task_expired")
+            }else if dataModel.response.sensitiveError { //敏感内容
+                buttonTapped?("delete_task_sensitive")
+            }else{
+//                if kJudgeVipFreeType(vipFreeNumType: .picToPic){ return }
+                if TSGenerateBasePhotoOperationQueue.shared.isAvailability {
+                    let generatePTPOperation = TSGenerateBasePhotoOperationQueue.shared.creatOperation(uuid: dataModel.uuid)
+                    generatePTPOperation.isSaveProcessToDB = true
+                    generatePTPOperation.creatImage(oldModel: dataModel){ complete in }
+                    generateView.setProgress(progress: 0)
+                }
+            }
+        }
+        
+        generateView.longPressHandel = { [weak self]  in
+            guard let self = self else { return }
+            buttonTapped?("delete")
+        }
+        return generateView
+    }()
+    
+    
+    
+    lazy var textLabel: UILabel = {
+        let textLabel = UILabel.createLabel(
+            text: "Example".localized,
+            font: .font(size: 12),
+            textColor: .white
+        )
+        return textLabel
+    }()
+    
+    lazy var exampleView: UIView = {
+        let exampleView = UIView()
+        exampleView.backgroundColor = "#232323".uiColor.withAlphaComponent(0.3)
+        
+        exampleView.addSubview(textLabel)
+        textLabel.snp.makeConstraints { make in
+            make.top.edges.equalTo(UIEdgeInsets(top: 4, left: 6, bottom: 4, right: 6))
+        }
+        exampleView.isHidden = true
+        return exampleView
+    }()
+    
+    lazy var showImageView: UIImageView = {
+        let showImageView = UIImageView.createImageView(imageName:"",contentMode: .scaleAspectFill)
+        showImageView.backgroundColor = .gray
+        return showImageView
+    }()
+    
+    lazy var hiddenImageView: UIImageView = {
+        let hiddenImageView = UIImageView.createImageView(imageName:"",contentMode: .scaleAspectFill)
+        hiddenImageView.backgroundColor = .gray
+        hiddenImageView.isHidden = true
+        return hiddenImageView
+    }()
+    
+    lazy var videoIconImageView: UIImageView = {
+        let videoIconImageView = UIImageView.createImageView(image:.videoIcon,contentMode: .scaleToFill,autoMirrored:false)
+        videoIconImageView.isHidden = true
+        return videoIconImageView
+    }()
+    
+    @objc func handleLongPress(_ gestureRecognizer: UILongPressGestureRecognizer) {
+        // 确保只在手势开始时触发一次
+        guard gestureRecognizer.state == .began else { return }
+        buttonTapped?("delete")
+    }
+    
+    override func creatUI() {
+        
+        let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
+        longPressRecognizer.minimumPressDuration = 0.5 // 设置最小长按时间(秒)
+        contentView.addGestureRecognizer(longPressRecognizer)
+        contentView.cornerRadius = 12.0
+
+        contentView.addSubview(hiddenImageView)
+        hiddenImageView.snp.makeConstraints { make in
+            make.top.equalTo(0)
+            make.leading.equalTo(0)
+            make.trailing.bottom.equalTo(0)
+        }
+        
+        contentView.addSubview(showImageView)
+        showImageView.snp.makeConstraints { make in
+            make.top.equalTo(0)
+            make.leading.equalTo(0)
+            make.trailing.bottom.equalTo(0)
+        }
+        
+        contentView.addSubview(exampleView)
+        exampleView.snp.makeConstraints { make in
+            make.top.equalTo(8)
+            make.leading.equalTo(8)
+            make.height.equalTo(20)
+        }
+        
+        contentView.addSubview(videoIconImageView)
+        videoIconImageView.snp.makeConstraints { make in
+            make.top.equalTo(8)
+            make.leading.equalTo(8)
+            make.width.height.equalTo(20)
+        }
+        
+        contentView.addSubview(generateView)
+        generateView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+}
+
+extension TSGenerateHistoryCell {
+    func updataActionInfoModelView(model:TSActionInfoModel){
+        
+        if model.modelType == .example {
+            model.actionStatus = .success
+        }
+        showImageView.image = nil
+        //dePrint("updataActionInfoModelView model.actionStatus 收到 = \(model.actionStatus)")
+        switch model.actionStatus {
+        case .pending,.running:
+            generateView.isHidden = false
+            generateView.setProgress(progress: model.percent)
+        case .success:
+            generateView.isHidden = true
+            videoIconImageView.isHidden = true
+            if model.modelType == .example {
+                textLabel.text = "Example".localized
+                exampleView.isHidden = false
+                showImageView.image = UIImage(named: model.response.resultUrl)
+            }else{
+                exampleView.isHidden = true
+                
+                videoIconImageView.isHidden = !model.isVideo
+                if dataModel.isVideo {
+                    videoIconImageView.isHidden = false
+                    showImageView.setAsyncImage(urlString: model.videoPreviewUrlString,contentMode: .scaleAspectFill,backgroundColor: .white.withAlphaComponent(0.1))
+                }else {
+                    showImageView.setAsyncImage(urlString: model.response.resultUrl,contentMode: .scaleAspectFill,backgroundColor: .white.withAlphaComponent(0.1))
+                    hiddenImageView.setAsyncImage(urlString: model.request.imageUrl,contentMode: .scaleAspectFill)
+                }
+            }
+
+        case .failed:
+            generateView.isHidden = false
+            if model.upImageURLExpired { //任务已经过期了
+                generateView.setTaskExpired()
+            }else{
+                generateView.setFailText(text: model.response.codeErrorMsg, refresh: !model.response.sensitiveError)
+            }
+            
+        }
+    }
+}

+ 124 - 0
AIEmoji/Business2/TSGenerateHistoryVC/View/TSGennerateCellView.swift

@@ -0,0 +1,124 @@
+//
+//  TSGennerateCellView.swift
+//  TSLiveWallpaper
+//
+//  Created by 100Years on 2025/6/16.
+//
+
+class TSGennerateCellView: TSBaseView {
+    
+    var refreshHandel:(()->Void)?
+    var longPressHandel:(()->Void)?
+    lazy var infoLabel: UILabel = {
+        let infoLabel = UILabel.createLabel(font: .font(size: 12),textColor: .themeColor,textAlignment: .center,numberOfLines: 0)
+        return infoLabel
+    }()
+    
+    lazy var refreshBtn: TSUIExpandedTouchButton = {
+        let refreshBtn = TSUIExpandedTouchButton()
+        refreshBtn.setUpButton(image: UIImage(named: "refresh_white"))
+        {[weak self]  in
+            guard let self = self else { return }
+            refreshHandel?()
+        }
+        refreshBtn.isHidden = true
+        return refreshBtn
+    }()
+    
+    
+
+    var titleTop:CGFloat = 86.0 {
+        didSet{
+            infoLabel.snp.updateConstraints { make in
+                make.top.equalTo(titleTop)
+            }
+        }
+    }
+    
+    override func creatUI() {
+        backgroundColor = "#1D1812".uiColor
+
+        contentView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickContentView)))
+        
+
+//        let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
+//        longPressRecognizer.minimumPressDuration = 0.5 // 设置最小长按时间(秒)
+//        contentView.addGestureRecognizer(longPressRecognizer)
+        
+        
+        contentView.addSubview(infoLabel)
+        infoLabel.snp.makeConstraints { make in
+//            make.top.equalTo(titleTop)
+            make.leading.equalTo(8)
+            make.trailing.equalTo(-8)
+            make.centerY.equalToSuperview().offset(0)
+        }
+        
+        contentView.addSubview(refreshBtn)
+        refreshBtn.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(infoLabel.snp.bottom).offset(8)
+            make.width.height.equalTo(24)
+        }
+        
+    }
+    
+    func updateInfoLabelCenterY() {
+        infoLabel.snp.updateConstraints { make in
+            make.centerY.equalToSuperview().offset(refreshBtn.isHidden ? 0 : -14.0)
+        }
+    }
+    
+    private var isCanClick:Bool = false
+    
+    @objc func clickContentView() {
+        if isCanClick{
+            refreshHandel?()
+        }
+    }
+    
+//    @objc func handleLongPress(_ gestureRecognizer: UILongPressGestureRecognizer) {
+//        // 确保只在手势开始时触发一次
+//        guard gestureRecognizer.state == .began else { return }
+//        longPressHandel?()
+//    }
+    
+    func setProgress(progress:Float) {
+        refreshBtn.isHidden = true
+        isCanClick = false
+        let progressInt = Int(progress*100)
+
+        infoLabel.text = "Processing you photo".localized + "..." + "\n\n" + kPercentlocalized(progressInt)
+        infoLabel.textColor = .themeColor
+
+        updateInfoLabelCenterY()
+    }
+    
+    
+    func setTaskExpired(){
+        isCanClick = true
+        setProgress(progress: 0.0)
+        infoLabel.text = "This task has expired".localized
+        infoLabel.textColor = .white
+        refreshBtn.isHidden = false
+        isCanClick = true
+        refreshBtn.setImage(UIImage(named: "ai_delete"), for: .normal)
+        
+        updateInfoLabelCenterY()
+    }
+
+    func setFailText(text:String,refresh:Bool = true){
+        setProgress(progress: 0.0)
+        infoLabel.text = text
+        infoLabel.textColor = .white
+        
+        if refresh {
+            refreshBtn.isHidden = false
+            refreshBtn.setImage(UIImage(named: "refresh_white"), for: .normal)
+        }else{
+            refreshBtn.isHidden = true
+        }
+        isCanClick = true
+        updateInfoLabelCenterY()
+    }
+}

+ 6 - 6
AIEmoji/Common/Purchase/TSPurchaseManager.swift

@@ -203,9 +203,9 @@ public class PurchaseManager: NSObject {
     }
 
     @objc public var isVip: Bool {
-//#if DEBUG
-//        return vipType != .none
-//#endif
+#if DEBUG
+        return vipType != .none
+#endif
         guard let expiresDate = expiredDate else {
             return false
         }
@@ -217,9 +217,9 @@ public class PurchaseManager: NSObject {
     }
 
     public var vipType: PremiumPeriod {
-//#if DEBUG
-//        return PremiumPeriod.none
-//#endif
+#if DEBUG
+        return PremiumPeriod.week
+#endif
         guard isVip, let type = vipInformation["type"] as? String else {
             return .none
         }

+ 7 - 4
AIEmoji/Common/TSRealmManager/TSRealmManager.swift

@@ -9,9 +9,6 @@ import RealmSwift
 
 let TSRMShared = TSRealmManager.shared
 
-
-
-
 class TSRealmManager {
     static let shared = TSRealmManager()
     private init() {
@@ -20,9 +17,10 @@ class TSRealmManager {
          1.9 ->2    //新增
          2.1 ->3    //新增ai思考
          3.6.1  ->4   //将UserDefaults 的历史记录迁移到数据库中
+         ui大改版 - >5
          **/
    
-        let newSchemaVersion: UInt64 = 4
+        let newSchemaVersion: UInt64 = 5
         // 获取默认配置
         var config = Realm.Configuration.defaultConfiguration
         // 设置新版本号
@@ -95,6 +93,11 @@ class TSRealmManager {
     }
 }
 
+extension List {
+    subscript(safe index: Int) -> Element? {
+        return indices.contains(index) ? self[index] : nil
+    }
+}
 
 /*
 // 创建数据

+ 0 - 208
AIEmoji/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGenerateBaseOperation.swift

@@ -1,208 +0,0 @@
-//
-//  TSGenerateBaseOperation.swift
-//  AIRingtone
-//
-//  Created by 100Years on 2025/3/24.
-//
-
-import Combine
-import Alamofire
-class TSGenerateBaseOperationQueue: TSBaseOperationQueue {
-    // 存储每个操作的 AnyCancellable
-    var stateables: [String: AnyCancellable] = [:]
-    
-    var generateOperationStateChanged:((String)->Void)?
-    
-    
-    override func cancelOperations(uuid: String) {
-        super.cancelOperations(uuid: uuid)
-        stateables.removeValue(forKey: uuid)
-    }
-
-    func handleStateDatauPblished(uuid:String,generateOperation: TSGenerateBaseOperation,notificationName:Notification.Name) {
-        stateables[uuid] = generateOperation.$stateDatauPblished.sink { [weak self] state in
-            guard let self = self else { return }
-            DispatchQueue.main.async {
-                self.generateOperationStateChanged?(uuid)
-                
-                let uuidData = self.getUUIDData(uuid: uuid)
-                NotificationCenter.default.post(
-                    name: notificationName,
-                    object: nil,
-                    userInfo: [
-                        "uuid": uuid,
-                        "count":self.queue.maxConcurrentOperationCount,
-                        "state":uuidData.0,
-                        "actionInfo":uuidData.1,
-                    ])
-            }
-        }
-    }
-    
-    func getUUIDData(uuid:String)->(TSProgressState,TSActionInfoModel?){
-        return (.none,TSActionInfoModel())
-    }
-    
-}
-
-class TSGenerateBaseOperation: TSBaseOperation , @unchecked Sendable{
-    
-    var actionInfoDict:[String:Any]{
-        return [:]
-    }
-    
-    @Published var stateDatauPblished:(TSProgressState,TSActionInfoModel?) = (TSProgressState.none,nil){
-        didSet{
-            dePrint("TSBaseOperation stateDatauPblished didSet = \(stateDatauPblished)")
-            if case .start = stateDatauPblished.0 {
-                start()
-            }else if stateDatauPblished.0.isResult {
-                DispatchQueue.main.asyncAfter(deadline: .now()+0.3){//稍微延迟,让通知报成功状态发送出去
-                    self.finished()
-                }
-            }
-        }
-    }
-    
-    var queryRequest:Request?
-    var stopNetwork = false
-    var generatingProgress = 0
-    var action_id:Int = 0
-    var isSaveDB:Bool = false //是否保存到数据库
-    var currentActionInfoModelChanged:((TSActionInfoModel)->Void)?
-    @Published var currentActionInfoModel: TSActionInfoModel = TSActionInfoModel()
-    
-    func initializeActionInfoModel(oldModel:TSActionInfoModel) {
-        currentActionInfoModel = oldModel
-        replaceSaveInfoModel(model: currentActionInfoModel)
-        stateDatauPblished = (.start,currentActionInfoModel)
-    }
-    
-    func replaceSaveInfoModel(model:TSActionInfoModel){ }
-    
-    func handleGenerateSuccess(){
-        
-    }
-
-    func handleFailInfoModel(errorString:String?,code:Int = 0){
-        self.currentActionInfoModel.actionStatus = .failed
-        self.currentActionInfoModel.status = "failed"
-        generatingProgress = 0
-        self.replaceSaveInfoModel(model: self.currentActionInfoModel)
-        self.stateDatauPblished = (TSProgressState.getFailed(errorString ?? "",code),self.currentActionInfoModel)
-    }
-    
-    func getActionInfo(oldModel:TSActionInfoModel) {
-        currentActionInfoModel = oldModel
-        self.getActionInfo(action_id:oldModel.id)
-    }
-
-    func getActionInfo(action_id:Int){
-        self.action_id = action_id
-        queryRequest = TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { [weak self] data,error in
-            guard let self = self else { return }
-            
-            if stopNetwork == true {
-                return
-            }
-            
-            if let error = error {
-                debugPrint("getActionInfo error error = \(error)")
-                handleFailInfoModel(errorString: error.tsDesc,code: error.tsCode)
-                return
-            }
-            
-            if let result = kNetWorkResultSuccess(data: data) {
-                if let genmojiModel = TSActionInfoModel(JSON: result) {
-                    
-                    if genmojiModel.actionStatus != .success {
-                        self.replaceSaveInfoModel(model: genmojiModel)
-                    }
-                    
-                    switch genmojiModel.actionStatus {
-                    case .success:
-                        
-                        let successBlock = { [weak self]  in
-                            guard let self = self else { return }
-                            self.replaceSaveInfoModel(model: genmojiModel)
-                            self.stateDatauPblished = (.success(nil),genmojiModel)
-                            generatingProgress = 0
-                            self.handleGenerateSuccess()
-                        }
-                        
-                        if URL(string:genmojiModel.response.resultUrl) != nil {
-                            TSImageStoreTool.downloadImageWithProgress(urlString: genmojiModel.response.resultUrl) { [weak self]  progress in
-                                guard let self = self else { return }
-                                let progressInt = Int(progress*10.0)
-                                let progressString = "Generating".localized + " \(90 + progressInt)%"
-                                stateDatauPblished = (.progressString(progressString),currentActionInfoModel)
-                                dePrint("生成后图片下载进度 \(progress)")
-                            } completion: { image in
-                                successBlock()
-                            }
-
-                        }else{
-                            successBlock()
-                        }
-                    case .failed:
-                        debugPrint("getActionInfo error failed")
-                        handleFailInfoModel(errorString:genmojiModel.response.codeErrorMsg,code: genmojiModel.response.code)
-                    default:
-                        stateDatauPblished = (.progressString(generating(progress: genmojiModel.percent)),currentActionInfoModel)
-                        if stopNetwork == false {
-                            kDelayOnMainThread(2.0) {
-                                self.getActionInfo(action_id: action_id)
-                            }
-                        }
-                    }
-                    
-                    return
-                }
-            }
-            debugPrint("getActionInfo error nil")
-            handleFailInfoModel(errorString: nil)
-            
-        }
-    }
-     func generating(progress:Float) -> String {
-
-         //Generating 0%-100%
-         var progressInt = Int(progress*100)
-
-         if generatingProgress >= progressInt{
-             return getGeneratingProgressText()
-         }
-
-         if progressInt > 99 {
-             progressInt = 99
-         }
-         
-         generatingProgress = progressInt
-         return getGeneratingProgressText()
-     }
-     
-     
-    func getGeneratingProgressText()->String{
-        return "Working on your ringtone \(generatingProgress)%..."
-    }
-     
-
-    override func cancelCleanContent() {
-        debugPrint("cancelCleanContent")
-        stopNetwork = true
-        queryRequest?.cancel()
-    }
-}
- var kRandomBoolLastResult:Bool = true
-func kRandomBool() -> Bool {
-    if !kRandomBoolLastResult {
-        // 如果上一次是 false,这次必须返回 true
-        kRandomBoolLastResult = true
-        return true
-    } else {
-        // 如果上一次是 true,随机返回 true 或 false
-        let randomResult = Bool.random()
-        kRandomBoolLastResult = randomResult
-        return randomResult
-    }
-}

+ 9 - 12
AIEmoji/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGeneratePosterOperation.swift

@@ -29,10 +29,7 @@ class TSGeneratePTPOperationQueue: TSGenerateBaseOperationQueue {
 }
 
 class TSGeneratePTPOperation: TSGenerateBaseOperation , @unchecked Sendable{
-    
-    //是否展示成功后的 View 提醒
-    public var isShowSuccessView:Bool = false
-    
+
     override var actionInfoDict:[String:Any]{
         return [
             "actionType":"image_create",
@@ -50,8 +47,8 @@ class TSGeneratePTPOperation: TSGenerateBaseOperation , @unchecked Sendable{
     override func replaceSaveInfoModel(model:TSActionInfoModel){
         model.uuid = uuid
         model.request.imageUrlTimestamp = currentActionInfoModel.request.imageUrlTimestamp
-        if isSaveDB {
-            TSRMShared.ptpDBHistory.updateData(model,id: currentActionInfoModel.id)
+        if isSaveProcessToDB {
+            TSRMShared.ptpDBHistory.updateData(model,uuid: uuid)
         }
         currentActionInfoModel = model
         dePrint("model actionStatus 发出=\(model.actionStatus)")
@@ -60,7 +57,7 @@ class TSGeneratePTPOperation: TSGenerateBaseOperation , @unchecked Sendable{
 
     override func handleGenerateSuccess() {
         kPurchaseDefault.useOnceForFree(type: .picToPic)
-        TSRMShared.ptpDBHistory.updateData(currentActionInfoModel,id: currentActionInfoModel.id)
+        TSRMShared.ptpDBHistory.updateData(currentActionInfoModel,uuid: currentActionInfoModel.uuid)
         if isShowSuccessView == false {
             return
         }
@@ -115,7 +112,7 @@ class TSGeneratePTPOperation: TSGenerateBaseOperation , @unchecked Sendable{
         infoModel.request.imageUrlTimestamp = Date.timestampInt
         
         infoModel.request.prompt = generateStyleModel.prompt
-        infoModel.request.promptSort = generateStyleModel.inputText
+        infoModel.request.inputText = generateStyleModel.inputText
         infoModel.request.style = generateStyleModel.style
         infoModel.request.advance = generateStyleModel.advance
         infoModel.request.model = generateStyleModel.model
@@ -182,13 +179,13 @@ class TSGeneratePTPOperation: TSGenerateBaseOperation , @unchecked Sendable{
         
         let request = currentActionInfoModel.request
         var prompt = request.prompt
-        let promptSort = request.promptSort
+        let inputText = request.inputText
         
-        if promptSort.count>0{
+        if inputText.count>0{
             if prompt.count > 0 {
-                prompt = prompt + ", " + promptSort
+                prompt = prompt + ", " + inputText
             }else {
-                prompt = promptSort
+                prompt = inputText
             }
         }
         

+ 283 - 0
AIEmoji/Common/Tool/OperationQueue/V2/TSGenerateBaseOperation.swift

@@ -0,0 +1,283 @@
+//
+//  TSGenerateBaseOperation.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/24.
+//
+
+import Combine
+import Alamofire
+
+
+class TSGenerateBaseOperationQueue: TSBaseOperationQueue {
+    // 存储每个操作的 AnyCancellable
+    var stateables: [String: AnyCancellable] = [:]
+    
+    var generateOperationStateChanged:((String)->Void)?
+    override func clearOperationsData(uuid: String) {
+        super.clearOperationsData(uuid: uuid)
+        stateables.removeValue(forKey: uuid)
+    }
+    
+//    override func cancelOperations(uuid: String) {
+//        super.cancelOperations(uuid: uuid)
+//        stateables.removeValue(forKey: uuid)
+//    }
+
+    func handleStateDatauPblished(uuid:String,generateOperation: TSGenerateBaseOperation,notificationName:Notification.Name) {
+        stateables[uuid] = generateOperation.$stateDatauPblished.sink { [weak self] state in
+            guard let self = self else { return }
+            DispatchQueue.main.async {
+                self.generateOperationStateChanged?(uuid)
+                
+                let uuidData = self.getUUIDData(uuid: uuid)
+                NotificationCenter.default.post(
+                    name: notificationName,
+                    object: nil,
+                    userInfo: [
+                        "uuid": uuid,
+                        "count":self.queue.maxConcurrentOperationCount,
+                        "state":uuidData.0,
+                        "actionInfo":uuidData.1,
+                    ])
+            }
+        }
+    }
+    
+    func getUUIDData(uuid:String)->(TSProgressState,TSActionInfoModel?){
+        return (.none,TSActionInfoModel())
+    }
+    
+}
+
+class TSGenerateBaseOperation: TSBaseOperation , @unchecked Sendable{
+    var actionInfoDict:[String:Any]{
+        return [:]
+    }
+    
+    @Published var stateDatauPblished:(TSProgressState,TSActionInfoModel?) = (TSProgressState.none,nil){
+        didSet{
+            dePrint("TSBaseOperation stateDatauPblished didSet = \(stateDatauPblished)")
+            if case .start = stateDatauPblished.0 {
+                start()
+            }else if stateDatauPblished.0.isResult {
+                DispatchQueue.main.asyncAfter(deadline: .now()+0.3){//稍微延迟,让通知报成功状态发送出去
+                    self.finished()
+                }
+            }
+        }
+    }
+    
+    var queryRequest:Request?
+    var stopNetwork = false
+    var generatingProgress = 0
+    var action_id:Int = 0
+    var retryDownloadCount = 0
+    public var isShowSuccessView:Bool = false //是否展示成功后的 View 提醒
+    var isSaveProcessToDB:Bool = false //是否保存过程到数据库
+    {
+        didSet{
+            if isSaveProcessToDB == true {
+                saveDataDB()
+            }
+        }
+    }
+    
+    var currentActionInfoModelChanged:((TSActionInfoModel)->Void)?
+    @Published var currentActionInfoModel: TSActionInfoModel = TSActionInfoModel()
+    
+    func initializeActionInfoModel(oldModel:TSActionInfoModel) {
+        currentActionInfoModel = oldModel
+        replaceSaveInfoModel(model: currentActionInfoModel)
+        stateDatauPblished = (.start,currentActionInfoModel)
+    }
+    
+    func replaceSaveInfoModel(model:TSActionInfoModel){ }
+    
+    func handleGenerateSuccess(){}
+    func saveDataDB(){}
+    
+    func backstageGeneration(){
+        isSaveProcessToDB = true
+        isShowSuccessView = true
+    }
+    
+    func handleFailInfoModel(errorString:String?,code:Int = 0){
+        self.currentActionInfoModel.actionStatus = .failed
+        self.currentActionInfoModel.status = "failed"
+        generatingProgress = 0
+        self.replaceSaveInfoModel(model: self.currentActionInfoModel)
+        self.stateDatauPblished = (TSProgressState.getFailed(errorString ?? "",code),self.currentActionInfoModel)
+    }
+    
+    func getActionInfo(oldModel:TSActionInfoModel) {
+        currentActionInfoModel = oldModel
+        self.getActionInfo(action_id:oldModel.id)
+    }
+    
+    func getActionInfo(action_id:Int){
+        self.action_id = action_id
+        queryRequest = TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { [weak self] data,error in
+            guard let self = self else { return }
+            
+            if stopNetwork == true {
+                return
+            }
+            
+            if let error = error {
+                debugPrint("getActionInfo error error = \(error)")
+                handleFailInfoModel(errorString: error.tsDesc,code: error.tsCode)
+                return
+            }
+            
+            if let result = kNetWorkResultSuccess(data: data) {
+                if let infoModel = TSActionInfoModel(JSON: result) {
+                    
+                    if infoModel.actionStatus != .success {
+                        self.replaceSaveInfoModel(model: infoModel)
+                    }
+                    
+                    switch infoModel.actionStatus {
+                    case .success:
+                        if URL(string:infoModel.response.resultUrl) != nil {
+                            downResultUrl(infoModel: infoModel)
+                        }else{
+                            handleSuccess(infoModel: infoModel)
+                        }
+                    case .failed:
+                        debugPrint("getActionInfo error failed")
+                        handleFailInfoModel(errorString:infoModel.response.codeErrorMsg,code: infoModel.response.code)
+                    default:
+                        stateDatauPblished = (.progressString(generating(progress: infoModel.percent)),currentActionInfoModel)
+                        if stopNetwork == false {
+                            kDelayOnMainThread(2.0) {
+                                self.getActionInfo(action_id: action_id)
+                            }
+                        }
+                    }
+                    
+                    return
+                }
+            }
+            debugPrint("getActionInfo error nil")
+            handleFailInfoModel(errorString: nil)
+            
+        }
+    }
+    
+    
+    func handleSuccess(infoModel:TSActionInfoModel){
+        self.replaceSaveInfoModel(model: infoModel)
+        self.stateDatauPblished = (.success(nil),infoModel)
+        generatingProgress = 0
+        self.handleGenerateSuccess()
+    }
+    
+    func downResultUrl(infoModel:TSActionInfoModel){
+        
+        if retryDownloadCount > 3 {
+            debugPrint("生成后下载视频失败,重新尝试超过 3 次,直接失败")
+            handleFailInfoModel(errorString: nil)
+            return
+        }
+        
+        if currentActionInfoModel.request.generatorStyle.isVideo{
+            let group = DispatchGroup()
+            //下载视频源
+            group.enter()
+            downloadVideo(urlString: infoModel.response.resultUrl) { url in
+                if let url = url {
+                    infoModel.response.videoDocument = url.path.documentLastURLString
+                }
+                group.leave()
+            }
+            //下载封面图
+            group.enter()
+            TSImageStoreTool.downloadImageWithProgress(urlString: infoModel.response.previewUrl) { _ in
+                group.leave()
+            }
+            
+            group.notify(queue: .main){[weak self]  in
+                guard let self = self else { return }
+                if infoModel.response.videoDocument.isEmpty {
+                    debugPrint("生成后下载视频失败,重新尝试retryDownloadCount=\(retryDownloadCount)")
+                    downResultUrl(infoModel: infoModel)
+                }else{
+                    handleSuccess(infoModel: infoModel)
+                }
+            }
+            
+        }else{
+            downloadImage(urlString: infoModel.response.resultUrl) { [weak self] image in
+                guard let self = self else { return }
+                if image == nil {
+                    debugPrint("生成后下载视频失败,重新尝试retryDownloadCount=\(retryDownloadCount)")
+                    downResultUrl(infoModel: infoModel)
+                }else{
+                    handleSuccess(infoModel: infoModel)
+                }
+                
+            }
+        }
+        
+        retryDownloadCount += 1
+    }
+    
+    let generatingText:String = "Processing".localized
+    func downloadVideo(urlString:String,completion:@escaping (URL?)->Void){
+        TSDownloadManager.getDownLoadVideo(urlString: urlString) { progress in
+            let progressInt = Int(progress*10.0)
+            let progressString = "Processing".localized + " " + kPercentlocalized(90 + progressInt)
+            self.stateDatauPblished = (.progressString(progressString),nil)
+            dePrint("生成后视频下载进度: \(progress)")
+        } complete: { url, _ in
+            completion(url)
+        }
+    }
+    
+    func downloadImage(urlString:String,completion:@escaping (UIImage?)->Void){
+        TSImageStoreTool.downloadImageWithProgress(urlString: urlString) { [weak self]  progress in
+            guard let self = self else { return }
+            
+            let progressInt = Int(progress*10.0)
+            let progressString = "Processing".localized + " " + kPercentlocalized(90 + progressInt)
+            stateDatauPblished = (.progressString(progressString),currentActionInfoModel)
+            dePrint("生成后图片下载进度: \(progress)")
+        } completion: { image in
+            completion(image)
+        }
+    }
+    
+    func generating(progress:Float) -> String {
+        
+        //Generating 0%-100%
+        var progressInt = Int(progress*100)
+        
+        if generatingProgress >= progressInt{
+            return getGeneratingProgressText()
+        }
+        
+        if progressInt > 99 {
+            progressInt = 99
+        }
+        
+        generatingProgress = progressInt
+        return getGeneratingProgressText()
+    }
+    
+    func getGeneratingProgressText()->String{
+        return "Processing \(generatingProgress)%..."
+    }
+    
+    
+    override func cancelCleanContent() {
+        debugPrint("cancelCleanContent")
+        stopNetwork = true
+        queryRequest?.cancel()
+    }
+}
+
+
+func kPercentlocalized(_ num:Int)-> String{
+    return String(format: "%d%".localized, num)
+}

+ 273 - 0
AIEmoji/Common/Tool/OperationQueue/V2/TSGenerateBasePhotoOperation.swift

@@ -0,0 +1,273 @@
+//
+//  TSGenerateBasePhotoOperation.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/24.
+//
+
+import Combine
+import Alamofire
+import ObjectMapper
+import Kingfisher
+class TSGenerateBasePhotoOperationQueue: TSGenerateBaseOperationQueue {
+    static let shared:TSGenerateBasePhotoOperationQueue = TSGenerateBasePhotoOperationQueue()
+
+    func creatOperation(uuid: String) -> TSGenerateBasePhotoOperation {
+        let operation = super.creatOperation(uuid: uuid, type: TSGenerateBasePhotoOperation.self)
+        handleStateDatauPblished(uuid: uuid, generateOperation: operation as! TSGenerateBaseOperation, notificationName: .kGenerateBasePhotoOperation)
+        return operation as! TSGenerateBasePhotoOperation
+    }
+    
+    override func getUUIDData(uuid:String)->(TSProgressState,TSActionInfoModel?){
+        if let PosterOperation = TSGenerateBasePhotoOperationQueue.shared.findOperation(uuid: uuid) as? TSGenerateBasePhotoOperation {
+            dePrint("TSBaseOperation stateDatauPblished 发送 = \(PosterOperation.stateDatauPblished)")
+            return (PosterOperation.stateDatauPblished.0,PosterOperation.currentActionInfoModel)
+        }
+        return (.none,TSActionInfoModel())
+    }
+    
+}
+
+class TSGenerateBasePhotoOperation: TSGenerateBaseOperation , @unchecked Sendable{
+
+    override var actionInfoDict:[String:Any]{
+        return [
+            "actionType":"image_create",
+            "comments": "Success",
+            "costTime":9,
+            "createdTimestamp":1742183242,
+            "id":2449,
+            "percent":1,
+            "request":"{\"prompt\": \"Traditional Chinese ink painting style phoenix soaring through misty mountain peaks, dynamic black brushstrokes with crimson accents on rice paper texture, Googie architecture space station, 1950s atomic age aesthetic, curved aluminum panels, starburst patterns, glass dome observatory --edge_threshold 0.5 --atomic_age_style 0.8 --chrome_reflection 1.2\", \"width\": 800, \"height\": 1440, \"countryCode\": \"FR\"}",
+            "response": "{\"resultUrl\": \"https://be-aigc.s3-accelerate.amazonaws.com/4c946f78-b1e7-4ffe-ba18-fff26b10178c.png\"}",
+            "status":"success"
+        ]
+    }
+
+    override func replaceSaveInfoModel(model:TSActionInfoModel){
+        model.uuid = uuid
+        model.request.imageUrlTimestamp = currentActionInfoModel.request.imageUrlTimestamp
+        model.request.generatorStyle = currentActionInfoModel.request.generatorStyle
+        if isSaveProcessToDB {
+            saveDataDB()
+        }
+        currentActionInfoModel = model
+        dePrint("model actionStatus 发出=\(model.actionStatus)")
+        currentActionInfoModelChanged?(currentActionInfoModel)
+    }
+
+    override func saveDataDB() {
+        if currentActionInfoModel.id == 0 {
+            return
+        }
+        TSRMShared.aiGenerateDB.updateData(currentActionInfoModel,uuid: uuid)
+    }
+    override func handleGenerateSuccess() {
+//        kPurchaseBusiness.useOnceForFree(type: .general)
+        saveDataDB()
+
+        //生成成功后,不再提示用户上传规则弹窗
+        UserDefaults.standard.set("1", forKey: currentActionInfoModel.request.generatorStyle.userDefaultsKey)
+        UserDefaults.standard.synchronize()
+        
+        if isShowSuccessView  {
+            guard let window = WindowHelper.getKeyWindow() else {
+                debugPrint("getKeyWindow nil")
+                return
+            }
+            
+            guard let rootVC = WindowHelper.topViewController() else {
+                debugPrint("handleGenerateSuccess topViewController nil")
+                return
+            }
+            
+            let copyModel = self.currentActionInfoModel.copy()
+            if let cyModel = copyModel as? TSActionInfoModel {
+                let topY = k_Nav_Height+10
+                debugPrint("topY=\(topY)")
+                kSaveSuccesswShared.show(atView: window,text: "Process successfully".localized,deadline: 5.0) {
+//                    let gennerateVC = TSAIListPhotoGeneratorVC(generatorModel: TSAIGeneratorModel(upLoadImage: UIImage(), generatorStyle: cyModel.request.generatorStyle),infoModel: cyModel) { model in }
+//                    gennerateVC.modalPresentationStyle = .overFullScreen
+//                    gennerateVC.modalTransitionStyle = .crossDissolve
+//                    rootVC.present(gennerateVC, animated: true)
+                }
+            }else{
+                debugPrint("copyModel as? TSActionInfoModel error")
+            }
+        }
+
+    }
+    
+
+    /**
+        1.用户上传图片
+        2.调用生成接口
+        3.后台返回查询 id,根据 id 不断查询进度和结果.(此时才允许进度后台)
+     
+        利用3后台返回的TSActionRequestModel中存着关键的请求接口数据,请求数据
+     
+     */
+    
+    private var uploadRequest:Request?
+    private var creatRequest:Request?
+    
+    func createActionInfoModel(generateStyleModel:TSAIGeneratorModel) -> TSActionInfoModel? {
+        guard let upLoadImageUrl = generateStyleModel.upLoadImageUrl else { return nil }
+
+        let infoModel = TSActionInfoModel()
+        infoModel.id = Date.timestampInt
+        infoModel.request = TSActionRequestModel()
+        infoModel.request.imageUrl = upLoadImageUrl
+        infoModel.request.imageUrlTimestamp = Date.timestampInt
+        
+        infoModel.request.prompt = generateStyleModel.prompt
+        infoModel.request.inputText = generateStyleModel.inputText
+        infoModel.request.generatorStyle = generateStyleModel.generatorStyle
+        
+        return infoModel
+    }
+    
+    func uploadImage(generateStyleModel:TSAIGeneratorModel,complete:@escaping (TSActionInfoModel?)->Void) {
+        let upLoadImage = generateStyleModel.upLoadImage
+        if let imageUrl = generateStyleModel.upLoadImageUrl,imageUrl.contains("http") {
+            complete(createActionInfoModel(generateStyleModel: generateStyleModel))
+            return
+        }
+        
+        stopNetwork = false
+        stateDatauPblished = (.start,nil)
+        
+        stateDatauPblished = (.progressString(uploadingPhoto(progress: 0.0)),currentActionInfoModel)
+        uploadRequest = TSNetworkShared.uploadImage(upLoadImage: upLoadImage, maxKb: imageMaxKb) { [weak self]  progress in
+            guard let self = self else { return }
+            if generatingProgress == 0 {
+                stateDatauPblished = (.progressString(uploadingPhoto(progress: progress)),currentActionInfoModel)
+            }
+        } completion: { [weak self]  data, error in
+            guard let self = self else { return }
+            if stopNetwork == true { return }
+            if let error = error {
+                generateStyleModel.upLoadImageUrl = nil
+                self.stateDatauPblished = (TSProgressState.getFailed(error.tsDesc,error.tsCode),nil)
+                complete(nil)
+            }else{
+                if let string = data as? String {
+                    generateStyleModel.upLoadImageUrl = string
+                    TSImageStoreTool.storeImage(image: upLoadImage, urlString: string)
+
+                    complete(createActionInfoModel(generateStyleModel: generateStyleModel))
+                }else{
+                    complete(nil)
+                }
+            }
+        }
+    }
+    
+    func creatImage(oldModel:TSActionInfoModel,complete:@escaping (Bool)->Void) {
+        
+        initializeActionInfoModel(oldModel: oldModel)
+        if oldModel.upImageURLExpired { return  }
+
+        generatingProgress = 0
+        stopNetwork = false
+        stateDatauPblished = (.start,nil)
+
+        currentActionInfoModel.status = "running"
+        currentActionInfoModel.actionStatus = .running
+        currentActionInfoModel.percent = 0
+        replaceSaveInfoModel(model: currentActionInfoModel)
+        
+        stateDatauPblished = (.progressString(generating(progress: 0.0)),currentActionInfoModel)
+ 
+        
+        let request = currentActionInfoModel.request
+        
+        
+        var urlType:TSNeURLType = .imageRewrite
+        var postDict:[String:Any] = [
+            "device":getUserInfoJsonString(),
+            "imageUrl":request.imageUrl,
+            "model":request.model
+        ]
+//        switch request.generatorStyle {
+//        case .enhance:
+//            urlType = .imageRewrite
+//            postDict["prompt"] = "把图片变清晰"
+//        case .colorize:
+//            urlType = .imageRewrite
+//            postDict["prompt"] = "Add suitable colors to photos"
+//        case .descratch:
+//            urlType = .imageRewrite
+//            postDict["prompt"] = "Remove the photo's scratches and dirt"
+//        case .enlighten:
+//            urlType = .imageRewrite
+//            postDict["prompt"] = "Adjust the light and darkness of the photo to make the overall look coordinated"
+//            
+//        case .recreate:
+//            urlType = .imageRewrite
+//            postDict["prompt"] = "Recreate damaged portraits and added suitable color for photo"
+//            
+//        case .creatVideo:
+//            urlType = .createVideo
+//            postDict["prompt"] = request.prompt
+////            postDict["aspectRatio"] = "9:16"
+//            postDict["duration"] = 5
+//            postDict["quality"] = "720p"
+//        }
+
+        creatRequest = TSNetworkShared.post(urlType: urlType,parameters: postDict) { [weak self] data,error in
+            guard let self = self else { return }
+            if stopNetwork == true { return }
+            
+            if let error = error {
+                handleFailInfoModel(errorString: error.tsDesc,code: error.tsCode)
+                complete(false)
+            }else{
+                if let dataDict = kNetWorkCodeSuccess(data: data),
+                   let actionId = dataDict["actionId"] as? Int{
+                    if stopNetwork == false {
+                        complete(true)
+                        self.stateDatauPblished = (.pending,nil) //通知首页进行更新
+                        self.getActionInfo(action_id:actionId)
+                    }
+                }else{
+                    handleFailInfoModel(errorString: "",code: 0)
+                    complete(false)
+                }
+            }
+        }
+    }
+    override func generating(progress: Float) -> String {
+        let progress = Float(progress)*(0.9) // 预留 10% 进度给图片下载
+        //Generating 0%-100%
+        var progressInt = Int(progress*100)
+
+        if progressInt > 99 {
+            progressInt = 99
+        }
+        
+        generatingProgress = progressInt
+        return "Processing".localized + " " + kPercentlocalized(progressInt)
+    }
+
+    var imageMaxKb:Int{
+        return 10*1024
+    }
+    
+    func uploadingPhoto(progress:Float) -> String {
+        //Uploading Photo 0%-100%
+        var progressInt = Int(progress*100)
+        if progressInt > 99 {
+            progressInt = 99
+        }
+        return "Uploading Photo".localized + " " + kPercentlocalized(progressInt)
+    }
+    
+    
+    override func cancelCleanContent() {
+        super.cancelCleanContent()
+        debugPrint("cancelCleanContent")
+        uploadRequest?.cancel()
+        creatRequest?.cancel()
+    }
+}

+ 0 - 28
AIEmoji/Common/Tool/TSCommonTool/TSCommonTool.swift

@@ -193,34 +193,6 @@ class TSCommonTool {
 }
 
 let kMainQueue = DispatchQueue.main
-/// 主线程延迟执行回调
-/// - Parameters:
-///   - delay: 延迟时间(秒)
-///   - completion: 延迟后的回调
-func kDelayOnMainThread(_ delay: TimeInterval, completion: @escaping () -> Void) {
-    DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
-        completion()
-    }
-}
-
-func kDelayMainShort(completion: @escaping () -> Void) {
-    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
-        completion()
-    }
-}
-
-/// 在主线程上执行代码
-/// - Parameter block: 要执行的代码块
-func kExecuteOnMainThread(_ block: @escaping () -> Void) {
-    if Thread.isMainThread {
-        block()
-    } else {
-        DispatchQueue.main.async {
-            block()
-        }
-    }
-}
-
 let appid = "6740220736"
 let kAppName:String = "Picguru" //Picguru Chibii Chibi Ghiblii AI Image Picguru
 let kUploadImageMaxBit10Size:Int = 10 * 1024 * 1024 //10M