Jelajahi Sumber

3.0.0(1)打包

100Years 1 Minggu lalu
induk
melakukan
f4dde1ad07
52 mengubah file dengan 2275 tambahan dan 101 penghapusan
  1. 67 4
      AIEmoji.xcodeproj/project.pbxproj
  2. 22 0
      AIEmoji/Assets.xcassets/PTP/ptp_badImage.imageset/Contents.json
  3. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/PTP/ptp_badImage.imageset/ptp_badImage@2x.png
  4. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/PTP/ptp_badImage.imageset/ptp_badImage@3x.png
  5. 22 0
      AIEmoji/Assets.xcassets/PTP/ptp_goodImage.imageset/Contents.json
  6. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/PTP/ptp_goodImage.imageset/ptp_goodImage.png
  7. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/PTP/ptp_goodImage.imageset/ptp_goodImage@3x.png
  8. 22 0
      AIEmoji/Assets.xcassets/PTP/ptp_hint.imageset/Contents.json
  9. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/PTP/ptp_hint.imageset/ptp_hint@2x.png
  10. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/PTP/ptp_hint.imageset/ptp_hint@3x.png
  11. 22 0
      AIEmoji/Assets.xcassets/PTP/style/ptp_style_none.imageset/Contents.json
  12. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/PTP/style/ptp_style_none.imageset/ptp_style_none@2x.png
  13. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/PTP/style/ptp_style_none.imageset/ptp_style_none@3x.png
  14. 17 0
      AIEmoji/Assets.xcassets/boot/bootPage_2.imageset/Contents.json
  15. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/boot/bootPage_2.imageset/bootPage_2-zh-Hans@2x 1.png
  16. TEMPAT SAMPAH
      AIEmoji/Assets.xcassets/boot/bootPage_2.imageset/bootPage_2-zh-Hans@3x 1.png
  17. 176 0
      AIEmoji/Business/Data/TSUserDefaultData.swift
  18. 1 1
      AIEmoji/Business/TSGenmojiVC/TSGenmojiGennerateVC/TSGenmojiGennerateViewModel.swift
  19. 4 2
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPGeneratorVC/TSPTPGeneratorVC.swift
  20. 9 3
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPGeneratorVC/VM/TSPTPGeneratorVM.swift
  21. 138 0
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPImageHintVC/TSPTPImageHintVC.swift
  22. 630 0
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC.swift
  23. 184 0
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/VM/TSPTPInputVM.swift
  24. 173 0
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/View/TSPTPSelectStyleView.swift
  25. 144 0
      AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/View/TSPTPUploadView.swift
  26. 1 1
      AIEmoji/Business/TSPTPGeneratorVC/TSPhotoToPhotoVC/Cell/TSPTPSelectStyleCell.swift
  27. 3 1
      AIEmoji/Business/TSPTPGeneratorVC/TSPhotoToPhotoVC/M/TSPTPStyleModel.swift
  28. 5 5
      AIEmoji/Business/TSPTPGeneratorVC/TSPhotoToPhotoVC/TSPhotoToPhotoVC.swift
  29. 3 1
      AIEmoji/Business/TSTabBarController/TSTabBarController.swift
  30. 6 1
      AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/TSTTPInputVC.swift
  31. 3 5
      AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/VM/TSTTPInputVM.swift
  32. 1 1
      AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/View/TSTTPStyleView.swift
  33. 29 3
      AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/View/TSTitleView.swift
  34. 5 3
      AIEmoji/Business/TSTextGeneralPictureVC/TSTextPicGennerateVC/TSTextPicGennerateVC.swift
  35. 4 2
      AIEmoji/Business/TSTextGeneralPictureVC/TSTextPicGennerateVC/TSTextPicGennerateVM.swift
  36. 0 6
      AIEmoji/Common/GlobalImports/GlobalImports.swift
  37. 394 0
      AIEmoji/Common/Tool/CpuMapManager.swift
  38. 1 1
      AIEmoji/Res/photo_to_photo_style.json
  39. 2 2
      AIEmoji/Res/text_to_photo_style.json
  40. 7 0
      AIEmoji/de.lproj/Localizable.strings
  41. 7 0
      AIEmoji/en.lproj/Localizable.strings
  42. 7 0
      AIEmoji/es.lproj/Localizable.strings
  43. 7 0
      AIEmoji/ja.lproj/Localizable.strings
  44. 7 0
      AIEmoji/ko.lproj/Localizable.strings
  45. 7 0
      AIEmoji/pt-BR.lproj/Localizable.strings
  46. 7 0
      AIEmoji/pt-PT.lproj/Localizable.strings
  47. 7 0
      AIEmoji/zh-Hans.lproj/Localizable.strings
  48. 10 0
      AIEmoji/zh-Hant.lproj/InfoPlist.strings
  49. 1 0
      AIEmoji/zh-Hant.lproj/LaunchScreen.strings
  50. 118 0
      AIEmoji/zh-Hant.lproj/Localizable.strings
  51. 1 1
      Podfile
  52. 1 58
      Podfile.lock

+ 67 - 4
AIEmoji.xcodeproj/project.pbxproj

@@ -149,6 +149,12 @@
 		A89EA6CC2D642CE2000EB181 /* TSChatViewController+NaviBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6CB2D642CD4000EB181 /* TSChatViewController+NaviBar.swift */; };
 		A89EA6CF2D6430F3000EB181 /* TSChatViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = A89EA6CE2D6430EE000EB181 /* TSChatViewController+Keyboard.swift */; };
 		A8BA763C2DA4C225000B6707 /* SwiftUIX in Frameworks */ = {isa = PBXBuildFile; productRef = A8BA763B2DA4C225000B6707 /* SwiftUIX */; };
+		A8BA763F2DA4C908000B6707 /* TSPTPInputVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA763E2DA4C906000B6707 /* TSPTPInputVC.swift */; };
+		A8BA76422DA4C924000B6707 /* TSPTPInputVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76412DA4C920000B6707 /* TSPTPInputVM.swift */; };
+		A8BA76452DA4CB9A000B6707 /* TSPTPUploadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76442DA4CB99000B6707 /* TSPTPUploadView.swift */; };
+		A8BA76472DA4CC70000B6707 /* TSPTPSelectStyleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76462DA4CC6C000B6707 /* TSPTPSelectStyleView.swift */; };
+		A8BA764F2DA50B52000B6707 /* CpuMapManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA764E2DA50B52000B6707 /* CpuMapManager.swift */; };
+		A8BA76522DA51600000B6707 /* TSPTPImageHintVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BA76512DA515FF000B6707 /* TSPTPImageHintVC.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 */; };
@@ -371,6 +377,15 @@
 		A89EA6C92D642C03000EB181 /* TSChatViewController+SendMsg.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSChatViewController+SendMsg.swift"; sourceTree = "<group>"; };
 		A89EA6CB2D642CD4000EB181 /* TSChatViewController+NaviBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSChatViewController+NaviBar.swift"; sourceTree = "<group>"; };
 		A89EA6CE2D6430EE000EB181 /* TSChatViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSChatViewController+Keyboard.swift"; sourceTree = "<group>"; };
+		A8BA763E2DA4C906000B6707 /* TSPTPInputVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPInputVC.swift; sourceTree = "<group>"; };
+		A8BA76412DA4C920000B6707 /* TSPTPInputVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPInputVM.swift; sourceTree = "<group>"; };
+		A8BA76442DA4CB99000B6707 /* TSPTPUploadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPUploadView.swift; sourceTree = "<group>"; };
+		A8BA76462DA4CC6C000B6707 /* TSPTPSelectStyleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPSelectStyleView.swift; sourceTree = "<group>"; };
+		A8BA764A2DA4F689000B6707 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/LaunchScreen.strings"; sourceTree = "<group>"; };
+		A8BA764B2DA4F689000B6707 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
+		A8BA764C2DA4F689000B6707 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
+		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>"; };
 		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>"; };
@@ -928,6 +943,8 @@
 		A80EDDDC2D6EB17D003CD332 /* TSPTPGeneratorVC */ = {
 			isa = PBXGroup;
 			children = (
+				A8BA76502DA515F9000B6707 /* TSPTPImageHintVC */,
+				A8BA763D2DA4C8F9000B6707 /* TSPTPInputVC */,
 				A83404CF2D9D16E400C140E4 /* TSAIPhotoGeneratorBaseVC */,
 				A80EDE042D6F3429003CD332 /* TSPTPBrowseVC */,
 				A80EDDE92D6EBFF1003CD332 /* TSPhotoToPhotoVC */,
@@ -1234,6 +1251,41 @@
 			path = TSChatViewController;
 			sourceTree = "<group>";
 		};
+		A8BA763D2DA4C8F9000B6707 /* TSPTPInputVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA76432DA4C927000B6707 /* View */,
+				A8BA76402DA4C918000B6707 /* VM */,
+				A8BA763E2DA4C906000B6707 /* TSPTPInputVC.swift */,
+			);
+			path = TSPTPInputVC;
+			sourceTree = "<group>";
+		};
+		A8BA76402DA4C918000B6707 /* VM */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA76412DA4C920000B6707 /* TSPTPInputVM.swift */,
+			);
+			path = VM;
+			sourceTree = "<group>";
+		};
+		A8BA76432DA4C927000B6707 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA76462DA4CC6C000B6707 /* TSPTPSelectStyleView.swift */,
+				A8BA76442DA4CB99000B6707 /* TSPTPUploadView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
+		A8BA76502DA515F9000B6707 /* TSPTPImageHintVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8BA76512DA515FF000B6707 /* TSPTPImageHintVC.swift */,
+			);
+			path = TSPTPImageHintVC;
+			sourceTree = "<group>";
+		};
 		A8F774602D38E8B000AA6E93 = {
 			isa = PBXGroup;
 			children = (
@@ -1324,6 +1376,7 @@
 		A8F774CE2D38EA8C00AA6E93 /* Tool */ = {
 			isa = PBXGroup;
 			children = (
+				A8BA764E2DA50B52000B6707 /* CpuMapManager.swift */,
 				A85E479E2D6859F80018D62D /* TSRandomTextPicker.swift */,
 				A8F774C82D38EA8C00AA6E93 /* TSCommonTool */,
 				A8F774CA2D38EA8C00AA6E93 /* TSFileManagerTool.swift */,
@@ -1698,6 +1751,7 @@
 				"pt-PT",
 				ja,
 				de,
+				"zh-Hant",
 			);
 			mainGroup = A8F774602D38E8B000AA6E93;
 			minimizedProjectReferenceProxies = 1;
@@ -1815,6 +1869,7 @@
 				A80E726A2D409E5400C64288 /* TSDiyTLYFlowersView.swift in Sources */,
 				A8F7764E2D3E00A800AA6E93 /* TSEmojisColViewModel.swift in Sources */,
 				A89EA6C82D6359ED000EB181 /* TSChatViewController+VipView.swift in Sources */,
+				A8BA763F2DA4C908000B6707 /* TSPTPInputVC.swift in Sources */,
 				A8F776422D3B75FC00AA6E93 /* TSBottomAlertVC.swift in Sources */,
 				A8F775192D38EC6800AA6E93 /* TSEmojisVC.swift in Sources */,
 				A80E725C2D3FB09400C64288 /* TSKeyboardView.swift in Sources */,
@@ -1856,6 +1911,7 @@
 				A80EDD5A2D6C3F82003CD332 /* MarkdownParser.swift in Sources */,
 				A80EDD5B2D6C3F82003CD332 /* MarkdownCommonElement.swift in Sources */,
 				A80EDD682D6C5098003CD332 /* TSChatMsgBaseView.swift in Sources */,
+				A8BA764F2DA50B52000B6707 /* CpuMapManager.swift in Sources */,
 				A80EDD5C2D6C3F82003CD332 /* MarkdownList.swift in Sources */,
 				A80EDD5D2D6C3F82003CD332 /* MarkdownCodeEscaping.swift in Sources */,
 				A80EDD5E2D6C3F82003CD332 /* MarkdownLinkElement.swift in Sources */,
@@ -1912,7 +1968,9 @@
 				A83404D12D9D16FA00C140E4 /* TSAIPhotoGeneratorBaseVC.swift in Sources */,
 				A80327BF2D81578900AF7878 /* TSPromptTextView.swift in Sources */,
 				A80EDE022D6F1CCD003CD332 /* TSPTPGeneratorVC.swift in Sources */,
+				A8BA76452DA4CB9A000B6707 /* TSPTPUploadView.swift in Sources */,
 				A85E479F2D6859FA0018D62D /* TSRandomTextPicker.swift in Sources */,
+				A8BA76522DA51600000B6707 /* TSPTPImageHintVC.swift in Sources */,
 				A80E72262D3F3A9A00C64288 /* HYHAddImageView.m in Sources */,
 				A80E72272D3F3A9A00C64288 /* DiyTextElement.swift in Sources */,
 				A8FB02BA2D3E3BB20031A396 /* TSEmojisCoLItemCell.swift in Sources */,
@@ -1933,7 +1991,9 @@
 				A83404D52D9D28D700C140E4 /* TSAIPhotoBrowseVC.swift in Sources */,
 				A89EA66C2D59AA31000EB181 /* TSMessageContentCell.swift in Sources */,
 				A87587122D81702700286A66 /* TSUserDefaultData.swift in Sources */,
+				A8BA76422DA4C924000B6707 /* TSPTPInputVM.swift in Sources */,
 				A89EA66D2D59AA31000EB181 /* TableViewCells.swift in Sources */,
+				A8BA76472DA4CC70000B6707 /* TSPTPSelectStyleView.swift in Sources */,
 				A8F7750A2D38EA8C00AA6E93 /* TSNetworkTool.swift in Sources */,
 				A8F7762D2D3A74A100AA6E93 /* TSGenmojiGennerateCell.swift in Sources */,
 				A89EA6BC2D5DFB12000EB181 /* TSViewController.swift in Sources */,
@@ -1978,6 +2038,7 @@
 				A83405142DA3826600C140E4 /* pt-PT */,
 				A83405172DA3827C00C140E4 /* ja */,
 				A834051A2DA3828E00C140E4 /* de */,
+				A8BA764C2DA4F689000B6707 /* zh-Hant */,
 			);
 			name = Localizable.strings;
 			sourceTree = "<group>";
@@ -1993,6 +2054,7 @@
 				A83405132DA3826600C140E4 /* pt-PT */,
 				A83405162DA3827C00C140E4 /* ja */,
 				A83405192DA3828E00C140E4 /* de */,
+				A8BA764B2DA4F689000B6707 /* zh-Hant */,
 			);
 			name = InfoPlist.strings;
 			sourceTree = "<group>";
@@ -2008,6 +2070,7 @@
 				A83405122DA3826600C140E4 /* pt-PT */,
 				A83405152DA3827C00C140E4 /* ja */,
 				A83405182DA3828E00C140E4 /* de */,
+				A8BA764A2DA4F689000B6707 /* zh-Hant */,
 			);
 			name = LaunchScreen.storyboard;
 			sourceTree = "<group>";
