Explorar el Código

3.1年龄变化需求开发了 40%

100Years hace 1 semana
padre
commit
c3d6a709a3
Se han modificado 27 ficheros con 1310 adiciones y 97 borrados
  1. 76 0
      AIEmoji.xcodeproj/project.pbxproj
  2. 6 0
      AIEmoji/Assets.xcassets/AIList/Contents.json
  3. 22 0
      AIEmoji/Assets.xcassets/AIList/aiList_oldPeople.imageset/Contents.json
  4. BIN
      AIEmoji/Assets.xcassets/AIList/aiList_oldPeople.imageset/aiList_oldPeople@2x.png
  5. BIN
      AIEmoji/Assets.xcassets/AIList/aiList_oldPeople.imageset/aiList_oldPeople@3x.png
  6. 22 0
      AIEmoji/Assets.xcassets/AIList/ailist_child.imageset/Contents.json
  7. BIN
      AIEmoji/Assets.xcassets/AIList/ailist_child.imageset/ailist_child@2x.png
  8. BIN
      AIEmoji/Assets.xcassets/AIList/ailist_child.imageset/ailist_child@3x.png
  9. 22 0
      AIEmoji/Assets.xcassets/AIList/alList_shadow.imageset/Contents.json
  10. BIN
      AIEmoji/Assets.xcassets/AIList/alList_shadow.imageset/alList_shadow@2x.png
  11. BIN
      AIEmoji/Assets.xcassets/AIList/alList_shadow.imageset/alList_shadow@3x.png
  12. 22 0
      AIEmoji/Assets.xcassets/Tabbar/tabbar_select_ailist.imageset/Contents.json
  13. BIN
      AIEmoji/Assets.xcassets/Tabbar/tabbar_select_ailist.imageset/tabbar_select_ailist@2x.png
  14. BIN
      AIEmoji/Assets.xcassets/Tabbar/tabbar_select_ailist.imageset/tabbar_select_ailist@3x.png
  15. 22 0
      AIEmoji/Assets.xcassets/Tabbar/tabbar_unSelect_ailist.imageset/Contents.json
  16. BIN
      AIEmoji/Assets.xcassets/Tabbar/tabbar_unSelect_ailist.imageset/tabbar_unSelect_ailist@2x.png
  17. BIN
      AIEmoji/Assets.xcassets/Tabbar/tabbar_unSelect_ailist.imageset/tabbar_unSelect_ailist@3x.png
  18. 15 0
      AIEmoji/Business/TSAILIstVC/TSAIAgeImageHintVC/TSAIAgeImageHintVC.swift
  19. 164 0
      AIEmoji/Business/TSAILIstVC/TSAIAgeImageHintVC/TSAIListHintBaseVC.swift
  20. 91 0
      AIEmoji/Business/TSAILIstVC/TSAILIstVC/TSAILIstCell.swift
  21. 184 0
      AIEmoji/Business/TSAILIstVC/TSAILIstVC/TSAILIstVC.swift
  22. 214 0
      AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIListPhotoGeneratorBaseVC.swift
  23. 233 0
      AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIPhotoGeneratorBaseVM/TSAIListPhotoGeneratorBaseVM.swift
  24. 203 0
      AIEmoji/Business/TSAILIstVC/TSAIUploadPhotoBaseVC/TSAIUploadPhotoBaseVC.swift
  25. 9 8
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPImageHintVC/TSPTPImageHintVC.swift
  26. 0 85
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/View/TSPTPSelectStyleView.swift
  27. 5 4
      AIEmoji/Business/TSTabBarController/TSTabBarController.swift

+ 76 - 0
AIEmoji.xcodeproj/project.pbxproj

@@ -156,6 +156,13 @@
 		A8BA764F2DA50B52000B6707 /* CpuMapManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA764E2DA50B52000B6707 /* CpuMapManager.swift */; };
 		A8BA76522DA51600000B6707 /* TSPTPImageHintVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76512DA515FF000B6707 /* TSPTPImageHintVC.swift */; };
 		A8BA76542DA54571000B6707 /* CollectionViewObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76532DA5456E000B6707 /* CollectionViewObserver.swift */; };
+		A8BA76612DA647AC000B6707 /* TSAILIstVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76602DA647AB000B6707 /* TSAILIstVC.swift */; };
+		A8BA76632DA64A84000B6707 /* TSAILIstCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76622DA64A7D000B6707 /* TSAILIstCell.swift */; };
+		A8BA76652DA65583000B6707 /* TSAIAgeImageHintVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76642DA65576000B6707 /* TSAIAgeImageHintVC.swift */; };
+		A8BA76682DA6567E000B6707 /* TSAIListHintBaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76672DA6566E000B6707 /* TSAIListHintBaseVC.swift */; };
+		A8BA766C2DA657E8000B6707 /* TSAIListPhotoGeneratorBaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA766B2DA657E6000B6707 /* TSAIListPhotoGeneratorBaseVC.swift */; };
+		A8BA766F2DA65824000B6707 /* TSAIListPhotoGeneratorBaseVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA766E2DA65823000B6707 /* TSAIListPhotoGeneratorBaseVM.swift */; };
+		A8BA76722DA65A95000B6707 /* TSAIUploadPhotoBaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76712DA65A94000B6707 /* TSAIUploadPhotoBaseVC.swift */; };
 		A8EEADD42D3E6C660032C5A0 /* Flower💐.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD32D3E6C610032C5A0 /* Flower💐.json */; };
 		A8EEADD62D3E6CD80032C5A0 /* Fish🐠.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */; };
 		A8EEADD82D3E74D20032C5A0 /* Pink🩷.json in Resources */ = {isa = PBXBuildFile; fileRef = A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */; };
