Procházet zdrojové kódy

AI 扩图基本开发完毕

100Years před 1 dnem
rodič
revize
e86dca7f95
43 změnil soubory, kde provedl 955 přidání a 43 odebrání
  1. 24 0
      AIEmoji.xcodeproj/project.pbxproj
  2. 22 0
      AIEmoji/Assets.xcassets/AIList/aiList_photoExpand.imageset/Contents.json
  3. binární
      AIEmoji/Assets.xcassets/AIList/aiList_photoExpand.imageset/aiList_photoExpand@2x.png
  4. binární
      AIEmoji/Assets.xcassets/AIList/aiList_photoExpand.imageset/aiList_photoExpand@3x.png
  5. 6 0
      AIEmoji/Assets.xcassets/AIList/expand/Contents.json
  6. 22 0
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_16:9.imageset/Contents.json
  7. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_16:9.imageset/ai_expand_16:9@2x.png
  8. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_16:9.imageset/ai_expand_16:9@3x.png
  9. 22 0
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_1:1.imageset/Contents.json
  10. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_1:1.imageset/ai_expand_1:1@2x.png
  11. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_1:1.imageset/ai_expand_1:1@3x.png
  12. 22 0
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_2:3.imageset/Contents.json
  13. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_2:3.imageset/ai_expand_2:3@2x.png
  14. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_2:3.imageset/ai_expand_2:3@3x.png
  15. 22 0
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:2.imageset/Contents.json
  16. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:2.imageset/ai_expand_3:2@2x.png
  17. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:2.imageset/ai_expand_3:2@3x.png
  18. 22 0
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:4.imageset/Contents.json
  19. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:4.imageset/ai_expand_3:4@2x.png
  20. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:4.imageset/ai_expand_3:4@3x.png
  21. 22 0
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_4:3.imageset/Contents.json
  22. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_4:3.imageset/ai_expand_4:3@2x.png
  23. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_4:3.imageset/ai_expand_4:3@3x.png
  24. 22 0
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_9:16.imageset/Contents.json
  25. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_9:16.imageset/ai_expand_9:16@2x.png
  26. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_9:16.imageset/ai_expand_9:16@3x.png
  27. 22 0
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_change.imageset/Contents.json
  28. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_change.imageset/ai_expand_change@2x.png
  29. binární
      AIEmoji/Assets.xcassets/AIList/expand/ai_expand_change.imageset/ai_expand_change@3x.png
  30. 22 0
      AIEmoji/Assets.xcassets/AIList/expand/clear_Bg.imageset/Contents.json
  31. binární
      AIEmoji/Assets.xcassets/AIList/expand/clear_Bg.imageset/clear_Bg@2x.png
  32. binární
      AIEmoji/Assets.xcassets/AIList/expand/clear_Bg.imageset/clear_Bg@3x.png
  33. 13 0
      AIEmoji/Business/Data/TSUserDefaultData.swift
  34. 281 0
      AIEmoji/Business/TSAILIstVC/TSAIExpandImageVC/TSAIExpandImageVC.swift
  35. 92 0
      AIEmoji/Business/TSAILIstVC/TSAIExpandImageVC/TSAIExpandImageVM.swift
  36. 181 0
      AIEmoji/Business/TSAILIstVC/TSAIExpandImageVC/TSAIExpandStyleView.swift
  37. 18 0
      AIEmoji/Business/TSAILIstVC/TSAILIstVC/TSAILIstVC.swift
  38. 4 0
      AIEmoji/Business/TSAILIstVC/TSAIListHistoryBaseVC/TSAIListHistoryBaseVM.swift
  39. 26 25
      AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIListPhotoGeneratorBaseVC.swift
  40. 26 16
      AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIPhotoGeneratorBaseVM/TSAIListPhotoGeneratorBaseVM.swift
  41. 4 1
      AIEmoji/Business/TSAILIstVC/TSAIUploadPhotoBaseVC/TSAIUploadPhotoBaseVC.swift
  42. 1 1
      AIEmoji/Common/NetworkManager/TSNetWork/TSNetWork+Business.swift
  43. 59 0
      AIEmoji/Res/ai_expand_image_style.json

+ 24 - 0
AIEmoji.xcodeproj/project.pbxproj

@@ -90,6 +90,10 @@
 		A80EDE022D6F1CCD003CD332 /* TSPTPGeneratorVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDE012D6F1CCB003CD332 /* TSPTPGeneratorVC.swift */; };
 		A80EDE062D6F3491003CD332 /* TSPTPBrowseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDE052D6F3490003CD332 /* TSPTPBrowseVC.swift */; };
 		A80EDE082D700395003CD332 /* rotatingAnimation.gif in Resources */ = {isa = PBXBuildFile; fileRef = A80EDE072D700395003CD332 /* rotatingAnimation.gif */; };
+		A82D60792DB7703D00596190 /* TSAIExpandImageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82D60782DB7703C00596190 /* TSAIExpandImageVC.swift */; };
+		A82D607B2DB7724700596190 /* TSAIExpandStyleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82D607A2DB7724600596190 /* TSAIExpandStyleView.swift */; };
+		A82D607D2DB7748800596190 /* ai_expand_image_style.json in Resources */ = {isa = PBXBuildFile; fileRef = A82D607C2DB7748200596190 /* ai_expand_image_style.json */; };
+		A82D607F2DB7772200596190 /* TSAIExpandImageVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82D607E2DB7771B00596190 /* TSAIExpandImageVM.swift */; };
 		A83404C82D9BEC0E00C140E4 /* UIFont+TSEx.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83404C72D9BEC0700C140E4 /* UIFont+TSEx.swift */; };
 		A83404CC2D9BEED800C140E4 /* Poppins-BlackItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = A83404CB2D9BEED800C140E4 /* Poppins-BlackItalic.ttf */; };
 		A83404D12D9D16FA00C140E4 /* TSAIPhotoGeneratorBaseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83404D02D9D16F800C140E4 /* TSAIPhotoGeneratorBaseVC.swift */; };