@@ -2023,7 +2086,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 3;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -2039,7 +2102,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 2.9;
+				MARKETING_VERSION = 3.0;
 				PRODUCT_BUNDLE_IDENTIFIER = com.girl.music.wallpaper;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
@@ -2062,7 +2125,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 3;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -2078,7 +2141,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 2.9;
+				MARKETING_VERSION = 3.0;
 				PRODUCT_BUNDLE_IDENTIFIER = com.girl.music.wallpaper;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";

+ 22 - 0
AIEmoji/Assets.xcassets/PTP/ptp_badImage.imageset/Contents.json

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

TEMPAT SAMPAH
AIEmoji/Assets.xcassets/PTP/ptp_badImage.imageset/ptp_badImage@2x.png


TEMPAT SAMPAH
AIEmoji/Assets.xcassets/PTP/ptp_badImage.imageset/ptp_badImage@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/PTP/ptp_goodImage.imageset/Contents.json

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

TEMPAT SAMPAH
AIEmoji/Assets.xcassets/PTP/ptp_goodImage.imageset/ptp_goodImage.png


TEMPAT SAMPAH
AIEmoji/Assets.xcassets/PTP/ptp_goodImage.imageset/ptp_goodImage@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/PTP/ptp_hint.imageset/Contents.json

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

TEMPAT SAMPAH
AIEmoji/Assets.xcassets/PTP/ptp_hint.imageset/ptp_hint@2x.png


TEMPAT SAMPAH
AIEmoji/Assets.xcassets/PTP/ptp_hint.imageset/ptp_hint@3x.png


+ 22 - 0
AIEmoji/Assets.xcassets/PTP/style/ptp_style_none.imageset/Contents.json

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

TEMPAT SAMPAH
AIEmoji/Assets.xcassets/PTP/style/ptp_style_none.imageset/ptp_style_none@2x.png


TEMPAT SAMPAH
AIEmoji/Assets.xcassets/PTP/style/ptp_style_none.imageset/ptp_style_none@3x.png


+ 17 - 0
AIEmoji/Assets.xcassets/boot/bootPage_2.imageset/Contents.json

@@ -30,6 +30,23 @@
       "idiom" : "universal",
       "locale" : "zh-Hans",
       "scale" : "3x"