@@ -388,6 +395,13 @@
 		A8BA764E2DA50B52000B6707 /* CpuMapManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CpuMapManager.swift; sourceTree = "<group>"; };
 		A8BA76512DA515FF000B6707 /* TSPTPImageHintVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPImageHintVC.swift; sourceTree = "<group>"; };
 		A8BA76532DA5456E000B6707 /* CollectionViewObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewObserver.swift; sourceTree = "<group>"; };
+		A8BA76602DA647AB000B6707 /* TSAILIstVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAILIstVC.swift; sourceTree = "<group>"; };
+		A8BA76622DA64A7D000B6707 /* TSAILIstCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAILIstCell.swift; sourceTree = "<group>"; };
+		A8BA76642DA65576000B6707 /* TSAIAgeImageHintVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIAgeImageHintVC.swift; sourceTree = "<group>"; };
+		A8BA76672DA6566E000B6707 /* TSAIListHintBaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListHintBaseVC.swift; sourceTree = "<group>"; };
+		A8BA766B2DA657E6000B6707 /* TSAIListPhotoGeneratorBaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListPhotoGeneratorBaseVC.swift; sourceTree = "<group>"; };
+		A8BA766E2DA65823000B6707 /* TSAIListPhotoGeneratorBaseVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIListPhotoGeneratorBaseVM.swift; sourceTree = "<group>"; };
+		A8BA76712DA65A94000B6707 /* TSAIUploadPhotoBaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIUploadPhotoBaseVC.swift; sourceTree = "<group>"; };
 		A8EEADD32D3E6C610032C5A0 /* Flower💐.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Flower💐.json"; sourceTree = "<group>"; };
 		A8EEADD52D3E6CD30032C5A0 /* Fish🐠.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Fish🐠.json"; sourceTree = "<group>"; };
 		A8EEADD72D3E74CB0032C5A0 /* Pink🩷.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "Pink🩷.json"; sourceTree = "<group>"; };
@@ -1289,6 +1303,60 @@
 			path = TSPTPImageHintVC;
 			sourceTree = "<group>";
 		};
+		A8BA765F2DA6479A000B6707 /* TSAILIstVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA76702DA65A81000B6707 /* TSAIUploadPhotoBaseVC */,
+				A8BA766A2DA6579A000B6707 /* TSAIPhotoGeneratorBaseVC */,
+				A8BA76692DA6578C000B6707 /* TSAILIstVC */,
+				A8BA76662DA6558B000B6707 /* TSAIAgeImageHintVC */,
+			);
+			path = TSAILIstVC;
+			sourceTree = "<group>";
+		};
+		A8BA76662DA6558B000B6707 /* TSAIAgeImageHintVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA76672DA6566E000B6707 /* TSAIListHintBaseVC.swift */,
+				A8BA76642DA65576000B6707 /* TSAIAgeImageHintVC.swift */,
+			);
+			path = TSAIAgeImageHintVC;
+			sourceTree = "<group>";
+		};
+		A8BA76692DA6578C000B6707 /* TSAILIstVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA76602DA647AB000B6707 /* TSAILIstVC.swift */,
+				A8BA76622DA64A7D000B6707 /* TSAILIstCell.swift */,
+			);
+			path = TSAILIstVC;
+			sourceTree = "<group>";
+		};
+		A8BA766A2DA6579A000B6707 /* TSAIPhotoGeneratorBaseVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA766D2DA65818000B6707 /* TSAIPhotoGeneratorBaseVM */,
+				A8BA766B2DA657E6000B6707 /* TSAIListPhotoGeneratorBaseVC.swift */,
+			);
+			path = TSAIPhotoGeneratorBaseVC;
+			sourceTree = "<group>";
+		};
+		A8BA766D2DA65818000B6707 /* TSAIPhotoGeneratorBaseVM */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA766E2DA65823000B6707 /* TSAIListPhotoGeneratorBaseVM.swift */,
+			);
+			path = TSAIPhotoGeneratorBaseVM;
+			sourceTree = "<group>";
+		};
+		A8BA76702DA65A81000B6707 /* TSAIUploadPhotoBaseVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA76712DA65A94000B6707 /* TSAIUploadPhotoBaseVC.swift */,
+			);
+			path = TSAIUploadPhotoBaseVC;
+			sourceTree = "<group>";
+		};
 		A8F774602D38E8B000AA6E93 = {
 			isa = PBXGroup;
 			children = (
@@ -1327,6 +1395,7 @@
 		A8F774922D38EA8C00AA6E93 /* Business */ = {
 			isa = PBXGroup;
 			children = (
+				A8BA765F2DA6479A000B6707 /* TSAILIstVC */,
 				A87587112D81702700286A66 /* Data */,
 				A80EDDDC2D6EB17D003CD332 /* TSPTPGeneratorVC */,
 				A85E478D2D670DF10018D62D /* TSTextGeneralPictureVC */,
@@ -1859,6 +1928,7 @@
 				A80E72652D409B0D00C64288 /* DiyStaticElement.swift in Sources */,
 				A80EDE002D6EFD22003CD332 /* TSPhotoPickerManager.swift in Sources */,
 				A89EA6B42D5C9D43000EB181 /* TSAIChatHistoryVM.swift in Sources */,
+				A8BA766F2DA65824000B6707 /* TSAIListPhotoGeneratorBaseVM.swift in Sources */,
 				A80E72532D3F985E00C64288 /* TSWallpaperVC.swift in Sources */,
 				A8FB02B32D3E39A40031A396 /* TSEmojisModel.swift in Sources */,
 				A89EA6542D59A9F4000EB181 /* TSTextLayoutSizeCalculator.swift in Sources */,
@@ -1880,6 +1950,7 @@
 				A8F7753B2D3918DE00AA6E93 /* TSNetworkManager+Loading.swift in Sources */,
 				A80E721A2D3F393A00C64288 /* DiyStickerModel.swift in Sources */,
 				A80EDDEB2D6EC014003CD332 /* TSPhotoToPhotoVC.swift in Sources */,
+				A8BA76652DA65583000B6707 /* TSAIAgeImageHintVC.swift in Sources */,
 				A80E726F2D40DE2B00C64288 /* TSWallpaperPreviewVC.swift in Sources */,
 				A8F775492D3935D600AA6E93 /* TSBusinessWebVC.swift in Sources */,
 				A8F776392D3B38E600AA6E93 /* TSGenmojiGennerateVC.swift in Sources */,
@@ -1897,6 +1968,7 @@
 				A80EDD4A2D6C3F82003CD332 /* MarkdownLevelElement.swift in Sources */,
 				A80EDD4B2D6C3F82003CD332 /* MarkdownParser+AppKit.swift in Sources */,
 				A80EDD4C2D6C3F82003CD332 /* Typealias.swift in Sources */,
+				A8BA76632DA64A84000B6707 /* TSAILIstCell.swift in Sources */,
 				A80EDD4D2D6C3F82003CD332 /* MarkdownStrikethrough.swift in Sources */,
 				A80EDD4E2D6C3F82003CD332 /* MarkdownUnescaping.swift in Sources */,
 				A80EDD4F2D6C3F82003CD332 /* MarkdownParser+UIKit.swift in Sources */,
@@ -1915,6 +1987,7 @@
 				A80EDD5B2D6C3F82003CD332 /* MarkdownCommonElement.swift in Sources */,
 				A80EDD682D6C5098003CD332 /* TSChatMsgBaseView.swift in Sources */,
 				A8BA764F2DA50B52000B6707 /* CpuMapManager.swift in Sources */,
+				A8BA766C2DA657E8000B6707 /* TSAIListPhotoGeneratorBaseVC.swift in Sources */,
 				A80EDD5C2D6C3F82003CD332 /* MarkdownList.swift in Sources */,
 				A80EDD5D2D6C3F82003CD332 /* MarkdownCodeEscaping.swift in Sources */,
 				A80EDD5E2D6C3F82003CD332 /* MarkdownLinkElement.swift in Sources */,
@@ -1924,6 +1997,7 @@
 				A80EDD602D6C3F82003CD332 /* MarkdownElement.swift in Sources */,
 				A80EDD612D6C3F82003CD332 /* MarkdownLink+AppKit.swift in Sources */,
 				A80EDD622D6C3F82003CD332 /* MarkdownLink.swift in Sources */,
+				A8BA76722DA65A95000B6707 /* TSAIUploadPhotoBaseVC.swift in Sources */,
 				A80EDD632D6C3F82003CD332 /* MarkdownAutomaticLink.swift in Sources */,
 				A80EDD642D6C3F82003CD332 /* MarkdownStyle.swift in Sources */,
 				A89EA6CF2D6430F3000EB181 /* TSChatViewController+Keyboard.swift in Sources */,
@@ -1935,6 +2009,7 @@
 				A89EA6C12D5ED289000EB181 /* TSChatCellConfig.swift in Sources */,
 				A8F775502D39ECED00AA6E93 /* PhotoManager.swift in Sources */,
 				A8F7763F2D3B68E100AA6E93 /* TSGenmojiGennerateViewModel.swift in Sources */,
+				A8BA76612DA647AC000B6707 /* TSAILIstVC.swift in Sources */,
 				A80E72352D3F473400C64288 /* DiyPaperTemplateBaseView.swift in Sources */,
 				A80E72362D3F473400C64288 /* DiyPaperTemplate.swift in Sources */,
 				A80327C32D81581D00AF7878 /* TSTTPStyleView.swift in Sources */,
@@ -2014,6 +2089,7 @@
 				A83405202DA3ADA900C140E4 /* TSPhotoSizeHelper.swift in Sources */,
 				A8F775382D390C3C00AA6E93 /* TSNetworkManager.swift in Sources */,
 				A80EDDE72D6EBFC1003CD332 /* TSPTPGeneratorVM.swift in Sources */,
+				A8BA76682DA6567E000B6707 /* TSAIListHintBaseVC.swift in Sources */,
 				A85E47982D672AE70018D62D /* TSTextPicGennerateVM.swift in Sources */,
 				A89EA65F2D59AA11000EB181 /* TSChatViewController.swift in Sources */,
 				A89EA6C62D5F5C22000EB181 /* TSChatInputFullScreenVC.swift in Sources */,

+ 6 - 0
AIEmoji/Assets.xcassets/AIList/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 22 - 0
AIEmoji/Assets.xcassets/AIList/aiList_oldPeople.imageset/Contents.json

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

BIN
AIEmoji/Assets.xcassets/AIList/aiList_oldPeople.imageset/aiList_oldPeople@2x.png


BIN
AIEmoji/Assets.xcassets/AIList/aiList_oldPeople.imageset/aiList_oldPeople@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIList/ailist_child.imageset/Contents.json

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

BIN
AIEmoji/Assets.xcassets/AIList/ailist_child.imageset/ailist_child@2x.png


BIN
AIEmoji/Assets.xcassets/AIList/ailist_child.imageset/ailist_child@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIList/alList_shadow.imageset/Contents.json

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

BIN
AIEmoji/Assets.xcassets/AIList/alList_shadow.imageset/alList_shadow@2x.png


BIN
AIEmoji/Assets.xcassets/AIList/alList_shadow.imageset/alList_shadow@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/Tabbar/tabbar_select_ailist.imageset/Contents.json

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

BIN
AIEmoji/Assets.xcassets/Tabbar/tabbar_select_ailist.imageset/tabbar_select_ailist@2x.png


BIN
AIEmoji/Assets.xcassets/Tabbar/tabbar_select_ailist.imageset/tabbar_select_ailist@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/Tabbar/tabbar_unSelect_ailist.imageset/Contents.json

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

BIN
AIEmoji/Assets.xcassets/Tabbar/tabbar_unSelect_ailist.imageset/tabbar_unSelect_ailist@2x.png


BIN
AIEmoji/Assets.xcassets/Tabbar/tabbar_unSelect_ailist.imageset/tabbar_unSelect_ailist@3x.png


+ 15 - 0
AIEmoji/Business/TSAILIstVC/TSAIAgeImageHintVC/TSAIAgeImageHintVC.swift

@@ -0,0 +1,15 @@
+//
+//  TSAIAgeImageHintVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/9.
+//
+
+class TSAIAgeImageHintVC: TSAIListHintBaseVC {
+    override func createData() {
+        Self.userDefaultsKey = "isFirstAIListAge"
+        goodImageNamed = ""
+        badImageNamed = ""
+        super.createData()
+    }
+}

+ 164 - 0
AIEmoji/Business/TSAILIstVC/TSAIAgeImageHintVC/TSAIListHintBaseVC.swift

@@ -0,0 +1,164 @@
+//
+//  TSAIListHintBaseVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/9.
+//
+
+
+class TSAIListHintBaseVC: TSBaseVC {
+    
+    static var userDefaultsKey:String = "isFirstAIListAge"
+    
+    
+    var goodImageNamed:String = "ptp_goodImage"
+    var badImageNamed:String = "ptp_badImage"
+    
+    
+    let popupContentViewW:CGFloat = k_ScreenWidth - 40.0
+    let popupContentViewH:CGFloat = k_ScreenHeight - 268.0
+    
+    var clickUpImageHandle:(()->Void)?
+    lazy var popupContentView: UIView = {
+        let popupContentView = UIView(frame: CGRectMake(0, 0, popupContentViewW, popupContentViewH))
+        popupContentView.backgroundColor = "#222222".uiColor
+        popupContentView.cornerRadius = 20.0
+        return popupContentView
+    }()
+    
+    
+    lazy var noPromptsBtn: UIButton = {
+        let noPromptsBtn = UIButton.createButton(title: "No more prompts".localized,image: UIImage(named: "selected_circle"),font: .font(size: 11),titleColor: .white.withAlphaComponent(0.6)){ [weak self]  in
+            guard let self = self else { return }
+            changeNoPromptsBtn()
+        }
+        noPromptsBtn.setImage(UIImage(named: "radioboxSelected"), for: .selected)
+        return noPromptsBtn
+    }()
+    override func createView() {
+        setNavBarViewHidden(true)
+        view.backgroundColor = .black.withAlphaComponent(0.7)
+        
+        
+        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickView)))
+        
+        contentView.addSubview(popupContentView)
+        popupContentView.center = view.center
+        
+        popupContentView.snp.makeConstraints { make in
+            make.leading.equalTo(20)
+            make.trailing.equalTo(-20)
+            make.center.equalToSuperview()
+        }
+        
+        setUpUI()
+    }
+    
+    
+    @objc func clickView() {
+        dismiss()
+    }
+    
+    
+    func setUpUI(){
+ 
+        let titleLabel = UILabel.createLabel(text: "Upload your photos".localized,font: .font(size: 18,weight: .semibold),textColor: .white,numberOfLines: 0)
+        popupContentView.addSubview(titleLabel)
+        titleLabel.snp.makeConstraints { make in
+            make.leading.top.equalTo(32)
+            make.trailing.equalTo(-32)
+        }
+        
+        let goodLabel = UILabel.createLabel(text: "Good photo examples".localized,font: .font(size: 14,weight: .medium),textColor: .white,numberOfLines: 0)
+        popupContentView.addSubview(goodLabel)
+        goodLabel.snp.makeConstraints { make in
+            make.top.equalTo(titleLabel.snp.bottom).offset(28)
+            make.leading.equalTo(32)
+            make.trailing.equalTo(-32)
+        }
+        
+        let goodInfoLabel = UILabel.createLabel(text: "Fully clear and visible face, in good lighting".localized,font: .font(size: 14,weight: .medium),textColor: .white.withAlphaComponent(0.6),numberOfLines: 0)
+        popupContentView.addSubview(goodInfoLabel)
+        goodInfoLabel.snp.makeConstraints { make in
+            make.top.equalTo(goodLabel.snp.bottom).offset(8)
+            make.leading.equalTo(32)
+            make.trailing.equalTo(-32)
+        }
+        
+        let goodImageView = UIImageView.createImageView(imageName: goodImageNamed)
+        popupContentView.addSubview(goodImageView)
+        goodImageView.snp.makeConstraints { make in
+            make.top.equalTo(goodInfoLabel.snp.bottom).offset(12)
+            make.leading.equalTo(32)
+            make.trailing.equalTo(-32)
+            make.height.equalTo(108*kDesignScale)
+        }
+        
+        
+        
+        let badLabel = UILabel.createLabel(text: "Bad photo examples".localized,font: .font(size: 14,weight: .medium),textColor: .white,numberOfLines: 0)
+        popupContentView.addSubview(badLabel)
+        badLabel.snp.makeConstraints { make in
+            make.top.equalTo(goodImageView.snp.bottom).offset(28)
+            make.leading.equalTo(32)
+            make.trailing.equalTo(-32)
+        }
+        
+        let badInfoLabel = UILabel.createLabel(text: "Group photos, covered faces, nudes".localized,font: .font(size: 14,weight: .medium),textColor: .white.withAlphaComponent(0.6),numberOfLines: 0)
+        popupContentView.addSubview(badInfoLabel)
+        badInfoLabel.snp.makeConstraints { make in
+            make.top.equalTo(badLabel.snp.bottom).offset(8)
+            make.leading.equalTo(32)
+            make.trailing.equalTo(-32)
+        }
+        
+        let badImageView = UIImageView.createImageView(imageName: badImageNamed)
+        popupContentView.addSubview(badImageView)
+        badImageView.snp.makeConstraints { make in
+            make.top.equalTo(badInfoLabel.snp.bottom).offset(12)
+            make.leading.equalTo(32)
+            make.trailing.equalTo(-32)
+            make.height.equalTo(108*kDesignScale)
+        }
+        
+        let submitBtn = kCreateNormalSubmitBtn(title: "Upload Photo".localized) { [weak self]  in
+            guard let self = self else { return }
+            dismiss()
+            clickUpImageHandle?()
+        }
+        submitBtn.cornerRadius = 24.0
+        popupContentView.addSubview(submitBtn)
+        submitBtn.snp.makeConstraints { make in
+            make.top.equalTo(badImageView.snp.bottom).offset(35)
+            make.centerX.equalToSuperview()
+            make.width.equalTo(250*kDesignScale)
+            make.height.equalTo(48)
+        }
+
+        
+        noPromptsBtn.isSelected = true
+        popupContentView.addSubview(noPromptsBtn)
+        noPromptsBtn.snp.makeConstraints { make in
+            make.top.equalTo(submitBtn.snp.bottom).offset(12)
+            make.centerX.equalToSuperview()
+            make.height.equalTo(16)
+            make.bottom.equalTo(-24)
+        }
+    }
+    
+    func changeNoPromptsBtn(){
+        noPromptsBtn.isSelected = !noPromptsBtn.isSelected
+        Self.isShowUploadImageHint = noPromptsBtn.isSelected
+    }
+    
+    static var isShowUploadImageHint:Bool{
+        get {
+            return UserDefaults.standard.string(forKey: userDefaultsKey) == nil
+        }
+        
+        set {
+            UserDefaults.standard.set(newValue ? nil : "1", forKey: userDefaultsKey)
+            UserDefaults.standard.synchronize()
+        }
+    }
+}

+ 91 - 0
AIEmoji/Business/TSAILIstVC/TSAILIstVC/TSAILIstCell.swift

@@ -0,0 +1,91 @@
+//
+//  TSAILIstCell.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/8.
+//
+
+
+class TSAILIstCell: TSBaseCollectionCell {
+    
+    static let cellID = "TSAILIstCell"
+
+    override var isSelected: Bool{
+        didSet{
+            
+        }
+    }
+    
+    var itemModel:TSBasicItemModel = TSBasicItemModel(){
+        didSet{
+            bgImageView.image = UIImage(named: itemModel.leftImageName ?? "")
+            titleLab.text = itemModel.leftTitle
+            leftSubLab.text = itemModel.leftSubTitle
+        }
+    }
+    
+    lazy var bgImageView: UIImageView = {
+        let bgImageView = UIImageView()
+        return bgImageView
+    }()
+    
+    
+    lazy var shadowImageView: UIImageView = {
+        let shadowImageView = UIImageView.createImageView(imageName: "alList_shadow")
+        return shadowImageView
+    }()
+    
+    lazy var titleLab: UILabel = {
+        let titleLab = UILabel.createLabel(font: .font(size: 16,weight: .medium),textColor: .fromHex("FFFFFF"))
+        return titleLab
+    }()
+    
+    lazy var leftSubLab: UILabel = {
+        return UILabel.createLabel(font: .font(size: 14,weight: .medium),textColor: .white.withAlphaComponent(0.8),numberOfLines: 0)
+    }()
+
+    lazy var submitBtn: UIButton = {
+        let submitBtn = UIButton.createButton(title: "Try Now".localized,backgroundColor: .themeColor,font: .font(size: 12),titleColor: "#111111".uiColor)
+        submitBtn.contentEdgeInsets = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
+        submitBtn.cornerRadius = 12
+        return submitBtn
+    }()
+    
+
+    override func creatUI() {
+        
+        bgContentView.addSubview(bgImageView)
+        bgImageView.snp.makeConstraints { make in
+            make.top.bottom.leading.trailing.equalTo(0)
+        }
+
+        bgContentView.addSubview(shadowImageView)
+        shadowImageView.snp.makeConstraints { make in
+            make.bottom.leading.trailing.equalTo(0)
+            make.height.equalTo(90*kDesignScale)
+        }
+ 
+        bgContentView.addSubview(leftSubLab)
+        leftSubLab.snp.makeConstraints { make in
+            make.trailing.equalTo(-110*kDesignScale)
+            make.leading.equalTo(16)
+            make.bottom.equalTo(-12)
+        }
+        
+        bgContentView.addSubview(titleLab)
+        titleLab.snp.makeConstraints { make in
+            make.trailing.equalTo(leftSubLab.snp.trailing)
+            make.leading.equalTo(leftSubLab.snp.leading)
+            make.bottom.equalTo(leftSubLab.snp.top).offset(-8)
+        }
+        
+        bgContentView.addSubview(submitBtn)
+        submitBtn.snp.makeConstraints { make in
+            make.trailing.equalTo(-16)
+            make.bottom.equalTo(-27)
+            make.height.equalTo(24)
+        }
+    }
+    
+}
+

+ 184 - 0
AIEmoji/Business/TSAILIstVC/TSAILIstVC/TSAILIstVC.swift

@@ -0,0 +1,184 @@
+//
+//  TSAILIstVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/8.
+//
+
+class TSAILIstVC: TSBaseVC {
+    
+    lazy var dataArray: [TSBasicSectionModel] = {
+        var dataArray = [TSBasicSectionModel]()
+        let sectionModel = TSBasicSectionModel()
+        dataArray.append(sectionModel)
+
+        sectionModel.addSubItemModel(
+            createItemModel(
+                leftImageName:"aiList_oldPeople",
+                leftTitle: "Change Age".localized,
+                leftSubTitle: "AI predicts what you look like in your old age.".localized,
+                rightViewStyle: 0,
+                tapBlock: { [weak self] _, _, _ in
+                   guard let self = self else { return }
+                    let baseVc = TSAIUploadPhotoBaseVC(generatorStyle: .ageOld)
+                    kPushVC(target: self, modelVC: baseVc)
+        }))
+        
+        sectionModel.addSubItemModel(
+            createItemModel(
+                leftImageName:"ailist_child",
+                leftTitle: "Back to Baby".localized,
+                leftSubTitle: "AI helps you go back to being a baby.".localized,
+                rightViewStyle: 0,
+                tapBlock: { [weak self] _, _, _ in
+                   guard let self = self else { return }
+                                
+        }))
+
+        return dataArray
+
+    }()
+    
+    //###################################### 导航栏 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 titleImageView = UIImageView.createImageView(imageName: "nav_title_pic",contentMode: .scaleToFill)
+       navBarView.barView.addSubview(titleImageView)
+       titleImageView.snp.makeConstraints { make in
+           make.centerY.equalToSuperview()
+           make.left.equalTo(16)
+       }
+       
+       let keyboardBtn = UIButton.createButton(image: UIImage(named: "keyboard")) { [weak self]  in
+           guard let self = self else { return }
+           kPresentModalVC(target: self, modelVC: TSWallpaperVC())
+       }
+       navBarView.barView.addSubview(keyboardBtn)
+        keyboardBtn.snp.makeConstraints { make in
+           make.centerY.equalToSuperview()
+           make.trailing.equalTo(-16)
+           make.width.height.equalTo(24)
+       }
+       
+       navBarView.barView.addSubview(vipBtn)
+       vipBtn.snp.makeConstraints { make in
+           make.centerY.equalToSuperview()
+           make.trailing.equalTo(-60)
+           make.width.height.equalTo(24)
+       }
+       
+       return navBarView
+   }()
+    
+    //###################################### 导航栏 ######################################
+    lazy var layout: UICollectionViewFlowLayout = {
+        let layout = UICollectionViewFlowLayout()
+        layout.scrollDirection = .vertical
+        layout.itemSize = CGSize(width: k_ScreenWidth-32, height: 180*kDesignScale)
+        layout.minimumInteritemSpacing = 0.0
+        layout.minimumLineSpacing = 16.0
+        
+        layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
+        return layout
+    }()
+    lazy var collectionView: UICollectionView = {
+        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+        collectionView.delegate = self
+        collectionView.dataSource = self
+        collectionView.showsVerticalScrollIndicator = false
+        collectionView.showsHorizontalScrollIndicator = false
+        collectionView.backgroundColor = .clear
+        collectionView.register(TSAILIstCell.self, forCellWithReuseIdentifier: TSAILIstCell.cellID)
+        if #available(iOS 11.0, *) {
+            collectionView.contentInsetAdjustmentBehavior = .never
+        }
+        return collectionView
+    }()
+
+    
+    override func createView() {
+        
+        navBarContentView.addSubview(navBarView)
+        navBarView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+
+        contentView.addSubview(collectionView)
+        collectionView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+    
+    override func dealThings() {
+        NotificationCenter.default.addObserver(self, selector: #selector(updateVipView), name: .kPurchaseDidChanged, object: nil)
+        updateVipView()
+        
+    }
+}
+
+
+extension TSAILIstVC {
+
+    @objc func updateVipView() {
+        kExecuteOnMainThread {
+            self.vipBtn.isHidden = PurchaseManager.default.isVip
+        }
+    }
+
+    func createItemModel(leftImageName: String,
+                         leftTitle: String,
+                         leftSubTitle: String,
+                        rightViewStyle: Int,
+                        tapBlock: @escaping ((TSBasicItemModel, Int, Any?) -> Void)) -> TSBasicItemModel {
+        let model = TSBasicItemModel()
+        model.leftImageName = leftImageName
+        model.leftTitle = leftTitle
+        model.leftSubTitle = leftSubTitle
+        model.rightViewStyle = rightViewStyle
+        model.tapBlock = tapBlock
+        return model
+    }
+}
+
+extension TSAILIstVC: UICollectionViewDataSource ,UICollectionViewDelegate {
+    
+    public func numberOfSections(in collectionView: UICollectionView) -> Int {
+        return dataArray.count
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        if let sectionModel = dataArray.safeObj(At: section){
+            return sectionModel.itemsArray.count
+        }
+        return 0
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        
+        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TSAILIstCell.cellID, for: indexPath)
+        if let cell = cell as? TSAILIstCell {
+            if let sectionModel = dataArray.safeObj(At: indexPath.section),let itemModel = sectionModel.itemsArray.safeObj(At: indexPath.row){
+                cell.itemModel = itemModel
+            }
+        }
+        
+        return cell
+    }
+
+    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        if let sectionModel = dataArray.safeObj(At: indexPath.section),let itemModel = sectionModel.itemsArray.safeObj(At: indexPath.row){
+            itemModel.tapBlock?(itemModel,indexPath.row,nil)
+        }
+    }
+}