@@ -323,6 +327,10 @@
 		A80EDE012D6F1CCB003CD332 /* TSPTPGeneratorVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPGeneratorVC.swift; sourceTree = "<group>"; };
 		A80EDE052D6F3490003CD332 /* TSPTPBrowseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPBrowseVC.swift; sourceTree = "<group>"; };
 		A80EDE072D700395003CD332 /* rotatingAnimation.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = rotatingAnimation.gif; sourceTree = "<group>"; };
+		A82D60782DB7703C00596190 /* TSAIExpandImageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIExpandImageVC.swift; sourceTree = "<group>"; };
+		A82D607A2DB7724600596190 /* TSAIExpandStyleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIExpandStyleView.swift; sourceTree = "<group>"; };
+		A82D607C2DB7748200596190 /* ai_expand_image_style.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = ai_expand_image_style.json; sourceTree = "<group>"; };
+		A82D607E2DB7771B00596190 /* TSAIExpandImageVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIExpandImageVM.swift; sourceTree = "<group>"; };
 		A83404C72D9BEC0700C140E4 /* UIFont+TSEx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+TSEx.swift"; sourceTree = "<group>"; };
 		A83404CB2D9BEED800C140E4 /* Poppins-BlackItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Poppins-BlackItalic.ttf"; sourceTree = "<group>"; };
 		A83404D02D9D16F800C140E4 /* TSAIPhotoGeneratorBaseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIPhotoGeneratorBaseVC.swift; sourceTree = "<group>"; };
@@ -1079,6 +1087,16 @@
 			path = TSPTPBrowseVC;
 			sourceTree = "<group>";
 		};
+		A82D60772DB7703000596190 /* TSAIExpandImageVC */ = {
+			isa = PBXGroup;
+			children = (
+				A82D607E2DB7771B00596190 /* TSAIExpandImageVM.swift */,
+				A82D607A2DB7724600596190 /* TSAIExpandStyleView.swift */,
+				A82D60782DB7703C00596190 /* TSAIExpandImageVC.swift */,
+			);
+			path = TSAIExpandImageVC;
+			sourceTree = "<group>";
+		};
 		A83404C62D9BEC0300C140E4 /* Ex */ = {
 			isa = PBXGroup;
 			children = (
@@ -1338,6 +1356,7 @@
 		A8BA765F2DA6479A000B6707 /* TSAILIstVC */ = {
 			isa = PBXGroup;
 			children = (
+				A82D60772DB7703000596190 /* TSAIExpandImageVC */,
 				A8D6383A2DB1FC6E00A96C0E /* TSAIListVideoPlayerVC */,
 				A8F413562DA8E500001E715A /* TSAIChangeEmoteVC */,
 				A8BA76732DA67E60000B6707 /* TSAIListHistoryBaseVC */,
@@ -1845,6 +1864,7 @@
 				A8F413542DA8BA47001E715A /* ai_change_emote_style.json */,
 				A8F413632DAA6F84001E715A /* ai_change_hair_style.json */,
 				A8F413672DAA7460001E715A /* ai_change_hair_color_style.json */,
+				A82D607C2DB7748200596190 /* ai_expand_image_style.json */,
 			);
 			path = Res;
 			sourceTree = "<group>";
@@ -1952,6 +1972,7 @@
 				A8F413552DA8BA4E001E715A /* ai_change_emote_style.json in Resources */,
 				A8EEADE72D3E76860032C5A0 /* Drink🥤.json in Resources */,
 				A83404DB2D9D382200C140E4 /* AccentURW-Reg.ttf in Resources */,
+				A82D607D2DB7748800596190 /* ai_expand_image_style.json in Resources */,
 				A8F413642DAA6F8C001E715A /* ai_change_hair_style.json in Resources */,
 				A80EDE082D700395003CD332 /* rotatingAnimation.gif in Resources */,
 				A83404FE2DA35BFE00C140E4 /* Localizable.strings in Resources */,
@@ -2082,10 +2103,12 @@
 				A8D6384A2DB252F100A96C0E /* TSAIListHistoryBaseCell.swift in Sources */,
 				A80EDD5A2D6C3F82003CD332 /* MarkdownParser.swift in Sources */,
 				A80EDD5B2D6C3F82003CD332 /* MarkdownCommonElement.swift in Sources */,
+				A82D60792DB7703D00596190 /* TSAIExpandImageVC.swift in Sources */,
 				A80EDD682D6C5098003CD332 /* TSChatMsgBaseView.swift in Sources */,
 				A8BA764F2DA50B52000B6707 /* CpuMapManager.swift in Sources */,
 				A8BA766C2DA657E8000B6707 /* TSAIListPhotoGeneratorBaseVC.swift in Sources */,
 				A80EDD5C2D6C3F82003CD332 /* MarkdownList.swift in Sources */,
+				A82D607F2DB7772200596190 /* TSAIExpandImageVM.swift in Sources */,
 				A80EDD5D2D6C3F82003CD332 /* MarkdownCodeEscaping.swift in Sources */,
 				A8D638352DB10BAC00A96C0E /* CrashReporter.swift in Sources */,
 				A80EDD5E2D6C3F82003CD332 /* MarkdownLinkElement.swift in Sources */,
@@ -2131,6 +2154,7 @@
 				A8F776352D3A7C2B00AA6E93 /* TSGenmojiColSectionView.swift in Sources */,
 				A80327B32D813D4900AF7878 /* TSTTPInputVC.swift in Sources */,
 				A80E724F2D3F6D7F00C64288 /* DiyFixedTextElement.swift in Sources */,
+				A82D607B2DB7724700596190 /* TSAIExpandStyleView.swift in Sources */,
 				A85E478F2D67115A0018D62D /* TSTextGeneralPictureVC.swift in Sources */,
 				A89EA6C42D5F40CC000EB181 /* TSChatInputBarVC.swift in Sources */,
 				A8BA76542DA54571000B6707 /* CollectionViewObserver.swift in Sources */,

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

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

binární
AIEmoji/Assets.xcassets/AIList/aiList_photoExpand.imageset/aiList_photoExpand@2x.png


binární
AIEmoji/Assets.xcassets/AIList/aiList_photoExpand.imageset/aiList_photoExpand@3x.png


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

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

+ 22 - 0
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_16:9.imageset/Contents.json

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

binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_16:9.imageset/ai_expand_16:9@2x.png


binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_16:9.imageset/ai_expand_16:9@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_1:1.imageset/Contents.json

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

binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_1:1.imageset/ai_expand_1:1@2x.png


binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_1:1.imageset/ai_expand_1:1@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_2:3.imageset/Contents.json

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

binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_2:3.imageset/ai_expand_2:3@2x.png


binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_2:3.imageset/ai_expand_2:3@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:2.imageset/Contents.json

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

binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:2.imageset/ai_expand_3:2@2x.png


binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:2.imageset/ai_expand_3:2@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:4.imageset/Contents.json

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

binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:4.imageset/ai_expand_3:4@2x.png


binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_3:4.imageset/ai_expand_3:4@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_4:3.imageset/Contents.json

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

binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_4:3.imageset/ai_expand_4:3@2x.png


binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_4:3.imageset/ai_expand_4:3@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_9:16.imageset/Contents.json

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

binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_9:16.imageset/ai_expand_9:16@2x.png


binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_9:16.imageset/ai_expand_9:16@3x.png


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

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

binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_change.imageset/ai_expand_change@2x.png


binární
AIEmoji/Assets.xcassets/AIList/expand/ai_expand_change.imageset/ai_expand_change@3x.png


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

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

binární
AIEmoji/Assets.xcassets/AIList/expand/clear_Bg.imageset/clear_Bg@2x.png


binární
AIEmoji/Assets.xcassets/AIList/expand/clear_Bg.imageset/clear_Bg@3x.png


+ 13 - 0
AIEmoji/Business/Data/TSUserDefaultData.swift

@@ -249,6 +249,19 @@ final class TSAIPhotoLiveHistory: TSBaseHistoryManager<TSActionInfoModel> {
 }
 
 
+// MARK: - 照片扩展
+final class TSAIPhotoExpandHistory: TSBaseHistoryManager<TSActionInfoModel> {
+    static let shared = TSAIPhotoExpandHistory()
+    override var historyKey: String { "kTSAIPhotoExpandHistoryListString" }
+    
+    override var exampleModels: [TSActionInfoModel] {
+        []
+    }
+    override func findModelID(modelID: Int) -> Int? {
+        return listModels.firstIndex(where: {$0.id == modelID})
+    }
+}
+
 
 
 

+ 281 - 0
AIEmoji/Business/TSAILIstVC/TSAIExpandImageVC/TSAIExpandImageVC.swift

@@ -0,0 +1,281 @@
+//
+//  TSAIExpandImageVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/21.
+//
+
+import PhotosUI
+
+class TSAIExpandImageVC: TSBaseVC {
+    
+    var upLoadImage:UIImage?{
+        didSet{
+            topImageView.image = upLoadImage
+        }
+    }
+    
+    init(upLoadImage: UIImage) {
+        self.upLoadImage = upLoadImage
+        super.init()
+    }
+    
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    lazy var viewModel: TSAIExpandImageVM = {
+        let viewModel:TSAIExpandImageVM = TSAIExpandImageVM()
+        return viewModel
+    }()
+    
+    var photoExpand = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
+    
+    lazy var maxSize: CGSize = {
+        let maxSize = CGSizeMake(k_ScreenWidth, k_ScreenWidth)
+        return maxSize
+    }()
+    
+    lazy var photoPickerManager: TSPhotoPickerManager = {
+        let photoPickerManager = TSPhotoPickerManager(viewController: self)
+        return photoPickerManager
+    }()
+
+    
+    //###################################### topImageView ######################################
+    lazy var topAreaView: UIView = {
+        let view = UIView()
+
+        view.addSubview(expandAreaView)
+        expandAreaView.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.equalTo(maxSize.width)
+            make.height.equalTo(maxSize.height)
+        }
+
+        return view
+    }()
+    
+    lazy var expandAreaView: UIView = {
+        let view = UIView()
+        
+        let imageView = UIImageView.createImageView(imageName: "clear_bg",contentMode: .scaleToFill)
+        view.addSubview(imageView)
+        imageView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        view.addSubview(topImageView)
+        topImageView.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.equalTo(maxSize.width)
+            make.height.equalTo(maxSize.height)
+        }
+        
+        let boardView = UIView()
+        boardView.layer.borderColor = UIColor.white.cgColor
+        boardView.layer.borderWidth = 1.5
+        view.addSubview(boardView)
+        boardView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        return view
+    }()
+    
+    lazy var topImageView: UIImageView = {
+        let imageView = UIImageView()
+        imageView.isUserInteractionEnabled = true
+        imageView.contentMode = .scaleAspectFit
+        return imageView
+    }()
+    //###################################### style类型 ######################################
+    lazy var styleView: TSAIExpandStyleView = {
+        let styleView = TSAIExpandStyleView()
+        styleView.dataArray = viewModel.selectStyleModels
+        styleView.currentIndexPath = IndexPath(item: viewModel.selectedStyleIndex, section: 0)
+        styleView.selectedValueBlock = { [weak self] model in
+            guard let self = self else { return }
+            handelSelectedValueBlock(model: model)
+        }
+        return styleView
+    }()
+    
+    //###################################### 提交按钮 ######################################
+    lazy var submitBtn: UIButton = {
+        let submitBtn = kCreateNormalSubmitBtn(title: "Expand".localized) { [weak self]  in
+            guard let self = self else { return }
+            generateImage()
+        }
+        submitBtn.cornerRadius = 24.0
+        return submitBtn
+    }()
+    //###################################### createView ######################################
+    override func createView() {
+        addNormalNavBarView()
+        setPageTitle("AI Expand Photo".localized)
+        _ = setNavigationItem("", imageName: "aichat_history", direction: .right, action: #selector(clickNavRight))
+        
+        contentView.addSubview(submitBtn)
+        contentView.addSubview(styleView)
+        contentView.addSubview(topAreaView)
+
+
+        submitBtn.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.width.equalTo(250*kDesignScale)
+            make.height.equalTo(48)
+            make.bottom.equalTo(-10-k_Height_safeAreaInsetsBottom())
+        }
+        
+        styleView.snp.makeConstraints { make in
+            make.bottom.equalTo(submitBtn.snp.top).offset(-30)
+            make.leading.trailing.equalTo(0)
+            make.height.equalTo(52)
+        }
+        
+        topAreaView.snp.makeConstraints { make in
+            make.top.leading.trailing.equalTo(0)
+            make.bottom.equalTo(styleView.snp.top).offset(0)
+        }
+
+        let image = upLoadImage
+        upLoadImage = image
+        updateExpandArea()
+    }
+}
+
+extension TSAIExpandImageVC {
+    
+    @objc func clickNavRight() {
+        kPushVC(target: self, modelVC: TSAIListHistoryBaseVC(generatorStyle: .photoExpand))
+    }
+    
+    func handelSelectedValueBlock(model:TSGenerateStyleModel)  {
+        if model.clickType == 2 { //换图
+            self.pickSinglePhoto()
+        }else{
+            viewModel.selectStyleModel = model
+            styleView.agreeWillSelectIndexPath()
+            updateExpandArea()
+        }
+    }
+    
+    func pickSinglePhoto()  {
+        photoPickerManager.pickCustomSinglePhoto() { [weak self] image, errorString in
+            guard let self = self else { return }
+            if let errorString = errorString {
+                TSToastShared.showToast(text: errorString)
+            }else{
+                handlePhotoPicke(image: image)
+            }
+        }
+    }
+
+    func handlePhotoPicke(image:UIImage?){
+        if let image = image {
+            upLoadImage = image
+            viewModel.upLoadImage = image
+            //选中后,去到 1:1
+            styleView.currentIndexPath = IndexPath(item: 1, section: 0)
+            viewModel.selectStyleModel = viewModel.selectStyleModels.safeObj(At: 1)
+            updateExpandArea()
+        }
+        
+        if upLoadImage == nil {
+            pop()
+        }
+    }
+    // MARK: - 更新扩图区域
+    private func updateExpandArea() {
+        guard let upLoadImage = upLoadImage else { return }
+        let imageSize = upLoadImage.size
+        let imageAspectRatio = imageSize.width / imageSize.height
+        let targetAspectRatio = viewModel.currentRatio.value
+        
+        print("imageAspectRatio=\(imageAspectRatio)")
+        print("targetAspectRatio=\(targetAspectRatio)")
+        print("\n")
+        
+        var expandWidth: CGFloat
+        var expandHeight: CGFloat
+        
+        if targetAspectRatio > imageAspectRatio {
+            // 以宽度为基准
+            expandWidth = maxSize.width
+            expandHeight = expandWidth / targetAspectRatio
+        }else {
+            // 以高度为基准
+            expandHeight = maxSize.height
+            expandWidth = expandHeight * targetAspectRatio
+        }
+        
+        // 确保扩图区域不超过最大限制(100%)
+        let maxExpandWidth = view.bounds.width
+        let maxExpandHeight = view.bounds.height
+        print("expandWidth=\(expandWidth)")
+        print("expandHeight=\(expandHeight)")
+        print("\n")
+        expandWidth = min(expandWidth, maxExpandWidth)
+        expandHeight = min(expandHeight, maxExpandHeight)
+        
+        print("expandWidth=\(expandWidth)")
+        print("expandHeight=\(expandHeight)")
+        print("\n")
+        
+        // 使用 SnapKit 更新约束
+        expandAreaView.snp.updateConstraints { make in
+            make.width.equalTo(expandWidth)
+            make.height.equalTo(expandHeight)
+        }
+        
+        let imageRatio = min(expandWidth/imageSize.width,expandHeight/imageSize.height)
+        var scaleFactor = 1.0
+        if targetAspectRatio == 1.0,imageAspectRatio == 1.0 {
+            scaleFactor = 0.67
+        }
+        
+        let imageViewW = imageSize.width * imageRatio * scaleFactor
+        let imageViewH = imageSize.height * imageRatio * scaleFactor
+        topImageView.snp.updateConstraints { make in
+            make.width.equalTo(imageViewW)
+            make.height.equalTo(imageViewH)
+        }
+        
+        let ws = 1.0 - imageViewW/expandWidth
+        let hs = 1.0 - imageViewH/expandHeight
+        
+        if targetAspectRatio == 1.0,imageAspectRatio == 1.0 {
+            photoExpand = UIEdgeInsets(top: 0.25, left: 0.25, bottom: 0.25, right: 0.25)
+        }else{
+            photoExpand = UIEdgeInsets(top: hs/2.0, left: ws/2.0, bottom: hs/2.0, right: ws/2.0)
+        }
+        
+        print("ws=\(ws),hs=\(hs)")
+        print("1-ws=\(1.0-ws),1-hs=\(1.0-hs)")
+        print("postEdge=\(photoExpand)")
+        
+        UIView.animate(withDuration: 0.3) {
+            self.topAreaView.layoutIfNeeded()
+        }
+    }
+}
+
+extension TSAIExpandImageVC {
+    
+    func generateImage() {
+        if kJudgeVip(externalBool: true, vc: self){ return } //判断 vip
+        
+        guard let upLoadImage = upLoadImage else { return }
+        let gennerateVC = TSAIListPhotoGeneratorBaseVC(generatorModel: TSAIListPhotoGeneratorModel(upLoadImage: upLoadImage, generatorStyle: .photoExpand,expandEdge: photoExpand)) { [weak self] model in
+            guard let self = self else { return }
+            saveModel(model: model)
+        }
+        
+        kPresentModalVC(target: self, modelVC: gennerateVC,transitionStyle: .crossDissolve)
+    }
+    
+    func saveModel(model:TSActionInfoModel){
+        TSAIPhotoExpandHistory.shared.saveModel(model: model)
+    }
+}

+ 92 - 0
AIEmoji/Business/TSAILIstVC/TSAIExpandImageVC/TSAIExpandImageVM.swift

@@ -0,0 +1,92 @@
+//
+//  TSAIExpandImageVM.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/22.
+//
+
+import ObjectMapper
+import Alamofire
+
+class TSAIExpandImageVM {
+    
+    // MARK: - 比例枚举
+    enum AspectRatio: Int {
+        case ratio1_1 = 0
+        case ratio16_9
+        case ratio9_16
+        case ratio4_3
+        case ratio3_4
+        case ratio2_3
+        case ratio3_2
+        
+        var value: CGFloat {
+            switch self {
+            case .ratio1_1: return 1.0
+            case .ratio16_9: return 16.0/9.0
+            case .ratio9_16: return 9.0/16.0
+            case .ratio4_3: return 4.0/3.0
+            case .ratio3_4: return 3.0/4.0
+            case .ratio2_3: return 2.0/3.0
+            case .ratio3_2: return 3.0/2.0
+            }
+        }
+        
+        var displayName: String {
+            switch self {
+            case .ratio1_1: return "1:1"
+            case .ratio16_9: return "16:9"
+            case .ratio9_16: return "9:16"
+            case .ratio4_3: return "4:3"
+            case .ratio3_4: return "3:4"
+            case .ratio2_3: return "2:3"
+            case .ratio3_2: return "3:2"
+            }
+        }
+        
+        static func creatAspectRatio(string:String)->AspectRatio{
+            switch string {
+            case "1:1": return .ratio1_1
+            case "16:9": return .ratio16_9
+            case "9:16": return .ratio9_16
+            case "4:3": return .ratio4_3
+            case "3:4": return .ratio3_4
+            case "2:3": return .ratio2_3
+            case "3:2": return .ratio3_2
+            default: return .ratio1_1
+            }
+        }
+    }
+
+    var currentRatio: AspectRatio{
+        if let selectStyleModel = selectStyleModel {
+            return AspectRatio.creatAspectRatio(string: selectStyleModel.imageText)
+        }
+        return AspectRatio.ratio1_1
+    }
+    
+    //###################################### 样式选择 ######################################
+    var selectedStyleIndex:Int = 1
+    lazy var selectStyleModels: [TSGenerateStyleModel] = {
+        var selectStyleModels = [TSGenerateStyleModel]()
+        if let dataArray = Mapper<TSGenerateStyleModel>().mapArray(JSONfile: "ai_expand_image_style.json"){
+            selectStyleModels = dataArray
+            
+            if let model = dataArray.safeObj(At: selectedStyleIndex) {
+                selectStyleModel = model //加上默认的选择
+            }
+        }
+        
+        return selectStyleModels
+    }()
+    
+    var selectStyleModel:TSGenerateStyleModel?
+    
+    
+    var upLoadImage:UIImage?{
+        didSet{
+        
+        }
+    }
+    
+}

+ 181 - 0
AIEmoji/Business/TSAILIstVC/TSAIExpandImageVC/TSAIExpandStyleView.swift

@@ -0,0 +1,181 @@
+//
+//  TSAIExpandStyleView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/21.
+//
+
+
+class TSAIExpandStyleView:TSBaseView {
+    
+    var selectedValueBlock:((TSGenerateStyleModel)->Void)?
+    
+    var dataArray: [TSGenerateStyleModel] = [TSGenerateStyleModel](){
+        didSet{
+            styleCollectionView.reloadData()
+            if dataArray.count > 0 {
+                self.styleCollectionView.selectItem(at: self.currentIndexPath, animated: false, scrollPosition: .centeredHorizontally)
+            }
+        }
+    }
+    
+    lazy var layout: UICollectionViewFlowLayout = {
+        let layout = UICollectionViewFlowLayout()
+        layout.scrollDirection = .horizontal
+        layout.itemSize = CGSize(width: 60, height: 52)
+        layout.minimumInteritemSpacing = 0.0
+//        layout.minimumLineSpacing = 0.0
+        layout.sectionInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
+        return layout
+    }()
+    
+    
+    lazy var styleCollectionView: 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(TSAIExpandStyleCell.self, forCellWithReuseIdentifier: TSAIExpandStyleCell.cellID)
+        if #available(iOS 11.0, *) {
+            collectionView.contentInsetAdjustmentBehavior = .never
+        }
+        return collectionView
+    }()
+    lazy var willSelectIndexPath = currentIndexPath
+    var currentIndexPath:IndexPath = IndexPath(item: 0, section: 0){
+        didSet{
+            for (i,model) in dataArray.enumerated(){
+                if i == currentIndexPath.item {
+                    model.isSelected = true
+                }else {
+                    model.isSelected = false
+                }
+            }
+            UIView.performWithoutAnimation {
+                self.styleCollectionView.reloadData()
+            }
+        }
+    }
+    
+    override func creatUI() {
+
+        currentIndexPath = IndexPath(item: 0, section: 0)
+        contentView.addSubview(styleCollectionView)
+        styleCollectionView.snp.makeConstraints { make in
+            make.top.equalTo(0)
+            make.leading.trailing.equalTo(0)
+            make.height.equalTo(0)
+            make.bottom.equalTo(0)
+        }
+    }
+    
+    func unCheck(){
+        styleCollectionView.deselectItem(at: currentIndexPath, animated: true)
+    }
+    
+    func agreeWillSelectIndexPath(){
+        currentIndexPath = willSelectIndexPath
+    }
+    
+}
+
+extension TSAIExpandStyleView: UICollectionViewDataSource ,UICollectionViewDelegate {
+    
+    public func numberOfSections(in collectionView: UICollectionView) -> Int {
+        return 1
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        return dataArray.count
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        
+        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TSAIExpandStyleCell.cellID, for: indexPath)
+        if let cell = cell as? TSAIExpandStyleCell,let itemModel = dataArray.safeObj(At: indexPath.item){
+            cell.itemModel = itemModel
+        }
+        return cell
+    }
+
+    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        if let model = dataArray.safeObj(At: indexPath.item){
+            willSelectIndexPath = indexPath
+            selectedValueBlock?(model)
+        }
+    }
+}
+
+class TSAIExpandStyleCell: TSBaseCollectionCell {
+    
+    static let cellID = "TSAIExpandStyleCell"
+
+    var itemModel:TSGenerateStyleModel = TSGenerateStyleModel(){
+        didSet{
+            
+            if let image = UIImage(named: itemModel.imageName)?.withRenderingMode(.alwaysTemplate) {
+                imageView.image = image
+            }
+//            vipImageView.isHidden = itemModel.isVip == false
+            textLabel.text = itemModel.imageText.localized
+            
+            if itemModel.isSelected {
+                textLabel.textColor = .themeColor
+                imageView.tintColor = .themeColor
+            }else{
+                textLabel.textColor = .white
+                imageView.tintColor = .white
+            }
+        }
+    }
+    
+    lazy var imageView: UIImageView = {
+        let imageView = UIImageView()
+        return imageView
+    }()
+    
+//    lazy var vipImageView: UIImageView = {
+//        let vipImageView = UIImageView.createImageView(imageName: "ai_emo_style_vip")
+//        vipImageView.isHidden = true
+//        return vipImageView
+//    }()
+
+    lazy var textLabel: UILabel = {
+        let textLabel = UILabel.createLabel(font: .font(size: 10,weight: .medium),textColor: .white,textAlignment: .center,numberOfLines: 2)
+        textLabel.adjustsFontSizeToFitWidth = true
+        textLabel.contentMode = .bottom
+        return textLabel
+    }()
+    
+    override func creatUI() {
+        //cell 100*110
+        bgContentView.addSubview(imageView)
+        imageView.snp.makeConstraints { make in
+            make.top.equalTo(0)
+            make.centerX.equalToSuperview()
+            make.width.equalTo(24)
+            make.height.equalTo(24)
+        }
+        
+//        imageView.addSubview(vipImageView)
+//        vipImageView.snp.makeConstraints { make in
+//            make.trailing.equalTo(0)
+//            make.top.equalTo(0.0)
+//            make.width.equalTo(18)
+//            make.height.equalTo(14)
+//        }
+        
+        bgContentView.addSubview(textLabel)
+        textLabel.snp.makeConstraints { make in
+            make.height.equalTo(16.0)
+//            make.top.greaterThanOrEqualTo(imageView.snp.bottom).offset(2)
+//            make.top.equalTo(imageView.snp.bottom).offset(2)
+            make.bottom.equalTo(0)
+            make.leading.trailing.equalToSuperview()
+        }
+    }
+    
+}
+

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