+    },
+    {
+      "idiom" : "universal",
+      "locale" : "zh-Hant",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "bootPage_2-zh-Hans@2x 1.png",
+      "idiom" : "universal",
+      "locale" : "zh-Hant",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "bootPage_2-zh-Hans@3x 1.png",
+      "idiom" : "universal",
+      "locale" : "zh-Hant",
+      "scale" : "3x"
     }
   ],
   "info" : {

TEMPAT SAMPAH
AIEmoji/Assets.xcassets/boot/bootPage_2.imageset/bootPage_2-zh-Hans@2x 1.png


TEMPAT SAMPAH
AIEmoji/Assets.xcassets/boot/bootPage_2.imageset/bootPage_2-zh-Hans@3x 1.png


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

@@ -6,6 +6,181 @@
 //
 import ObjectMapper
 
+func getUserInfoJsonString()->String {
+    let uuid: String
+    let uuidUdKey = "my_UUID"
+    if let saved = UserDefaults.standard.string(forKey: uuidUdKey),
+       !saved.isEmpty {
+        uuid = saved
+    } else {
+        let newUuid = UUID().uuidString
+        UserDefaults.standard.set(newUuid, forKey: uuidUdKey)
+        UserDefaults.standard.synchronize()
+        uuid = newUuid
+    }
+    
+    let dic:[String:Any] = [
+        "device":UIDevice.current.modelName,
+        "deviceId":uuid,
+        "iosVersion":UIDevice.current.systemVersion,
+        "appVersion":appShortVersion(),
+        "subscriptionStatus":kPurchaseDefault.isVip ? "active" : "fallow",
+    ]
+    
+    if let jSONString = dic.toJSONString() {
+        return jSONString
+    }
+    
+    return ""
+}
+
+func kHandleTSHistory(){
+
+    
+}
+
+// MARK: - 基础历史记录类
+class TSBaseHistoryManager<ModelType: TSBaseModel> {
+    // 子类必须重写的属性
+    var historyKey: String { fatalError("必须重写 historyKey") }
+    var exampleDataKey: String { fatalError("必须重写 exampleDataKey") }
+    var exampleModels: [ModelType] { fatalError("必须重写 exampleModels") }
+
+    func findModelID(modelID: Int)->Int?{
+        fatalError("必须重写 findModelID")
+    }
+
+    func saveModelAfterProcess(){
+        
+    }
+    
+    // 存储属性
+    private var _historyString: String {
+        get { UserDefaults.standard.string(forKey: historyKey) ?? "" }
+        set { UserDefaults.standard.set(newValue, forKey: historyKey) }
+    }
+    
+    private var _listModels: [ModelType]?
+    var listModels: [ModelType] {
+        get {
+            if _listModels == nil { loadModels() }
+            return _listModels ?? []
+        }
+        set {
+            _listModels = newValue
+        }
+    }
+    
+    // MARK: - 公共方法
+    func saveModel(model: ModelType, at index: Int = 0) {
+        listModels.insert(model, at: index)
+        saveHistory()
+        saveModelAfterProcess()
+    }
+    
+    func removeModel(model:ModelType) {
+        self.listModels.removeAll { $0 === model }
+        saveHistory()
+    }
+    
+    func removeModel(index: Int) {
+        guard index >= 0 && index < listModels.count else { return }
+        listModels.remove(at: index)
+        saveHistory()
+    }
+    
+    func replaceModel(oldID: Int, newModel: ModelType){
+        if let index = findModelID(modelID: oldID) {
+            listModels[index] = newModel
+            dePrint("\(Self.self).listModels Model replaced at index \(index)")
+        } else {
+            listModels.insert(newModel, at: 0)
+            dePrint("\(Self.self).listModels Model not found")
+        }
+        dePrint("\(Self.self).listModels.count=\(listModels.count)")
+        saveHistory()
+    }
+    
+    func replaceAndSaveModel(saveModel:ModelType,compareBlock:(ModelType,ModelType)->Bool){
+        if let index = listModels.firstIndex(where: { model in
+            compareBlock(saveModel,model)
+        }){
+            dePrint("\(Self.self).listModels Model replaced at index \(index)")
+           listModels[index] = saveModel
+            saveHistory()
+        }else{
+            self.saveModel(model: saveModel)
+        }
+    }
+    
+    func dePrintAllModel() {
+        dePrint("=======================结果查询开始======================")
+        dePrint("\(Self.self).listModels.count=\(listModels.count)")
+        for model in listModels {
+            dePrint(model.toJSON())
+        }
+        dePrint("=======================结果查询结束======================")
+    }
+    
+    // MARK: - 私有方法
+    private func saveHistory() {
+        if let jsonString = listModels.toJSONString() {
+            _historyString = jsonString
+        }
+    }
+    
+    private func loadModels() {
+        if exampleModels.count > 0 {
+            // 第一次运行时插入示例数据
+            if UserDefaults.standard.string(forKey: exampleDataKey) == nil {
+                insertExampleData()
+                UserDefaults.standard.set("1", forKey: exampleDataKey)
+            }
+        }
+
+        // 从历史记录加载模型
+        if let models = Mapper<ModelType>().mapArray(JSONString: _historyString) {
+            _listModels = models
+        } else {
+            _listModels = []
+        }
+    }
+    
+    private func insertExampleData() {
+        if let jsonString = exampleModels.toJSONString() {
+            _historyString = jsonString
+        }
+    }
+}
+
+// MARK: - 海报历史记录
+final class TSPosterHistory: TSBaseHistoryManager<TSGenmojiModel> {
+    static let shared = TSPosterHistory()
+    override var historyKey: String { "kPosterTextPicHistoryListString" }
+    override var exampleDataKey: String { "insertPosterExampleData" }
+    
+    override func findModelID(modelID: Int) -> Int? {
+        return listModels.firstIndex(where: {$0.id == modelID})
+    }
+    
+    override var exampleModels: [TSGenmojiModel] {
+        [
+            createExampleModel(imageName: "poster_example_0"),
+            createExampleModel(imageName: "poster_example_1"),
+            createExampleModel(imageName: "poster_example_2")
+        ]
+    }
+    
+    private func createExampleModel(imageName: String) -> TSGenmojiModel {
+        let model = TSGenmojiModel()
+        model.modelType = .example
+        model.request.prompt = "Example"
+        model.request.promptSort = "Example"
+        model.response.resultUrl = imageName
+        return model
+    }
+}
+
 
 //海报历史记录
 class TSTextToPicHistory{
@@ -73,3 +248,4 @@ class TSTextToPicHistory{
 //        return model
 //    }
 }
+

+ 1 - 1
AIEmoji/Business/TSGenmojiVC/TSGenmojiGennerateVC/TSGenmojiGennerateViewModel.swift

@@ -110,7 +110,7 @@ class TSGenmojiGennerateViewModel {
         generatingProgress = 0
         stateDatauPblished = (.start,nil)
         stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
-        creatRequest = TSNetworkShared.post(urlType: .imageEmoji,parameters: ["prompt":text]) { [weak self] data,error in
+        creatRequest = TSNetworkShared.post(urlType: .imageEmoji,parameters: ["prompt":text,"device":getUserInfoJsonString()]) { [weak self] data,error in
             guard let self = self else { return }
             
             if let dataDict = data as? [String:Any] ,

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

@@ -14,18 +14,20 @@ class TSPTPGeneratorVC: TSAIPhotoGeneratorBaseVC {
     var promptSort:String
     var imageUrl:String
     var upLoadImage:UIImage
+    var style:String
     var progressState = TSProgressState.none
-    init(prompt:String,promptSort:String,imageUrl:String,upLoadImage:UIImage,complete:@escaping ((TSGenmojiModel)->Void)) {
+    init(prompt:String,promptSort:String,imageUrl:String,upLoadImage:UIImage,style:String,complete:@escaping ((TSGenmojiModel)->Void)) {
         self.prompt = prompt
         self.promptSort = promptSort
         self.imageUrl = imageUrl
         self.upLoadImage = upLoadImage
+        self.style = style
         self.complete = complete
         super.init()
     }
     
     lazy var viewModel: TSPTPGeneratorVM = {
-        let viewModel:TSPTPGeneratorVM = TSPTPGeneratorVM(prompt: prompt,upLoadImage:upLoadImage)
+        let viewModel:TSPTPGeneratorVM = TSPTPGeneratorVM(prompt: prompt,upLoadImage:upLoadImage,style: style)
         return viewModel
     }()
 

+ 9 - 3
AIEmoji/Business/TSPTPGeneratorVC/TSPTPGeneratorVC/VM/TSPTPGeneratorVM.swift

@@ -44,11 +44,12 @@ class TSPTPGeneratorVM {
     var prompt:String
     var imageUrl:String?
     var upLoadImage:UIImage
-    
+    var style:String
     var generatingProgress = 0
-    init(prompt:String,upLoadImage:UIImage) {
+    init(prompt:String,upLoadImage:UIImage,style:String) {
         self.prompt = prompt
         self.upLoadImage = upLoadImage
+        self.style = style
     }
     
 //    //模拟数据
@@ -87,7 +88,12 @@ class TSPTPGeneratorVM {
         stopNetwork = false
         stateDatauPblished = (.start,nil)
         stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
-        creatRequest = TSNetworkShared.post(urlType: .imageRewrite,parameters: ["prompt":prompt,"imageUrl":imageUrl]) { [weak self] data,error in
+        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] ,

+ 138 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPImageHintVC/TSPTPImageHintVC.swift

@@ -0,0 +1,138 @@
+//
+//  TSPTPImageHintVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/8.
+//
+
+class TSPTPImageHintVC: TSBaseVC {
+    
+    
+    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
+    }()
+    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,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: "ptp_goodImage")
+        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,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: "ptp_badImage")
+        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)
+            make.bottom.equalTo(-24)
+        }
+        
+//        let okBtn = UIButton.createButton(title: "Upload Photo".localized,backgroundColor: .white.withAlphaComponent(0.4),titleColor: .white,corner: 24){ [weak self]  in
+//            guard let self = self else { return }
+//            
+//            dismiss()
+//        }
+//        popupContentView.addSubview(okBtn)
+//        okBtn.snp.makeConstraints { make in
+//            make.top.equalTo(badImageView.snp.bottom).offset(35)
+//            make.centerX.equalToSuperview()
+//            make.width.equalTo(250*kDesignScale)
+//            make.height.equalTo(48*kDesignScale)
+//            make.bottom.equalTo(-24)
+//        }
+        
+    }
+    
+}

+ 630 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/TSPTPInputVC.swift

@@ -0,0 +1,630 @@
+//
+//  TSPTPInputVC.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/7.
+//
+
+//import IQKeyboardManagerSwift
+
+class TSPTPInputVC: TSBaseVC {
+
+    lazy var viewModel: TSPTPInputVM = {
+        let viewModel = TSPTPInputVM()
+        viewModel.isCanGennerateBlock = { [weak self] isCan in
+            guard let self = self else { return }
+            submitBtn.isEnabled = isCan
+        }
+        return viewModel
+    }()
+    
+    lazy var photoPickerManager: TSPhotoPickerManager = {
+        let photoPickerManager = TSPhotoPickerManager(viewController: self)
+        return photoPickerManager
+    }()
+    
+    //###################################### 导航栏 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
+   }()
+    
+    //###################################### cusStackView ######################################
+    lazy var cusStackView: TSCustomStackView = {
+        let cusStackView = TSCustomStackView(axis: .vertical,spacing: 0)
+        cusStackView.scrollView.isScrollEnabled = false
+        return cusStackView
+    }()
+    
+    //###################################### 入口 view ######################################
+
+    let bannerY:CGFloat = 17
+    let bannerW:CGFloat = 166*kDesignScale
+    let bannerH:CGFloat = 117*kDesignScale
+    lazy var textToPhotoBannerBtn: UIButton = {
+        let textToPhotoBannerBtn = UIButton.createButton(backgroundImage: UIImage(named: "textToPhoto_banner"))
+        textToPhotoBannerBtn.addTarget(self, action: #selector(clickTextToPhoto), for: .touchUpInside)
+        textToPhotoBannerBtn.frame = CGRect(x: 16, y: bannerY, width: bannerW, height: bannerH)
+    
+        let label = UILabel.createLabel(text: "Text ➡️ Photo".localized,font: .font(name:.PoppinsBlackItalic,size: 16),textColor: .white)
+        textToPhotoBannerBtn.addSubview(label)
+        label.snp.makeConstraints { make in
+            make.top.equalTo(12)
+            make.leading.equalTo(8)
+            make.height.equalTo(24)
+        }
+        
+        let button = UIButton.createButton(title:"Try Now".localized,backgroundColor:.white,font: .font(size: 11),titleColor: "#ED69AA".uiColor,corner: 9)
+        button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 6, bottom: 0, right: 6)
+        textToPhotoBannerBtn.addSubview(button)
+        button.snp.makeConstraints { make in
+            make.top.equalTo(44)
+            make.leading.equalTo(8)
+            make.height.equalTo(18)
+        }
+        
+        return textToPhotoBannerBtn
+    }()
+
+    lazy var textToEmojiBannerBtn: UIButton = {
+        let textToEmojiBannerBtn = UIButton.createButton(backgroundImage: UIImage(named: "textToEmoji_banner"))
+        textToEmojiBannerBtn.addTarget(self, action: #selector(clickTextToEmoji), for: .touchUpInside)
+        let x = textToPhotoBannerBtn.x + textToPhotoBannerBtn.width + 11.0
+        textToEmojiBannerBtn.frame = CGRect(x: x, y: bannerY, width: bannerW, height: bannerH)
+        
+        let color:UIColor = "#7855D6".uiColor
+        let label = UILabel.createLabel(text: "Text ➡️ Emoji".localized,font: .font(name:.PoppinsBlackItalic,size: 16),textColor: color)
+        textToEmojiBannerBtn.addSubview(label)
+        label.snp.makeConstraints { make in
+            make.top.equalTo(12)
+            make.leading.equalTo(8)
+            make.height.equalTo(24)
+        }
+        
+        let button = UIButton.createButton(title:"Try Now".localized,backgroundColor:color,font: .font(size: 11),titleColor: "#D0D5FF".uiColor,corner: 9)
+        button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 6, bottom: 0, right: 6)
+        textToEmojiBannerBtn.addSubview(button)
+        button.snp.makeConstraints { make in
+            make.top.equalTo(44)
+            make.leading.equalTo(8)
+            make.height.equalTo(18)
+        }
+        
+        return textToEmojiBannerBtn
+    }()
+    
+    
+    lazy var entranceView: UIView = {
+        let entranceView = UIView()
+        entranceView.addSubview(textToPhotoBannerBtn)
+        entranceView.addSubview(textToEmojiBannerBtn)
+        return entranceView
+    }()
+    
+    //###################################### 上传图片 ######################################
+    lazy var uploadView: TSPTPUploadView = {
+        let uploadView = TSPTPUploadView()
+        uploadView.clickHandel = { [weak self] index in
+            guard let self = self else { return }
+            
+            if index == 0 {//删除
+                viewModel.upLoadImage = nil
+                uploadView.upLoadImage = nil
+            }else{//添加
+                
+                if UserDefaults.standard.string(forKey: "isFirstUploadImagePTP") == nil {
+                    UserDefaults.standard.set("1", forKey: "isFirstUploadImagePTP")
+                    UserDefaults.standard.synchronize()
+                    presentModalHintVC()
+                }else {
+                    pickSinglePhoto()
+                }
+            }
+        }
+        return uploadView
+    }()
+    
+    
+    func pickSinglePhoto()  {
+        photoPickerManager.pickSinglePhoto { [weak self] image,phAsset in
+            guard let self = self else { return }
+
+            let maxSize = 10 * 1024 * 1024
+            
+            if let image = image,let phAsset = phAsset {
+                // 方法2:异步获取详细大小(不阻塞主线程)
+                TSPhotoSizeHelper.getImageFileSizeAsync(asset: phAsset) {[weak self] size in
+                    guard let self = self else { return }
+                    
+                    let mbSize = Double(size) / (1024 * 1024)
+                    print("精确大小: \(mbSize) MB,size = \(size)")
+                    if size > maxSize {
+                        TSToastShared.showToast(text: "Photo must be smaller than 10MB.".localized)
+                    }else{
+                        viewModel.upLoadImage = image
+                        uploadView.upLoadImage = image
+                    }
+                }
+            }else if let image = image {
+                if image.isLargerThan(byteSize: maxSize) {
+                    TSToastShared.showToast(text: "Photo must be smaller than 10MB.".localized)
+                }else{
+                    viewModel.upLoadImage = image
+                    uploadView.upLoadImage = image
+                }
+            }
+        }
+    }
+    //###################################### 选择风格 ######################################
+    lazy var selectStyleView: TSPTPSelectStyleView = {
+        let selectStyleView = TSPTPSelectStyleView()
+        selectStyleView.currentIndexPath = IndexPath(item: viewModel.selectedStyleIndex, section: 0)
+        selectStyleView.dataArray = viewModel.ptpStyleModels
+        selectStyleView.clickHandle = { [weak self] model in
+            guard let self = self else { return }
+            viewModel.selectedPTPStyleModel = model
+            updateVipView()
+            updateTextFiledView()
+        }
+        return selectStyleView
+    }()
+    
+    
+    //###################################### 输入框 ######################################
+    private let maxLength = 200 // 最大长度限制
+    lazy var customTextView: UITextField = {
+        let customTextView = UITextField()
+        customTextView.placeholder = "Please describe your photo".localized
+        customTextView.font = .font(size: 14)
+        customTextView.textColor = .white
+        customTextView.delegate = self
+        customTextView.returnKeyType = .send
+//        customTextView.iq.distanceFromKeyboard = 0
+        
+        customTextView.attributedPlaceholder = NSAttributedString(
+            string: "Please describe your photo".localized,
+            attributes: [
+                .foregroundColor: UIColor.white.withAlphaComponent(0.4),
+                .font: UIFont.font(size: 14)
+            ]
+        )
+        
+        return customTextView
+    }()
+    
+    lazy var clearBtn: UIButton = {
+        let clearBtn = UIButton.createButton(
+            image: UIImage(named: "clear_text")
+        )
+        { [weak self]  in
+            guard let self = self else { return }
+            customTextView.text = ""
+        }
+        clearBtn.isHidden = true
+        return clearBtn
+    }()
+    
+    var promptTextViewH:CGFloat = 84.0
+    lazy var promptTextView:UIView =  {
+        let promptTextView = UIView()
+        //promptTextView.backgroundColor = "#333333".uiColor
+        promptTextView.clipsToBounds = true
+        let bgView = UIView()
+        bgView.backgroundColor = "#333333".uiColor
+        bgView.cornerRadius = 16.0
+        promptTextView.addSubview(bgView)
+        bgView.snp.makeConstraints { make in
+            make.edges.equalTo(UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16))
+        }
+        
+        bgView.addSubview(customTextView)
+        bgView.addSubview(clearBtn)
+        
+        customTextView.snp.makeConstraints { make in
+            make.top.bottom.equalTo(0)
+            make.leading.equalTo(12.0)
+            make.trailing.equalTo(-32)
+        }
+        
+        clearBtn.snp.makeConstraints { make in
+            make.centerY.equalToSuperview()
+            make.width.height.equalTo(16.0)
+            make.trailing.equalTo(-12)
+        }
+        
+        return promptTextView
+    }()
+    //###################################### 集合视图 ######################################
+    let collectionViewBtootm:CGFloat = 80
+    lazy var collectionComponent: TSCollectionViewComponent = {
+        let layout = UICollectionViewFlowLayout()
+        let cp = TSCollectionViewComponent(frame: CGRect.zero, layout: layout, attributes: [:])
+        cp.collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: collectionViewBtootm, right: 0)
+        
+        cp.sectionActionHandler = { [weak self] cellCp, indexPath in
+            guard let self = self else { return }
+            if let cmd = cellCp as? String, cmd == "delete"  {
+                showCustomAlert(message: "Are you sure to delete".localized, deleteHandler:  {
+                    self.viewModel.removeAllHistoryList()
+                    self.collectionComponent.clear()
+                    self.collectionComponent.reloadView(with: self.viewModel.colDataArray)
+                })
+            }
+        }
+        
+        cp.itemDidSelectedHandler = { [weak self] (object, indexPath) in
+            guard let self = self else { return }
+            if indexPath.section == 0{
+                return
+            }
+            
+            if let sections = viewModel.colDataArray.safeObj(At: indexPath.section) as? TSGenmojiCoLSectionModel{
+                var dataModelArray:[TSGenmojiModel] = []
+                for itemModel in sections.items {
+                    dataModelArray.append(itemModel.dataModel)
+                }
+                
+                let browseVC = TSAIPhotoBrowseVC()
+                browseVC.dataModelArray = dataModelArray
+                browseVC.currentIndex = indexPath.item
+                kPresentModalVC(target: self, modelVC: browseVC,transitionStyle: .crossDissolve)
+            }
+        }
+
+        return cp
+    }()
+    
+    //###################################### 按钮 ######################################
+    lazy var submitBtn: UIButton = {
+        let submitBtn = kCreateNormalSubmitBtn(title: getVipText()) { [weak self]  in
+            guard let self = self else { return }
+            generateImage()
+        }
+        submitBtn.cornerRadius = 24.0
+        submitBtn.isEnabled = false
+        return submitBtn
+    }()
+    override func createView() {
+        
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(clickView))
+        tapGesture.cancelsTouchesInView = false
+        view.addGestureRecognizer(tapGesture)
+        
+        navBarContentView.addSubview(navBarView)
+        navBarView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+
+
+        
+        contentView.addSubview(collectionComponent.collectionView)
+        collectionComponent.collectionView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        collectionComponent.clear()
+        collectionComponent.reloadView(with:viewModel.colDataArray)
+        
+        contentView.addSubview(submitBtn)
+        submitBtn.snp.makeConstraints { make in
+            make.bottom.equalTo(-k_Height_safeAreaInsetsBottom())
+            make.leading.equalTo(16)
+            make.trailing.equalTo(-16)
+            make.height.equalTo(48)
+        }
+        
+        setUpCusStackView()
+        
+        upDateCusStackViewH()
+        kDelayMainShort {
+            self.upDateCusStackViewH()
+        }
+    }
+    
+    override func dealThings() {
+        NotificationCenter.default.addObserver(self, selector: #selector(vipInfoChanged), name: .kPurchaseDidChanged, object: nil)
+        updateVipView()
+        
+//        // 监听键盘事件
+//        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
+//        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
+    }
+//    
+//    override func viewWillAppear(_ animated: Bool) {
+//        super.viewWillAppear(animated)
+//        IQKeyboardManager.shared.isEnabled = false
+//    }
+//    override func viewWillDisappear(_ animated: Bool) {
+//        super.viewWillDisappear(animated)
+//        
+//        IQKeyboardManager.shared.isEnabled = true
+//    }
+}
+
+extension TSPTPInputVC {
+    
+    var cusStackViewH:CGFloat{
+        get {
+            if cusStackView.viewH > 0{
+                return cusStackView.viewH
+            }
+            return 551+bannerH+bannerY
+        }
+    }
+    
+    func upDateCusStackViewH(){
+        self.collectionComponent.collectionView.contentInset = UIEdgeInsets(top: cusStackViewH, left: 0, bottom: collectionViewBtootm, right: 0)
+        cusStackView.snp.remakeConstraints { make in
+            make.top.equalTo(-cusStackViewH)
+            make.leading.trailing.equalTo(0)
+            make.height.equalTo(cusStackViewH)
+        }
+    }
+    
+    func presentModalHintVC(){
+        let vc = TSPTPImageHintVC()
+        vc.clickUpImageHandle = { [weak self]  in
+            guard let self = self else { return }
+            pickSinglePhoto()
+        }
+        kPresentModalVC(target: self, modelVC: vc,transitionStyle: .crossDissolve)
+    }
+    func setUpCusStackView(){
+        
+        collectionComponent.collectionView.addSubview(cusStackView)
+
+        cusStackView.addSubviewToStack(entranceView)
+        entranceView.snp.makeConstraints { make in
+            make.height.equalTo(bannerH+bannerY)
+            make.width.equalTo(k_ScreenWidth)
+        }
+
+        let uploadPhotoTitleView = TSTitleView.creatTitleView(title: "Upload Photo".localized, subTitle: "(Size ≤ 10MB)".localized)
+        cusStackView.addSubviewToStack(uploadPhotoTitleView)
+        uploadPhotoTitleView.snp.makeConstraints { make in
+            make.height.equalTo(uploadPhotoTitleView.viewH)
+            make.width.equalTo(k_ScreenWidth)
+        }
+
+        let hintBtn = TSUIExpandedTouchButton()
+        hintBtn.setUpButton(image: UIImage(named: "ptp_hint")){ [weak self]  in
+            guard let self = self else { return }
+            presentModalHintVC()
+        }
+        uploadPhotoTitleView.addSubview(hintBtn)
+        hintBtn.snp.makeConstraints { make in
+            make.centerY.equalToSuperview()
+            make.trailing.equalTo(-16)
+            make.width.height.equalTo(16)
+        }
+ 
+        cusStackView.addSubviewToStack(uploadView)
+        uploadView.snp.makeConstraints { make in
+            make.height.equalTo(uploadView.viewH)
+            make.width.equalTo(k_ScreenWidth)
+        }
+        
+        let selectStyleTitleView = TSTitleView.creatTitleView(title: "Select Style".localized)
+        cusStackView.addSubviewToStack(selectStyleTitleView)
+        selectStyleTitleView.snp.makeConstraints { make in
+            make.height.equalTo(selectStyleTitleView.viewH)
+            make.width.equalTo(k_ScreenWidth)
+        }
+        
+        cusStackView.addSubviewToStack(selectStyleView)
+        selectStyleView.snp.makeConstraints { make in
+            make.height.equalTo(selectStyleView.viewH)
+            make.width.equalTo(k_ScreenWidth)
+        }
+        
+//        cusStackView.addSubviewToStack(promptTextView)
+//        promptTextView.snp.makeConstraints { make in
+//            make.height.equalTo(promptTextViewH)
+//            make.width.equalTo(k_ScreenWidth)
+//        }
+        
+    }
+}
+
+
+
+extension TSPTPInputVC: UITextFieldDelegate{
+    // MARK: - UITextFieldDelegate
+    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
+        if textField.returnKeyType == .send {
+            textField.resignFirstResponder() // 可选:收起键盘
+            
+            // 触发发送逻辑
+            
+            
+            return true
+        }
+        return false
+    }
+
+    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
+        // 获取当前文本
+        guard let currentText = textField.text else {
+            return true
+        }
+        
+        clearBtn.isHidden = currentText.count <= 0
+        
+        // 计算新文本
+        let newText = (currentText as NSString).replacingCharacters(in: range, with: string)
+        
+        // 如果新文本长度 > maxLength,截断并返回 false
+        if newText.count > maxLength {
+            textField.text = String(newText.prefix(maxLength))
+            return false
+        }
+        
+        return true
+    }
+    
+    func textFieldDidBeginEditing(_ textField: UITextField) {
+        print("输入框开始编辑 - 被点击了")
+        // 在这里可以通知控制器滚动到合适位置
+        
+//        DispatchQueue.main.async {
+//            let rect = self.promptTextView.convert(self.promptTextView.bounds, to: self.collectionComponent.collectionView)
+//            self.collectionComponent.collectionView.scrollRectToVisible(rect, animated: true)
+//        }
+    }
+
+}
+
+
+extension TSPTPInputVC {
+    
+    @objc func vipInfoChanged() {
+        kExecuteOnMainThread {
+            self.updateVipView()
+        }
+    }
+    func updateVipView() {
+        kExecuteOnMainThread {
+            self.vipBtn.isHidden = PurchaseManager.default.isVip
+            
+            var showVip = kPurchaseDefault.generateVipShow(type: .picToPic)
+            if showVip == false {
+                showVip = self.viewModel.selectedPTPStyleModel?.isVip ?? false
+            }
+            
+            kSetBtnVipIcon(btn: self.submitBtn, show: showVip)
+        }
+    }
+    
+    func getVipText()->String{
+        return "Generate".localized
+    }
+ 
+
+    func updateTextFiledView () {
+//        promptTextView.snp.updateConstraints { make in
+//            make.height.equalTo(viewModel.selectedPTPStyleModel?.style == "No Style" ? promptTextViewH : 0 )
+//        }
+    }
+}
+extension TSPTPInputVC {
+    
+    @objc func clickTextToPhoto() {
+        kPushVC(target: self, modelVC: TSTextGeneralPictureVC())
+    }
+    
+    @objc func clickTextToEmoji() {
+        kPushVC(target: self, modelVC: TSGenmojiVC())
+    }
+    
+    @objc func clickView() {
+        view.endEditing(true)
+    }
+    
+    func generateImage() {
+        
+        var isVip = kPurchaseDefault.freeNumAvailable(type: .picToPic) == false
+        if viewModel.selectedPTPStyleModel?.isVip == true {
+            isVip = true
+        }
+        
+        //判断 vip
+        if kJudgeVip(externalBool: isVip, vc: self) { [weak self] in
+            guard let self = self else { return }
+        }{ return }
+        
+
+        guard let selectedPTPStyleModel = viewModel.selectedPTPStyleModel else { return }
+        guard let upLoadImage = viewModel.upLoadImage else { return }
+
+        let gennerateVC = TSPTPGeneratorVC(prompt: viewModel.prompt,promptSort: selectedPTPStyleModel.imageText , imageUrl: "",upLoadImage: upLoadImage,style: selectedPTPStyleModel.style) { [weak self] model in
+            guard let self = self else { return }
+            if viewModel.saveModel(model:model) {
+                collectionComponent.clear()
+                collectionComponent.reloadView(with:viewModel.colDataArray)
+            }else{
+                collectionComponent.reloadData()
+            }
+            
+            updateVipView()
+        }
+        
+        kPresentModalVC(target: self, modelVC: gennerateVC,transitionStyle: .crossDissolve)
+    }
+
+}
+extension TSPTPInputVC {
+    
+    @objc func keyboardWillShow(_ notification: Notification) {
+
+        guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect,
+              let animationDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else {
+            return
+        }
+//        dePrint("keyboardWillShow contentInset IQKeyboardManager=\(IQKeyboardManager.shared.isEnabled)")
+        
+        let keyboardHeight = keyboardFrame.height
+        let contentInset = UIEdgeInsets(top:cusStackViewH, left: 0, bottom: keyboardHeight, right: 0)
+        dePrint("keyboardWillShow contentInset=\(contentInset)")
+//        UIView.animate(withDuration: animationDuration) {
+            self.collectionComponent.collectionView.contentInset = contentInset
+            self.collectionComponent.collectionView.scrollIndicatorInsets = contentInset
+//        }
+        
+//        kDelayMainShort {
+//            self.collectionComponent.collectionView.scrollToLastItem(animated: false)
+//        }
+    }
+
+    @objc func keyboardWillHide(_ notification: Notification) {
+        guard let animationDuration = notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval else {
+            return
+        }
+
+        let contentInset = UIEdgeInsets(top: cusStackViewH, left: 0, bottom: collectionViewBtootm, right: 0)
+        dePrint("keyboardWillHide contentInset=\(contentInset)")
+//        UIView.animate(withDuration: animationDuration) {
+            self.collectionComponent.collectionView.contentInset = contentInset
+            self.collectionComponent.collectionView.scrollIndicatorInsets = contentInset
+//        }
+    }
+    
+    
+}