+ 214 - 0
AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIListPhotoGeneratorBaseVC.swift

@@ -0,0 +1,214 @@
+//
+//  TSAIListPhotoGeneratorBaseVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/9.
+//
+
+class TSAIListPhotoGeneratorBaseVC: TSAIPhotoGeneratorBaseVC {
+    
+    var imageModel:TSGenmojiModel?
+    var complete:((TSGenmojiModel)->Void)
+    
+    var prompt:String
+    var promptSort:String
+    var imageUrl:String
+    var upLoadImage:UIImage
+    var style:String
+    var generatorStyle:TSGeneratorImageStyle
+    
+    var progressState = TSProgressState.none
+    init(prompt:String,promptSort:String,imageUrl:String,upLoadImage:UIImage,style:String,generatorStyle:TSGeneratorImageStyle,complete:@escaping ((TSGenmojiModel)->Void)) {
+        self.prompt = prompt
+        self.promptSort = promptSort
+        self.imageUrl = imageUrl
+        self.upLoadImage = upLoadImage
+        self.style = style
+        self.generatorStyle = generatorStyle
+        self.complete = complete
+        
+        super.init()
+    }
+    
+    lazy var viewModel: TSAIListPhotoGeneratorBaseVM = {
+        let viewModel:TSAIListPhotoGeneratorBaseVM = TSAIListPhotoGeneratorBaseVM(prompt: prompt,upLoadImage:upLoadImage,style: style, generatorStyle: generatorStyle)
+        return viewModel
+    }()
+
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+
+    lazy var generateInView : TSGeneratorloadingView = {
+        let generateInView = TSGeneratorloadingView()
+        return generateInView
+    }()
+    
+    override func createView() {
+
+        contentView.addSubview(generateInView)
+        generateInView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        super.createView()
+    }
+    
+    override func closePage() {
+        if progressState.isResult {
+            viewModel.cancelAllRequest()
+            self.dismiss(animated: true, completion: nil)
+        }else{
+            TSCustomAlertController.show(in: self, config: TSCustomAlertController.AlertConfig(
+                message: "As you leave, your generation will be interrupted and no result.".localized,
+                messageColor: .white,
+                messageFont: .systemFont(ofSize: 16),
+                
+                cancelTitle: "Leave".localized,
+                cancelColor: .white,
+                
+                confirmTitle: "Wait".localized,
+                confirmColor: .themeColor,
+                
+                cancelAction: { [weak self]  in
+                    guard let self = self else { return }
+                    print("用户点击了Leave")
+                    viewModel.cancelAllRequest()
+                    self.dismiss(animated: true, completion: nil)
+                },
+                confirmAction: {
+                    print("用户点击了Stay")
+                }
+            ))
+        }
+    }
+    
+    //重试
+    @objc override func clickTryAgainBtn(){
+        clickRegenerateBtn()
+    }
+    
+    //重新生成
+    @objc override func clickRegenerateBtn(){
+        //判断 vip
+        if kJudgeVip(externalBool: kPurchaseDefault.freeNumAvailable(type: .picToPic) == false, vc: self) {[weak self] in
+            guard let self = self else { return }
+        }{ return }
+        
+        viewModel.uploadAndCreatImage()
+    }
+    
+    //保存功能
+    @objc override func clickSaveBtn(){
+        if let image = getSuccessImage() {
+            PhotoManagerShared.saveImageToAlbum(image) { success, error in
+                if success {
+                    kSavePhotoSuccesswShared.show(atView:self.view)
+                }else{
+                    debugPrint(error)
+                }
+            }
+        }
+    }
+    
+    override func dealThings() {
+        viewModel.uploadAndCreatImage()
+        viewModel.$stateDatauPblished.receive(on: DispatchQueue.main).sink {[weak self]  (state,model) in
+            guard let self = self else { return }
+            self.upDateView(state: state, model: model)
+        }.store(in: &cancellable)
+    }
+    
+}
+
+extension TSAIListPhotoGeneratorBaseVC {
+    
+    
+    func getSuccessImage()->UIImage?{
+        if let image = netWorkImageView.image {
+            return image.pngImage
+        }
+        return nil
+    }
+    
+}
+extension TSAIListPhotoGeneratorBaseVC {
+    
+    func upDateView(state:TSProgressState,model:TSGenmojiModel?){
+        progressState = state
+        switch state {
+            case .failed(let errorStr):
+                showError(text: errorStr)
+            case .success:
+                if let model = model {
+                    showSuccess(model: model)
+                }else{
+                    showError(text: nil)
+                }
+            case .progressString(let string):
+                showProgress(text: string)
+            default:
+                showLoading()
+        }
+    }
+    
+    func showProgress(text:String) {
+        generateInView.isHidden = false
+        generateInView.showLoading(text: text)
+        generateInView.isRotating = true
+        
+        isClickTheBlankClosePage = false
+        bottomView.isHidden = true
+        netWorkImageView.isHidden = true
+    }
+    
+    func showLoading(){
+        generateInView.isHidden = false
+        generateInView.showLoading(text: "Generating".localized + " ...")
+        generateInView.isRotating = true
+
+        isClickTheBlankClosePage = false
+        bottomView.isHidden = true
+        netWorkImageView.isHidden = true
+    }
+    
+    func showError(text:String?){
+        let msg = "Failed to generate, please try later".localized
+        generateInView.isHidden = false
+        generateInView.showError(text: msg)
+        generateInView.isRotating = false
+
+        isClickTheBlankClosePage = true
+        
+        tryAgainBtn.isHidden = false
+        bigSaveBtn.isHidden = true
+        bottomView.isHidden = false
+        netWorkImageView.isHidden = true
+    }
+    
+    func showSuccess(model:TSGenmojiModel){
+        generateInView.isHidden = true
+        generateInView.isRotating = false
+
+        imageModel = model
+        isClickTheBlankClosePage = true
+        
+        tryAgainBtn.isHidden = false
+        bigSaveBtn.isHidden = false
+        bottomView.isHidden = false
+        netWorkImageView.isHidden = false
+        
+        self.netWorkImageView.setAsyncImage(urlString: model.response.resultUrl,placeholder:kPlaceholderImage,backgroundColor:netWorkImageView.backgroundColor!){ [weak self] image in
+            guard let self = self else { return }
+            
+            netWorkImageView.adaptiveScale()
+        }
+        
+        kPurchaseDefault.useOnceForFree(type: .picToPic)
+        if let model = imageModel {
+            model.request.promptSort = promptSort
+            complete(model)
+        }
+    }
+}