@@ -24,6 +24,24 @@ class TSAILIstVC: TSBaseVC {
                     kPushVC(target: self, modelVC: TSTextGeneralPictureVC())
         }))
         
+        sectionModel.addSubItemModel(
+            createItemModel(
+                leftImageName:"aiList_photoExpand",
+                leftTitle: "AI Expand Photo".localized,
+                leftSubTitle: "".localized,
+                rightViewStyle: 0,
+                tapBlock: { [weak self] model, _, _ in
+                   guard let self = self else { return }
+                    enterSelectPhotos(
+                        userDefaultsKey: "isFirstAIPhotoExpand",
+                        maxBitSize: kUploadImageMaxBit10Size,
+                         config:.getDefaultConfig(imageMaxBitSize: kUploadImageMaxBit10Size)
+                    ) { image in
+                        let baseVc = TSAIExpandImageVC(upLoadImage: image)
+                        kPushVC(target: self, modelVC: baseVc)
+                    }
+        }))
+        
         sectionModel.addSubItemModel(
             createItemModel(
                 leftImageName:"aiList_livePhoto",

+ 4 - 0
AIEmoji/Business/TSAILIstVC/TSAIListHistoryBaseVC/TSAIListHistoryBaseVM.swift

@@ -51,6 +51,8 @@ class TSAIListHistoryBaseVM {
             TSAIPhotoPrettyHistory.shared.removeALLModel()
         case .photoLive:
             TSAIPhotoLiveHistory.shared.removeALLModel()
+        case .photoExpand:
+            TSAIPhotoExpandHistory.shared.removeALLModel()
         }
         
         colDataArray.removeAll()
@@ -73,6 +75,8 @@ extension TSAIListHistoryBaseVM {
             TSAIPhotoPrettyHistory.shared.listModels
         case .photoLive:
             TSAIPhotoLiveHistory.shared.listModels
+        case .photoExpand:
+            TSAIPhotoExpandHistory.shared.listModels
         }
     }
 }