+ 184 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/VM/TSPTPInputVM.swift

@@ -0,0 +1,184 @@
+//
+//  TSPTPInputVM.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/7.
+//
+
+import Alamofire
+import ObjectMapper
+class TSPTPInputVM {
+    
+    var colDataArray:[TSComponent] = [TSComponent]()
+    
+    var uploadRequest:Request?
+
+    //上传图片模型,用于上传图片参数的传递
+    private var updateImageModel: TSPTPStyleModel = {
+        var updateImageModel = TSPTPStyleModel()
+        return updateImageModel
+    }()
+    
+    var upLoadImageUrl:String?
+    var upLoadImage:UIImage?{
+        didSet{
+            updateImageModel.image = upLoadImage
+            upLoadImageUrl = nil
+            isCanGennerateBlock?(isCanGennerate)
+        }
+    }
+    
+    var selectedPTPStyleModel:TSPTPStyleModel?{
+        didSet{
+            isCanGennerateBlock?(isCanGennerate)
+        }
+    }
+    
+    var selectedStyleIndex:Int = 0
+    
+    //选择类型组
+    lazy var ptpStyleModels: [TSPTPStyleModel] = {
+        var ptpStyleModels = [TSPTPStyleModel]()
+        if let dataArray = Mapper<TSPTPStyleModel>().mapArray(JSONfile: "photo_to_photo_style.json"){
+            ptpStyleModels = dataArray
+            
+            if let model = dataArray.safeObj(At: selectedStyleIndex) {
+                selectedPTPStyleModel = model //加上默认的选择
+            }
+        }
+        
+        return ptpStyleModels
+    }()
+    //历史记录
+    @UserDefault(key: "photoToPhotoHistoryListString", defaultValue: "")
+    private var historyListString: String
+    
+    
+    lazy var listModelArray: [TSGenmojiModel] = {
+        if let listModelArray = Mapper<TSGenmojiModel>().mapArray(JSONString: historyListString){
+            return listModelArray
+        }
+        return []
+    }()
+    
+
+    lazy var historySeciton: TSGenmojiCoLSectionModel = {
+        let sectionModel = TSGenmojiCoLSectionModel()
+        sectionModel.style = .ptpPicHistory
+        sectionModel.name = "History".localized
+        for model in listModelArray {
+            let itemModel = TSGenmojiCoLItemModel()
+            itemModel.style = sectionModel.style
+            itemModel.dataModel = model
+            sectionModel.items.append(itemModel)
+        }
+        return sectionModel
+    }()
+    
+
+    var isCanGennerate:Bool {
+        if upLoadImage != nil , selectedPTPStyleModel != nil {
+            return true
+        }
+        return false
+    }
+    
+    var isCanGennerateBlock:((Bool)->Void)?
+    init() {
+        if UserDefaults.standard.string(forKey: "insertPTPExampleData") == nil {
+            insertExampleData()
+            UserDefaults.standard.set("1", forKey: "insertPTPExampleData")
+            UserDefaults.standard.synchronize()
+        }
+        combinedData()
+    }
+    
+    func insertExampleData(){
+        let array = [
+            createExampleModel(imageName: "ptp_example_image0"),
+            createExampleModel(imageName: "ptp_example_image1")
+        ]
+        if let jsonString = array.toJSONString() {
+            historyListString = jsonString
+        }
+    }
+    
+    func createExampleModel(imageName:String)->TSGenmojiModel{
+        let model = TSGenmojiModel()
+        model.modelType = .example
+        model.request.prompt = "Example"
+        model.request.promptSort = "Example"
+        model.request.width = 330
+        model.request.height = 440
+        model.response.resultUrl = imageName
+        return model
+    }
+    
+    func combinedData(){
+        colDataArray.removeAll()
+        
+        if historySeciton.items.count > 0 {
+            colDataArray.append(historySeciton)
+        }
+    }
+    
+}
+ 
+extension TSPTPInputVM {
+    //历史记录
+    var modelArray:[TSGenmojiModel]{
+        get{
+            if let modelArray = Mapper<TSGenmojiModel>().mapArray(JSONString: historyListString){
+                return modelArray
+            }
+            return []
+        }
+        set{
+            if let jsonString = newValue.toJSONString() {
+                historyListString = jsonString
+            }
+        }
+    }
+    
+    //返回值,是否需要清空后刷新
+    func saveModel(model:TSGenmojiModel)->Bool{
+        listModelArray.insert(model, at: 0)
+        if let jsonString = listModelArray.toJSONString() {
+            historyListString = jsonString
+        }
+        var isNeed = false
+        if historySeciton.items.count == 0 {
+            colDataArray.append(historySeciton)
+            isNeed = true
+        }
+          
+        let colItemModel = TSGenmojiCoLItemModel()
+        colItemModel.style = .ptpPicHistory
+        colItemModel.dataModel = model
+        historySeciton.items.insert(colItemModel, at: 0)
+        return isNeed
+    }
+    
+    
+    var prompt:String{
+        var prompt = ""
+
+        if let selectPromptModel = selectedPTPStyleModel,selectPromptModel.prompt.count > 0 {
+            prompt = "\(selectPromptModel.prompt)," + prompt
+        }
+        return prompt
+    }
+
+    func removeAllHistoryList(){
+        listModelArray.removeAll()
+        if let jsonString = listModelArray.toJSONString() {
+            historyListString = jsonString
+        }
+        
+        historySeciton.items.removeAll()
+        colDataArray.removeLast()
+    }
+    
+}
+
+

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