+ 233 - 0
AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIPhotoGeneratorBaseVM/TSAIListPhotoGeneratorBaseVM.swift

@@ -0,0 +1,233 @@
+//
+//  TSAIListPhotoGeneratorBaseVM.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/9.
+//
+
+import Alamofire
+
+class TSAIListPhotoGeneratorBaseVM {
+    
+    var uploadRequest:Request?
+    var creatRequest:Request?
+    var queryRequest:Request?
+    var stopNetwork = false
+    
+    @Published var stateDatauPblished:(TSProgressState,TSGenmojiModel?) = (TSProgressState.none,nil)
+   
+    var prompt:String
+    var imageUrl:String?
+    var upLoadImage:UIImage
+    var style:String
+    var generatorStyle:TSGeneratorImageStyle
+    
+    var generatingProgress = 0
+    init(prompt:String,upLoadImage:UIImage,style:String,generatorStyle:TSGeneratorImageStyle) {
+        self.prompt = prompt
+        self.upLoadImage = upLoadImage
+        self.style = style
+        self.generatorStyle = generatorStyle
+    }
+    
+//    //模拟数据
+//    func creatImage() {
+//
+//        stateDatauPblished = (.start,nil)
+//        stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
+//
+//        kDelayOnMainThread(0.2) {
+//            self.stateDatauPblished = (.progressString(self.generating(progress: 0.2)),nil)
+//        }
+//
+//        kDelayOnMainThread(0.5) {
+//            self.stateDatauPblished = (.progressString(self.generating(progress: 0.5)),nil)
+//        }
+//
+//        kDelayOnMainThread(0.8) {
+//            self.stateDatauPblished = (.progressString(self.generating(progress: 0.8)),nil)
+//        }
+//
+//
+//        kDelayOnMainThread(2.0) {
+//            if kRandomBool() {
+//                let infoModel = TSGenmojiModel(JSON:actionInfoDictPoster )
+//                self.stateDatauPblished = (.success(nil),infoModel)
+//            }else{
+//                self.stateDatauPblished = (.failed("error?.localizedDescription"),nil)
+//            }
+//        }
+//
+//    }
+    
+    func creatImage() {
+        guard let imageUrl = imageUrl else { return }
+        generatingProgress = 0
+        stopNetwork = false
+        stateDatauPblished = (.start,nil)
+        stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
+        creatRequest = TSNetworkShared.post(urlType: .imageRewrite,parameters:
+                                                ["prompt":prompt,
+                                                 "imageUrl":imageUrl,
+                                                 "style":style,
+                                                 "device":getUserInfoJsonString()
+                                                ]) { [weak self] data,error in
+            guard let self = self else { return }
+            
+            if let dataDict = data as? [String:Any] ,
+               dataDict.safeInt(forKey: "code") == 200,
+               let actionId = dataDict["actionId"] as? Int{
+                if stopNetwork == false {
+                    self.getActionInfo(action_id:actionId)
+                }
+            }else{
+                self.stateDatauPblished = (.failed(error?.localizedDescription ?? ""),nil)
+            }
+        }
+    }
+    
+    func getActionInfo(action_id:Int){
+        queryRequest = TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { [weak self] data,error in
+            guard let self = self else { return }
+            if let result = kNetWorkResultSuccess(data: data) {
+                if let genmojiModel = TSGenmojiModel(JSON: result) {
+                    switch genmojiModel.actionStatus {
+                    case .success:
+                        if let url = URL(string:genmojiModel.response.resultUrl) {
+                            UIImageView.downloadImageWithProgress(url: url) { [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),nil)
+                                dePrint("当前进度: \(progress)")
+                            } completion: {[weak self] image in
+                                guard let self = self else { return }
+                                self.stateDatauPblished = (.success(nil),genmojiModel)
+                                generatingProgress = 0
+                            }
+
+                        }else{
+                            self.stateDatauPblished = (.success(nil),genmojiModel)
+                            generatingProgress = 0
+                        }
+                        
+                    case .failed:
+                        self.stateDatauPblished = (.failed(kNetWorkMessage(data: data) ?? ""),nil)
+                        generatingProgress = 0
+                    default:
+                        stateDatauPblished = (.progressString(generating(progress: genmojiModel.percent)),nil)
+                        if stopNetwork == false {
+                            kDelayOnMainThread(1.0) {
+                                self.getActionInfo(action_id: action_id)
+                            }
+                        }
+                    }
+                }
+            }else{
+                self.stateDatauPblished = (.failed(error?.localizedDescription ?? ""),nil)
+            }
+        }
+    }
+    
+    
+    func cancelAllRequest(){
+        creatRequest?.cancel()
+        queryRequest?.cancel()
+        stopNetwork = true
+    }
+    
+    
+    func uploadAndCreatImage() {
+        
+        if let imageUrl = imageUrl,imageUrl.contains("http") {
+            creatImage()
+            return
+        }
+        
+        stopNetwork = false
+        stateDatauPblished = (.start,nil)
+        
+        stateDatauPblished = (.progressString(uploadingPhoto(progress: 0.0)),nil)
+        uploadImage { [weak self]  progress in
+            guard let self = self else { return }
+            if generatingProgress == 0 {
+                stateDatauPblished = (.progressString(uploadingPhoto(progress: progress)),nil)
+            }
+        } completion: { [weak self]  data, error in
+            guard let self = self else { return }
+            if let error = error {
+                imageUrl = nil
+                self.stateDatauPblished = (.failed(error.localizedDescription),nil)
+            }else{
+                if let string = data as? String {
+                    imageUrl = string
+                    creatImage()
+                }
+            }
+        }
+    }
+    
+    func uploadingPhoto(progress:Float) -> String {
+        //Uploading Photo 0%-100%
+        var progressInt = Int(progress*100)
+        if progressInt > 99 {
+            progressInt = 99
+        }
+        return "Uploading Photo".localized + " \(progressInt)%"
+    }
+    
+    func generating(progress:Float) -> String {
+        let progress = progress*(0.9) // 预留 10% 进度给图片下载
+        //Generating 0%-100%
+        var progressInt = Int(progress*100)
+
+        if progressInt > 99 {
+            progressInt = 99
+        }
+        
+        generatingProgress = progressInt
+        return "Generating".localized + " \(progressInt)%"
+    }
+}
+
+
+extension TSAIListPhotoGeneratorBaseVM {
+    func uploadImage(
+        progressHandler: @escaping (Float) -> Void, // 上传进度回调
+        completion: @escaping (Any?, Error?) -> Void)
+    {
+        guard let imageData = upLoadImage.pngData() else { return }
+        stateDatauPblished = (.start,nil)
+        let dataArray = [
+            ["data": imageData,
+             "fieldName": "file", // 字段名
+             "fileName": "image.png", // 文件名
+             "mimeType": "image/png" // MIME 类型
+            ]
+        ]
+        
+        uploadRequest = TSNetworkShared.uploadData(
+            urlType: .upload,
+            dataArray: dataArray,
+            progressHandler: { progress in
+                progressHandler(progress)
+            },completion: { [weak self] result in
+            guard let self = self else { return }
+            switch result {
+            case .success(let data):
+                if let dataDict = data as? [String:Any] ,
+                   dataDict.safeInt(forKey: "code") == 200,
+                   let picUrl = dataDict["result"] as? String{
+                    completion(picUrl,nil)
+                }else{
+                    let error = NSError(domain: "Service exception", code: 0)
+                    completion(nil,error)
+                }
+            case .failure(let error):
+                completion(nil,error)
+            }
+        })
+    }
+    
+}

