Browse Source

ai 铃声 界面开发大半

100Years 1 month ago
parent
commit
15187ee6aa
71 changed files with 1583 additions and 193 deletions
  1. 91 5
      AIRingtone.xcodeproj/project.pbxproj
  2. 22 0
      AIRingtone/Assets.xcassets/AIRing/ai_rintone_icon.imageset/Contents.json
  3. BIN
      AIRingtone/Assets.xcassets/AIRing/ai_rintone_icon.imageset/ai_rintone_icon@2x.png
  4. BIN
      AIRingtone/Assets.xcassets/AIRing/ai_rintone_icon.imageset/ai_rintone_icon@3x.png
  5. 22 0
      AIRingtone/Assets.xcassets/AIRing/ai_setRing_icon.imageset/Contents.json
  6. BIN
      AIRingtone/Assets.xcassets/AIRing/ai_setRing_icon.imageset/ai_setRing_icon@2x.png
  7. BIN
      AIRingtone/Assets.xcassets/AIRing/ai_setRing_icon.imageset/ai_setRing_icon@3x.png
  8. 6 0
      AIRingtone/Assets.xcassets/AIRing/style/Contents.json
  9. 22 0
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/Contents.json
  10. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/ttr_style_0@2x.png
  11. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/ttr_style_0@3x.png
  12. 22 0
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/Contents.json
  13. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/ttr_style_1@2x.png
  14. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/ttr_style_1@3x.png
  15. 22 0
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/Contents.json
  16. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/ttr_style_2@2x.png
  17. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/ttr_style_2@3x.png
  18. 22 0
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/Contents.json
  19. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/ttr_style_3@2x.png
  20. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/ttr_style_3@3x.png
  21. 22 0
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/Contents.json
  22. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/ttr_style_4@2x.png
  23. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/ttr_style_4@3x.png
  24. 22 0
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/Contents.json
  25. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/ttr_style_5@2x.png
  26. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/ttr_style_5@3x.png
  27. 22 0
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/Contents.json
  28. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/ttr_style_6@2x.png
  29. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/ttr_style_6@3x.png
  30. 22 0
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/Contents.json
  31. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/ttr_style_7@2x.png
  32. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/ttr_style_7@3x.png
  33. 22 0
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/Contents.json
  34. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/ttr_style_8@2x.png
  35. BIN
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/ttr_style_8@3x.png
  36. 22 0
      AIRingtone/Assets.xcassets/Common/ringtone_loading.imageset/Contents.json
  37. BIN
      AIRingtone/Assets.xcassets/Common/ringtone_loading.imageset/ringtone_loading@2x.png
  38. BIN
      AIRingtone/Assets.xcassets/Common/ringtone_loading.imageset/ringtone_loading@3x.png
  39. 6 6
      AIRingtone/Business/Data/TSUserDefaultData.swift
  40. 2 2
      AIRingtone/Business/TSAIPhotoVC/TSAIPhotoChildVC/TSAIPhotoChildVC.swift
  41. 1 1
      AIRingtone/Business/TSAIPhotoVC/TSAIPhotoChildVC/TSAIPhotoChildVM.swift
  42. 1 1
      AIRingtone/Business/TSAIPhotoVC/TSAIPhotoChildVC/View/TSAIPhotoImageCell.swift
  43. 26 8
      AIRingtone/Business/TSAIPhotoVC/TSGeneralPicBrowseVC/TSGeneralPicBrowseVC.swift
  44. 8 8
      AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/Model/TSGeneralPicModel.swift
  45. 10 3
      AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGeneralPicVC+Event.swift
  46. 23 9
      AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGeneralPicVC.swift
  47. 5 5
      AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGenneralPicVM.swift
  48. 9 19
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/TSTextGeneralPicVC.swift
  49. 13 1
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/VM/TSTextGeneralPicVM.swift
  50. 75 0
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSCreatBtnView.swift
  51. 2 4
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSPromptStyleView.swift
  52. 14 21
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSPromptTextView.swift
  53. 0 0
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSTGPPhotoStyleView.swift
  54. 0 60
      AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC.swift
  55. 225 0
      AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/TSAIRintoneVC.swift
  56. 91 0
      AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/View/TSAIRintoneHistoryCell.swift
  57. 32 0
      AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/ViewModel/TSAIRintoneVM.swift
  58. 101 0
      AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVC+Event.swift
  59. 114 0
      AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVC.swift
  60. 145 0
      AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVM.swift
  61. 140 0
      AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/TSTextGeneralRintoneVC.swift
  62. 80 0
      AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/VM/TSTextGeneralRintoneVM.swift
  63. 56 0
      AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/VM/text_rintone_style.json
  64. 2 2
      AIRingtone/Business/TSSetingVC/TSBusinessWebVC/TSBusinessWebVC.swift
  65. 3 1
      AIRingtone/Business/TSThemeVC/TSThemeBrowseVC/VM/TSThemeBrowseVM.swift
  66. 1 1
      AIRingtone/Business/TSThemeVC/TSThemeBrowseVC/View/TSTBBtnView.swift
  67. 1 1
      AIRingtone/Business/TSThemeVC/TSThemeSetVC/TSThemeSetVC.swift
  68. 0 26
      AIRingtone/Business/TSThemeVC/TSThemeSetVC/VM/TSThemeSetVM.swift
  69. 11 2
      AIRingtone/Business/VIewTool/TSBottomAlertVC.swift
  70. 3 1
      AIRingtone/Business/VIewTool/TSCommonloadingView.swift
  71. 22 6
      AIRingtone/Business/VIewTool/TSRingToneCellView.swift

+ 91 - 5
AIRingtone.xcodeproj/project.pbxproj

@@ -42,6 +42,10 @@
 		A80EDF272D71C13D003CD332 /* TSColVVMHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDF262D71C13C003CD332 /* TSColVVMHeaderModel.swift */; };
 		A80EDF2A2D71C215003CD332 /* TSThemeVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDF292D71C211003CD332 /* TSThemeVM.swift */; };
 		A80EDF2D2D71C2CA003CD332 /* TSThemeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80EDF2C2D71C2BF003CD332 /* TSThemeModel.swift */; };
+		A8272E982D7A88F400F1C814 /* text_rintone_style.json in Resources */ = {isa = PBXBuildFile; fileRef = A8272E972D7A88E300F1C814 /* text_rintone_style.json */; };
+		A8272E9B2D7A8F1000F1C814 /* TSGeneralRintoneVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8272E9A2D7A8F0E00F1C814 /* TSGeneralRintoneVC.swift */; };
+		A8272E9D2D7A8F4600F1C814 /* TSGeneralRintoneVC+Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8272E9C2D7A8F3A00F1C814 /* TSGeneralRintoneVC+Event.swift */; };
+		A8272E9F2D7A8F6500F1C814 /* TSGeneralRintoneVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8272E9E2D7A8F6000F1C814 /* TSGeneralRintoneVM.swift */; };
 		A83F871D2D79409B00D29B1B /* TSUserDefaultData.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83F871C2D79409300D29B1B /* TSUserDefaultData.swift */; };
 		A83F87202D794FF000D29B1B /* TSAIPhotoImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83F871F2D794FE600D29B1B /* TSAIPhotoImageCell.swift */; };
 		A83F87222D7953C000D29B1B /* Notification+TSEx.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83F87212D7953BA00D29B1B /* Notification+TSEx.swift */; };
@@ -83,7 +87,7 @@
 		A868A9032D77E5A500F6D884 /* TSPTPStyleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A9022D77E5A400F6D884 /* TSPTPStyleModel.swift */; };
 		A868A9052D77E5AB00F6D884 /* photo_to_photo_style.json in Resources */ = {isa = PBXBuildFile; fileRef = A868A9042D77E5AB00F6D884 /* photo_to_photo_style.json */; };
 		A868A9072D77EED800F6D884 /* TSTGPTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A9062D77EECC00F6D884 /* TSTGPTitleView.swift */; };
-		A868A9092D7828EC00F6D884 /* TsTGPPhotoStyleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A9082D7828DF00F6D884 /* TsTGPPhotoStyleView.swift */; };
+		A868A9092D7828EC00F6D884 /* TSTGPPhotoStyleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A9082D7828DF00F6D884 /* TSTGPPhotoStyleView.swift */; };
 		A868A90C2D78311A00F6D884 /* TSTextGeneralPicVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A90B2D78311400F6D884 /* TSTextGeneralPicVM.swift */; };
 		A868A90E2D7846D600F6D884 /* TSSavePhotoSuccessTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A90D2D7846D400F6D884 /* TSSavePhotoSuccessTool.swift */; };
 		A868A9112D784CFB00F6D884 /* TSGeneralPicVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A9102D784CFA00F6D884 /* TSGeneralPicVC.swift */; };
@@ -93,7 +97,12 @@
 		A868A91A2D78559800F6D884 /* TSProgressState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A9192D78559600F6D884 /* TSProgressState.swift */; };
 		A868A91C2D78592600F6D884 /* rotatingAnimation.gif in Resources */ = {isa = PBXBuildFile; fileRef = A868A91B2D78592600F6D884 /* rotatingAnimation.gif */; };
 		A868A91E2D785CEA00F6D884 /* TSGeneralPicVC+Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A91D2D785CE600F6D884 /* TSGeneralPicVC+Event.swift */; };
+		A8C6436C2D79A8C8001068D0 /* TSAIRintoneHistoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C6436B2D79A8C7001068D0 /* TSAIRintoneHistoryCell.swift */; };
 		A8CC55822D797720002E0CAA /* TSGeneralPicBrowseVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8CC55812D79771F002E0CAA /* TSGeneralPicBrowseVC.swift */; };
+		A8CC55862D798E2D002E0CAA /* TSTextGeneralRintoneVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8CC55852D798E2D002E0CAA /* TSTextGeneralRintoneVC.swift */; };
+		A8CC55892D798E5D002E0CAA /* TSTextGeneralRintoneVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8CC55882D798E5A002E0CAA /* TSTextGeneralRintoneVM.swift */; };
+		A8CC558B2D79905A002E0CAA /* TSCreatBtnView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8CC558A2D799051002E0CAA /* TSCreatBtnView.swift */; };
+		A8CC55902D799F9F002E0CAA /* TSAIRintoneVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8CC558F2D799F9C002E0CAA /* TSAIRintoneVM.swift */; };
 		F5FF0EC10B0056B65FDB9C78 /* Pods_AIRingtone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39C823AB7F3D49E8B2356E07 /* Pods_AIRingtone.framework */; };
 /* End PBXBuildFile section */
 