@@ -0,0 +1,173 @@
+//
+//  TSPTPSelectStyleView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/7.
+//
+
+class TSPTPSelectStyleView : TSBaseView{
+    var viewH: CGFloat = 110.0
+    var dataArray: [TSPTPStyleModel] = [TSPTPStyleModel](){
+        didSet{
+            styleCollectionView.reloadData()
+            
+            if dataArray.count > 0 {
+//                DispatchQueue.main.async {
+                self.styleCollectionView.selectItem(at: self.currentIndexPath, animated: false, scrollPosition: .centeredHorizontally)
+//                }
+            }
+        }
+    }
+    
+    var clickHandle:((TSPTPStyleModel)->Void)?
+    lazy var layout: UICollectionViewFlowLayout = {
+        let layout = UICollectionViewFlowLayout()
+        layout.scrollDirection = .horizontal
+        layout.itemSize = CGSize(width: 110, height: 110)
+        layout.minimumInteritemSpacing = 0.0
+        layout.minimumLineSpacing = 12.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(TSPTPSelectStyleCCell.self, forCellWithReuseIdentifier: TSPTPSelectStyleCCell.cellID)
+        if #available(iOS 11.0, *) {
+            collectionView.contentInsetAdjustmentBehavior = .never
+        }
+        return collectionView
+    }()
+
+    var currentIndexPath:IndexPath = IndexPath(item: 0, section: 0)
+    
+    override func creatUI() {
+        currentIndexPath = IndexPath(item: 0, section: 0)
+        addSubview(styleCollectionView)
+        styleCollectionView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+    
+    func unCheck(){
+        styleCollectionView.deselectItem(at: currentIndexPath, animated: true)
+    }
+}
+
+extension TSPTPSelectStyleView: 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: TSPTPSelectStyleCCell.cellID, for: indexPath)
+        if let cell = cell as? TSPTPSelectStyleCCell,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){
+            currentIndexPath = indexPath
+            clickHandle?(model)
+        }
+    }
+}
+
+//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)
+//        }
+//    }
+//    
+//}

+ 144 - 0
AIEmoji/Business/TSPTPGeneratorVC/TSPTPInputVC/View/TSPTPUploadView.swift

@@ -0,0 +1,144 @@
+//
+//  TSPTPUploadView.swift
+//  AIEmoji
+//
+//  Created by 100Years on 2025/4/7.
+//
+
+class TSPTPUploadView: TSBaseView {
+    
+    var viewH: CGFloat = 232.0
+    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
+            }
+        }
+    }
+    
+    var clickHandel:((Int)->Void)?
+    
+    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 bgView: 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
+            clickHandel?(0)
+        }
+        deleteBtn.isHidden = true
+        return deleteBtn
+    }()
+    
+    override func creatUI() {
+        contentView.addSubview(bgView)
+        bgView.snp.makeConstraints { make in
+            make.leading.equalTo(16)
+            make.trailing.equalTo(-16)
+            make.top.bottom.equalTo(0)
+        }
+        
+        contentView.addSubview(deleteBtn)
+        deleteBtn.snp.makeConstraints { make in
+            make.top.equalTo(4)
+            make.trailing.equalTo(-4)
+            make.width.height.equalTo(32)
+        }
+    }
+    
+
+    @objc func clickBgView() {
+        clickHandel?(1)
+    }
+}

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