+ 203 - 0
AIEmoji/Business/TSAILIstVC/TSAIUploadPhotoBaseVC/TSAIUploadPhotoBaseVC.swift

@@ -0,0 +1,203 @@
+//
+//  TSAIUploadPhotoBaseVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/9.
+//
+
+
+enum TSGeneratorImageStyle {
+    case ageOld
+    case ageChild
+}
+
+
+class TSAIUploadPhotoBaseVC: TSBaseVC {
+    var generatorStyle:TSGeneratorImageStyle
+    
+    init(generatorStyle:TSGeneratorImageStyle) {
+        self.generatorStyle = generatorStyle
+        super.init()
+    }
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    //#####################################底部基础#####################################
+    lazy var cusStackView: TSCustomStackView = {
+        let cusStackView = TSCustomStackView(axis: .vertical,spacing: 0)
+        return cusStackView
+    }()
+
+    
+    lazy var submitBtn: UIButton = {
+        let submitBtn = kCreateNormalSubmitBtn(title: "Accept".localized) { [weak self]  in
+            guard let self = self else { return }
+        
+        }
+        submitBtn.cornerRadius = 24.0
+        return submitBtn
+    }()
+
+    //#####################################上传 view#####################################
+    var upLoadImage:UIImage? = nil {
+        didSet{
+            if let image = upLoadImage {
+                upLoadView.isHidden = true
+                uploadExampleImageView.isHidden = true
+                uploadImageView.isHidden = false
+                deleteBtn.isHidden = false
+                uploadImageView.image = image
+            }else {
+                upLoadView.isHidden = false
+                uploadExampleImageView.isHidden = false
+                uploadImageView.isHidden = true
+                deleteBtn.isHidden = true
+                uploadImageView.image = nil
+            }
+        }
+    }
+    
+    lazy var upLoadView: UIView = {
+        let bgView = UIView()
+        
+        let addImageView = UIImageView.createImageView(imageName: "add")
+        bgView.addSubview(addImageView)
+        addImageView.snp.makeConstraints { make in
+            make.top.equalTo(0)
+            make.centerX.equalToSuperview()
+            make.width.height.equalTo(24)
+        }
+        
+        let textLabel = UILabel.createLabel(text: "Upload Image".localized,font: .font(size: 16),textColor: .white)
+        bgView.addSubview(textLabel)
+        textLabel.snp.makeConstraints { make in
+            make.top.equalTo(addImageView.snp.bottom).offset(16)
+            make.centerX.equalToSuperview()
+            make.bottom.equalToSuperview()
+        }
+        
+        return bgView
+    }()
+    
+    lazy var uploadExampleImageView: UIImageView = {
+        let uploadExampleImageView = UIImageView()
+        uploadExampleImageView.image = UIImage(named: "ptp_upload_example")
+        uploadExampleImageView.contentMode = .scaleAspectFill
+        uploadExampleImageView.cornerRadius = 12
+        uploadExampleImageView.isHidden = false
+        
+        let button = UIButton.createButton(title:"Tap to select photo".localized,backgroundColor:.black.withAlphaComponent(0.4),font: .font(size: 14),titleColor: .white,corner: 12)
+        button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12)
+        uploadExampleImageView.addSubview(button)
+        button.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.bottom.equalTo(-20)
+            make.height.equalTo(24)
+        }
+        
+        return uploadExampleImageView
+    }()
+    
+    lazy var uploadImageView: UIImageView = {
+        let uploadImageView = UIImageView()
+        uploadImageView.contentMode = .scaleAspectFit
+        uploadImageView.cornerRadius = 12
+        upLoadView.isHidden = true
+        return uploadImageView
+    }()
+    
+    
+    lazy var uploadImageBgView: UIView = {
+        
+        let bgView = UIView()
+        bgView.addGestureRecognizer(UITapGestureRecognizer(target: self, action:#selector(clickBgView)))
+        let bgImageView = UIImageView.createImageView(imageName: "ptp_upload_bg")
+        bgImageView.contentMode = .scaleToFill
+        bgView.addSubview(bgImageView)
+        bgImageView.snp.makeConstraints { make in
+            make.leading.bottom.trailing.top.equalTo(0)
+        }
+
+        bgView.addSubview(upLoadView)
+        upLoadView.snp.makeConstraints { make in
+            make.top.equalTo(88)
+            make.centerX.equalToSuperview()
+        }
+        
+        bgView.addSubview(uploadExampleImageView)
+        uploadExampleImageView.snp.makeConstraints { make in
+            make.top.leading.equalTo(8)
+            make.bottom.trailing.equalTo(-8)
+        }
+        
+        bgView.addSubview(uploadImageView)
+        uploadImageView.snp.makeConstraints { make in
+            make.top.leading.equalTo(8)
+            make.bottom.trailing.equalTo(-8)
+        }
+        
+        return bgView
+    }()
+    
+    
+    lazy var deleteBtn: UIButton = {
+        let deleteBtn = UIButton.createButton(backgroundImage: UIImage(named: "delete_redRound")) { [weak self]  in
+            guard let self = self else { return }
+            upLoadImage = nil
+        }
+        deleteBtn.isHidden = true
+        return deleteBtn
+    }()
+    
+    
+    override func createView() {
+        
+        addNormalNavBarView()
+        setPageTitle("Change Age")
+        
+        
+        contentView.addSubview(submitBtn)
+        submitBtn.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.width.equalTo(250*kDesignScale)
+            make.height.equalTo(48)
+            make.bottom.equalTo(-10-k_Height_safeAreaInsetsBottom())
+        }
+        
+        contentView.addSubview(cusStackView)
+        cusStackView.snp.makeConstraints { make in
+            make.top.equalTo(0)
+            make.leading.trailing.equalToSuperview()
+            make.bottom.equalTo(submitBtn.snp.top).offset(-10)
+        }
+        
+
+    }
+    
+    
+    func setUpStackView(){
+        
+        let bgView = UIView()
+        bgView.addSubview(uploadImageBgView)
+        cusStackView.addSubviewToStack(bgView)
+    
+        uploadImageBgView.snp.makeConstraints { make in
+            make.width.equalTo(296*kDesignScale)
+            make.height.equalTo(528*kDesignScale)
+            make.centerX.equalToSuperview()
+            make.top.equalTo(8)
+            make.bottom.equalTo(-16)
+        }
+
+        uploadImageBgView.addSubview(deleteBtn)
+        deleteBtn.snp.makeConstraints { make in
+            make.top.equalTo(-6)
+            make.trailing.equalTo(-4)
+            make.width.height.equalTo(32)
+        }
+    }
+    
+    @objc func clickBgView() {
+    }
+}