+ 26 - 25
AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIListPhotoGeneratorBaseVC.swift

@@ -5,15 +5,30 @@
 //  Created by 100Years on 2025/4/9.
 //
 
+struct TSAIListPhotoGeneratorModel {
+    var upLoadImage:UIImage
+    var generatorStyle:TSGeneratorImageStyle
+    var expandEdge:UIEdgeInsets
+    init(upLoadImage: UIImage, generatorStyle: TSGeneratorImageStyle,expandEdge:UIEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)) {
+        self.upLoadImage = upLoadImage
+        self.generatorStyle = generatorStyle
+        self.expandEdge = expandEdge
+    }
+}
+
 class TSAIListPhotoGeneratorBaseVC: TSAIPhotoGeneratorBaseVC {
+
+    init(generatorModel:TSAIListPhotoGeneratorModel,complete:@escaping ((TSActionInfoModel)->Void)) {
+        self.complete = complete
+        self.viewModel = TSAIListPhotoGeneratorBaseVM(generatorModel: generatorModel)
+        super.init()
+    }
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
     
     var imageModel:TSActionInfoModel?
     var complete:((TSActionInfoModel)->Void)
-    
-    var imageUrl:String?
-    var upLoadImage:UIImage
-    var generatorStyle:TSGeneratorImageStyle
-    
     var progressState = TSProgressState.none
     
     var isSavePhotoMark:Bool = false
@@ -24,23 +39,9 @@ class TSAIListPhotoGeneratorBaseVC: TSAIPhotoGeneratorBaseVC {
         return false
     }
     
-    init(upLoadImage:UIImage,generatorStyle:TSGeneratorImageStyle,complete:@escaping ((TSActionInfoModel)->Void)) {
-        self.upLoadImage = upLoadImage
-        self.generatorStyle = generatorStyle
-        self.complete = complete
-        
-        super.init()
-    }
-    
+    var viewModel: TSAIListPhotoGeneratorBaseVM!
     var videoPlayerVC: TSAIListVideoPlayerVC = TSAIListVideoPlayerVC(videoURL: URL(string: "www.baidu.com")!)
-    lazy var viewModel: TSAIListPhotoGeneratorBaseVM = {
-        let viewModel:TSAIListPhotoGeneratorBaseVM = TSAIListPhotoGeneratorBaseVM(upLoadImage: upLoadImage, generatorStyle: generatorStyle)
-        return viewModel
-    }()
-
-    @MainActor required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
+  
 
     lazy var generateInView : TSGeneratorloadingView = {
         let generateInView = TSGeneratorloadingView()
@@ -148,7 +149,7 @@ class TSAIListPhotoGeneratorBaseVC: TSAIPhotoGeneratorBaseVC {
     //保存功能
     @objc override func clickSaveBtn(){
     
-        if generatorStyle == .photoLive,let imageModel = imageModel {
+        if viewModel.generatorModel.generatorStyle == .photoLive,let imageModel = imageModel {
             TSDownloadManager.getDownLoadVideo(urlString: imageModel.response.resultUrl) { url, success in
                 if let url = url {
                     PhotoManagerShared.saveVideoToAlbum(videoURL: url) { [weak self] success, error in
@@ -277,7 +278,7 @@ extension TSAIListPhotoGeneratorBaseVC {
     }
     
     @objc func switchOriginalPictureTouchDown() {
-        self.netWorkImageView.image = upLoadImage
+        self.netWorkImageView.image = self.viewModel.generatorModel.upLoadImage
     }
     
     @objc func switchOriginalPictureTouchUp() {
@@ -286,14 +287,14 @@ extension TSAIListPhotoGeneratorBaseVC {
     }
     
     func setVideoHidden(){
-        if generatorStyle == .photoLive {
+        if viewModel.generatorModel.generatorStyle == .photoLive {
             videoPlayerVC.removeFromParent()
             videoPlayerVC.view.removeFromSuperview()
         }
     }
     
     func setVideoURL(){
-        if generatorStyle == .photoLive {
+        if viewModel.generatorModel.generatorStyle == .photoLive {
             if let model = imageModel {
                 switchOriginalPictureBtn.isHidden = true
                 self.videoPlayerVC = TSAIListVideoPlayerVC(videoURL: model.videoURL)

+ 26 - 16
AIEmoji/Business/TSAILIstVC/TSAIPhotoGeneratorBaseVC/TSAIPhotoGeneratorBaseVM/TSAIListPhotoGeneratorBaseVM.swift

@@ -33,11 +33,9 @@ class TSAIListPhotoGeneratorBaseVM {
     var generatingProgress = 0
     
     var imageUrl:String?
-    var upLoadImage:UIImage
-    var generatorStyle:TSGeneratorImageStyle
-    init(upLoadImage:UIImage,generatorStyle:TSGeneratorImageStyle) {
-        self.upLoadImage = upLoadImage
-        self.generatorStyle = generatorStyle
+    var generatorModel:TSAIListPhotoGeneratorModel
+    init(generatorModel:TSAIListPhotoGeneratorModel) {
+        self.generatorModel = generatorModel
     }
     
 //    //模拟数据
@@ -80,7 +78,7 @@ class TSAIListPhotoGeneratorBaseVM {
         stateDatauPblished = (.start,nil)
         
         stateDatauPblished = (.progressString(uploadingPhoto(progress: 0.0)),nil)
-        uploadRequest = TSNetworkShared.uploadImage(upLoadImage: upLoadImage, maxKb: imageMaxKb) { [weak self]  progress in
+        uploadRequest = TSNetworkShared.uploadImage(upLoadImage: generatorModel.upLoadImage, maxKb: imageMaxKb) { [weak self]  progress in
             guard let self = self else { return }
             if generatingProgress == 0 {
                 stateDatauPblished = (.progressString(uploadingPhoto(progress: progress)),nil)
@@ -108,7 +106,7 @@ class TSAIListPhotoGeneratorBaseVM {
         
         var urlType:TSNeURLType = .changeAge
         var postDict:[String:Any] = [:]
-        switch generatorStyle {
+        switch generatorModel.generatorStyle {
             case .ageOld:
             postDict = ["targetAge":70,
                         "imageUrl":imageUrl,
@@ -135,11 +133,21 @@ class TSAIListPhotoGeneratorBaseVM {
                         "level":1.0,
                         "device":getUserInfoJsonString()
                        ]
-        case .photoLive:
-            urlType = .photoAnimation
-            postDict = ["imageUrl":imageUrl,
-                        "device":getUserInfoJsonString()
-                       ]
+            case .photoLive:
+                urlType = .photoAnimation
+                postDict = ["imageUrl":imageUrl,
+                            "device":getUserInfoJsonString()
+                           ]
+            case .photoExpand:
+                urlType = .photoExpand
+                postDict = ["imageUrl":imageUrl,
+                            "prompt":"根据图片内容智能扩图",
+                            "device":getUserInfoJsonString(),
+                            "top":generatorModel.expandEdge.top,
+                            "left":generatorModel.expandEdge.left,
+                            "bottom":generatorModel.expandEdge.bottom,
+                            "right":generatorModel.expandEdge.right
+                           ]
         }
         creatRequest = TSNetworkShared.post(urlType: urlType,parameters: postDict) { [weak self] data,error in
             guard let self = self else { return }
@@ -164,7 +172,7 @@ class TSAIListPhotoGeneratorBaseVM {
                     switch genmojiModel.actionStatus {
                     case .success:
                         if let url = URL(string:genmojiModel.response.resultUrl) {
-                            if generatorStyle == .photoLive {
+                            if generatorModel.generatorStyle == .photoLive {
                                 downloadVideo(urlString: genmojiModel.response.resultUrl) { url in
                                     if let url = url {
                                         
@@ -243,7 +251,7 @@ class TSAIListPhotoGeneratorBaseVM {
     }
  
     var imageMaxKb:Int{
-        switch generatorStyle {
+        switch generatorModel.generatorStyle {
         case .ageOld:
             return 10*1024
         case .ageChild:
@@ -256,6 +264,8 @@ class TSAIListPhotoGeneratorBaseVM {
             return 5*1024
         case .photoLive:
             return 10*1024
+        case .photoExpand:
+            return 10*1024
         }
     }
     
@@ -283,10 +293,10 @@ class TSAIListPhotoGeneratorBaseVM {
     
     
     var generatingText:String{
-        if generatorStyle == .oldPhoto {
+        if generatorModel.generatorStyle == .oldPhoto {
             return "Restoring".localized
         }else
-        if generatorStyle == .pretty {
+        if generatorModel.generatorStyle == .pretty {
             return "Changing".localized
         }
         return "Generating".localized

+ 4 - 1
AIEmoji/Business/TSAILIstVC/TSAIUploadPhotoBaseVC/TSAIUploadPhotoBaseVC.swift

@@ -13,6 +13,7 @@ enum TSGeneratorImageStyle {
     case eyeOpen    //开眼
     case pretty     //变美
     case photoLive     //把照片变活
+    case photoExpand     //照片扩展
 }
 
 class TSAIUploadPhotoBaseVC: TSBaseVC {
@@ -267,7 +268,7 @@ extension TSAIUploadPhotoBaseVC {
         if kJudgeVip(externalBool: true, vc: self){ return } //判断 vip
         
         guard let upLoadImage = upLoadImage else { return }
-        let gennerateVC = TSAIListPhotoGeneratorBaseVC(upLoadImage: upLoadImage, generatorStyle: generatorStyle) { [weak self] model in
+        let gennerateVC = TSAIListPhotoGeneratorBaseVC(generatorModel: TSAIListPhotoGeneratorModel(upLoadImage: upLoadImage, generatorStyle: generatorStyle)){ [weak self] model in
             guard let self = self else { return }
             saveModel(model: model)
         }
@@ -289,6 +290,8 @@ extension TSAIUploadPhotoBaseVC {
             TSAIPhotoPrettyHistory.shared.saveModel(model: model)
         case .photoLive:
             TSAIPhotoLiveHistory.shared.saveModel(model: model)
+        case .photoExpand:
+            dePrint("photoExpand")
         }
     }
 

+ 1 - 1
AIEmoji/Common/NetworkManager/TSNetWork/TSNetWork+Business.swift

@@ -29,7 +29,7 @@ enum TSNeURLType:String {
     case eyeOpen = "/api/image/eye-open"          //睁眼
     case pretty = "/api/image/pretty"          //美容
     case photoAnimation = "/api/image/animation"          //照片变活
-    
+    case photoExpand = "/api/image/outpaint"          //照片扩展
     
     func getUrlString() -> String {
         if Locale.current.identifier.contains("_CN") {//中国区

+ 59 - 0
AIEmoji/Res/ai_expand_image_style.json

@@ -0,0 +1,59 @@
+[
+    {
+        "imageName": "ai_expand_change",
+        "imageText": "Change",
+        "prompt":"",
+        "style":"",
+        "clickType":2,
+        "isVip": false
+    },
+    {
+        "imageName": "ai_expand_1:1",
+        "imageText": "1:1",
+        "prompt":"",
+        "style":"",
+        "isVip": true
+    },
+    {
+        "imageName": "ai_expand_16:9",
+        "imageText": "16:9",
+        "prompt":"",
+        "style":"",
+        "isVip": true
+    },
+    {
+        "imageName": "ai_expand_9:16",
+        "imageText": "9:16",
+        "prompt":"",
+        "style":"",
+        "isVip": true
+    },
+    {
+        "imageName": "ai_expand_4:3",
+        "imageText": "4:3",
+        "prompt":"",
+        "style":"",
+        "isVip": true
+    },
+    {
+        "imageName": "ai_expand_3:4",
+        "imageText": "3:4",
+        "prompt":"",
+        "style":"",
+        "isVip": true
+    },
+    {
+        "imageName": "ai_expand_2:3",
+        "imageText": "2:3",
+        "prompt":"",
+        "style":"",
+        "isVip": true
+    },
+    {
+        "imageName": "ai_expand_3:2",
+        "imageText": "3:2",
+        "prompt":"",
+        "style":"",
+        "isVip": true
+    }
+]