@@ -106,7 +106,7 @@ class TSPTPSelectStyleCCell: TSBaseCollectionCell {
             imageView.image = UIImage(named: itemModel.imageName)
             var strokeColor = UIColor.white
             var font = UIFont.font(size: 14)
-            if itemModel.style == 1 {
+            if itemModel.specialStyle == 1 {
                 hotImageView.isHidden = false
                 font = UIFont.font(name:.PoppinsBlackItalic,size: 18)
                 strokeColor = "#FFB73C".uiColor

+ 3 - 1
AIEmoji/Business/TSPTPGeneratorVC/TSPhotoToPhotoVC/M/TSPTPStyleModel.swift

@@ -14,12 +14,14 @@ class TSPTPStyleModel: TSBaseModel {
     var imageText:String = ""
     var prompt:String = ""
     var isVip:Bool = false
-    var style:Int = 0 //0 普通类型,1 热门类型
+    var specialStyle:Int = 0 //0 普通类型,1 热门类型
+    var style:String = ""
     override func mapping(map: ObjectMapper.Map) {
         imageName               <- map["imageName"]
         imageText               <- map["imageText"]
         prompt                  <- map["prompt"]
         isVip                   <- map["isVip"]
+        specialStyle            <- map["specialStyle"]
         style                   <- map["style"]
     }
 }

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

@@ -15,7 +15,8 @@ class TSPhotoToPhotoVC: TSBaseVC {
         return vm
     }()
     
-    
+    //###################################### 导航栏 view ######################################
+
     lazy var vipBtn: UIButton = {
        let vipBtn = UIButton.createButton(image: UIImage(named: "nav_vip")) { [weak self]  in
            guard let self = self else { return }
@@ -26,7 +27,7 @@ class TSPhotoToPhotoVC: TSBaseVC {
        return vipBtn
    }()
     
-    //###################################### 入口 view ######################################
+
     lazy var navBarView: TSBaseNavContentBarView = {
        let navBarView = TSBaseNavContentBarView()
        
@@ -335,11 +336,10 @@ extension TSPhotoToPhotoVC {
             guard let self = self else { return }
         }{ return }
         
-        guard let prompt = viewModel.selectedPTPStyleModel?.prompt else { return }
-        guard let imageText = viewModel.selectedPTPStyleModel?.imageText else { return }
+        guard let selectedPTPStyleModel = viewModel.selectedPTPStyleModel else { return }
         guard let upLoadImage = viewModel.upLoadImage else { return }
 
-        let gennerateVC = TSPTPGeneratorVC(prompt: prompt,promptSort: imageText , imageUrl: "",upLoadImage: upLoadImage) { [weak self] model in
+        let gennerateVC = TSPTPGeneratorVC(prompt: selectedPTPStyleModel.prompt,promptSort: selectedPTPStyleModel.imageText , imageUrl: "",upLoadImage: upLoadImage,style: selectedPTPStyleModel.style) { [weak self] model in
             guard let self = self else { return }
             if viewModel.saveModel(model:model) {
                 collectionComponent.clear()

+ 3 - 1
AIEmoji/Business/TSTabBarController/TSTabBarController.swift

@@ -24,8 +24,10 @@ class TSTabBarController: UITabBarController {
     }
 
     @objc private func setUpData() {
-        viewControllerArray = ["TSPhotoToPhotoVC","TSChatViewController","TSEmojisVC","TSSetingVC"]
+        viewControllerArray = ["TSPTPInputVC","TSChatViewController","TSEmojisVC","TSSetingVC"]
+//        viewControllerArray = ["TSPhotoToPhotoVC","TSChatViewController","TSEmojisVC","TSSetingVC"]
 //        viewControllerArray = ["TSTTPInputVC","TSChatViewController","TSEmojisVC","TSSetingVC"]
+
         titleArray = ["Photo","Chat","Emoji","Setting"]
         selectedImageArray = [
             "tabbar_select_pic",

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

@@ -52,6 +52,7 @@ class TSTTPInputVC: TSBaseVC {
     //###################################### Prompt类型 ######################################
     lazy var promptStyleView: TSTTPStyleView = {
         let promptStyleView = TSTTPStyleView()
+        promptStyleView.currentIndexPath = IndexPath(item: viewModel.selectedStyleIndex, section: 0)
         promptStyleView.dataArray = viewModel.ptpStyleModels
         promptStyleView.selectedValueBlock = { [weak self] model in
             guard let self = self else { return }
@@ -137,6 +138,9 @@ class TSTTPInputVC: TSBaseVC {
 
 extension TSTTPInputVC {
     func generateImage() {
+        
+        guard let selectPromptModel = viewModel.selectPromptModel else { return }
+        
         var isVip = kPurchaseDefault.freeNumAvailable(type: .textGeneratePic) == false
         if viewModel.selectPromptModel?.isVip == true {
             isVip = true
@@ -147,7 +151,8 @@ extension TSTTPInputVC {
             guard let self = self else { return }
         }{ return }
         
-        let gennerateVC = TSTextPicGennerateVC(aiText: viewModel.prompt) {[weak self] model in
+       
+        let gennerateVC = TSTextPicGennerateVC(aiText: viewModel.prompt,style: selectPromptModel.style) {[weak self] model in
             guard let self = self else { return }
             model.request.promptSort = viewModel.promptText
             viewModel.saveModel(model: model)

+ 3 - 5
AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/VM/TSTTPInputVM.swift

@@ -21,14 +21,14 @@ let kRandomTextToRintone:[String] = [
 ]
 
 class TSTTPInputVM {
-    
+    var selectedStyleIndex:Int = 0
     //选择 prompt 类型组
     lazy var ptpStyleModels: [TSPTPStyleModel] = {
         var ptpStyleModels = [TSPTPStyleModel]()
         if let dataArray = Mapper<TSPTPStyleModel>().mapArray(JSONfile: "text_to_photo_style.json"){
             ptpStyleModels = dataArray
             
-            if let model = dataArray.first {
+            if let model = dataArray.safeObj(At: selectedStyleIndex) {
                 selectPromptModel = model //加上默认的选择
             }
         }
@@ -70,9 +70,7 @@ extension TSTTPInputVM {
 
     var prompt:String{
         var prompt = promptText
-//        if let selectPromptModel = selectPromptModel {
-//            prompt+=", \(selectPromptModel.prompt)"
-//        }
+
         if let selectPromptModel = selectPromptModel,selectPromptModel.prompt.count > 0 {
             prompt = "\(selectPromptModel.prompt)," + prompt
         }

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

@@ -120,7 +120,7 @@ class TSPromptStyleViewCell: TSBaseCollectionCell {
         didSet{
             imageView.image = UIImage(named: itemModel.imageName)
     
-            if itemModel.style == 1 {
+            if itemModel.specialStyle == 1 {
                 hotImageView.isHidden = false
             }else{
                 hotImageView.isHidden = true

+ 29 - 3
AIEmoji/Business/TSTextGeneralPictureVC/TSTTPInputVC/View/TSTitleView.swift

@@ -8,19 +8,45 @@
 
 class TSTitleView: TSBaseView {
     
-    static let viewH:Float = 60.0
-    let viewH:Float = TSTitleView.viewH
+    static let viewH:CGFloat = 60.0
+    let viewH:CGFloat = TSTitleView.viewH
     
     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: 12,weight: .medium),textColor: .fromHex("#A7A7A7"))
+    }()
+
+
     override func creatUI() {
+        
+        let centerYOffset = 8.0
+
         contentView.addSubview(titleLab)
         titleLab.snp.makeConstraints { make in
             make.leading.equalTo(16)
-            make.centerY.equalToSuperview()
+            make.centerY.equalToSuperview().offset(centerYOffset)
+        }
+        
+        contentView.addSubview(leftSubLab)
+        leftSubLab.snp.makeConstraints { make in
+            make.leading.equalTo(titleLab.snp.trailing).offset(8)
+            make.centerY.equalTo(titleLab)
         }
     }
 }
+
+extension TSTitleView {
+    
+    static func creatTitleView(title:String,subTitle:String = "") -> TSTitleView {
+        let titleView = TSTitleView()
+        titleView.titleLab.text = title
+        titleView.leftSubLab.text = subTitle
+        return titleView
+    }
+    
+}

+ 5 - 3
AIEmoji/Business/TSTextGeneralPictureVC/TSTextPicGennerateVC/TSTextPicGennerateVC.swift

@@ -10,9 +10,11 @@ class TSTextPicGennerateVC: TSAIPhotoGeneratorBaseVC {
     var imageModel:TSGenmojiModel?
     var complete:((TSGenmojiModel)->Void)
     var aiText:String
+    var style:String
     var progressState = TSProgressState.none
-    init(aiText: String,complete:@escaping ((TSGenmojiModel)->Void)) {
+    init(aiText: String,style: String,complete:@escaping ((TSGenmojiModel)->Void)) {
         self.aiText = aiText
+        self.style = style
         self.complete = complete
         super.init()
     }
@@ -81,7 +83,7 @@ class TSTextPicGennerateVC: TSAIPhotoGeneratorBaseVC {
             guard let self = self else { return }
         }{ return }
         
-        viewModel.creatImageEmoji(text:aiText)
+        viewModel.creatImageEmoji(text:aiText,style: style)
     }
     
 
@@ -99,7 +101,7 @@ class TSTextPicGennerateVC: TSAIPhotoGeneratorBaseVC {
     }
     
     override func dealThings() {
-        viewModel.creatImageEmoji(text: self.aiText)
+        viewModel.creatImageEmoji(text: self.aiText,style: style)
         viewModel.$stateDatauPblished.receive(on: DispatchQueue.main).sink {[weak self]  (state,model) in
             guard let self = self else { return }
             self.upDateView(state: state, model: model)

+ 4 - 2
AIEmoji/Business/TSTextGeneralPictureVC/TSTextPicGennerateVC/TSTextPicGennerateVM.swift

@@ -53,13 +53,15 @@ class TSTextPicGennerateVM {
 //    }
     
     //width 和 height 必须是 32 的倍数
-    func creatImageEmoji(text:String,width:Int = Int(kTextPicW) ,height:Int = Int(kTextPicH)) {
+    func creatImageEmoji(text:String,style:String,width:Int = Int(kTextPicW) ,height:Int = Int(kTextPicH)) {
         generatingProgress = 0
         aiText = text
         let postDict:[String : Any] = [
             "prompt":text,
             "width":width,
-            "height":height
+            "height":height,
+            "style":style,
+            "device":getUserInfoJsonString()
         ]
         stateDatauPblished = (.start,nil)
         stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)

+ 0 - 6
AIEmoji/Common/GlobalImports/GlobalImports.swift

@@ -113,12 +113,6 @@ public func className(from object: Any) -> String {
     return String(describing: type(of: object))
 }
 
-
-func appVersion() ->String{
-    let short = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
-    return "V" + short
-}
-
 /// 震动
 func playVibration() {
     // 默认震动   kSystemSoundID_Vibrate

+ 394 - 0
AIEmoji/Common/Tool/CpuMapManager.swift

@@ -0,0 +1,394 @@
+//
+//  CpuMapManager.swift
+//  ClockWidget
+//
+//  Created by fff on 2023/7/28.
+//
+
+import UIKit
+
+class CpuMapManager: NSObject {
+    static let shared = CpuMapManager()
+    
+    /// 数据来源 https://kylebing.cn/tools/iphone/
+    ///         http://kylebing.cn/tools/iphone/
+    ///
+    private let deviceMap: [String: [String: String]] = [
+        
+        "iPhone 16 Pro Max" : ["CPU":"A18 Pro",
+                               "Freq": "4.04GHz",
+                               "Battery": "4685 mah"],
+        "iPhone 16 Pro"     : ["CPU":"A18 Pro",
+                               "Freq": "4.04GHz",
+                               "Battery": "3582 mah"],
+        "iPhone 16 Plus"    : ["CPU":"A18",
+                               "Freq": "3.78GHz",
+                               "Battery": "4674 mah"],
+        "iPhone 16"         : ["CPU":"A18",
+                               "Freq": "3.78GHz",
+                               "Battery": "3561 mah"],
+        
+        "iPhone 15 Pro Max" : ["CPU":"A17 Pro",
+                               "Freq": "3.77GHz",
+                               "Battery": "4422 mah"],
+        "iPhone 15 Pro"     : ["CPU":"A17 Pro",
+                               "Freq": "3.77GHz",
+                               "Battery": "3274 mah"],
+        "iPhone 15 Plus"    : ["CPU":"A16",
+                               "Freq": "3.46GHz",
+                               "Battery": "4383 mah"],
+        "iPhone 15"         : ["CPU":"A16",
+                               "Freq": "3.46GHz",
+                               "Battery": "3349 mah"],
+        
+        "iPhone 14 Pro Max" : ["CPU":"A16",
+                               "Freq": "3.46GHz",
+                               "Battery": "4323 mah"],
+        "iPhone 14 Pro"     : ["CPU":"A16",
+                               "Freq": "3.46GHz",
+                               "Battery": "3200 mah"],
+        "iPhone 14 Plus"    : ["CPU":"A15",
+                               "Freq": "3.20GHz",
+                               "Battery": "4325 mah"],
+        "iPhone 14"         : ["CPU":"A15",
+                               "Freq": "3.20GHz",
+                               "Battery": "3279 mah"],
+        
+        "iPhone SE3"        : ["CPU":"A15",
+                               "Freq": "3.20GHz",
+                               "Battery": "2018 mah"],
+        "iPhone 13 Pro Max" : ["CPU":"A15",
+                               "Freq": "3.20GHz",
+                               "Battery": "4352 mah"],
+        "iPhone 13 Pro"     : ["CPU":"A15",
+                               "Freq": "3.20GHz",
+                               "Battery": "3095 mah"],
+        "iPhone 13"         : ["CPU":"A15",
+                               "Freq": "3.20GHz",
+                               "Battery": "3227 mah"],
+        "iPhone 13 Mini"    : ["CPU":"A15",
+                               "Freq": "3.20GHz",
+                               "Battery": "2406 mah"],
+        
+        "iPhone 12 Pro Max" : ["CPU":"A14",
+                               "Freq": "3.00GHz",
+                               "Battery": "3687 mah"],
+        "iPhone 12 Pro"     : ["CPU":"A14",
+                               "Freq": "3.00GHz",
+                               "Battery": "2815 mah"],
+        "iPhone 12"         : ["CPU":"A14",
+                               "Freq": "3.00GHz",
+                               "Battery": "2851 mah"],
+        "iPhone 12 Mini"    : ["CPU":"A14",
+                               "Freq": "3.00GHz",
+                               "Battery": "2227 mah"],
+        
+        "iPhone SE2"        : ["CPU":"A13",
+                               "Freq": "2.0GHz",
+                               "Battery": "1821 mah"],
+        
+        "iPhone 11 Pro Max" : ["CPU":"A13",
+                               "Freq": "2.0GHz",
+                               "Battery": "3969 mah"],
+        "iPhone 11 Pro"     : ["CPU":"A13",
+                               "Freq": "2.0GHz",
+                               "Battery": "3046 mah"],
+        "iPhone 11"         : ["CPU":"A13",
+                               "Freq": "2.0GHz",
+                               "Battery": "3110 mah"],
+        
+        "iPhone XR"         : ["CPU":"A13",
+                               "Freq": "2.0GHz",
+                               "Battery": "2942 mah"],
+        "iPhone XS Max"     : ["CPU":"A12",
+                               "Freq": "2.49GHz",
+                               "Battery": "3174 mah"],
+        "iPhone XS"         : ["CPU":"A12",
+                               "Freq": "2.49GHz",
+                               "Battery": "2658 mah"],
+        "iPhone X"          : ["CPU":"A11",
+                               "Freq": "1.4GHz",
+                               "Battery": "2716 mah"],
+        
+        "iPhone 8 Plus"     : ["CPU":"A11",
+                               "Freq": "1.4GHz",
+                               "Battery": "2691 mah"],
+        "iPhone 8"          : ["CPU":"A11",
+                               "Freq": "1.4GHz",
+                               "Battery": "1821 mah"],
+        "iPhone 7 Plus"     : ["CPU":"A11",
+                               "Freq": "1.4GHz",
+                               "Battery": "2900 mah"],
+        "iPhone 7"          : ["CPU":"A10",
+                               "Freq": "1.3GHz",
+                               "Battery": "1960 mah"],
+        "iPhone SE"         : ["CPU":"A9",
+                               "Freq": "1.85GHz",
+                               "Battery": "1624 mah"],
+        "iPhone 6s Plus"    : ["CPU":"A9",
+                               "Freq": "1.85GHz",
+                               "Battery": "2750 mah"],
+        "iPhone 6s"         : ["CPU":"A9",
+                               "Freq": "1.85GHz",
+                               "Battery": "1715 mah"],
+    ]
+    
+    private(set) var modelName: String
+    private(set) var cpuName: String?
+    /// CPU频率
+    private(set) var cpuFreq: String?
+    private(set) var batteryCapacity: String?
+    
+    override init() {
+        
+        modelName = UIDevice.current.modelName
+        cpuName = deviceMap[modelName]?["CPU"]
+        cpuFreq = deviceMap[modelName]? ["Freq"]
+        batteryCapacity = deviceMap[modelName]?["Battery"]
+        
+        super.init()
+    }
+}
+
+extension UIDevice {
+    
+    var modelIdentifier: String {
+        var systemInfo = utsname()
+        uname(&systemInfo)
+        
+        let machineMirror = Mirror(reflecting: systemInfo.machine)
+        let identifier = machineMirror.children.reduce("") { (identifier, element) in
+            guard let value = element.value as? Int8, value != 0 else {
+                return identifier
+            }
+            return identifier + String(UnicodeScalar(UInt8(value)))
+        }
+        
+        return identifier
+    }
+    
+    /// 数据来源 https://www.jianshu.com/p/d9068fee295e
+    var modelName: String {
+        
+        let identifier = modelIdentifier
+        
+        switch identifier {
+        case "iPhone8,1":
+            return "iPhone 6s"
+        case "iPhone8,2":
+            return "iPhone 6s Plus"
+        case "iPhone8,4":
+            return "iPhone SE"
+        case "iPhone9,1":
+            return "iPhone 7"; //国行、日版、港行
+        case "iPhone9,2":
+            return "iPhone 7 Plus"; //国行、港行
+        case "iPhone9,3":
+            return "iPhone 7"; //美版、台版
+        case "iPhone9,4":
+            return "iPhone 7 Plus"; //美版、台版
+        case "iPhone10,1":
+            return "iPhone 8"; //国行(A1863)、日行(A1906)
+        case "iPhone10,2":
+            return "iPhone 8 Plus"; //国行(A1864)、日行(A1898)
+        case "iPhone10,3":
+            return "iPhone X"; //国行(A1865)、日行(A1902)
+        case "iPhone10,4":
+            return "iPhone 8"; //美版(Global/A1905)
+        case "iPhone10,5":
+            return "iPhone 8 Plus"; //美版(Global/A1897)
+        case "iPhone10,6":
+            return "iPhone X";//美版(Global/A1901)
+            
+        // 刘海屏(除SE外)
+        case "iPhone11,8":
+            return "iPhone XR"
+        case "iPhone11,2":
+            return "iPhone XS"
+        case "iPhone11,6":
+            return "iPhone XS Max"
+        case "iPhone11,4":
+            return "iPhone XS Max"
+        case "iPhone12,1":
+            return "iPhone 11"
+        case "iPhone12,3":
+            return "iPhone 11 Pro"
+        case "iPhone12,5":
+            return "iPhone 11 Pro Max"
+        case "iPhone12,8":
+            return "iPhone SE2"; //(2nd generation)
+        case "iPhone13,1":
+            return "iPhone 12 mini"
+        case "iPhone13,2":
+            return "iPhone 12"
+        case "iPhone13,3":
+            return "iPhone 12 Pro"
+        case "iPhone13,4":
+            return "iPhone 12 Pro Max"
+        case "iPhone14,2":
+            return "iPhone 13 Pro"
+        case "iPhone14,3":
+            return "iPhone 13 Pro Max"
+        case "iPhone14,4":
+            return "iPhone 13 mini"
+        case "iPhone14,5":
+            return "iPhone 13"
+        case "iPhone14,6":
+            return "iPhone SE3"; //(2nd generation)
+        case "iPhone14,7":
+            return "iPhone 14"
+        case "iPhone14,8":
+            return "iPhone 14 Plus"
+            
+        // 灵动岛
+        case "iPhone15,2":
+            return "iPhone 14 Pro"
+        case "iPhone15,3":
+            return "iPhone 14 Pro Max"
+            
+        case "iPhone16,2":
+            return "iPhone 15 Pro Max"
+        case "iPhone16,1":
+            return "iPhone 15 Pro"
+        case "iPhone15,5":
+            return "iPhone 15 Plus"
+        case "iPhone15,4":
+            return "iPhone 15"
+
+            
+        case "iPhone17,3":
+            return "iPhone 16"
+        case "iPhone17,4":
+            return "iPhone 16 Plus"
+        case "iPhone17,1":
+            return "iPhone 16 Pro"
+        case "iPhone17,2":
+            return "iPhone 16 Pro Max"
+            
+            
+            
+        default:
+            return "--"
+        }
+    }
+    
+    var currentSysVersion: Int {
+        let version = UIDevice.current.systemVersion
+        let v1 = version.components(separatedBy: ".").first ?? "0"
+        let doubleVersion = Double(v1)
+        if let doubleVersion = doubleVersion {
+            return Int(doubleVersion)
+        }
+        return 0
+    }
+    
+    // 版本判断
+    func currentSysVersionEqualOrGreater(than version: String) -> Bool {
+        var sysValues = UIDevice.current.systemVersion.components(separatedBy: ".")
+        var values = version.components(separatedBy: ".")
+        
+        // 位数不同,少的补0
+        let count = max(sysValues.count, values.count)
+        if sysValues.count < count {
+            let more = Array(repeating: "0", count: count-sysValues.count)
+            sysValues.append(contentsOf: more)
+        }
+        if values.count < count {
+            let more = Array(repeating: "0", count: count-values.count)
+            values.append(contentsOf: more)
+        }
+        
+        for idx in 0..<count {
+            if let sv = Int(sysValues.safeObj(At: idx) ?? "0"),
+                let v = Int(values.safeObj(At: idx) ?? "0") {
+                if sv > v {
+                    return true
+                } else if sv < v {
+                    return false
+                }
+            }
+        }
+        return true
+    }
+    
+    var iPhoneXids: [String] {
+        return ["iPhone10,3", "iPhone10,6"]
+    }
+    
+    var iPhoneSEids: [String] {
+        return ["iPhone8,4", "iPhone12,8", "iPhone14,6"]
+    }
+}
+
+// 传感器样式: 无 | 刘海 | 灵动岛
+enum DeviceSensorStyle {
+    case none
+    case bang
+    case island
+}
+
+extension UIDevice {
+    func sensorStyle() -> DeviceSensorStyle {
+#if targetEnvironment(simulator)
+        return .island
+#endif
+        let identifier = UIDevice.current.modelIdentifier
+        // SE
+        if iPhoneSEids.contains(identifier) {
+            return .none
+        }
+        // X
+        if iPhoneXids.contains(identifier) {
+            return .bang
+        }
+        if identifier.hasPrefix("iPhone") {
+            let digital = identifier.replacingOccurrences(of: "iPhone", with: "")
+            let arr = digital.components(separatedBy: ",")
+            if let v1 = arr.safeObj(At: 0),
+               let vv1 = Double(v1) {
+                if vv1 >= 15 {
+                    return .island
+                } else {
+                    if vv1 < 11 {
+                        return .none
+                    }
+                    return .bang
+                }
+            }
+        }
+        return .none
+    }
+    
+    // 刘海屏 及以后设备才可以升级到16.1
+    var supportLiveActivity: Bool {
+        guard #available(iOS 16.1, *) else {
+            return false
+        }
+        let style = sensorStyle()
+        return style != .none
+    }
+    
+    var sensorSize: CGSize {
+        let style = sensorStyle()
+        switch style {
+        case .none:
+            return .zero
+        case .bang:
+            let ratio: CGFloat = UIScreen.main.bounds.width/375.0
+            return CGSize(width: 219*ratio, height: 30*ratio)
+        case .island:
+            return CGSize(width: 125, height: 36.7)//16s 和 16sp 是 126*37.3
+        }
+    }
+    
+    var sensorTop:Double{
+        let kScreenWidth = UIScreen.main.bounds.size.width
+        let kScreenHeight = UIScreen.main.bounds.size.height
+        //16s和 16sp
+        if (kScreenWidth == 440 && kScreenHeight == 956) || (kScreenWidth == 402 && kScreenHeight == 874) ||  modelName.contains("iPhone 16 Pro") {
+            return 14.0
+        } else {
+            return 11.3
+        }
+    }
+}

+ 1 - 1
AIEmoji/Res/photo_to_photo_style.json

@@ -3,7 +3,7 @@
         "imageName": "ptp_style_10",
         "imageText": "Ghibli",
         "prompt":"Studio Ghibli-inspired anime aesthetic, Hayao Miyazaki style, vibrant yet soft color palette, detailed hand-painted textures, whimsical dreamlike atmosphere, soft cel-shading, watercolor wash effect, subtle grain texture, preserving original composition. Style strength: 85%",
-        "style":1,
+        "specialStyle":1,
         "isVip": true
     },
     {

+ 2 - 2
AIEmoji/Res/text_to_photo_style.json

@@ -1,7 +1,7 @@
 [
     {
         "imageName": "ttp_style_none",
-        "imageText": "Default",
+        "imageText": "No Style",
         "prompt":"",
         "isVip": false
     },
@@ -9,7 +9,7 @@
         "imageName": "ttp_style_10",
         "imageText": "Ghibli",
         "prompt":"ghibli ${user_input}, Studio Ghibli-styled masterpiece,(Miyazaki's pastel palette:teal|ochre|coral), dynamic cloud shadows, (hand-drawn line imperfections:1.2), 3/4 perspective view,  (nature reclaiming civilization motif), (Kiki's Delivery Service lighting:1.1),  --no 3D,octane,hyperrealistic,digital art --style_boost 80",
-        "style":1,
+        "specialStyle":1,
         "isVip": true
     },
     {

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

@@ -125,3 +125,10 @@
 "Hyperrealistic macro view of dewdrops on spiderweb, morning sunlight creating rainbow spectra, blurred forest background with bokeh effects" = "Hyperrealistische Makroansicht von Tautropfen auf Spinnennetz, Morgensonnenlicht, das Regenbogenspektren erzeugt, verschwommener Waldhintergrund mit Bokeh-Effekten";
 "Cybernetic wildlife sanctuary at dawn, solar-panel trees powering force fields, robotic caretakers feeding holographic animals in savanna simulation" = "Kybernetisches Naturschutzgebiet im Morgengrauen, Solarpanel-Bäume, die Kraftfelder antreiben, robotische Betreuer, die holografische Tiere in einer Savannensimulation füttern";
 "Minimalist geometric landscape with gradient-colored pyramids, clean lines intersecting with organic cloud formations, symmetrical composition" = "Minimalistische geometrische Landschaft mit Pyramiden in Farbverläufen, klaren Linien, die sich mit organischen Wolkenformationen überschneiden, symmetrische Komposition";
+
+"Upload your photos" = "Lade dein Foto hoch";
+"Good photo examples" = "Beispiele für gute Fotos";
+"Fully clear and visible face, in good lighting" = "Gesicht vollständig sichtbar und Foto gut beleuchtet";
+"Bad photo examples" = "Beispiele für schlechte Fotos";
+"Group photos, covered faces, nudes" = "Gruppenfoto, verdecktes Gesicht, Nacktaufnahmen";
+"No Style" = "Kein Stil";

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

@@ -125,3 +125,10 @@
 "Hyperrealistic macro view of dewdrops on spiderweb, morning sunlight creating rainbow spectra, blurred forest background with bokeh effects" = "Hyperrealistic macro view of dewdrops on spiderweb, morning sunlight creating rainbow spectra, blurred forest background with bokeh effects";
 "Cybernetic wildlife sanctuary at dawn, solar-panel trees powering force fields, robotic caretakers feeding holographic animals in savanna simulation" = "Cybernetic wildlife sanctuary at dawn, solar-panel trees powering force fields, robotic caretakers feeding holographic animals in savanna simulation";
 "Minimalist geometric landscape with gradient-colored pyramids, clean lines intersecting with organic cloud formations, symmetrical composition" = "Minimalist geometric landscape with gradient-colored pyramids, clean lines intersecting with organic cloud formations, symmetrical composition";
+
+"Upload your photos" = "Upload your photos";
+"Good photo examples" = "Good photo examples";
+"Fully clear and visible face, in good lighting" = "Fully clear and visible face, in good lighting";
+"Bad photo examples" = "Bad photo examples";
+"Group photos, covered faces, nudes" = "Group photos, covered faces, nudes";
+"No Style" = "No Style";

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

@@ -125,3 +125,10 @@
 "Hyperrealistic macro view of dewdrops on spiderweb, morning sunlight creating rainbow spectra, blurred forest background with bokeh effects" = "Vista macro hiperrealista de gotas de rocío en telaraña, luz solar matutina creando espectros de arco iris, fondo de bosque borroso con efectos bokeh";
 "Cybernetic wildlife sanctuary at dawn, solar-panel trees powering force fields, robotic caretakers feeding holographic animals in savanna simulation" = "Santuario cibernético de vida silvestre al amanecer, árboles con paneles solares que alimentan campos de fuerza, cuidadores robóticos que alimentan a animales holográficos en una simulación de sabana";
 "Minimalist geometric landscape with gradient-colored pyramids, clean lines intersecting with organic cloud formations, symmetrical composition" = "Paisaje geométrico minimalista con pirámides de colores degradados, líneas limpias que se cruzan con formaciones de nubes orgánicas, composición simétrica";
+
+"Upload your photos" = "Sube tu foto";
+"Good photo examples" = "Ejemplos de buenas fotos";
+"Fully clear and visible face, in good lighting" = "Rostro completamente visible y foto bien iluminada";
+"Bad photo examples" = "Ejemplos de malas fotos";
+"Group photos, covered faces, nudes" = "Foto grupal, rostro cubierto, desnudo";
+"No Style" = "Sin estilo";

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

@@ -125,3 +125,10 @@
 "Hyperrealistic macro view of dewdrops on spiderweb, morning sunlight creating rainbow spectra, blurred forest background with bokeh effects" = "クモの巣上の露の超現実的なマクロビュー、虹のスペクトルを生み出す朝の日差し、ボケ効果のあるぼやけた森の背景";
 "Cybernetic wildlife sanctuary at dawn, solar-panel trees powering force fields, robotic caretakers feeding holographic animals in savanna simulation" = "夜明けのサイバネティック野生動物保護区、フォースフィールドに電力を供給するソーラーパネルの木、サバンナシミュレーションでホログラフィック動物に餌を与えるロボット管理人";
 "Minimalist geometric landscape with gradient-colored pyramids, clean lines intersecting with organic cloud formations, symmetrical composition" = "グラデーション色のピラミッドを備えたミニマリストの幾何学的な風景、有機的な雲の形成と交差するきれいな線、対称的な構成";
+
+"Upload your photos" = "写真をアップロード";
+"Good photo examples" = "良い写真の例";
+"Fully clear and visible face, in good lighting" = "顔が完全にはっきり見えて、明るい写真";
+"Bad photo examples" = "悪い写真の例";
+"Group photos, covered faces, nudes" = "集合写真、顔が隠れている、裸体";
+"No Style" = "スタイルがありません";

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

@@ -125,3 +125,10 @@
 "Hyperrealistic macro view of dewdrops on spiderweb, morning sunlight creating rainbow spectra, blurred forest background with bokeh effects" = "거미줄의 이슬방울에 대한 초현실적인 매크로 뷰, 무지개 스펙트럼을 생성하는 아침 햇빛, 보케 효과로 흐릿한 숲 배경";
 "Cybernetic wildlife sanctuary at dawn, solar-panel trees powering force fields, robotic caretakers feeding holographic animals in savanna simulation" = "새벽의 사이버네틱 야생동물 보호구역, 역장에 전력을 공급하는 태양열 패널 나무, 사바나 시뮬레이션에서 홀로그램 동물에게 먹이를 주는 로봇 관리인";
 "Minimalist geometric landscape with gradient-colored pyramids, clean lines intersecting with organic cloud formations, symmetrical composition" = "그라데이션 색상 피라미드, 유기적 구름 형성과 교차하는 깨끗한 선, 대칭 구성을 갖춘 미니멀한 기하학적 풍경";
+
+"Upload your photos" = "사진 업로드";
+"Good photo examples" = "좋은 사진 예시";
+"Fully clear and visible face, in good lighting" = "얼굴이 완전히 선명하게 보이고 조명이 밝은 사진";
+"Bad photo examples" = "나쁜 사진 예시";
+"Group photos, covered faces, nudes" = "단체 사진, 얼굴 가려짐, 노출";
+"No Style" = "스타일 없음";

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

@@ -125,3 +125,10 @@
 "Hyperrealistic macro view of dewdrops on spiderweb, morning sunlight creating rainbow spectra, blurred forest background with bokeh effects" = "Visão macro hiper-realista de gotas de orvalho na teia de aranha, luz solar matinal criando espectros de arco-íris, fundo desfocado da floresta com efeitos bokeh";
 "Cybernetic wildlife sanctuary at dawn, solar-panel trees powering force fields, robotic caretakers feeding holographic animals in savanna simulation" = "Santuário cibernético da vida selvagem ao amanhecer, árvores com painéis solares alimentando campos de força, cuidadores robóticos alimentando animais holográficos em simulação de savana";
 "Minimalist geometric landscape with gradient-colored pyramids, clean lines intersecting with organic cloud formations, symmetrical composition" = "Paisagem geométrica minimalista com pirâmides coloridas em gradiente, linhas limpas que se cruzam com formações de nuvens orgânicas, composição simétrica";
+
+"Upload your photos" = "Envie sua foto";
+"Good photo examples" = "Exemplos de boas fotos";
+"Fully clear and visible face, in good lighting" = "Rosto totalmente visível e foto bem iluminada";
+"Bad photo examples" = "Exemplos de más fotos";
+"Group photos, covered faces, nudes" = "Foto em grupo, rosto coberto, nudez";
+"No Style" = "Sem estilo";

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

@@ -125,3 +125,10 @@
 "Hyperrealistic macro view of dewdrops on spiderweb, morning sunlight creating rainbow spectra, blurred forest background with bokeh effects" = "Visão macro hiper-realista de gotas de orvalho na teia de aranha, luz solar matinal criando espectros de arco-íris, fundo desfocado da floresta com efeitos bokeh";
 "Cybernetic wildlife sanctuary at dawn, solar-panel trees powering force fields, robotic caretakers feeding holographic animals in savanna simulation" = "Santuário cibernético da vida selvagem ao amanhecer, árvores com painéis solares alimentando campos de força, cuidadores robóticos alimentando animais holográficos em simulação de savana";
 "Minimalist geometric landscape with gradient-colored pyramids, clean lines intersecting with organic cloud formations, symmetrical composition" = "Paisagem geométrica minimalista com pirâmides coloridas em gradiente, linhas limpas que se cruzam com formações de nuvens orgânicas, composição simétrica";
+
+"Upload your photos" = "Envie sua foto";
+"Good photo examples" = "Exemplos de boas fotos";
+"Fully clear and visible face, in good lighting" = "Rosto totalmente visível e foto bem iluminada";
+"Bad photo examples" = "Exemplos de más fotos";
+"Group photos, covered faces, nudes" = "Foto em grupo, rosto coberto, nudez";
+"No Style" = "Sem estilo";

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

@@ -125,3 +125,10 @@
 "Hyperrealistic macro view of dewdrops on spiderweb, morning sunlight creating rainbow spectra, blurred forest background with bokeh effects" = "蜘蛛网上露珠的超现实宏观视图、晨光创造彩虹光谱、模糊的森林背景与散景效果";
 "Cybernetic wildlife sanctuary at dawn, solar-panel trees powering force fields, robotic caretakers feeding holographic animals in savanna simulation" = "黎明时分的控制论野生动物保护区,太阳能电池板树为力场提供动力,机器人看护者在稀树草原模拟中喂养全息动物";
 "Minimalist geometric landscape with gradient-colored pyramids, clean lines intersecting with organic cloud formations, symmetrical composition" = "极简主义几何景观,渐变色金字塔,干净的线条与有机云层相交,对称的构图";
+
+"Upload your photos" = "上传你的照片";
+"Good photo examples" = "优秀照片示例";
+"Fully clear and visible face, in good lighting" = "脸部完全清晰可见且照片光线明亮";
+"Bad photo examples" = "糟糕照片示例";
+"Group photos, covered faces, nudes" = "多人集体照、脸部遮挡、裸体";
+"No Style" = "无风格";

+ 10 - 0
AIEmoji/zh-Hant.lproj/InfoPlist.strings

@@ -0,0 +1,10 @@
+/* 
+  InfoPlist.strings
+  AIEmoji
+
+  Created by 100Years on 2025/4/6.
+  
+*/
+
+
+NSPhotoLibraryUsageDescription = "Allow us to access photos to upload your photos to generate new styles.";

+ 1 - 0
AIEmoji/zh-Hant.lproj/LaunchScreen.strings

@@ -0,0 +1 @@
+

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

@@ -0,0 +1,118 @@
+/* 
+  Localizable.strings
+  AIEmoji
+
+  Created by 100Years on 2025/4/6.
+  
+*/
+
+"Upload your photos" = "上傳你的照片";
+"Good photo examples" = "優秀照片示例";
+"Fully clear and visible face, in good lighting" = "臉部完全清晰可見且照片光線明亮";
+"Bad photo examples" = "糟糕照片示例";
+"Group photos, covered faces, nudes" = "多人集體照、臉部遮擋、裸體";
+"No Style" = "無風格";
+"Today" = "今天";
+"1 Day" = "1 天";
+"7 Days" = "7天";
+"30 Days" = "30天";
+"Thinking..." = "思考...";
+"Thought for %ds" = "已思考 %d 秒";
+"Copyed Successfully" = "複製成功";
+"Save Successfully" = "保存成功";
+"View" = "查看";
+"Are you sure to delete" = "確定要刪除嗎";
+"Cancel" = "取消";
+"Delete" = "刪除";
+"Allow us to access photos to upload your photos to generate new styles." = "允許我們存取照片以上傳你的照片以產生新的樣式。";
+"Send a message" = "發訊息試試吧";
+"Art" = "藝術";
+"Generating" = "生成中";
+"Uploading Photo" = "上傳照片";
+"Try Again" = "重試";
+"Save" = "保持";
+"AI Text to Emoji" = "AI 文字轉表情";
+"AI Text to Photo" = "AI 文字轉圖像";
+"Ghibli Style Example" = "吉卜力風格範例";
+"Before" = "前";
+"After" = "後";
+"Change image styles" = "改變圖像風格";
+"AI image generation" = "AI 生成影像";
+"Ask Ai anything" = "全能 AI 對話助手";
+"Continue" = "繼續";
+"Premium" = "會員";
+"Unlimited AI image generation" = "無限次 AI 影像生成";
+"Change image styles" = "改變圖像風格";
+"Unlimited AI chat" = "全能 AI 對話助手";
+"Ad-free experience" = "無廣告體驗";
+"One Year" = "每年";
+"One Month" = "每月";
+"One Week" = "每週";
+"Recurring billing, cancel anytime" = "定期計費,隨時取消";
+",Payment will be charged to your iTunes account at confirmation of purchase. Subscriptions automatically renew for the same applicable term and price, unless auto-renew is turned off at least 24 hours before the end of the current period." = ",付款將在確認購買時從您的 iTunes 帳戶中扣除。訂閱會自動續訂相同的適用條款和價格,除非在當前期間結束前至少 24 小時關閉自動續訂。";
+"Terms of us" = "使用者協定";
+"Privacy Policy" = "隱私協議";
+"Restore" = "恢復購買";
+"Purchasing now" = "立即購買";
+"Congratulation you have become VIP" = "恭喜您成為 VIP";
+"Finish" = "結束";
+"Restoring now" = "正在恢復訂閱中";
+"Couldn't Restore Subscription" = "無法恢復訂閱";
+"Getting price" = "取得價格中";
+"Failed to get the price, will automatically retry in 5 seconds" = "取得價格失敗,5秒後自動重試";
+"Failed to restore subscribe, please try again" = "恢復訂閱失敗,請重試";
+"Verifying receipt..." = "正在驗證收據...";
+"Failed to validate receipt" = "驗證收據失敗";
+"Photo" = "照片";
+"Text ➡️ Photo" = "文字➡️照片";
+"Text ➡️ Emoji" = "人物➡️臉部表情";
+"Try Now" = "試一試";
+"Upload Photo" = "上傳照片";
+"(Size ≤ 10MB)" = "(大小≤10MB)";
+"Photo must be smaller than 10MB." = "照片必須小於 10MB";
+"Tap to select photo" = "點擊以選擇照片";
+"Select Style" = "選擇風格";
+"Ghibli" = "吉卜力";
+"Fantasy Illustration" = "精美插畫";
+"Retro Anime" = "復古動漫";
+"Classical Painting" = "古典油畫";
+"Cyberpunk" = "賽博朋克";
+"Pop Art" = "普普藝術";
+"Retrofuturism" = "復古未來主義";
+"Photorealism" = "寫實主義";
+"Modern Digital Art" = "現代數位藝術";
+"Vaporwave" = "蒸氣波";
+"Abstract Expressionism" = "抽象表現主義";
+"History" = "歷史記錄";
+"Example" = "範例";
+"Generate" = "立刻生成";
+"Save" = "節省";
+"Type your idea here." = "在此輸入您的想法";
+"Hint Inspiration" = "靈感提示";
+"Graffiti" = "塗鴉";
+"Abstract" = "抽象";
+"Retro Americana" = "復古美式";
+"Comic" = "漫畫";
+"Social Realism" = "社會現實主義";
+"Regenerate" = "重新生成";
+"As you leave, your generation will be interrupted and no result." = "一旦離開,你的圖像生成就會中斷導致沒有結果";
+"Leave" = "離開";
+"Wait" = "等待";
+"Failed to generate, please try later" = "生成失敗,請稍後再試";
+"Greetings! Curious about\nwhat I can do?" = "你好!好奇\n我能做什麼?";
+"I can tackle your questions, my skillset includes, but is not limited to:\n`📧 Composing high-quality emails`\n`🇺🇸 Facilitating language learning`\n`📑 Assisting in your studies`\n`💡Brainstorming ideas`\n`and much more!`" = "我可以解決您的問題,我的技能包括但不限於:\n`📧 撰寫高品質的電子郵件`\n`🇺🇸 學習多語言`\n`📑 協助您的學業`\n`💡為您提供靈感`\n`等等! `";
+"No record" = "無記錄";
+"Emoji" = "表情";
+"Copy" = "複製";
+"Setting" = "設定";
+"Upgrade" = "升級";
+"Limited Time Discount" = "限時折扣";
+"Due Date:" = "過期時間:";
+"How to add emojis to iMessages?" = "如何將表情符號加入 iMessage ?";
+"Update Version" = "更新版本";
+"Share us" = "分享我們";
+"Rate us" = "評價我們";
+"Terms of Service" = "使用者協定";
+"Privacy Policy" = "隱私協議";
+"Allow us to access Photos in order to save emoji to your device." = "允許我們存取照片權限以便將表情圖片等保存到您的裝置中";
+"Chat" = "聊天";

+ 1 - 1
Podfile

@@ -13,7 +13,7 @@ target 'AIEmoji' do
   pod 'Kingfisher', '7.10.0'
   pod 'Alamofire'
   pod 'MJRefresh'
-  pod 'IQKeyboardManagerSwift'
+  #pod 'IQKeyboardManagerSwift'
   pod 'JXSegmentedView'
   pod 'JXPagingView/Paging'
   pod 'Masonry'

+ 1 - 58
Podfile.lock

@@ -1,45 +1,5 @@
 PODS:
   - Alamofire (5.10.2)
-  - IQKeyboardCore (1.0.5)
-  - IQKeyboardManagerSwift (8.0.0):
-    - IQKeyboardManagerSwift/Appearance (= 8.0.0)
-    - IQKeyboardManagerSwift/Core (= 8.0.0)
-    - IQKeyboardManagerSwift/IQKeyboardReturnManager (= 8.0.0)
-    - IQKeyboardManagerSwift/IQKeyboardToolbarManager (= 8.0.0)
-    - IQKeyboardManagerSwift/IQTextView (= 8.0.0)
-    - IQKeyboardManagerSwift/Resign (= 8.0.0)
-  - IQKeyboardManagerSwift/Appearance (8.0.0):
-    - IQKeyboardManagerSwift/Core
-  - IQKeyboardManagerSwift/Core (8.0.0):
-    - IQKeyboardNotification
-    - IQTextInputViewNotification
-  - IQKeyboardManagerSwift/IQKeyboardReturnManager (8.0.0):
-    - IQKeyboardReturnManager
-  - IQKeyboardManagerSwift/IQKeyboardToolbarManager (8.0.0):
-    - IQKeyboardManagerSwift/Core
-    - IQKeyboardToolbarManager
-  - IQKeyboardManagerSwift/IQTextView (8.0.0):
-    - IQTextView
-  - IQKeyboardManagerSwift/Resign (8.0.0):
-    - IQKeyboardManagerSwift/Core
-  - IQKeyboardNotification (1.0.3)
-  - IQKeyboardReturnManager (1.0.4):
-    - IQKeyboardCore (= 1.0.5)
-  - IQKeyboardToolbar (1.1.1):
-    - IQKeyboardCore
-    - IQKeyboardToolbar/Core (= 1.1.1)
-  - IQKeyboardToolbar/Core (1.1.1):
-    - IQKeyboardCore
-    - IQKeyboardToolbar/Placeholderable
-  - IQKeyboardToolbar/Placeholderable (1.1.1):
-    - IQKeyboardCore
-  - IQKeyboardToolbarManager (1.1.2):
-    - IQKeyboardToolbar
-    - IQTextInputViewNotification
-  - IQTextInputViewNotification (1.0.8):
-    - IQKeyboardCore
-  - IQTextView (1.0.5):
-    - IQKeyboardToolbar/Placeholderable
   - JXPagingView/Paging (2.1.3)
   - JXSegmentedView (1.4.1)
   - Kingfisher (7.10.0)
@@ -65,7 +25,6 @@ PODS:
 
 DEPENDENCIES:
   - Alamofire
-  - IQKeyboardManagerSwift
   - JXPagingView/Paging
   - JXSegmentedView
   - Kingfisher (= 7.10.0)
@@ -80,14 +39,6 @@ DEPENDENCIES:
 SPEC REPOS:
   trunk:
     - Alamofire
-    - IQKeyboardCore
-    - IQKeyboardManagerSwift
-    - IQKeyboardNotification
-    - IQKeyboardReturnManager
-    - IQKeyboardToolbar
-    - IQKeyboardToolbarManager
-    - IQTextInputViewNotification
-    - IQTextView
     - JXPagingView
     - JXSegmentedView
     - Kingfisher
@@ -106,14 +57,6 @@ EXTERNAL SOURCES:
 
 SPEC CHECKSUMS:
   Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
-  IQKeyboardCore: 28c8bf3bcd8ba5aa1570b318cbc4da94b861711e
-  IQKeyboardManagerSwift: 0c6fbbaa2e60739e48d7cf59f25661471a7a3a65
-  IQKeyboardNotification: d7382c4466c5a5adef92c7452ebf861b36050088
-  IQKeyboardReturnManager: 972be48528ce9e7508ab3ab15ac7efac803f17f5
-  IQKeyboardToolbar: d4bdccfb78324aec2f3920659c77bb89acd33312
-  IQKeyboardToolbarManager: 6f4072ac620c2572d4af8c09f42a801f3e4909f7
-  IQTextInputViewNotification: f5e954d8881fd9808b744e49e024cc0d4bcfe572
-  IQTextView: ae13b4922f22e6f027f62c557d9f4f236b19d5c7
   JXPagingView: afdd2e9af09c90160dd232b970d603cc6e7ddd0e
   JXSegmentedView: cd73555ce2134d1656db2cb383ba9c2f36fb5078
   Kingfisher: a18f05d3b6d37d8650ee4a3e61d57a28fc6207f6
@@ -127,6 +70,6 @@ SPEC CHECKSUMS:
   SwipeCellKit: 3972254a826da74609926daf59b08d6c72e619ea
   TSSmalCoacopods: 6aa97167f0c76b16fc7d1fd1eb198bb6aece4f68
 
-PODFILE CHECKSUM: 5f1a9b50d5f2041d75518c8ffbc2f8cd02fa11a2
+PODFILE CHECKSUM: ce1b55ab9fd89ca0cf7de7aadc2c0f0045e3386b
 
 COCOAPODS: 1.16.2