+ 9 - 8
AIEmoji/Business/TSPTPGeneratorVC/TSPTPImageHintVC/TSPTPImageHintVC.swift

@@ -126,17 +126,18 @@ class TSPTPImageHintVC: TSBaseVC {
             make.centerX.equalToSuperview()
             make.width.equalTo(250*kDesignScale)
             make.height.equalTo(48)
+            make.bottom.equalTo(-24)
         }
 
         
-        noPromptsBtn.isSelected = true
-        popupContentView.addSubview(noPromptsBtn)
-        noPromptsBtn.snp.makeConstraints { make in
-            make.top.equalTo(submitBtn.snp.bottom).offset(12)
-            make.centerX.equalToSuperview()
-            make.height.equalTo(16)
-            make.bottom.equalTo(-24)
-        }
+//        noPromptsBtn.isSelected = true
+//        popupContentView.addSubview(noPromptsBtn)
+//        noPromptsBtn.snp.makeConstraints { make in
+//            make.top.equalTo(submitBtn.snp.bottom).offset(12)
+//            make.centerX.equalToSuperview()
+//            make.height.equalTo(16)
+//            make.bottom.equalTo(-24)
+//        }
     }
     
     func changeNoPromptsBtn(){

+ 0 - 85
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/View/TSPTPSelectStyleView.swift

@@ -86,88 +86,3 @@ extension TSPTPSelectStyleView: UICollectionViewDataSource ,UICollectionViewDele
         }
     }
 }