@@ -138,6 +147,10 @@
 		A80EDF262D71C13C003CD332 /* TSColVVMHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSColVVMHeaderModel.swift; sourceTree = "<group>"; };
 		A80EDF292D71C211003CD332 /* TSThemeVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSThemeVM.swift; sourceTree = "<group>"; };
 		A80EDF2C2D71C2BF003CD332 /* TSThemeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSThemeModel.swift; sourceTree = "<group>"; };
+		A8272E972D7A88E300F1C814 /* text_rintone_style.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = text_rintone_style.json; sourceTree = "<group>"; };
+		A8272E9A2D7A8F0E00F1C814 /* TSGeneralRintoneVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGeneralRintoneVC.swift; sourceTree = "<group>"; };
+		A8272E9C2D7A8F3A00F1C814 /* TSGeneralRintoneVC+Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSGeneralRintoneVC+Event.swift"; sourceTree = "<group>"; };
+		A8272E9E2D7A8F6000F1C814 /* TSGeneralRintoneVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGeneralRintoneVM.swift; sourceTree = "<group>"; };
 		A83F871C2D79409300D29B1B /* TSUserDefaultData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSUserDefaultData.swift; sourceTree = "<group>"; };
 		A83F871F2D794FE600D29B1B /* TSAIPhotoImageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIPhotoImageCell.swift; sourceTree = "<group>"; };
 		A83F87212D7953BA00D29B1B /* Notification+TSEx.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+TSEx.swift"; sourceTree = "<group>"; };
@@ -183,7 +196,7 @@
 		A868A9022D77E5A400F6D884 /* TSPTPStyleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPTPStyleModel.swift; sourceTree = "<group>"; };
 		A868A9042D77E5AB00F6D884 /* photo_to_photo_style.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = photo_to_photo_style.json; sourceTree = "<group>"; };
 		A868A9062D77EECC00F6D884 /* TSTGPTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTGPTitleView.swift; sourceTree = "<group>"; };
-		A868A9082D7828DF00F6D884 /* TsTGPPhotoStyleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TsTGPPhotoStyleView.swift; sourceTree = "<group>"; };
+		A868A9082D7828DF00F6D884 /* TSTGPPhotoStyleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTGPPhotoStyleView.swift; sourceTree = "<group>"; };
 		A868A90B2D78311400F6D884 /* TSTextGeneralPicVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextGeneralPicVM.swift; sourceTree = "<group>"; };
 		A868A90D2D7846D400F6D884 /* TSSavePhotoSuccessTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSSavePhotoSuccessTool.swift; sourceTree = "<group>"; };
 		A868A9102D784CFA00F6D884 /* TSGeneralPicVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGeneralPicVC.swift; sourceTree = "<group>"; };
@@ -193,7 +206,12 @@
 		A868A9192D78559600F6D884 /* TSProgressState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSProgressState.swift; sourceTree = "<group>"; };
 		A868A91B2D78592600F6D884 /* rotatingAnimation.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = rotatingAnimation.gif; sourceTree = "<group>"; };
 		A868A91D2D785CE600F6D884 /* TSGeneralPicVC+Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TSGeneralPicVC+Event.swift"; sourceTree = "<group>"; };
+		A8C6436B2D79A8C7001068D0 /* TSAIRintoneHistoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIRintoneHistoryCell.swift; sourceTree = "<group>"; };
 		A8CC55812D79771F002E0CAA /* TSGeneralPicBrowseVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGeneralPicBrowseVC.swift; sourceTree = "<group>"; };
+		A8CC55852D798E2D002E0CAA /* TSTextGeneralRintoneVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextGeneralRintoneVC.swift; sourceTree = "<group>"; };
+		A8CC55882D798E5A002E0CAA /* TSTextGeneralRintoneVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSTextGeneralRintoneVM.swift; sourceTree = "<group>"; };
+		A8CC558A2D799051002E0CAA /* TSCreatBtnView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSCreatBtnView.swift; sourceTree = "<group>"; };
+		A8CC558F2D799F9C002E0CAA /* TSAIRintoneVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIRintoneVM.swift; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -442,7 +460,9 @@
 		A80EDF0E2D718E58003CD332 /* TSAIRintoneVC */ = {
 			isa = PBXGroup;
 			children = (
-				A80EDF102D718ECF003CD332 /* TSAIRintoneVC.swift */,
+				A8272E992D7A8F0500F1C814 /* TSGeneralRintoneVC */,
+				A8CC55842D798E26002E0CAA /* TSAIRintoneVC */,
+				A8CC55832D798E05002E0CAA /* TSTextGeneralRintoneVC */,
 			);
 			path = TSAIRintoneVC;
 			sourceTree = "<group>";
@@ -511,6 +531,16 @@
 			path = Model;
 			sourceTree = "<group>";
 		};