-
-//class TSPTPSelectStyleCCell: TSBaseCollectionCell {
-//    
-//    static let cellID = "TSPTPSelectStyleCCell"
-//
-//    override var isSelected: Bool{
-//        didSet{
-//            boardImageView.isHidden = isSelected ? false : true
-//        }
-//    }
-//    
-//    var itemModel:TSPTPStyleModel = TSPTPStyleModel(){
-//        didSet{
-//            imageView.image = UIImage(named: itemModel.imageName)
-//            var strokeColor = UIColor.white
-//            var font = UIFont.font(size: 14)
-//            if itemModel.specialStyle == 1 {
-//                hotImageView.isHidden = false
-//                font = UIFont.font(name:.PoppinsBlackItalic,size: 18)
-//                strokeColor = "#FFB73C".uiColor
-//            }else{
-//                hotImageView.isHidden = true
-//            }
-//        
-//            textLabel.attributedText = NSAttributedString(
-//                string: itemModel.imageText.localized,
-//                attributes: [
-//                    .strokeColor: strokeColor,       // 描边颜色
-//                    .strokeWidth: -4.0,                // 负值表示同时填充和描边(正值仅描边)
-//                    .foregroundColor: UIColor.white,   // 文字填充色
-//                    .font: font
-//                ]
-//            )
-//        }
-//    }
-//    
-//    lazy var imageView: UIImageView = {
-//        let imageView = UIImageView()
-//        return imageView
-//    }()
-//    
-//    lazy var hotImageView: UIImageView = {
-//        let hotImageView = UIImageView.createImageView(imageName: "ptp_style_hot")
-//        hotImageView.isHidden = true
-//        return hotImageView
-//    }()
-//    
-//    lazy var boardImageView: UIImageView = {
-//        let boardImageView = UIImageView.createImageView(imageName: "ptp_selected_border")
-//        boardImageView.isHidden = true
-//        return boardImageView
-//    }()
-//
-//    lazy var textLabel: UILabel = {
-//        let textLabel = UILabel.createLabel(font: .font(size: 14),textColor: .white,textAlignment: .center,numberOfLines: 0)
-//        return textLabel
-//    }()
-//    
-//    override func creatUI() {
-//        
-//        bgContentView.addSubview(imageView)
-//        imageView.snp.makeConstraints { make in
-//            make.top.bottom.leading.trailing.equalTo(0)
-//        }
-//        
-//        imageView.addSubview(hotImageView)
-//        hotImageView.snp.makeConstraints { make in
-//            make.top.leading.equalTo(0)
-//            make.width.height.equalTo(36)
-//        }
-//        
-//        bgContentView.addSubview(boardImageView)
-//        boardImageView.snp.makeConstraints { make in
-//            make.top.bottom.leading.trailing.equalTo(0)
-//        }
-// 
-//        bgContentView.addSubview(textLabel)
-//        textLabel.snp.makeConstraints { make in
-//            make.leading.trailing.equalTo(0)
-//            make.bottom.equalTo(-4)
-//            make.height.equalTo(37)
-//        }
-//    }
-//    
-//}

+ 5 - 4
AIEmoji/Business/TSTabBarController/TSTabBarController.swift

@@ -24,21 +24,22 @@ class TSTabBarController: UITabBarController {
     }
 
     @objc private func setUpData() {
-        viewControllerArray = ["TSPTPInputVC","TSChatViewController","TSEmojisVC","TSSetingVC"]
+        viewControllerArray = ["TSPTPInputVC","TSAILIstVC","TSChatViewController","TSSetingVC"]
+//        viewControllerArray = ["TSPTPInputVC","TSChatViewController","TSEmojisVC","TSSetingVC"]
 //        viewControllerArray = ["TSPhotoToPhotoVC","TSChatViewController","TSEmojisVC","TSSetingVC"]
 //        viewControllerArray = ["TSTTPInputVC","TSChatViewController","TSEmojisVC","TSSetingVC"]
 
-        titleArray = ["Photo","Chat","Emoji","Setting"]
+        titleArray = ["Photo","AI","Chat","Setting"]
         selectedImageArray = [
             "tabbar_select_pic",
+            "tabbar_select_ailist",
             "tabbar_select_aichat",
-            "tabbar_select_emoji",
             "tabbar_select_setting"
         ]
         unselectedImageArray = [
             "tabbar_unSelect_pic",
+            "tabbar_unSelect_ailist",
             "tabbar_unSelect_aichat",
-            "tabbar_unSelect_emoji",
             "tabbar_unSelect_setting"
         ]