+		A8272E992D7A8F0500F1C814 /* TSGeneralRintoneVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8272E9E2D7A8F6000F1C814 /* TSGeneralRintoneVM.swift */,
+				A8272E9A2D7A8F0E00F1C814 /* TSGeneralRintoneVC.swift */,
+				A8272E9C2D7A8F3A00F1C814 /* TSGeneralRintoneVC+Event.swift */,
+			);
+			path = TSGeneralRintoneVC;
+			sourceTree = "<group>";
+		};
 		A83F871B2D79408300D29B1B /* Data */ = {
 			isa = PBXGroup;
 			children = (
@@ -690,7 +720,8 @@
 		A868A8FB2D77E36000F6D884 /* View */ = {
 			isa = PBXGroup;
 			children = (
-				A868A9082D7828DF00F6D884 /* TsTGPPhotoStyleView.swift */,
+				A8CC558A2D799051002E0CAA /* TSCreatBtnView.swift */,
+				A868A9082D7828DF00F6D884 /* TSTGPPhotoStyleView.swift */,
 				A868A9062D77EECC00F6D884 /* TSTGPTitleView.swift */,
 				A868A8FF2D77E54A00F6D884 /* TSPromptStyleView.swift */,
 				A868A8F92D77E34D00F6D884 /* TSPromptTextView.swift */,
@@ -735,6 +766,14 @@
 			path = Model;
 			sourceTree = "<group>";
 		};
+		A8C6436A2D79A8BD001068D0 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				A8C6436B2D79A8C7001068D0 /* TSAIRintoneHistoryCell.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		A8CC55802D7976E7002E0CAA /* TSGeneralPicBrowseVC */ = {
 			isa = PBXGroup;
 			children = (
@@ -743,6 +782,42 @@
 			path = TSGeneralPicBrowseVC;
 			sourceTree = "<group>";
 		};
+		A8CC55832D798E05002E0CAA /* TSTextGeneralRintoneVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8CC55872D798E51002E0CAA /* VM */,
+				A8CC55852D798E2D002E0CAA /* TSTextGeneralRintoneVC.swift */,
+			);
+			path = TSTextGeneralRintoneVC;
+			sourceTree = "<group>";
+		};
+		A8CC55842D798E26002E0CAA /* TSAIRintoneVC */ = {
+			isa = PBXGroup;
+			children = (
+				A8C6436A2D79A8BD001068D0 /* View */,
+				A8CC558E2D799F93002E0CAA /* ViewModel */,
+				A80EDF102D718ECF003CD332 /* TSAIRintoneVC.swift */,
+			);
+			path = TSAIRintoneVC;
+			sourceTree = "<group>";
+		};
+		A8CC55872D798E51002E0CAA /* VM */ = {
+			isa = PBXGroup;
+			children = (
+				A8272E972D7A88E300F1C814 /* text_rintone_style.json */,
+				A8CC55882D798E5A002E0CAA /* TSTextGeneralRintoneVM.swift */,
+			);
+			path = VM;
+			sourceTree = "<group>";
+		};
+		A8CC558E2D799F93002E0CAA /* ViewModel */ = {
+			isa = PBXGroup;
+			children = (
+				A8CC558F2D799F9C002E0CAA /* TSAIRintoneVM.swift */,
+			);
+			path = ViewModel;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -807,6 +882,7 @@
 			files = (
 				A868A91C2D78592600F6D884 /* rotatingAnimation.gif in Resources */,
 				A868A9052D77E5AB00F6D884 /* photo_to_photo_style.json in Resources */,
+				A8272E982D7A88F400F1C814 /* text_rintone_style.json in Resources */,
 				A80EDE5B2D718623003CD332 /* Assets.xcassets in Resources */,
 				A868A8ED2D76FE5D00F6D884 /* tutorial-ring.mp4 in Resources */,
 				A868A8BF2D76A17E00F6D884 /* Poppins-BlackItalic.ttf in Resources */,
@@ -876,7 +952,7 @@
 				A80EDE582D718623003CD332 /* AppDelegate.swift in Sources */,
 				A868A8EF2D77041400F6D884 /* TSLoadingAnimation.swift in Sources */,
 				A80EDE652D718CAF003CD332 /* GlobalImports.swift in Sources */,
-				A868A9092D7828EC00F6D884 /* TsTGPPhotoStyleView.swift in Sources */,
+				A868A9092D7828EC00F6D884 /* TSTGPPhotoStyleView.swift in Sources */,
 				A80EDF112D718ED1003CD332 /* TSAIRintoneVC.swift in Sources */,
 				A80EDF1B2D71AC90003CD332 /* TSCollectionViewVM.swift in Sources */,
 				A80EDE612D718AF4003CD332 /* TSConfig.swift in Sources */,
@@ -886,6 +962,7 @@
 				A80EDEC82D718CEA003CD332 /* TSNetworkManager+Loading.swift in Sources */,
 				A868A9182D78555200F6D884 /* TSGenneralPicVM.swift in Sources */,
 				A80EDECB2D718CEA003CD332 /* TSNetWork+Business.swift in Sources */,
+				A8CC558B2D79905A002E0CAA /* TSCreatBtnView.swift in Sources */,
 				A80EDF0B2D718DF7003CD332 /* TSBootPageVC.swift in Sources */,
 				A80EDF0C2D718DF7003CD332 /* TSLaunchVC.swift in Sources */,
 				A80EDEDB2D718CEA003CD332 /* TSPhotoPickerManager.swift in Sources */,
@@ -896,6 +973,7 @@
 				A80EDEF52D718DEA003CD332 /* TSTabBarController.swift in Sources */,
 				A868A8B52D7598C000F6D884 /* TSTSIslandView.swift in Sources */,
 				A80EDEE72D718CEA003CD332 /* TSCustomStackView.swift in Sources */,
+				A8272E9F2D7A8F6500F1C814 /* TSGeneralRintoneVM.swift in Sources */,
 				A868A9142D784D4D00F6D884 /* TSGeneralPicModel.swift in Sources */,
 				A868A8D52D76E41800F6D884 /* TSSetContactAvatar.swift in Sources */,
 				A868A8F52D77179D00F6D884 /* TSAIPhotoChildVC.swift in Sources */,
@@ -914,6 +992,7 @@
 				A868A8A22D7560B900F6D884 /* TSPageNullView.swift in Sources */,
 				A868A8CE2D76AAC600F6D884 /* TSThemeSetRingToneView.swift in Sources */,
 				A868A90E2D7846D600F6D884 /* TSSavePhotoSuccessTool.swift in Sources */,
+				A8C6436C2D79A8C8001068D0 /* TSAIRintoneHistoryCell.swift in Sources */,
 				A868A8A32D7560B900F6D884 /* TSViewTool.swift in Sources */,
 				A83F871D2D79409B00D29B1B /* TSUserDefaultData.swift in Sources */,
 				A868A9112D784CFB00F6D884 /* TSGeneralPicVC.swift in Sources */,
@@ -921,10 +1000,12 @@
 				A868A89A2D75505E00F6D884 /* TSThemeBannerCell.swift in Sources */,
 				A80EDF182D7193EE003CD332 /* TSTutorialsVC.swift in Sources */,
 				A80EDEEA2D718CEA003CD332 /* PaddedLabel.swift in Sources */,
+				A8CC55862D798E2D002E0CAA /* TSTextGeneralRintoneVC.swift in Sources */,
 				A80EDEEB2D718CEA003CD332 /* StreamPostRequest.swift in Sources */,
 				A80EDF2A2D71C215003CD332 /* TSThemeVM.swift in Sources */,
 				A868A8AA2D7588A500F6D884 /* TSThemeBrowseVC.swift in Sources */,
 				A868A8B12D758CA400F6D884 /* TSTBBtnView.swift in Sources */,
+				A8272E9B2D7A8F1000F1C814 /* TSGeneralRintoneVC.swift in Sources */,
 				A868A8D32D76DE7600F6D884 /* TSThemeSetVM.swift in Sources */,
 				A80EDF272D71C13D003CD332 /* TSColVVMHeaderModel.swift in Sources */,
 				A83F87222D7953C000D29B1B /* Notification+TSEx.swift in Sources */,
@@ -934,11 +1015,14 @@
 				A868A8A72D757DD600F6D884 /* UICollectionView+Refresh.swift in Sources */,
 				A868A8F82D77E2BC00F6D884 /* TSTextGeneralPicVC.swift in Sources */,
 				A80EDF022D718DF1003CD332 /* TSSettingListView.swift in Sources */,
+				A8CC55902D799F9F002E0CAA /* TSAIRintoneVM.swift in Sources */,
 				A80EDF032D718DF1003CD332 /* ShareActivityItemProvider.swift in Sources */,
 				A80EDF042D718DF1003CD332 /* TSSetingModel.swift in Sources */,
+				A8CC55892D798E5D002E0CAA /* TSTextGeneralRintoneVM.swift in Sources */,
 				A80EDF052D718DF1003CD332 /* TSSetingVC.swift in Sources */,
 				A868A8FA2D77E35E00F6D884 /* TSPromptTextView.swift in Sources */,
 				A80EDF062D718DF1003CD332 /* SettingPurchaseTopView.swift in Sources */,
+				A8272E9D2D7A8F4600F1C814 /* TSGeneralRintoneVC+Event.swift in Sources */,
 				A80EDF072D718DF1003CD332 /* TSSetingViewModel.swift in Sources */,
 				A868A8C72D76A44500F6D884 /* TSThemeSetVC.swift in Sources */,
 				A80EDEEC2D718CEA003CD332 /* WindowHelper.swift in Sources */,
@@ -972,6 +1056,7 @@
 				DEVELOPMENT_TEAM = 65UD255J84;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = AIRingtone/Info.plist;
+				INFOPLIST_KEY_CFBundleDisplayName = "AI Ringtones";
 				INFOPLIST_KEY_NSContactsUsageDescription = "Allow \"Contacts\" permission to set contact photo";
 				INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Allow us to access Photos in order to save wallpapers to your device.";
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@@ -1013,6 +1098,7 @@
 				DEVELOPMENT_TEAM = 65UD255J84;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = AIRingtone/Info.plist;
+				INFOPLIST_KEY_CFBundleDisplayName = "AI Ringtones";
 				INFOPLIST_KEY_NSContactsUsageDescription = "Allow \"Contacts\" permission to set contact photo";
 				INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Allow us to access Photos in order to save wallpapers to your device.";
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;

+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/ai_rintone_icon.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/ai_rintone_icon.imageset/ai_rintone_icon@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/ai_rintone_icon.imageset/ai_rintone_icon@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/ai_setRing_icon.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/ai_setRing_icon.imageset/ai_setRing_icon@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/ai_setRing_icon.imageset/ai_setRing_icon@3x.png


+ 6 - 0
AIRingtone/Assets.xcassets/AIRing/style/Contents.json

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

+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/ttr_style_0@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/ttr_style_0@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/ttr_style_1@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/ttr_style_1@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/ttr_style_2@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/ttr_style_2@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/ttr_style_3@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/ttr_style_3@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/ttr_style_4@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/ttr_style_4@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/ttr_style_5@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/ttr_style_5@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/ttr_style_6@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/ttr_style_6@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/ttr_style_7@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/ttr_style_7@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/ttr_style_8@2x.png


BIN
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/ttr_style_8@3x.png


+ 22 - 0
AIRingtone/Assets.xcassets/Common/ringtone_loading.imageset/Contents.json

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

BIN
AIRingtone/Assets.xcassets/Common/ringtone_loading.imageset/ringtone_loading@2x.png


BIN
AIRingtone/Assets.xcassets/Common/ringtone_loading.imageset/ringtone_loading@3x.png


+ 6 - 6
AIRingtone/Business/Data/TSUserDefaultData.swift

@@ -11,14 +11,14 @@ import ObjectMapper
 class TSPosterHistory{
     @UserDefault(key: "kPosterTextPicHistoryListString", defaultValue: "")
     static private var historyString: String
-    static var listModelArray: [TSGeneralPicModel] = {
-        if let listModelArray = Mapper<TSGeneralPicModel>().mapArray(JSONString: historyString){
+    static var listModelArray: [TSActionInfoModel] = {
+        if let listModelArray = Mapper<TSActionInfoModel>().mapArray(JSONString: historyString){
             return listModelArray
         }
         return []
     }()
     
-    static func saveModel(model:TSGeneralPicModel){
+    static func saveModel(model:TSActionInfoModel){
         listModelArray.insert(model, at: 0)
         if let jsonString = listModelArray.toJSONString() {
             historyString = jsonString
@@ -30,14 +30,14 @@ class TSPosterHistory{
 class TSPhotoHistory{
     @UserDefault(key: "kPhotoTextPicHistoryListString", defaultValue: "")
     static private var historyString: String
-    static var listModelArray: [TSGeneralPicModel] = {
-        if let listModelArray = Mapper<TSGeneralPicModel>().mapArray(JSONString: historyString){
+    static var listModelArray: [TSActionInfoModel] = {
+        if let listModelArray = Mapper<TSActionInfoModel>().mapArray(JSONString: historyString){
             return listModelArray
         }
         return []
     }()
     
-    static func saveModel(model:TSGeneralPicModel){
+    static func saveModel(model:TSActionInfoModel){
         listModelArray.insert(model, at: 0)
         if let jsonString = listModelArray.toJSONString() {
             historyString = jsonString

+ 2 - 2
AIRingtone/Business/TSAIPhotoVC/TSAIPhotoChildVC/TSAIPhotoChildVC.swift

@@ -37,9 +37,9 @@ class TSAIPhotoChildVC: TSBaseVC {
             guard let self = self else { return }
             
             if let sections = vm.colDataArray.safeObj(At: indexPath.section) as? TSColVVMSectionModel{
-                var dataModelArray:[TSGeneralPicModel] = []
+                var dataModelArray:[TSActionInfoModel] = []
                 for itemModel in sections.items {
-                    if let model = itemModel.dataModel as? TSGeneralPicModel {
+                    if let model = itemModel.dataModel as? TSActionInfoModel {
                         dataModelArray.append(model)
                     }
                 }

+ 1 - 1
AIRingtone/Business/TSAIPhotoVC/TSAIPhotoChildVC/TSAIPhotoChildVM.swift

@@ -35,7 +35,7 @@ class TSAIPhotoChildVM {
         contentSecitonModel.items = array
     }
     
-    var dataList:[TSGeneralPicModel]{
+    var dataList:[TSActionInfoModel]{
         if style == .photo {
             return TSPhotoHistory.listModelArray
         }else{

+ 1 - 1
AIRingtone/Business/TSAIPhotoVC/TSAIPhotoChildVC/View/TSAIPhotoImageCell.swift

@@ -33,7 +33,7 @@ class TSAIPhotoImageCell: TSBaseCollectionCell {
     override func renderView(with object: Any?, component: TSCollectionViewComponent, attributes: [String : Any]?) {
         super.renderView(with: object, component: component, attributes: attributes)
         if let itemModel = object as? TSColVVMItemModel{
-            if let generalPicModel = itemModel.dataModel as? TSGeneralPicModel{
+            if let generalPicModel = itemModel.dataModel as? TSActionInfoModel{
                 showImageView.setAsyncImage(urlString: generalPicModel.response.resultUrl,placeholder: kPlaceholderImage,contentMode: .scaleAspectFill)
             }
         }

+ 26 - 8
AIRingtone/Business/TSAIPhotoVC/TSGeneralPicBrowseVC/TSGeneralPicBrowseVC.swift

@@ -15,7 +15,7 @@ class TSGeneralPicBrowseVC: TSBottomAlertVC {
     
     var style:TSGennerateType = .poster
     
-    var dataModelArray = [TSGeneralPicModel]()
+    var dataModelArray = [TSActionInfoModel]()
     var currentImage:UIImage?{
         let cell = collectionView.cellForItem(at: IndexPath(item: currentIndex, section: 0)) as? TSGeneralPicBrowseCell
         var image = cell?.netWorkImageView.image
@@ -23,13 +23,17 @@ class TSGeneralPicBrowseVC: TSBottomAlertVC {
         return image
     }
 
-    var currentModel:TSGeneralPicModel?{
+    var currentModel:TSActionInfoModel?{
         if let model = dataModelArray.safeObj(At: currentIndex){
             return model
         }
         return nil
     }
     
+    lazy var contactsTool: TSContactsTool = {
+        let contactsTool = TSContactsTool(targetVC: self)
+        return contactsTool
+    }()
     
     var currentIndex:Int = 0 {
         didSet{
@@ -87,7 +91,7 @@ class TSGeneralPicBrowseVC: TSBottomAlertVC {
         againBtn.isHidden = true
         
         rightBtn.isHidden = false
-        rightBtn.setTitle("Save".localized, for: .normal)
+        rightBtn.setTitle(saveBtnText, for: .normal)
         
         leftBtn.isHidden = false
         leftBtn.setTitle("Copy Text".localized, for: .normal)
@@ -148,11 +152,19 @@ class TSGeneralPicBrowseVC: TSBottomAlertVC {
 //        }
         
         if let image = currentImage{
-            PhotoManagerShared.saveImageToAlbum(image) { success, error in
-                if success {
-                    kSavePhotoSuccesswShared.show(atView: self.view)
-                }else{
-                    debugPrint(error)
+            if style == .poster {
+                PhotoManagerShared.saveImageToAlbum(image) { success, error in
+                    if success {
+                        kSavePhotoSuccesswShared.show(atView:self.view)
+                    }else{
+                        debugPrint(error)
+                    }
+                }
+            }else if style == .photo {
+                contactsTool.setContactsAvatar(avatarImage: image) { data, error in
+                    if error == nil {
+                        kSavePhotoSuccesswShared.show(atView: self.view)
+                    }
                 }
             }
         }else{
@@ -185,6 +197,12 @@ extension TSGeneralPicBrowseVC {
         rightPageBtn.isHidden = isHiddenRight
     }
     
+    var saveBtnText:String{
+        if style == .photo{
+            return "Set Now".localized
+        }
+        return "Download".localized
+    }
     
     var cellImageSize:CGSize {
         if style == .photo {

+ 8 - 8
AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/Model/TSGeneralPicModel.swift

@@ -1,12 +1,12 @@
 //
-//  TSGeneralPicModel.swift
+//  TSActionInfoModel.swift
 //  AIRingtone
 //
 //  Created by 100Years on 2025/3/5.
 //
 
 import ObjectMapper
-class TSGeneralPicModel: TSBaseModel {
+class TSActionInfoModel: TSBaseModel {
     
     enum ModelType:Int {
         case normal
@@ -27,8 +27,8 @@ class TSGeneralPicModel: TSBaseModel {
     var id:Int = 0
     var actionType:String = ""
     var comments:String = ""
-    var request:TSGeneralPicRequestModel = TSGeneralPicRequestModel()
-    var response:TSGeneralPicResponseModel = TSGeneralPicResponseModel()
+    var request:TSActionInfoRequestModel = TSActionInfoRequestModel()
+    var response:TSActionInfoResponseModel = TSActionInfoResponseModel()
     var createdTimestamp:Int = 0
     var status:String = ""
     var costTime:Int = 0
@@ -41,8 +41,8 @@ class TSGeneralPicModel: TSBaseModel {
         id           <- map["id"]
         actionType   <- map["actionType"]
         comments     <- map["comments"]
-        request      <- (map["request"],JsonStringTransform<TSGeneralPicRequestModel>())
-        response           <- (map["response"],JsonStringTransform<TSGeneralPicResponseModel>())
+        request      <- (map["request"],JsonStringTransform<TSActionInfoRequestModel>())
+        response           <- (map["response"],JsonStringTransform<TSActionInfoResponseModel>())
         createdTimestamp   <- map["createdTimestamp"]
         status     <- map["status"]
         costTime      <- map["costTime"]
@@ -52,7 +52,7 @@ class TSGeneralPicModel: TSBaseModel {
     }
 }
 
-class TSGeneralPicRequestModel : TSBaseModel {
+class TSActionInfoRequestModel : TSBaseModel {
     var prompt:String = ""
     var promptSort:String = ""
     var width:Int = 0
@@ -65,7 +65,7 @@ class TSGeneralPicRequestModel : TSBaseModel {
     }
 }
 
-class TSGeneralPicResponseModel : TSBaseModel {
+class TSActionInfoResponseModel : TSBaseModel {
     var resultUrl:String = ""
     var vip:Bool = false
     override func mapping(map: ObjectMapper.Map) {

+ 10 - 3
AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGeneralPicVC+Event.swift

@@ -28,6 +28,13 @@ extension TSGeneralPicVC {
         return UIImage(named: "theme_icon_poster")
     }
     
+    var saveBtnText:String{
+        if gennerateType == .photo{
+            return "Set Now".localized
+        }
+        return "Download".localized
+    }
+    
     func getSuccessImage()->UIImage?{
         if let image = netWorkImageView.image {
             return image.pngImage
@@ -37,7 +44,7 @@ extension TSGeneralPicVC {
     
 }
 extension TSGeneralPicVC {
-    func upDateView(state:TSProgressState,model:TSGeneralPicModel?){
+    func upDateView(state:TSProgressState,model:TSActionInfoModel?){
         switch state {
             case .failed(let errorStr):
                 showError(text: errorStr)
@@ -83,7 +90,7 @@ extension TSGeneralPicVC {
    
         againBtn.isHidden = false//重试
         failView.isHidden = false
-        failLabel.text = msg
+//        failLabel.text = msg
         saveBtn.isHidden = true
         successTopView.isHidden = true
         
@@ -93,7 +100,7 @@ extension TSGeneralPicVC {
         isClickTheBlankClosePage = true
     }
     
-    func showSuccess(model:TSGeneralPicModel){
+    func showSuccess(model:TSActionInfoModel){
         generateInView.isHidden = true
         generateInView.isRotating = false
         

+ 23 - 9
AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGeneralPicVC.swift

@@ -9,12 +9,12 @@ class TSGeneralPicVC: TSBottomAlertVC {
     
     
 
-    var imageModel:TSGeneralPicModel?
-    var complete:((TSGeneralPicModel)->Void)
+    var imageModel:TSActionInfoModel?
+    var complete:((TSActionInfoModel)->Void)
     
     var aiText:String
     var gennerateType:TSGennerateType
-    init(aiText: String,gennerateType:TSGennerateType,complete:@escaping ((TSGeneralPicModel)->Void)) {
+    init(aiText: String,gennerateType:TSGennerateType,complete:@escaping ((TSActionInfoModel)->Void)) {
         self.aiText = aiText
         self.gennerateType = gennerateType
         self.complete = complete
@@ -28,6 +28,11 @@ class TSGeneralPicVC: TSBottomAlertVC {
         return viewModel
     }()
     
+    lazy var contactsTool: TSContactsTool = {
+        let contactsTool = TSContactsTool(targetVC: self)
+        return contactsTool
+    }()
+    
     @MainActor required init?(coder: NSCoder) {
         fatalError("init(coder:) has not been implemented")
     }
@@ -61,13 +66,13 @@ class TSGeneralPicVC: TSBottomAlertVC {
             make.size.equalTo(netWorkImageSize)
         }
         
-        
         diyView.addSubview(regenerateBtn)
         regenerateBtn.snp.makeConstraints { make in
             make.top.equalTo(netWorkImageView.snp.bottom).offset(16)
             make.centerX.equalToSuperview()
         }
         
+        saveBtn.setTitle(saveBtnText, for: .normal)
         resultIconImageView.image = resultIcon
         bottomViewH = 540.0
     }
@@ -83,11 +88,20 @@ class TSGeneralPicVC: TSBottomAlertVC {
     
     @objc override func clickSubmitBtn(){
         if let image = getSuccessImage() {
-            PhotoManagerShared.saveImageToAlbum(image) { success, error in
-                if success {
-                    kSavePhotoSuccesswShared.show(atView:self.view)
-                }else{
-                    debugPrint(error)
+            
+            if gennerateType == .poster {
+                PhotoManagerShared.saveImageToAlbum(image) { success, error in
+                    if success {
+                        kSavePhotoSuccesswShared.show(atView:self.view)
+                    }else{
+                        debugPrint(error)
+                    }
+                }
+            }else if gennerateType == .photo {
+                contactsTool.setContactsAvatar(avatarImage: image) { data, error in
+                    if error == nil {
+                        kSavePhotoSuccesswShared.show(atView: self.view)
+                    }
                 }
             }
         }

+ 5 - 5
AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGenneralPicVM.swift

@@ -8,8 +8,8 @@
 import Combine
 import Alamofire
 
-let kTextPicW = 800.0
-let kTextPicH = 1440.0
+private let kTextPicW = 800.0
+private let kTextPicH = 1440.0
 //let kTextWHScale = kTextPicW/kTextPicH
 
 
@@ -19,7 +19,7 @@ class TSGenneralPicVM {
     var queryRequest:Request?
     var stopNetwork = false
    
-    @Published var stateDatauPblished:(TSProgressState,TSGeneralPicModel?) = (TSProgressState.none,nil)
+    @Published var stateDatauPblished:(TSProgressState,TSActionInfoModel?) = (TSProgressState.none,nil)
     var aiText:String = ""
     var gennerateType:TSGennerateType = .poster
     var generatingProgress = 0
@@ -36,7 +36,7 @@ class TSGenneralPicVM {
 ////        }
 //
 //        kDelayOnMainThread(2.0) {
-//            self.stateDatauPblished = (.success(nil),TSGeneralPicModel())
+//            self.stateDatauPblished = (.success(nil),TSActionInfoModel())
 //        }
 //        
 //    }
@@ -70,7 +70,7 @@ class TSGenneralPicVM {
         queryRequest = TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { [weak self] data,error in
             guard let self = self else { return }
             if let result = kNetWorkResultSuccess(data: data) {
-                if let genmojiModel = TSGeneralPicModel(JSON: result) {
+                if let genmojiModel = TSActionInfoModel(JSON: result) {
                     switch genmojiModel.actionStatus {
                     case .success:
                         TSToastShared.hideLoading()

+ 9 - 19
AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/TSTextGeneralPicVC.swift

@@ -17,7 +17,7 @@ class TSTextGeneralPicVC: TSBaseVC {
         let viewModel:TSTextGeneralPicVM = TSTextGeneralPicVM()
         viewModel.isCanGennerateBlock = { [weak self] enabled in
             guard let self = self else { return }
-            creatBtn.isEnabled = enabled
+            creatBtnView.setBtnEnabled(isEnabled: enabled)
         }
         return viewModel
     }()
@@ -30,8 +30,7 @@ class TSTextGeneralPicVC: TSBaseVC {
     
     //###################################### 输入框 ######################################
     lazy var promptTextView: TSPromptTextView = {
-        let promptTextView = TSPromptTextView()
-        promptTextView.textChangedBlock = { [weak self] text in
+        let promptTextView = TSPromptTextView(randomTextArray: kRandomTextToPicArray) { [weak self] text in
             guard let self = self else { return }
             viewModel.promptText = text
         }
@@ -61,13 +60,13 @@ class TSTextGeneralPicVC: TSBaseVC {
     
     
     //###################################### Button ######################################
-    lazy var creatBtn:UIButton  = {
-        let creatBtn = kCreateNormalSubmitBtn(title: "Create Now") {[weak self] in
+    lazy var creatBtnView:TSCreatBtnView  = {
+        let creatBtnView = TSCreatBtnView {[weak self] in
             guard let self = self else { return }
             generateImage()
         }
-        creatBtn.isEnabled = false
-        return creatBtn
+        creatBtnView.setBtnEnabled(isEnabled: false)
+        return creatBtnView
     }()
     
     //###################################### Generate History ######################################
@@ -77,16 +76,7 @@ class TSTextGeneralPicVC: TSBaseVC {
         return historyTitleView
     }()
     
-    lazy var creatBtnView:UIView  = {
-        let creatBtnView = UIView()
-        creatBtnView.addSubview(creatBtn)
-        creatBtn.snp.makeConstraints { make in
-            make.center.equalToSuperview()
-            make.width.equalTo(creatBtn.width)
-            make.height.equalTo(creatBtn.height)
-        }
-        return creatBtnView
-    }()
+
 
     override func createView() {
         view.backgroundColor = .clear
@@ -112,12 +102,12 @@ class TSTextGeneralPicVC: TSBaseVC {
 
         cusStackView.addSubviewToStack(creatBtnView)
         creatBtnView.snp.makeConstraints { make in
-            make.height.equalTo(64)
+            make.height.equalTo(creatBtnView.viewH)
         }
         
         cusStackView.addSubviewToStack(historyTitleView)
         historyTitleView.snp.makeConstraints { make in
-            make.height.equalTo(photoStyleView.viewH)
+            make.height.equalTo(historyTitleView.viewH)
         }
         
     }

+ 13 - 1
AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/VM/TSTextGeneralPicVM.swift

@@ -8,6 +8,18 @@
 import Alamofire
 import ObjectMapper
 
+let kRandomTextToPicArray:[String] = [
+    "Ultra-detailed northern lights over a glacial lake, mirrored reflections with vibrant turquoise and magenta hues, surreal celestial atmosphere, digital painting style with soft glow effects.",
+    "Neon-lit cyberpunk night market in a rainy Asian metropolis, holographic food stalls and floating drones, teal-orange color grading, retro-futuristic architecture with glowing Kanji signs",
+    "Macro photography of rainbow candy landscape with gummy bear mountains, chocolate river and lollipop trees, hyper-realistic textures under golden hour lighting",
+    "Traditional Chinese ink painting style phoenix soaring through misty mountain peaks, dynamic black brushstrokes with crimson accents on rice paper texture",
+    "Bioluminescent underwater metropolis with glass dome structures, schools of glowing fish weaving through coral skyscrapers, deep-sea blue palette with neon coral highlights",
+    "1950s retro sci-fi movie poster style wallpaper featuring a rocket orbiting Saturn, vintage orange-teal color scheme with halftone textures and hand-drawn typography",
+    "Minimalist wallpaper with overlapping translucent 3D geometric shapes in gradient pastel colors, clean negative space, soft shadows and metallic accents, 4K abstract design.",
+    "Steampunk floating library with brass gears and clockwork mechanisms, leather-bound books flying through amber-lit fog, Victorian-era architecture blended with retro-futurism",
+    "Zen rock garden transformed into cosmic landscape, black sand waves surrounding cratered moon-like stones, starry galaxy reflected in miniature, monochromatic with silver foil accents",
+    "Futuristic AI core visualization with flowing golden data streams through transparent quantum circuits, dark background with floating holographic equations, cybernetic glow effect"
+]
 
 enum TSGennerateType:Int,Equatable{
     case poster = 0     //海报
@@ -77,7 +89,7 @@ extension TSTextGeneralPicVM {
         return prompt
     }
 
-    func saveModel(model:TSGeneralPicModel){
+    func saveModel(model:TSActionInfoModel){
         if gennerateType == .poster {
             TSPosterHistory.saveModel(model: model)
         }else if gennerateType == .photo{

+ 75 - 0
AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSCreatBtnView.swift

@@ -0,0 +1,75 @@
+//
+//  TSCreatBtnView.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/6.
+//
+
+class TSCreatBtnView: TSBaseView {
+
+    var viewH:CGFloat = 64
+    
+    var clickBlock:()->Void
+
+    init(clickBlock: @escaping () -> Void) {
+        self.clickBlock = clickBlock
+        super.init(frame: .zero)
+    }
+    
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    //###################################### Button ######################################
+    lazy var creatBtn:UIButton  = {
+        
+        let btn = UIButton.createButton(title:"Create Now",backgroundColor: .black,font: UIFont.font(size: 16,weight: .regular),titleColor:.themeColor,corner: 24)
+        {[weak self] in
+            guard let self = self else { return }
+            clickBlock()
+        }
+        
+        btn.layer.borderWidth = 1
+        btn.layer.borderColor = UIColor.themeColor.cgColor
+        btn.frame = CGRectMake(0, 0, 200, 48)
+        return btn
+    }()
+    
+    lazy var shadowView: UIView = {
+        let shadowView = UIView()
+        shadowView.frame = creatBtn.frame
+        shadowView.layer.shadowColor = UIColor.themeColor.cgColor
+        shadowView.layer.shadowOffset = .zero
+        shadowView.layer.shadowOpacity = 0.5
+        shadowView.layer.shadowRadius = 24
+        return shadowView
+    }()
+
+    override func creatUI() {
+        
+        contentView.addSubview(shadowView)
+        shadowView.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.equalTo(creatBtn.width)
+            make.height.equalTo(creatBtn.height)
+        }
+
+        shadowView.addSubview(creatBtn)
+        creatBtn.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+
+    func setBtnEnabled(isEnabled:Bool) {
+        creatBtn.isEnabled = isEnabled
+        if isEnabled {
+            shadowView.layer.shadowColor = UIColor.themeColor.cgColor
+            creatBtn.layer.borderColor = UIColor.themeColor.withAlphaComponent(1.0).cgColor
+            creatBtn.setTitleColor(UIColor.themeColor.withAlphaComponent(1.0), for: .normal)
+        }else{
+            shadowView.layer.shadowColor = UIColor.clear.cgColor
+            creatBtn.layer.borderColor = UIColor.themeColor.withAlphaComponent(0.4).cgColor
+            creatBtn.setTitleColor(UIColor.themeColor.withAlphaComponent(0.6), for: .normal)
+        }
+    }
+}

+ 2 - 4
AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSPromptStyleView.swift

@@ -13,9 +13,7 @@ class TSPromptStyleView:TSBaseView {
         didSet{
             styleCollectionView.reloadData()
             if dataArray.count > 0 {
-                kDelayMainShort{
-                    self.styleCollectionView.selectItem(at: self.currentIndexPath, animated: true, scrollPosition: .centeredHorizontally)
-                }
+                self.styleCollectionView.selectItem(at: self.currentIndexPath, animated: true, scrollPosition: .centeredHorizontally)
             }
         }
     }
@@ -23,7 +21,7 @@ class TSPromptStyleView:TSBaseView {
     lazy var layout: UICollectionViewFlowLayout = {
         let layout = UICollectionViewFlowLayout()
         layout.scrollDirection = .horizontal
-        layout.itemSize = CGSize(width: 110, height: 110)
+        layout.itemSize = CGSize(width: 109, height: 110)
         layout.minimumInteritemSpacing = 0.0
         layout.minimumLineSpacing = 12.0
         layout.sectionInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)

+ 14 - 21
AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSPromptTextView.swift

@@ -6,24 +6,20 @@
 //
 
 
-let kRandomTextArray:[String] = [
-    "Ultra-detailed northern lights over a glacial lake, mirrored reflections with vibrant turquoise and magenta hues, surreal celestial atmosphere, digital painting style with soft glow effects.",
-    "Neon-lit cyberpunk night market in a rainy Asian metropolis, holographic food stalls and floating drones, teal-orange color grading, retro-futuristic architecture with glowing Kanji signs",
-    "Macro photography of rainbow candy landscape with gummy bear mountains, chocolate river and lollipop trees, hyper-realistic textures under golden hour lighting",
-    "Traditional Chinese ink painting style phoenix soaring through misty mountain peaks, dynamic black brushstrokes with crimson accents on rice paper texture",
-    "Bioluminescent underwater metropolis with glass dome structures, schools of glowing fish weaving through coral skyscrapers, deep-sea blue palette with neon coral highlights",
-    "1950s retro sci-fi movie poster style wallpaper featuring a rocket orbiting Saturn, vintage orange-teal color scheme with halftone textures and hand-drawn typography",
-    "Minimalist wallpaper with overlapping translucent 3D geometric shapes in gradient pastel colors, clean negative space, soft shadows and metallic accents, 4K abstract design.",
-    "Steampunk floating library with brass gears and clockwork mechanisms, leather-bound books flying through amber-lit fog, Victorian-era architecture blended with retro-futurism",
-    "Zen rock garden transformed into cosmic landscape, black sand waves surrounding cratered moon-like stones, starry galaxy reflected in miniature, monochromatic with silver foil accents",
-    "Futuristic AI core visualization with flowing golden data streams through transparent quantum circuits, dark background with floating holographic equations, cybernetic glow effect"
-]
-
-
 class TSPromptTextView : TSBaseView{
     
-
-    var textChangedBlock:((String)->Void)?
+    var randomTextArray:[String]
+    var textChangedBlock:((String)->Void)
+    
+    init(randomTextArray: [String], textChangedBlock: @escaping (String) -> Void) {
+        self.randomTextArray = randomTextArray
+        self.textChangedBlock = textChangedBlock
+        super.init(frame: .zero)
+    }
+    
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
     
     lazy var titleView: TSTGPTitleView = {
         let titleView = TSTGPTitleView()
@@ -32,7 +28,7 @@ class TSPromptTextView : TSBaseView{
     }()
   
     lazy var randomTextPicker: TSRandomTextPicker = {
-        let textPicker = TSRandomTextPicker(texts: kRandomTextArray)
+        let textPicker = TSRandomTextPicker(texts: randomTextArray)
         return textPicker
     }()
     
@@ -96,9 +92,6 @@ class TSPromptTextView : TSBaseView{
     lazy var clearBtn: TSUIExpandedTouchButton = {
         let clearBtn = TSUIExpandedTouchButton()
         clearBtn.setUpButton(image: UIImage(named: "clear_text"))
-//        let clearBtn = UIButton.createButton(
-//            image: UIImage(named: "clear_text")
-//        )
         { [weak self]  in
             guard let self = self else { return }
             customTextView.text = ""
@@ -222,7 +215,7 @@ extension TSPromptTextView: UITextViewDelegate{
     
     func textViewDidChange(_ textView: UITextView) {
         currenMun = textView.text.count
-        textChangedBlock?(textView.text)
+        textChangedBlock(textView.text)
     }
     
 }

+ 0 - 0
AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TsTGPPhotoStyleView.swift → AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSTGPPhotoStyleView.swift


+ 0 - 60
AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC.swift

@@ -1,60 +0,0 @@
-//
-//  TSAIRintoneVC.swift
-//  AIRingtone
-//
-//  Created by 100Years on 2025/2/27.
-//
-
-class TSAIRintoneVC: TSBaseVC {
-    
-    lazy var navBarView: TSBaseNavContentBarView = {
-        let navBarView = TSBaseNavContentBarView()
-
-        let titleImageView = UIImageView.createImageView(imageName: "nav_title_aiRing",contentMode: .scaleToFill)
-        navBarView.barView.addSubview(titleImageView)
-        titleImageView.snp.makeConstraints { make in
-            make.center.equalToSuperview()
-        }
-
-        return navBarView
-    }()
-    
-    
-    
-    lazy var promptTextView: TSPromptTextView = {
-        let promptTextView = TSPromptTextView()
-        return promptTextView
-    }()
-    
-    override func createView() {
-        
-        setViewBgImageNamed(named: kViewBJ)
-        
-        edgesForExtendedLayout = []
-        navBarContentView.addSubview(navBarView)
-        navBarView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
-        }
-        
-        
-        
-        
-        
-        
-        
-        
-        
-        
-        
-        contentView.addSubview(promptTextView)
-        promptTextView.snp.makeConstraints { make in
-            make.leading.top.trailing.equalTo(0)
-//            make.bottom.equalTo(0)
-        }
-        
-        
-        
-        
-        
-    }
-}

+ 225 - 0
AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/TSAIRintoneVC.swift

@@ -0,0 +1,225 @@
+//
+//  TSAIRintoneVC.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/2/27.
+//
+import SwipeCellKit
+class TSAIRintoneVC: TSBaseVC {
+    
+    lazy var viewModel : TSAIRintoneVM = {
+        let viewModel = TSAIRintoneVM()
+        return viewModel
+    }()
+    
+    
+    lazy var navBarView: TSBaseNavContentBarView = {
+        let navBarView = TSBaseNavContentBarView()
+
+        let titleImageView = UIImageView.createImageView(imageName: "nav_title_aiRing",contentMode: .scaleToFill)
+        navBarView.barView.addSubview(titleImageView)
+        titleImageView.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+        }
+
+        return navBarView
+    }()
+    
+    var stickyHeaders: [Int: TSAIRintoneHistorySectionHeaderView] = [:] // 存储悬浮的区间头
+    lazy var layout: UICollectionViewFlowLayout = {
+        let layout = UICollectionViewFlowLayout()
+        layout.scrollDirection = .vertical
+        layout.itemSize = CGSize(width: k_ScreenWidth-32, height: 74)
+        layout.minimumInteritemSpacing = 10.0
+        layout.minimumLineSpacing = 18.0
+        layout.headerReferenceSize = CGSizeMake(k_ScreenWidth, 48)
+//        layout.sectionHeadersPinToVisibleBounds = true
+        return layout
+    }()
+    
+    lazy var collectionView: UICollectionView = {
+        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
+        collectionView.delegate = self
+        collectionView.dataSource = self
+        collectionView.showsVerticalScrollIndicator = false
+        collectionView.showsHorizontalScrollIndicator = false
+        collectionView.backgroundColor = .clear
+        collectionView.register(TSAIRintoneHistoryCell.self, forCellWithReuseIdentifier: TSAIRintoneHistoryCell.cellID)
+        collectionView.register(TSAIRintoneHistorySectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: TSAIRintoneHistorySectionHeaderView.reuseIdentifier)
+        if #available(iOS 11.0, *) {
+            collectionView.contentInsetAdjustmentBehavior = .never
+        }
+        return collectionView
+    }()
+    
+    lazy var generalRintoneVC: TSTextGeneralRintoneVC = {
+        let generalRintoneVC = TSTextGeneralRintoneVC()
+        return generalRintoneVC
+    }()
+
+    override func createView() {
+        
+        setViewBgImageNamed(named: kViewBJ)
+        
+        edgesForExtendedLayout = []
+        navBarContentView.addSubview(navBarView)
+        navBarView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        contentView.addSubview(collectionView)
+        collectionView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+        addredView()
+        kDelayOnMainThread(0.5){
+//            self.addredView()
+//            let vcViewH = 464.0//generalRintoneVC.viewH
+//            self.generalRintoneVC.view.frame = CGRectMake(0, -vcViewH, k_ScreenWidth, vcViewH)
+        }
+
+    }
+    
+    func addredView() {
+//        let vcViewH = 464.0
+//        let redView = UIView(frame: CGRectMake(0, -vcViewH, k_ScreenWidth, vcViewH))
+//        redView.backgroundColor = .red
+//        collectionView.addSubview(redView)
+//        collectionView.contentInset = UIEdgeInsets(top: vcViewH, left: 0, bottom: 0, right: 0)
+        let vcViewH = 464.0//generalRintoneVC.viewH
+//        generalRintoneVC.view.frame = CGRectMake(0, -vcViewH, k_ScreenWidth, vcViewH)
+        collectionView.addSubview(generalRintoneVC.view)
+        generalRintoneVC.view.snp.makeConstraints { make in
+            make.top.equalTo(-vcViewH)
+            make.leading.trailing.equalTo(0)
+            make.height.equalTo(vcViewH)
+        }
+        
+        collectionView.contentInset = UIEdgeInsets(top: vcViewH, left: 0, bottom: 0, right: 0)
+    }
+    
+    override func viewWillAppear(_ animated: Bool) {
+        //
+    }
+    override func dealThings() {
+//        updateListView()
+    }
+    
+    func updateListView(){
+        collectionView.reloadData()
+    }
+    
+    override func viewDidLayoutSubviews() {
+        super.viewDidLayoutSubviews()
+//        print("View did layout subviews")
+//        let vcViewH = 464.0//generalRintoneVC.viewH
+//        generalRintoneVC.view.frame = CGRectMake(0, -vcViewH, k_ScreenWidth, vcViewH)
+    }
+}
+
+extension TSAIRintoneVC: UICollectionViewDataSource ,UICollectionViewDelegate {
+    
+    public func numberOfSections(in collectionView: UICollectionView) -> Int {
+        return viewModel.historyModelList.count
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+        if let sectionModel = viewModel.historyModelList.safeObj(At: section) {
+            return sectionModel.list.count
+        }
+        return 0
+    }
+    
+    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        
+        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TSAIRintoneHistoryCell.cellID, for: indexPath)
+        
+        if let sectionModel = viewModel.historyModelList.safeObj(At: indexPath.section),
+            let itemModel = sectionModel.list.safeObj(At: indexPath.item),
+           let cell = cell as? TSAIRintoneHistoryCell
+        {
+            cell.delegate = self
+            cell.model = itemModel
+        }
+        
+        return cell
+    }
+
+    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+        if let sectionModel = viewModel.historyModelList.safeObj(At: indexPath.section),
+           let itemModel = sectionModel.list.safeObj(At: indexPath.item)
+        {
+            
+//            let chatVC = TSChatViewController()
+//            chatVC.viewModel.uiStyle = .history
+//            chatVC.viewModel.dbAIChatList = itemModel
+//            chatVC.deleteBlock = { [weak self]  in
+//                guard let self = self else { return }
+//                //删除 UI 层的 cell
+//                sectionModel.list.remove(at: indexPath.item)
+//                if sectionModel.list.count == 0 {
+//                    self.viewModel.historyModelList.remove(at: indexPath.section)
+//                }
+//                updateListView()
+//                
+//            }
+//            self.navigationController?.pushViewController(chatVC, animated: true)
+        }
+    }
+    
+    
+    public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
+        if let sectionModel = viewModel.historyModelList.safeObj(At: indexPath.section) {
+            if kind == UICollectionView.elementKindSectionHeader {
+                if let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: TSAIRintoneHistorySectionHeaderView.reuseIdentifier, for: indexPath) as? TSAIRintoneHistorySectionHeaderView {
+                    header.titleView.titleLab.text = sectionModel.title
+                    
+                    stickyHeaders[indexPath.section] = header // 存储区间头
+                    return header
+                }
+                
+                
+            }
+        }
+        return TSAIRintoneHistorySectionHeaderView()
+    }
+    
+
+}
+
+extension TSAIRintoneVC: SwipeCollectionViewCellDelegate {
+    
+    func collectionView(_ collectionView: UICollectionView, editActionsForItemAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]? {
+        guard orientation == .right else { return nil }
+
+        // 删除操作
+        let deleteAction = SwipeAction(style: .destructive, title: nil) {[weak self] action, indexPath in
+            guard let self = self else { return }
+            showCustomAlert(message: "Are you sure to delete".localized, deleteHandler:  {
+                if let sectionModel = self.viewModel.historyModelList.safeObj(At: indexPath.section),
+                let itemModel = sectionModel.list.safeObj(At: indexPath.item){
+                    sectionModel.list.remove(at: indexPath.item)
+              
+                    if sectionModel.list.count == 0 {
+                        self.viewModel.historyModelList.remove(at: indexPath.section)
+                    }
+                    
+                    self.updateListView()
+                }
+            })
+        }
+        
+        deleteAction.backgroundColor = "#E83E3E".uiColor
+        deleteAction.image = UIImage(named: "delete_white")
+        return [deleteAction]
+    }
+    
+    func collectionView(_ collectionView: UICollectionView, editActionsOptionsForItemAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions {
+        var options = SwipeOptions()
+//        options.expansionStyle = .destructive(automaticallyDelete: false) // 完全滑动时是否自动触发操作
+        options.transitionStyle = .border // 滑动动画样式
+        return options
+    }
+    
+}

+ 91 - 0
AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/View/TSAIRintoneHistoryCell.swift

@@ -0,0 +1,91 @@
+//
+//  TSAIRintoneHistoryCell.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/6.
+//
+
+import SwipeCellKit
+class TSAIRintoneHistoryCell: SwipeCollectionViewCell {
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        creatUI()
+    }
+    
+    required public init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    static let cellID = "TSAIRintoneHistoryCell"
+
+    lazy var setRingBtn: TSUIExpandedTouchButton = {
+        let setRingBtn = TSUIExpandedTouchButton()
+        setRingBtn.setImage(UIImage(named: "ai_setRing_icon"), for: .normal)
+        return setRingBtn
+    }()
+    
+    lazy var ringView: TSRingToneCellView = {
+        let ringToneView = TSRingToneCellView()
+        ringToneView.backgroundColor = .clear
+        return ringToneView
+    }()
+    
+    var model:TSActionInfoModel?{
+        didSet{
+
+        }
+    }
+    
+    override var isSelected: Bool{
+        didSet{
+            backgroundColor = isSelected ? "#3C213F".uiColor :.cardColor
+            
+            ringView.isloading = isSelected
+            
+        }
+    }
+    
+    func creatUI() {
+
+        backgroundColor = .cardColor
+        cornerRadius = 16.0
+        
+        contentView.addSubview(ringView)
+        ringView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    
+        contentView.addSubview(setRingBtn)
+        setRingBtn.snp.makeConstraints { make in
+            make.centerY.equalToSuperview()
+            make.trailing.equalTo(-16)
+            make.width.height.equalTo(20)
+        }
+    }
+
+}
+
+class TSAIRintoneHistorySectionHeaderView: UICollectionReusableView {
+    static let reuseIdentifier = "TSAIRintoneHistorySectionHeaderView"
+    
+    let titleView: TSTGPTitleView = {
+        let titleView = TSTGPTitleView()
+        return titleView
+    }()
+    
+    
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        
+        addSubview(titleView)
+        titleView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+}

+ 32 - 0
AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/ViewModel/TSAIRintoneVM.swift

@@ -0,0 +1,32 @@
+//
+//  TSAIRintoneVM.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/6.
+//
+
+class TSAIRintoneVM {
+    
+    
+    lazy var historyModelList: [TSAIRintoneHistoryModel] = {
+        var historyModelList =  [TSAIRintoneHistoryModel]()
+        
+        let model = TSAIRintoneHistoryModel(title: "Generate History", list: [TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel(),TSActionInfoModel()])
+        historyModelList.append(model)
+        
+        return historyModelList
+    }()
+    
+    
+}
+
+
+class TSAIRintoneHistoryModel {
+    var title:String = ""
+    var list:[TSActionInfoModel] = []
+    
+    init(title: String, list: [TSActionInfoModel]) {
+        self.title = title
+        self.list = list
+    }
+}

+ 101 - 0
AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVC+Event.swift

@@ -0,0 +1,101 @@
+//
+//  TSGeneralRintoneVC+Event.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/6.
+//
+
+extension TSGeneralRintoneVC {
+    
+    var resultIcon:UIImage?{
+        return UIImage(named: "ai_rintone_icon")
+    }
+
+}
+extension TSGeneralRintoneVC {
+    func upDateView(state:TSProgressState,model:TSActionInfoModel?){
+        switch state {
+            case .failed(let errorStr):
+                showError(text: errorStr)
+            case .success:
+                if let model = model {
+                    showSuccess(model: model)
+                }else{
+                    showError(text: nil)
+                }
+            case .progressString(let string):
+                showProgress(text: string)
+            default:
+                showLoading()
+        }
+    }
+    
+    func showProgress(text:String) {
+        generateInView.isHidden = false
+        generateInView.showLoading(text: text)
+        generateInView.isRotating = true
+        
+        bottomView.isHidden = true
+        
+        isClickTheBlankClosePage = false
+    }
+    
+    func showLoading(){
+        generateInView.isHidden = false
+        generateInView.showLoading(text: "Generating...".localized)
+        generateInView.isRotating = true
+        
+        bottomView.isHidden = true
+        
+        isClickTheBlankClosePage = false
+    }
+    
+    func showError(text:String?){
+        let msg = "Failed to Generate, please try later".localized
+        generateInView.isHidden = true
+        generateInView.isRotating = false
+    
+        bottomView.isHidden = false
+   
+        againBtn.isHidden = false//重试
+        failView.isHidden = false
+//        failLabel.text = msg
+        saveBtn.isHidden = true
+        successTopView.isHidden = true
+        
+        ringView.isHidden = true
+        regenerateBtn.isHidden = true
+        
+        isClickTheBlankClosePage = true
+    }
+    
+    func showSuccess(model:TSActionInfoModel){
+        generateInView.isHidden = true
+        generateInView.isRotating = false
+        
+        bottomView.isHidden = false
+        
+        againBtn.isHidden = true//重试
+        failView.isHidden = true
+        saveBtn.isHidden = false
+        successTopView.isHidden = false
+
+        infoModel = model
+        isClickTheBlankClosePage = true
+        
+        ringView.isHidden = false
+        regenerateBtn.isHidden = false
+        
+        
+        TSCommonTool.downloadAndCacheFile(from: "") { [weak self] path, error in
+            guard let self = self else { return }
+        
+        }
+        
+//        kPurchaseDefault.useOnceForFree(type: .generatePic)
+        
+        if let model = infoModel {
+            complete(model)
+        }
+    }
+}

+ 114 - 0
AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVC.swift

@@ -0,0 +1,114 @@
+//
+//  TSGeneralRintoneVC.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/6.
+//
+
+class TSGeneralRintoneVC: TSBottomAlertVC {
+    
+    var infoModel:TSActionInfoModel?
+    var complete:((TSActionInfoModel)->Void)
+    
+    var aiText:String
+    init(aiText: String,complete:@escaping ((TSActionInfoModel)->Void)) {
+        self.aiText = aiText
+        self.complete = complete
+        super.init()
+    }
+    
+    lazy var viewModel: TSGeneralRintoneVM = {
+        let viewModel:TSGeneralRintoneVM = TSGeneralRintoneVM()
+        viewModel.aiText = aiText
+        return viewModel
+    }()
+    
+    @MainActor required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    lazy var ringView: TSRingToneCellView = {
+        let ringToneView = TSRingToneCellView()
+        ringToneView.playBtn.addTarget(self, action: #selector(clickPlay), for: .touchUpInside)
+        return ringToneView
+    }()
+    
+    //############################## 生成动画 ##############################
+    lazy var generateInView : TSCommonloadingView = {
+        let generateInView = TSCommonloadingView()
+        generateInView.cancelBtn.addTarget(self, action: #selector(closePage), for: .touchUpInside)
+        return generateInView
+    }()
+
+    
+    override func createView() {
+        super.createView()
+        
+        view.addSubview(generateInView)
+        generateInView.snp.makeConstraints { make in
+            make.top.bottom.leading.trailing.equalTo(0)
+        }
+
+        diyView.addSubview(ringView)
+        ringView.snp.makeConstraints { make in
+            make.top.equalTo(98)
+            make.centerX.equalToSuperview()
+            make.width.equalTo(k_ScreenWidth - 40)
+            make.height.equalTo(72)
+        }
+        
+        diyView.addSubview(regenerateBtn)
+        regenerateBtn.snp.makeConstraints { make in
+            make.top.equalTo(ringView.snp.bottom).offset(16)
+            make.centerX.equalToSuperview()
+        }
+        saveBtn.setTitle("Set As Ringtone".localized, for: .normal)
+        resultIconImageView.image = resultIcon
+        bottomViewH = 340.0
+        
+        
+        diyView.addSubview(failView)
+        failView.snp.updateConstraints { make in
+            make.centerY.equalToSuperview().offset(0)
+        }
+    }
+    
+    @objc override func closePage() {
+        viewModel.cancelAllRequest()
+        self.dismiss(animated: true, completion: nil)
+    }
+    
+    override func clickAgainBtn() {
+        viewModel.creatRintone(text:aiText)
+    }
+    
+    @objc override func clickSubmitBtn(){
+
+        
+    }
+    
+    @objc func clickPlay(){
+        ringView.isPlay = !ringView.isPlay
+        viewModel.changeAudioState(isPlay: ringView.isPlay)
+    }
+    
+    override func dealThings() {
+        viewModel.creatRintone(text: self.aiText)
+        viewModel.$stateDatauPblished.receive(on: DispatchQueue.main).sink {[weak self]  (state,model) in
+            guard let self = self else { return }
+            self.upDateView(state: state, model: model)
+        }.store(in: &cancellable)
+    }
+}
+
+extension TSGeneralRintoneVC{
+    func setRingViewData(model:TSActionInfoModel) {
+        
+//        ringView.cellView.nameLab.text = model.ringtoneName
+//        ringView.cellView.coverImageView.setAsyncImage(urlString: model.ringtoneCover,contentMode: .scaleAspectFill)
+//        ringView.cellView.timeLab.text = duration.floatToMinuteSecond()
+//        vm.playRingtone(ringtone: model.ringtone)
+        
+    }
+}
+

+ 145 - 0
AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVM.swift

@@ -0,0 +1,145 @@
+//
+//  TSGeneralRintoneVM.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/6.
+//
+
+import Combine
+import Alamofire
+
+class TSGeneralRintoneVM {
+    
+    var audioPlayer: TSAudioPlayer?
+    
+    var creatRequest:Request?
+    var queryRequest:Request?
+    var stopNetwork = false
+   
+    @Published var stateDatauPblished:(TSProgressState,TSActionInfoModel?) = (TSProgressState.none,nil)
+    var aiText:String = ""
+    var generatingProgress = 0
+    
+    func creatRintone(text:String) {
+
+        stateDatauPblished = (.start,nil)
+        stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
+
+        kDelayOnMainThread(2.0) {
+            self.stateDatauPblished = (.failed("error?.localizedDescription" ?? ""),nil)
+        }
+
+//        kDelayOnMainThread(2.0) {
+//            self.stateDatauPblished = (.success(nil),TSActionInfoModel())
+//        }
+
+    }
+    
+ 
+    func creatRintone1(text:String) {
+        generatingProgress = 0
+        aiText = text
+        let postDict:[String : Any] = [
+            "prompt":text,
+            "width":10
+        ]
+        stateDatauPblished = (.start,nil)
+        stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
+        creatRequest = TSNetworkShared.post(urlType: .textPicCreate,parameters: postDict) { [weak self] data,error in
+            guard let self = self else { return }
+            if let dataDict = data as? [String:Any] ,
+               dataDict.safeInt(forKey: "code") == 200,
+               let actionId = dataDict["actionId"] as? Int{
+                if stopNetwork == false {
+                    self.getActionInfo(action_id:actionId)
+                }
+            }else{
+                self.stateDatauPblished = (.failed(error?.localizedDescription ?? ""),nil)
+            }
+        }
+    }
+    
+    func getActionInfo(action_id:Int){
+        queryRequest = TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { [weak self] data,error in
+            guard let self = self else { return }
+            if let result = kNetWorkResultSuccess(data: data) {
+                if let genmojiModel = TSActionInfoModel(JSON: result) {
+                    switch genmojiModel.actionStatus {
+                    case .success:
+                        TSToastShared.hideLoading()
+                        self.stateDatauPblished = (.success(nil),genmojiModel)
+                        generatingProgress = 0
+                    case .failed:
+                        self.stateDatauPblished = (.failed(kNetWorkMessage(data: data) ?? ""),nil)
+                        generatingProgress = 0
+                    default:
+                        stateDatauPblished = (.progressString(generating(progress: genmojiModel.percent)),nil)
+                        if stopNetwork == false {
+                            kDelayOnMainThread(1.0) {
+                                self.getActionInfo(action_id: action_id)
+                            }
+                        }
+                    }
+                }
+            }else{
+                self.stateDatauPblished = (.failed(error?.localizedDescription ?? ""),nil)
+            }
+        }
+    }
+    
+    func cancelAllRequest(){
+        creatRequest?.cancel()
+        queryRequest?.cancel()
+        stopNetwork = true
+    }
+    
+    func generating(progress:Float) -> String {
+
+        //Generating 0%-100%
+        var progressInt = Int(progress*100)
+
+        if generatingProgress >= progressInt{
+            return "Generating \(generatingProgress)%"
+        }
+
+        if progressInt > 99 {
+            progressInt = 99
+        }
+        
+        generatingProgress = progressInt
+        return "Generating \(progressInt)%"
+    }
+}
+
+extension TSGeneralRintoneVM {
+    
+    func playRingtone(ringtone:String?) {
+        if let ringtone = ringtone {
+            self.audioPlayer?.stop()
+            TSCommonTool.downloadAndCacheFile(from: ringtone) { [self] path, error in
+                if let path = path {
+                    //播放
+                    if let url = URL(string: path) {
+                        self.audioPlayer = TSAudioPlayer(url: url)
+                        self.audioPlayer?.setLoop(true)
+                        self.audioPlayer?.setVolume(1.0)
+                        dePrint(self.audioPlayer?.duration)
+                    }
+                    
+                }else{
+                    //暂停
+                    self.audioPlayer?.stop()
+                }
+            }
+        }
+    }
+
+    func changeAudioState(isPlay:Bool) {
+        if isPlay {
+            self.audioPlayer?.play()
+        }else{
+            self.audioPlayer?.pause()
+        }
+    }
+    
+}

+ 140 - 0
AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/TSTextGeneralRintoneVC.swift

@@ -0,0 +1,140 @@
+//
+//  TSTextGeneralRintoneVC.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/6.
+//
+
+
+class TSTextGeneralRintoneVC: TSBaseVC {
+    
+    var viewH:CGFloat{
+        get {
+            if cusStackView.viewH > 0{
+                return cusStackView.viewH
+            }
+            return 464.0
+        }
+    }
+    
+    lazy var viewModel: TSTextGeneralRintoneVM = {
+        let viewModel:TSTextGeneralRintoneVM = TSTextGeneralRintoneVM()
+        viewModel.isCanGennerateBlock = { [weak self] enabled in
+            guard let self = self else { return }
+            creatBtnView.setBtnEnabled(isEnabled: enabled)
+        }
+        return viewModel
+    }()
+    
+    //###################################### cusStackView ######################################
+    lazy var cusStackView: TSCustomStackView = {
+        let cusStackView = TSCustomStackView(axis: .vertical,spacing: 8)
+        return cusStackView
+    }()
+    
+    //###################################### 输入框 ######################################
+    lazy var promptTextView: TSPromptTextView = {
+        let promptTextView = TSPromptTextView(randomTextArray: kRandomTextToPicArray) { [weak self] text in
+            guard let self = self else { return }
+            viewModel.promptText = text
+        }
+        return promptTextView
+    }()
+    
+    //###################################### Prompt类型 ######################################
+    lazy var promptStyleView: TSPromptStyleView = {
+        let promptStyleView = TSPromptStyleView()
+        promptStyleView.dataArray = viewModel.ptpStyleModels
+        promptStyleView.selectedValueBlock = { [weak self] model in
+            guard let self = self else { return }
+            viewModel.selectPromptModel = model
+        }
+        return promptStyleView
+    }()
+    
+    
+    //###################################### Button ######################################
+    lazy var creatBtnView:TSCreatBtnView  = {
+        let creatBtnView = TSCreatBtnView {[weak self] in
+            guard let self = self else { return }
+            generateImage()
+        }
+        creatBtnView.setBtnEnabled(isEnabled: false)
+        return creatBtnView
+    }()
+    
+    //###################################### Generate History ######################################
+    lazy var historyTitleView: TSTGPTitleView = {
+        let historyTitleView = TSTGPTitleView()
+        historyTitleView.titleLab.text = "Generate History".localized
+        return historyTitleView
+    }()
+    
+
+
+    override func createView() {
+        view.backgroundColor = .clear
+        setNavBarViewHidden(true)
+        
+        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(clickView))
+        tapGesture.cancelsTouchesInView = false
+        view.addGestureRecognizer(tapGesture)
+        
+        contentView.addSubview(cusStackView)
+        cusStackView.snp.makeConstraints { make in
+            make.top.leading.bottom.trailing.equalTo(0)
+        }
+
+        cusStackView.addSubviewToStack(promptTextView)
+        
+        cusStackView.addSubviewToStack(promptStyleView)
+
+        cusStackView.addSubviewToStack(creatBtnView)
+        creatBtnView.snp.makeConstraints { make in
+            make.height.equalTo(creatBtnView.viewH)
+            make.width.equalTo(k_ScreenWidth)
+        }
+    }
+    
+    override func dealThings() {
+//        NotificationCenter.default.addObserver(self, selector: #selector(vipInfoChanged), name: .kPurchaseDidChanged, object: nil)
+    }
+    
+//    @objc func vipInfoChanged() {
+//        kExecuteOnMainThread {
+//            self.vipBtn.isHidden = PurchaseManager.default.isVip
+//            self.collectionComponent.reloadData()
+//        }
+//    }
+    
+    @objc func clickView() {
+        view.endEditing(true)
+    }
+
+    
+    @objc func clickCollectionView() {
+        view.endEditing(true)
+    }
+}
+
+extension TSTextGeneralRintoneVC {
+    func generateImage() {
+        
+//        //判断 vip
+//        if kJudgeVip(externalBool: kPurchaseDefault.freeNumAvailable(type: .textGeneratePic) == false, vc: self) {[weak self] in
+//            guard let self = self else { return }
+//        }{ return }
+        
+        let gennerateVC = TSGeneralRintoneVC(aiText:viewModel.prompt)
+        {[weak self] model in
+            guard let self = self else { return }
+            model.request.promptSort = viewModel.promptText
+            viewModel.saveModel(model:model)
+        
+            NotificationCenter.default.post(name: .kReloadUIData, object: nil, userInfo: ["TSGennerateType": viewModel.gennerateType])
+        }
+        
+        kPresentModalVC(target: self, modelVC: gennerateVC,transitionStyle: .crossDissolve)
+    }
+
+}

+ 80 - 0
AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/VM/TSTextGeneralRintoneVM.swift

@@ -0,0 +1,80 @@
+//
+//  TSTextGeneralRintoneVM.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/6.
+//
+
+import Alamofire
+import ObjectMapper
+
+class TSTextGeneralRintoneVM {
+    
+    //选择 prompt 类型组
+    lazy var ptpStyleModels: [TSPTPStyleModel] = {
+        var ptpStyleModels = [TSPTPStyleModel]()
+        if let dataArray = Mapper<TSPTPStyleModel>().mapArray(JSONfile: "text_rintone_style.json"){
+            ptpStyleModels = dataArray
+            
+            if let model = dataArray.first {
+                selectPromptModel = model //加上默认的选择
+            }
+        }
+        
+        return ptpStyleModels
+    }()
+    
+    //输入框内容
+    var promptText:String = "" {
+        didSet{
+            isCanGennerateBlock?(isCanGennerate)
+        }
+    }
+    
+    //选择的生成图片的 type
+    var gennerateType:TSGennerateType = .poster{
+        didSet{
+            isCanGennerateBlock?(isCanGennerate)
+        }
+    }
+
+    //选择的 prompt 类型
+    var selectPromptModel:TSPTPStyleModel?{
+        didSet{
+            isCanGennerateBlock?(isCanGennerate)
+        }
+    }
+    
+    //可生成状态变化 block
+    var isCanGennerateBlock:((Bool)->Void)?
+}
+
+
+extension TSTextGeneralRintoneVM {
+    //是否满足生成条件
+    var isCanGennerate:Bool {
+        if  selectPromptModel != nil ,
+            promptText.replacingOccurrences(of: " ", with: "").count > 0
+        {
+            return true
+        }
+        return false
+    }
+
+
+    var prompt:String{
+        var prompt = promptText
+        if let selectPromptModel = selectPromptModel {
+            prompt+=", \(selectPromptModel.prompt)"
+        }
+        return prompt
+    }
+
+    func saveModel(model:TSActionInfoModel){
+        if gennerateType == .poster {
+            TSPosterHistory.saveModel(model: model)
+        }else if gennerateType == .photo{
+            TSPhotoHistory.saveModel(model: model)
+        }
+    }
+}

+ 56 - 0
AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/VM/text_rintone_style.json

@@ -0,0 +1,56 @@
+[
+    {
+        "imageName": "ttr_style_0",
+        "imageText": "Normal",
+        "prompt":"Create a uplifting and modern music track blending Pop, Electronic, and Ambient elements. Use a BPM of 100-120, a catchy melody with synth or piano, warm harmonies, and a mix of electronic and organic sounds. Ensure a clear structure (Intro, Verse, Chorus, Outro) and a light, positive vibe suitable for background or casual listening",
+        "isVip": false
+    },
+    {
+        "imageName": "ttr_style_1",
+        "imageText": "Pop",
+        "prompt":"Create a upbeat Pop track with a catchy vocal melody, bright synths, and a driving rhythm. Use a BPM of 110-130, modern production, and a structure with a memorable chorus. Keep it radio-friendly and energetic",
+        "isVip": false
+    },
+    {
+        "imageName": "ttr_style_2",
+        "imageText": "Rock",
+        "prompt":"Generate a Rock track with powerful electric guitars, strong drums, and an anthemic melody. Use a BPM of 120-140, add a guitar solo, and create a raw, energetic vibe with a classic Verse-Chorus structure",
+        "isVip": false
+    },
+    {
+        "imageName": "ttr_style_3",
+        "imageText": "Hip Hop",
+        "prompt":"Produce a Hip Hop beat with a heavy bassline, crisp drums, and a looped melodic sample. Use a BPM of 80-100, add subtle synth layers, and leave space for vocals. Keep the vibe gritty yet modern",
+        "isVip": false
+    },
+    {
+        "imageName": "ttr_style_4",
+        "imageText": "Funk",
+        "prompt":"Create a Funk track with a groovy bassline, tight rhythm guitar, and punchy brass stabs. Use a BPM of 100-120, add dynamic drum fills, and focus on a danceable, upbeat groove",
+        "isVip": false
+    },
+    {
+        "imageName": "ttr_style_5",
+        "imageText": "Jazz",
+        "prompt":"Generate a Jazz track with smooth piano chords, a walking bassline, and expressive saxophone solos. Use a BPM of 90-110, incorporate swing rhythms, and create a relaxed, sophisticated atmosphere",
+        "isVip": false
+    },
+    {
+        "imageName": "ttr_style_6",
+        "imageText": "Disco",
+        "prompt":"Produce a Disco track with a four-on-the-floor beat, funky bassline, and shimmering strings. Use a BPM of 120-130, add lush vocal harmonies, and create a vibrant, danceable vibe",
+        "isVip": false
+    },
+    {
+        "imageName": "ttr_style_7",
+        "imageText": "Electro & Dance",
+        "prompt":"Create a Electro Dance track with a driving beat, pulsating synths, and a euphoric build-up. Use a BPM of 125-135, add a catchy drop, and keep the energy high for club or festival vibes",
+        "isVip": false
+    },
+    {
+        "imageName": "ttr_style_8",
+        "imageText": "Dubstep",
+        "prompt":"Generate a Dubstep track with heavy bass drops, aggressive wobble synths, and intricate drum patterns. Use a BPM of 140-150, add dark atmospheric elements, and focus on intense, dynamic energy",
+        "isVip": false
+    }
+]

+ 2 - 2
AIRingtone/Business/TSSetingVC/TSBusinessWebVC/TSBusinessWebVC.swift

@@ -10,8 +10,8 @@ import WebKit
 class TSBusinessWebVC: TSBaseVC , WKNavigationDelegate {
     
     enum UrlType:String {
-        case privacy = "http://100yearslater.com/AI-Chat-Privacy-Policy.html"
-        case terms = "https://doc-hosting.flycricket.io/hahaemoji-terms-of-use/7488c423-9bb6-480e-9a38-f52fba511335/terms"
+        case privacy = "https://doc-hosting.flycricket.io/ai-ringtones-privacy-policy/ad14f989-96c0-4f31-a711-8db8b288d0e2/privacy"
+        case terms = "https://doc-hosting.flycricket.io/ai-ringtones-terms-of-use/4f89d174-1559-453f-b12c-47a85e21cc01/terms"
 
         func getTitle() -> String {
             switch self {

+ 3 - 1
AIRingtone/Business/TSThemeVC/TSThemeBrowseVC/VM/TSThemeBrowseVM.swift

@@ -15,7 +15,9 @@ class TSThemeBrowseVM {
     func playRingtone(ringtone:String?) {
         if let ringtone = ringtone {
             self.audioPlayer?.stop()
-            TSCommonTool.downloadAndCacheFile(from: ringtone) { [self] path, error in
+            TSCommonTool.downloadAndCacheFile(from: ringtone) { [weak self] path, error in
+                guard let self = self else { return }
+                
                 if let path = path {
                     //播放
                     if let url = URL(string: path) {

+ 1 - 1
AIRingtone/Business/TSThemeVC/TSThemeBrowseVC/View/TSTBBtnView.swift

@@ -76,7 +76,7 @@ class TSTBBtnView: TSBaseView {
         setDone()
         
         kDelayMainShort {
-            self.doneBtn.addCornerRadiusShadow(cornerRadius: 24, shadowColor: UIColor.themeColor.cgColor, shadowOffset: .zero, shadowRadius: 10, shadowOpacity: 1.0)
+            self.doneBtn.addCornerRadiusShadow(cornerRadius: 24, shadowColor: UIColor.themeColor.cgColor, shadowOffset: .zero, shadowRadius: 24, shadowOpacity: 1.0)
         }
     }
         

+ 1 - 1
AIRingtone/Business/TSThemeVC/TSThemeSetVC/TSThemeSetVC.swift

@@ -88,7 +88,7 @@ class TSThemeSetVC: TSBaseVC {
     override func dealThings() {
         ringView.cellView.nameLab.text = model.ringtoneName
         ringView.cellView.coverImageView.setAsyncImage(urlString: model.ringtoneCover,contentMode: .scaleAspectFill)
-        ringView.cellView.timeLab.text = vm.floatToMinuteSecond(duration)
+        ringView.cellView.timeLab.text = duration.floatToMinuteSecond()
         posterView.netWorkImageView.setAsyncImage(urlString: model.poster,contentMode: .scaleAspectFill)
         photoView.netWorkImageView.setAsyncImage(urlString: model.photo,contentMode: .scaleAspectFill)
         

+ 0 - 26
AIRingtone/Business/TSThemeVC/TSThemeSetVC/VM/TSThemeSetVM.swift

@@ -38,29 +38,3 @@ class TSThemeSetVM {
     }
     
 }
-
-
-
-
-extension TSThemeSetVM{
-
-    func floatToMinuteSecond(_ time: Float) -> String {
-        // 将 Float 类型的时间转换为整数秒
-        let totalSeconds = Int(time)
-        // 计算分钟数
-        let minutes = totalSeconds / 60
-        // 计算剩余的秒数
-        let seconds = totalSeconds % 60
-        // 将分钟数和秒数格式化为两位数的字符串
-        let minuteString = String(format: "%02d", minutes)
-        let secondString = String(format: "%02d", seconds)
-        // 拼接成分秒格式的字符串
-        return "\(minuteString):\(secondString)"
-    }
-
-}
-
-extension TSThemeSetVM{
-    
-
-}

+ 11 - 2
AIRingtone/Business/VIewTool/TSBottomAlertVC.swift

@@ -61,6 +61,9 @@ class TSBottomAlertVC: TSBaseVC {
             guard let self = self else { return }
             clickSubmitBtn()
         }
+        kDelayMainShort {
+            saveBtn.addGradientBg(colors: ["#E961F6".uiColor.cgColor,"#7E57F4".uiColor.cgColor])
+        }
         return saveBtn
     }()
     
@@ -82,6 +85,10 @@ class TSBottomAlertVC: TSBaseVC {
             guard let self = self else { return }
             clickRightBtn()
         }
+        
+        kDelayMainShort {
+            rightBtn.addGradientBg(colors: ["#E961F6".uiColor.cgColor,"#7E57F4".uiColor.cgColor])
+        }
         rightBtn.isHidden = true
         return rightBtn
     }()
@@ -154,7 +161,7 @@ class TSBottomAlertVC: TSBaseVC {
             make.height.equalTo(88)
         }
         
-        let successLabel = UILabel.createLabel(text: "Successfully Generated".localized,font: .font(size: 18.0),textColor: .themeColor,textAlignment: .left)
+        let successLabel = UILabel.createLabel(text: "Successfully Generated".localized,font: .font(name: .PoppinsBlackItalic, size: 18.0),textColor: .themeColor,textAlignment: .left)
         resultView.addSubview(successLabel)
         successLabel.snp.makeConstraints { make in
             make.top.equalTo(30)
@@ -162,7 +169,9 @@ class TSBottomAlertVC: TSBaseVC {
             make.trailing.equalTo(resultIconImageView.snp.leading).offset(-20)
             make.height.equalTo(18)
         }
-        
+        kDelayMainShort {
+            successLabel.applyGradient(colors: [UIColor.white,"#D999FF".uiColor])
+        }
         resultView.isHidden = true
         return resultView
     }()

+ 3 - 1
AIRingtone/Business/VIewTool/TSCommonloadingView.swift

@@ -114,7 +114,9 @@ class TSCommonloadingView: TSBaseView {
     
     /// 开始旋转
     func startRotating(view:UIView,duration: Double = 2.0) {
-        animatedImageView.startAnimating()
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
+            self.animatedImageView.startAnimating()
+        }
     }
 
     /// 停止旋转

+ 22 - 6
AIRingtone/Business/VIewTool/TSRingToneCellView.swift

@@ -10,8 +10,8 @@ class TSRingToneCellView: TSBaseView {
     
     let coverImageView:UIImageView = UIImageView()
     let playBtn = UIButton.createButton(image: UIImage(named: "ringtone_play"))
-    let nameLab = UILabel.createLabel(font: .font(size: 14),textColor: .white)
-    let timeLab = UILabel.createLabel(font: .font(size: 12),textColor: .white.withAlphaComponent(0.6))
+    let nameLab = UILabel.createLabel(text: "--",font: .font(size: 14),textColor: .white)
+    let timeLab = UILabel.createLabel(text:"--:--",font: .font(size: 12),textColor: .white.withAlphaComponent(0.6))
     
     var isPlay:Bool = false {
         didSet{
@@ -19,21 +19,34 @@ class TSRingToneCellView: TSBaseView {
         }
     }
     
+    var isloading:Bool = false {
+        didSet{
+            if isloading {
+                playBtn.setImage(UIImage(named:"ringtone_loading"), for: .normal)
+                playBtn.startRotating()
+            }else{
+                let b = isPlay
+                isPlay = b
+                playBtn.stopRotating()
+            }
+        }
+    }
+    
+    
     override func creatUI() {
-        contentView.backgroundColor = .popupColor
+        contentView.backgroundColor = .cardColor
         contentView.cornerRadius = 16
         coverImageView.cornerRadius = 8
         coverImageView.backgroundColor = .black
         
         contentView.addSubview(coverImageView)
-        contentView.addSubview(playBtn)
+        coverImageView.addSubview(playBtn)
         contentView.addSubview(nameLab)
         contentView.addSubview(timeLab)
         
         
         playBtn.snp.makeConstraints { make in
-            make.trailing.equalTo(-20)
-            make.centerY.equalToSuperview()
+            make.center.equalToSuperview()
             make.width.height.equalTo(24)
         }
     
@@ -56,5 +69,8 @@ class TSRingToneCellView: TSBaseView {
             make.height.equalTo(12)
         }
     }
+    
+    
+    
 
 }