Procházet zdrojové kódy

1.ail铃声,生成的风格更换 icon
2.封装好了基础任务Operation
3.生成也更换对新设计
4.生成输入框调窄
5.下载铃声是更换 gif 动画
6.ai 铃声主页,取消推荐的底部更多,放在头部右边

100Years před 4 týdny
rodič
revize
b480879db1
49 změnil soubory, kde provedl 738 přidání a 402 odebrání
  1. 23 11
      AIRingtone.xcodeproj/project.pbxproj
  2. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/ttr_style_0@2x.png
  3. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/ttr_style_0@3x.png
  4. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/ttr_style_1@2x.png
  5. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/ttr_style_1@3x.png
  6. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/ttr_style_2@2x.png
  7. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/ttr_style_2@3x.png
  8. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/ttr_style_3@2x.png
  9. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/ttr_style_3@3x.png
  10. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/ttr_style_4@2x.png
  11. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/ttr_style_4@3x.png
  12. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/ttr_style_5@2x.png
  13. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/ttr_style_5@3x.png
  14. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/ttr_style_6@2x.png
  15. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/ttr_style_6@3x.png
  16. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/ttr_style_7@2x.png
  17. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/ttr_style_7@3x.png
  18. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/ttr_style_8@2x.png
  19. binární
      AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/ttr_style_8@3x.png
  20. binární
      AIRingtone/Assets.xcassets/Common/TextView/textView_bg.imageset/textView_bg@2x.png
  21. binární
      AIRingtone/Assets.xcassets/Common/TextView/textView_bg.imageset/textView_bg@3x.png
  22. 2 1
      AIRingtone/Business/TSAIPhotoVC/TSAIPhotoVC.swift
  23. 8 1
      AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGeneralPicVC.swift
  24. 26 10
      AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGenneralPicVM.swift
  25. 16 1
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/TSTextGeneralPicVC.swift
  26. 4 1
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSPromptStyleView.swift
  27. 5 24
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSPromptTextView.swift
  28. 4 2
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSTGPPhotoStyleView.swift
  29. 9 4
      AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSTGPTitleView.swift
  30. 45 35
      AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/TSAIRintoneVC.swift
  31. 54 51
      AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/View/TSAIRintoneHistorySectionHeaderView.swift
  32. 1 1
      AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/ViewModel/TSAIRintoneVM.swift
  33. 9 2
      AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVC.swift
  34. 22 10
      AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVM.swift
  35. 6 5
      AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/TSTextGeneralRintoneVC.swift
  36. 4 4
      AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/VM/text_rintone_style.json
  37. 167 8
      AIRingtone/Business/VIewTool/TSCommonloadingView.swift
  38. 125 0
      AIRingtone/Business/VIewTool/TSRingLoadingView.swift
  39. binární
      AIRingtone/Common/Res/ringAnimation.gif
  40. 0 0
      AIRingtone/Common/Tool/NotUse/TSAudioAVPlayer.swift
  41. 0 0
      AIRingtone/Common/Tool/NotUse/TSAudioPlayerFileTool.swift
  42. 0 0
      AIRingtone/Common/Tool/NotUse/TSDownloadManager.swift
  43. 34 147
      AIRingtone/Common/Tool/OperationQueue/TSBaseOperation.swift
  44. 60 34
      AIRingtone/Common/Tool/OperationQueue/TSBaseOperationQueue.swift
  45. 96 0
      AIRingtone/Common/Tool/OperationQueue/TSGenerateRintoneOperation/TSGenerateRintoneOperation.swift
  46. 3 1
      AIRingtone/Common/Tool/OperationQueue/TSGenerateRintoneOperation/TSGenerateRintoneOperationQueue.swift
  47. 0 0
      AIRingtone/Common/Tool/TSAudioPlayer/TSBusinessAudioPlayer.swift
  48. 15 37
      AIRingtone/Common/Tool/TSBandRingTool/TSBandRingTool.swift
  49. 0 12
      AIRingtone/Common/Tool/TSSetContactAvatar.swift

+ 23 - 11
AIRingtone.xcodeproj/project.pbxproj

@@ -52,6 +52,8 @@
 		A83F87242D7954BB00D29B1B /* TSAIPhotoChildVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83F87232D7954B800D29B1B /* TSAIPhotoChildVM.swift */; };
 		A840A7EB2D8D81CD0044B8B9 /* TSGenerateRintoneOperationQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = A840A7EA2D8D81C90044B8B9 /* TSGenerateRintoneOperationQueue.swift */; };
 		A840A7ED2D8D81DB0044B8B9 /* TSGenerateRintoneOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A840A7EC2D8D81DA0044B8B9 /* TSGenerateRintoneOperation.swift */; };
+		A840A7F02D8E5BA00044B8B9 /* TSRingLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A840A7EF2D8E5B8F0044B8B9 /* TSRingLoadingView.swift */; };
+		A840A7F22D8E60A40044B8B9 /* ringAnimation.gif in Resources */ = {isa = PBXBuildFile; fileRef = A840A7F12D8E60A40044B8B9 /* ringAnimation.gif */; };
 		A868A89A2D75505E00F6D884 /* TSThemeBannerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A8992D75505800F6D884 /* TSThemeBannerCell.swift */; };
 		A868A89C2D75506C00F6D884 /* TSThemeContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A89B2D75506500F6D884 /* TSThemeContentCell.swift */; };
 		A868A8A22D7560B900F6D884 /* TSPageNullView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A89D2D7560B900F6D884 /* TSPageNullView.swift */; };
@@ -71,7 +73,6 @@
 		A868A8C92D76A45900F6D884 /* TSThemeSetItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A8C82D76A45200F6D884 /* TSThemeSetItemView.swift */; };
 		A868A8CE2D76AAC600F6D884 /* TSThemeSetRingToneView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A8CD2D76AAAF00F6D884 /* TSThemeSetRingToneView.swift */; };
 		A868A8D02D76D03900F6D884 /* TSRingToneCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A8CF2D76D02300F6D884 /* TSRingToneCellView.swift */; };
-		A868A8D52D76E41800F6D884 /* TSSetContactAvatar.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A8D42D76E40E00F6D884 /* TSSetContactAvatar.swift */; };
 		A868A8DB2D76F00C00F6D884 /* TSBandRingTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A8DA2D76F00800F6D884 /* TSBandRingTool.swift */; };
 		A868A8DE2D76F91500F6D884 /* AudioTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = A868A8DD2D76F91500F6D884 /* AudioTool.swift */; };
 		A868A8E12D76F9BB00F6D884 /* AudioConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = A868A8E02D76F9BB00F6D884 /* AudioConverter.m */; };
@@ -186,6 +187,8 @@
 		A83F87232D7954B800D29B1B /* TSAIPhotoChildVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAIPhotoChildVM.swift; sourceTree = "<group>"; };
 		A840A7EA2D8D81C90044B8B9 /* TSGenerateRintoneOperationQueue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGenerateRintoneOperationQueue.swift; sourceTree = "<group>"; };
 		A840A7EC2D8D81DA0044B8B9 /* TSGenerateRintoneOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGenerateRintoneOperation.swift; sourceTree = "<group>"; };
+		A840A7EF2D8E5B8F0044B8B9 /* TSRingLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRingLoadingView.swift; sourceTree = "<group>"; };
+		A840A7F12D8E60A40044B8B9 /* ringAnimation.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = ringAnimation.gif; sourceTree = "<group>"; };
 		A868A8992D75505800F6D884 /* TSThemeBannerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSThemeBannerCell.swift; sourceTree = "<group>"; };
 		A868A89B2D75506500F6D884 /* TSThemeContentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSThemeContentCell.swift; sourceTree = "<group>"; };
 		A868A89D2D7560B900F6D884 /* TSPageNullView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPageNullView.swift; sourceTree = "<group>"; };
@@ -205,7 +208,6 @@
 		A868A8C82D76A45200F6D884 /* TSThemeSetItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSThemeSetItemView.swift; sourceTree = "<group>"; };
 		A868A8CD2D76AAAF00F6D884 /* TSThemeSetRingToneView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSThemeSetRingToneView.swift; sourceTree = "<group>"; };
 		A868A8CF2D76D02300F6D884 /* TSRingToneCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSRingToneCellView.swift; sourceTree = "<group>"; };
-		A868A8D42D76E40E00F6D884 /* TSSetContactAvatar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSSetContactAvatar.swift; sourceTree = "<group>"; };
 		A868A8DA2D76F00800F6D884 /* TSBandRingTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBandRingTool.swift; sourceTree = "<group>"; };
 		A868A8DD2D76F91500F6D884 /* AudioTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioTool.swift; sourceTree = "<group>"; };
 		A868A8DF2D76F9BB00F6D884 /* AudioConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioConverter.h; sourceTree = "<group>"; };
@@ -348,6 +350,7 @@
 		A80EDE622D718B0F003CD332 /* Res */ = {
 			isa = PBXGroup;
 			children = (
+				A840A7F12D8E60A40044B8B9 /* ringAnimation.gif */,
 				A868A91B2D78592600F6D884 /* rotatingAnimation.gif */,
 				A868A8BE2D76A17E00F6D884 /* Poppins-BlackItalic.ttf */,
 			);
@@ -397,15 +400,11 @@
 			children = (
 				A8D776FD2D8D3E4E007EAB35 /* TSPublicContent.swift */,
 				A8D776F62D8D342D007EAB35 /* OperationQueue */,
-				A899D3CA2D89A53C00AB9C1C /* TSDownloadManager.swift */,
-				A899D3A42D89785E00AB9C1C /* TSAudioAVPlayer.swift */,
-				A899D3CE2D89AD4800AB9C1C /* TSAudioPlayerFileTool.swift */,
-				A8272EBA2D7AFD0D00F1C814 /* TSBusinessAudioPlayer.swift */,
-				A868A8F02D77081B00F6D884 /* TSContactsTool.swift */,
+				A840A7EE2D8D82100044B8B9 /* NotUse */,
 				A868A8DC2D76F90E00F6D884 /* TSBandRingTool */,
-				A868A8D42D76E40E00F6D884 /* TSSetContactAvatar.swift */,
 				A868A8BC2D75C68300F6D884 /* TSAudioPlayer */,
 				A80EDEB32D718CEA003CD332 /* TSRandomTextPicker.swift */,
+				A868A8F02D77081B00F6D884 /* TSContactsTool.swift */,
 				A80EDEB62D718CEA003CD332 /* TSFileManagerTool.swift */,
 				A868A8EE2D77040F00F6D884 /* TSLoadingAnimation.swift */,
 			);
@@ -637,6 +636,16 @@
 			path = TSGenerateRintoneOperation;
 			sourceTree = "<group>";
 		};
+		A840A7EE2D8D82100044B8B9 /* NotUse */ = {
+			isa = PBXGroup;
+			children = (
+				A899D3CA2D89A53C00AB9C1C /* TSDownloadManager.swift */,
+				A899D3A42D89785E00AB9C1C /* TSAudioAVPlayer.swift */,
+				A899D3CE2D89AD4800AB9C1C /* TSAudioPlayerFileTool.swift */,
+			);
+			path = NotUse;
+			sourceTree = "<group>";
+		};
 		A868A8982D75505100F6D884 /* View */ = {
 			isa = PBXGroup;
 			children = (
@@ -655,6 +664,7 @@
 				A868A8CF2D76D02300F6D884 /* TSRingToneCellView.swift */,
 				A868A89D2D7560B900F6D884 /* TSPageNullView.swift */,
 				A868A89E2D7560B900F6D884 /* TSCommonloadingView.swift */,
+				A840A7EF2D8E5B8F0044B8B9 /* TSRingLoadingView.swift */,
 				A868A8A02D7560B900F6D884 /* TSViewTool.swift */,
 			);
 			path = VIewTool;
@@ -700,6 +710,7 @@
 		A868A8BC2D75C68300F6D884 /* TSAudioPlayer */ = {
 			isa = PBXGroup;
 			children = (
+				A8272EBA2D7AFD0D00F1C814 /* TSBusinessAudioPlayer.swift */,
 				A868A8BB2D75C68300F6D884 /* TSAudioPlayer.swift */,
 			);
 			path = TSAudioPlayer;
@@ -1102,6 +1113,7 @@
 				A8272E982D7A88F400F1C814 /* text_rintone_style.json in Resources */,
 				A80EDE5B2D718623003CD332 /* Assets.xcassets in Resources */,
 				A868A8ED2D76FE5D00F6D884 /* tutorial-ring.mp4 in Resources */,
+				A840A7F22D8E60A40044B8B9 /* ringAnimation.gif in Resources */,
 				A868A8BF2D76A17E00F6D884 /* Poppins-BlackItalic.ttf in Resources */,
 				A868A8EB2D76FD9800F6D884 /* placeholder.band in Resources */,
 				A80EDE5D2D718623003CD332 /* LaunchScreen.storyboard in Resources */,
@@ -1209,7 +1221,6 @@
 				A8272E9F2D7A8F6500F1C814 /* TSGeneralRintoneVM.swift in Sources */,
 				A868A9142D784D4D00F6D884 /* TSGeneralPicModel.swift in Sources */,
 				A899D3962D89258B00AB9C1C /* TSDiscoverListVM.swift in Sources */,
-				A868A8D52D76E41800F6D884 /* TSSetContactAvatar.swift in Sources */,
 				A868A8F52D77179D00F6D884 /* TSAIPhotoChildVC.swift in Sources */,
 				A899D3DB2D8A97F100AB9C1C /* TSRingDownVM.swift in Sources */,
 				A899D38A2D891ADE00AB9C1C /* TSDiscoverVM.swift in Sources */,
@@ -1268,6 +1279,7 @@
 				A899D3D42D8A6B6600AB9C1C /* TSGenerateHistoryVC.swift in Sources */,
 				A8272E9D2D7A8F4600F1C814 /* TSGeneralRintoneVC+Event.swift in Sources */,
 				A80EDF072D718DF1003CD332 /* TSSetingViewModel.swift in Sources */,
+				A840A7F02D8E5BA00044B8B9 /* TSRingLoadingView.swift in Sources */,
 				A868A8C72D76A44500F6D884 /* TSThemeSetVC.swift in Sources */,
 				A868A8D02D76D03900F6D884 /* TSRingToneCellView.swift in Sources */,
 			);
@@ -1299,7 +1311,7 @@
 				DEVELOPMENT_TEAM = 65UD255J84;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = AIRingtone/Info.plist;
-				INFOPLIST_KEY_CFBundleDisplayName = "AI Ringtones";
+				INFOPLIST_KEY_CFBundleDisplayName = "AI Ringtone";
 				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;
@@ -1341,7 +1353,7 @@
 				DEVELOPMENT_TEAM = 65UD255J84;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = AIRingtone/Info.plist;
-				INFOPLIST_KEY_CFBundleDisplayName = "AI Ringtones";
+				INFOPLIST_KEY_CFBundleDisplayName = "AI Ringtone";
 				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;

binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/ttr_style_0@2x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_0.imageset/ttr_style_0@3x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/ttr_style_1@2x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_1.imageset/ttr_style_1@3x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/ttr_style_2@2x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_2.imageset/ttr_style_2@3x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/ttr_style_3@2x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_3.imageset/ttr_style_3@3x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/ttr_style_4@2x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_4.imageset/ttr_style_4@3x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/ttr_style_5@2x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_5.imageset/ttr_style_5@3x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/ttr_style_6@2x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_6.imageset/ttr_style_6@3x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/ttr_style_7@2x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_7.imageset/ttr_style_7@3x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/ttr_style_8@2x.png


binární
AIRingtone/Assets.xcassets/AIRing/style/ttr_style_8.imageset/ttr_style_8@3x.png


binární
AIRingtone/Assets.xcassets/Common/TextView/textView_bg.imageset/textView_bg@2x.png


binární
AIRingtone/Assets.xcassets/Common/TextView/textView_bg.imageset/textView_bg@3x.png


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

@@ -26,7 +26,8 @@ class TSAIPhotoVC: TSBaseVC {
     
     var tableHeaderViewHeight: CGFloat{
         get{
-            generalPicVC.viewH <= 10 ? 542.0 : generalPicVC.viewH
+//            generalPicVC.viewH <= 10 ? 542.0 : generalPicVC.viewH
+            generalPicVC.viewH <= 10 ? 570.0 : generalPicVC.viewH
         }
     }
     var headerInSectionHeight: Int = 44

+ 8 - 1
AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGeneralPicVC.swift

@@ -46,7 +46,9 @@ class TSGeneralPicVC: TSBottomAlertVC {
     //############################## 生成动画 ##############################
     lazy var generateInView : TSCommonloadingView = {
         let generateInView = TSCommonloadingView()
-        generateInView.cancelBtn.addTarget(self, action: #selector(closePage), for: .touchUpInside)
+        generateInView.timeLabel.text = "~ 1min"
+        //generateInView.cancelBtn.addTarget(self, action: #selector(closePage), for: .touchUpInside)
+        generateInView.backstageBtn.addTarget(self, action: #selector(closePage), for: .touchUpInside)
         return generateInView
     }()
 
@@ -80,6 +82,11 @@ class TSGeneralPicVC: TSBottomAlertVC {
         netWorkImageView.cornerRadius = netWorkImageCorner
     }
     
+    @objc func clickBackstageBtn() {
+        viewModel.cancelAllRequest()
+        self.dismiss(animated: true, completion: nil)
+    }
+    
     @objc override func closePage() {
         viewModel.cancelAllRequest()
         self.dismiss(animated: true, completion: nil)

+ 26 - 10
AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGenneralPicVM.swift

@@ -54,17 +54,26 @@ class TSGenneralPicVM {
         stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
 
         kDelayOnMainThread(0.2) {
+            self.stateDatauPblished = (.progressString(self.generating(progress: 0.2)),nil)
+        }
+        
+        kDelayOnMainThread(0.5) {
             self.stateDatauPblished = (.progressString(self.generating(progress: 0.5)),nil)
         }
-
-        kDelayOnMainThread(1.0) {
-            if Bool.random() {
-                let infoModel = TSActionInfoModel(JSON: self.gennerateType == .poster ? actionInfoDictPoster : actionInfoDictPhoto)
-                self.stateDatauPblished = (.success(nil),infoModel)
-            }else{
-                self.stateDatauPblished = (.failed("error?.localizedDescription"),nil)
-            }
+        
+        kDelayOnMainThread(0.8) {
+            self.stateDatauPblished = (.progressString(self.generating(progress: 0.8)),nil)
         }
+
+
+//        kDelayOnMainThread(2.0) {
+//            if Bool.random() {
+//                let infoModel = TSActionInfoModel(JSON: self.gennerateType == .poster ? actionInfoDictPoster : actionInfoDictPhoto)
+//                self.stateDatauPblished = (.success(nil),infoModel)
+//            }else{
+//                self.stateDatauPblished = (.failed("error?.localizedDescription"),nil)
+//            }
+//        }
     }
     
 //    //width 和 height 必须是 32 的倍数
@@ -132,7 +141,7 @@ class TSGenneralPicVM {
         var progressInt = Int(progress*100)
 
         if generatingProgress >= progressInt{
-            return "Generating \(generatingProgress)%"
+            return generatingString
         }
 
         if progressInt > 99 {
@@ -140,7 +149,14 @@ class TSGenneralPicVM {
         }
         
         generatingProgress = progressInt
-        return "Generating \(progressInt)%"
+        return generatingString
+    }
+     
+    var generatingString:String {
+        if gennerateType == .photo {
+            return "Working on your contact photo \(generatingProgress)% ..."
+        }
+        return "Working on your contact poster \(generatingProgress)% ..."
     }
 }
 

+ 16 - 1
AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/TSTextGeneralPicVC.swift

@@ -26,11 +26,18 @@ class TSTextGeneralPicVC: TSBaseVC {
     
     //###################################### cusStackView ######################################
     lazy var cusStackView: TSCustomStackView = {
-        let cusStackView = TSCustomStackView(axis: .vertical,spacing: 8)
+        let cusStackView = TSCustomStackView(axis: .vertical,spacing: 0)
+        cusStackView.scrollView.isScrollEnabled = false
         return cusStackView
     }()
     
     //###################################### 输入框 ######################################
+    lazy var titleView: TSTGPTitleView = {
+        let titleView = TSTGPTitleView()
+        titleView.titleLab.text = "Enter a prompt".localized
+        return titleView
+    }()
+  
     lazy var promptTextView: TSPromptTextView = {
         let promptTextView = TSPromptTextView(randomTextArray: kRandomTextToPicArray) { [weak self] text in
             guard let self = self else { return }
@@ -99,6 +106,14 @@ class TSTextGeneralPicVC: TSBaseVC {
         cusStackView.snp.makeConstraints { make in
             make.top.leading.bottom.trailing.equalTo(0)
         }
+        
+        
+        cusStackView.addSubviewToStack(titleView)
+        titleView.snp.makeConstraints { make in
+            make.top.equalTo(0)
+            make.leading.trailing.equalTo(0)
+            make.height.equalTo(titleView.viewH)
+        }
 
         cusStackView.addSubviewToStack(promptTextView)
         

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

@@ -71,7 +71,9 @@ class TSPromptStyleView:TSBaseView {
         currentIndexPath = IndexPath(item: 0, section: 0)
         contentView.addSubview(styleCollectionView)
         styleCollectionView.snp.makeConstraints { make in
-            make.edges.equalToSuperview()
+//            make.edges.equalToSuperview()
+            make.top.trailing.left.equalToSuperview()
+            make.bottom.equalTo(-8)
             make.height.equalTo(110)
         }
     }
@@ -128,6 +130,7 @@ class TSPTPSelectStyleCCell: TSBaseCollectionCell {
     
     lazy var imageView: UIImageView = {
         let imageView = UIImageView()
+        imageView.cornerRadius = 16.0
         return imageView
     }()
     

+ 5 - 24
AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSPromptTextView.swift

@@ -21,12 +21,7 @@ class TSPromptTextView : TSBaseView{
         fatalError("init(coder:) has not been implemented")
     }
     
-    lazy var titleView: TSTGPTitleView = {
-        let titleView = TSTGPTitleView()
-        titleView.titleLab.text = "Enter a prompt".localized
-        return titleView
-    }()
-  
+
     lazy var randomTextPicker: TSRandomTextPicker = {
         let textPicker = TSRandomTextPicker(texts: randomTextArray)
         return textPicker
@@ -41,7 +36,7 @@ class TSPromptTextView : TSBaseView{
             make.top.equalTo(0)
             make.centerX.equalToSuperview()
             make.width.equalTo(343*kDesignScale)
-            make.height.equalTo(160*kDesignScale)
+            make.height.equalTo(140*kDesignScale)
         }
 
         return textBgView
@@ -137,26 +132,13 @@ class TSPromptTextView : TSBaseView{
     }()
     
     override func creatUI() {
-        let titleViewH = titleView.viewH
-        
-        addSubview(titleView)
-        titleView.snp.makeConstraints { make in
-            make.top.equalTo(0)
-            make.leading.trailing.equalTo(0)
-            make.height.equalTo(titleViewH)
-        }
-        
-        contentView.snp.updateConstraints { make in
-            make.top.equalTo(titleViewH)
-        }
-    
         contentView.addSubview(textBgView)
         textBgView.snp.makeConstraints { make in
             make.top.equalTo(0)
             make.leading.equalTo(16)
             make.trailing.equalTo(-16)
-            make.height.equalTo(160.0*kDesignScale)
-            make.bottom.equalTo(-10)
+            make.height.equalTo(140.0*kDesignScale)
+            make.bottom.equalTo(0)
         }
    
         textBgView.addSubview(customTextView)
@@ -164,11 +146,10 @@ class TSPromptTextView : TSBaseView{
             make.top.equalTo(16)
             make.leading.equalTo(16)
             make.trailing.equalTo(-16)
-            make.bottom.equalTo(-48)
+            make.bottom.equalTo(-52)
         }
         
         textBgView.addSubview(inspirationBtn)
-
         inspirationBtn.snp.makeConstraints { make in
             make.height.equalTo(32)
             make.bottom.equalTo(0)

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

@@ -8,7 +8,9 @@
 import BetterSegmentedControl
 
 class TSTGPPhotoStyleView: TSTGPTitleView {
-    
+    override var kTop: Double{
+        return 30.0
+    }
     var selectedValueBlock:((Int)->Void)?
     
     let titles = ["Poster".localized,"Photo".localized]
@@ -50,7 +52,7 @@ class TSTGPPhotoStyleView: TSTGPTitleView {
             make.width.equalTo(144)
             make.height.equalTo(32)
             make.trailing.equalTo(-16)
-            make.centerY.equalToSuperview()
+            make.centerY.equalTo(titleLab)
         }
     }
     

+ 9 - 4
AIRingtone/Business/TSAIPhotoVC/TSTextGeneralPicVC/View/TSTGPTitleView.swift

@@ -7,22 +7,27 @@
 
 class TSTGPTitleView: TSBaseView {
     
-    static let viewH:Float = 40.0
+    static let viewH:Float = 62.0
     let viewH:Float = TSTGPTitleView.viewH
-    
+    var kTop: Double{
+        return 22.0//28.0
+    }
     lazy var titleLab: UILabel = {
         let titleLab = UILabel.createLabel(font: .font(name: .PoppinsBlackItalic,size: 18),textColor: .white)
         return titleLab
     }()
     
+
     override func creatUI() {
-        
         contentView.addSubview(titleLab)
         titleLab.snp.makeConstraints { make in
             make.leading.equalTo(16)
-            make.centerY.equalToSuperview()
+//            make.trailing.equalTo(-80)
+            make.top.equalTo(kTop)
+//            make.centerY.equalToSuperview()
         }
         
         
+        
     }
 }

+ 45 - 35
AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/TSAIRintoneVC.swift

@@ -32,9 +32,9 @@ class TSAIRintoneVC: TSBaseVC {
         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.footerReferenceSize = CGSizeMake(k_ScreenWidth, 48)
+        layout.minimumLineSpacing = 14.0
+        layout.headerReferenceSize = CGSizeMake(k_ScreenWidth, 62)
+//        layout.footerReferenceSize = CGSizeMake(k_ScreenWidth, 62)
         return layout
     }()
     
@@ -47,7 +47,7 @@ class TSAIRintoneVC: TSBaseVC {
         collectionView.backgroundColor = .clear
         collectionView.register(TSAIRintoneHistoryCell.self, forCellWithReuseIdentifier: TSAIRintoneHistoryCell.cellID)
         collectionView.register(TSAIRintoneHistorySectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: TSAIRintoneHistorySectionHeaderView.reuseIdentifier)
-        collectionView.register(TSAIRintoneHistorySectionFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: TSAIRintoneHistorySectionFooterView.reuseIdentifier)
+//        collectionView.register(TSAIRintoneHistorySectionFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: TSAIRintoneHistorySectionFooterView.reuseIdentifier)
         if #available(iOS 11.0, *) {
             collectionView.contentInsetAdjustmentBehavior = .never
         }
@@ -179,52 +179,62 @@ extension TSAIRintoneVC: UICollectionViewDataSource ,UICollectionViewDelegate,UI
             if kind == UICollectionView.elementKindSectionHeader {
                 if let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: TSAIRintoneHistorySectionHeaderView.reuseIdentifier, for: indexPath) as? TSAIRintoneHistorySectionHeaderView {
                     header.titleView.titleLab.text = sectionModel.title
-                    header.rightBtn.isHidden = true
-                    if sectionModel.type == .history {
-                        header.rightBtn.isHidden = false
+                    header.rightBtn.isHidden = false
+//                    if sectionModel.type == .history {
+//                        header.rightBtn.isHidden = false
                         header.rightBtn.setUpButton{ [weak self]  in
                             guard let self = self else { return }
-                            
-                            let vc = TSGenerateHistoryVC()
-                            vc.reloadUIBlock = { [weak self]  in
-                                guard let self = self else { return }
-                                viewModel.updateRecentData()
-                                updateListView()
+
+                            if sectionModel.type == .history {
+                                let vc = TSGenerateHistoryVC()
+                                vc.reloadUIBlock = { [weak self]  in
+                                    guard let self = self else { return }
+                                    viewModel.updateRecentData()
+                                    updateListView()
+                                }
+                                kPushVC(target: self, modelVC: vc)
+                            }else if sectionModel.type == .recommend{
+                                let ringCategoryModel = TSRingCategoryModel()
+                                ringCategoryModel.title = "TikTok"
+                                ringCategoryModel.cover = "http://d3a93z8fj970a4.cloudfront.net/0c359196-aeeb-45e6-bc98-eddf50f1dd53"
+                                ringCategoryModel.categoryId = "Best of TikTok"
+                                kPushVC(target: self, modelVC: TSDiscoverListVC(ringCategoryModel: ringCategoryModel))
                             }
-                            kPushVC(target: self, modelVC: vc)
                         }
-                    }
+//                    }
         
                     return header
                 }
-            }else if kind == UICollectionView.elementKindSectionFooter{//},indexPath.section == (viewModel.modelList.count-1) {
-                if let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: TSAIRintoneHistorySectionFooterView.reuseIdentifier, for: indexPath) as? TSAIRintoneHistorySectionFooterView {
-                    footer.clickView = {
-                        let ringCategoryModel = TSRingCategoryModel()
-                        ringCategoryModel.title = "TikTok"
-                        ringCategoryModel.cover = "http://d3a93z8fj970a4.cloudfront.net/0c359196-aeeb-45e6-bc98-eddf50f1dd53"
-                        ringCategoryModel.categoryId = "Best of TikTok"
-                        kPushVC(target: self, modelVC: TSDiscoverListVC(ringCategoryModel: ringCategoryModel))
-                    }
-                    return footer
-                }
             }
+            
+//            else if kind == UICollectionView.elementKindSectionFooter{//},indexPath.section == (viewModel.modelList.count-1) {
+//                if let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: TSAIRintoneHistorySectionFooterView.reuseIdentifier, for: indexPath) as? TSAIRintoneHistorySectionFooterView {
+//                    footer.clickView = {
+//                        let ringCategoryModel = TSRingCategoryModel()
+//                        ringCategoryModel.title = "TikTok"
+//                        ringCategoryModel.cover = "http://d3a93z8fj970a4.cloudfront.net/0c359196-aeeb-45e6-bc98-eddf50f1dd53"
+//                        ringCategoryModel.categoryId = "Best of TikTok"
+//                        kPushVC(target: self, modelVC: TSDiscoverListVC(ringCategoryModel: ringCategoryModel))
+//                    }
+//                    return footer
+//                }
+//            }
         }
         return UICollectionReusableView()
     }
     
     
-    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
-        if let sectionModel = viewModel.modelList.safeObj(At: section) {
-            if  sectionModel.type == .recommend {
-                return  CGSizeMake(k_ScreenWidth, 48)
-            }
-        }
-        return .zero
-    }
+//    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
+//        if let sectionModel = viewModel.modelList.safeObj(At: section) {
+//            if  sectionModel.type == .recommend {
+//                return  CGSizeMake(k_ScreenWidth, 48)
+//            }
+//        }
+//        return .zero
+//    }
     
     public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
-        return UIEdgeInsets(top: 0, left: 0, bottom: 12, right: 0)
+        return UIEdgeInsets(top: 0, left: 0, bottom: 8, right: 0)
     }
 }
 

+ 54 - 51
AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/View/TSAIRintoneHistorySectionHeaderView.swift

@@ -18,7 +18,9 @@ class TSAIRintoneHistorySectionHeaderView: UICollectionReusableView {
         rightBtn.setUpButton(title: "See All".localized,font: .font(size: 14),titleColor: .themeColor)
         return rightBtn
     }()
-    
+    var kTop: Double{
+        return 22.0//28.0
+    }
     override init(frame: CGRect) {
         super.init(frame: frame)
         
@@ -29,7 +31,8 @@ class TSAIRintoneHistorySectionHeaderView: UICollectionReusableView {
         
         addSubview(rightBtn)
         rightBtn.snp.makeConstraints { make in
-            make.centerY.equalToSuperview()
+//            make.centerY.equalToSuperview()
+            make.top.equalTo(kTop)
             make.trailing.equalTo(-16)
         }
     }
@@ -40,52 +43,52 @@ class TSAIRintoneHistorySectionHeaderView: UICollectionReusableView {
 }
 
 
-class TSAIRintoneHistorySectionFooterView: UICollectionReusableView {
-    static let reuseIdentifier = "TSAIRintoneHistorySectionFooterView"
-    var clickView:(()->Void)?
-    
-    lazy var moreView: UIView = {
-        let moreView = UIView()
-        moreView.backgroundColor = .white.withAlphaComponent(0.1)
-        moreView.cornerRadius = 10.0
-        let textLabel = UILabel.createLabel(text: "more".localized,font: .font(size: 12),textColor: .white.withAlphaComponent(0.6))
-        moreView.addSubview(textLabel)
-        
-        let imageView = UIImageView.createImageView(imageName: "gary_right_arrow")
-        moreView.addSubview(imageView)
-        
-        textLabel.snp.makeConstraints { make in
-            make.leading.equalTo(8)
-            make.centerY.equalToSuperview()
-        }
-        
-        imageView.snp.makeConstraints { make in
-            make.centerY.equalToSuperview()
-            make.leading.equalTo(textLabel.snp.trailing).offset(2)
-            make.width.height.equalTo(12)
-            make.trailing.equalTo(-4)
-        }
-        moreView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickMoreView)))
-        return moreView
-    }()
-    
-    
-    
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        
-        addSubview(moreView)
-        moreView.snp.makeConstraints { make in
-            make.center.equalToSuperview()
-            make.height.equalTo(20)
-        }
-    }
-    
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-    
-    @objc func clickMoreView() {
-        clickView?()
-    }
-}
+//class TSAIRintoneHistorySectionFooterView: UICollectionReusableView {
+//    static let reuseIdentifier = "TSAIRintoneHistorySectionFooterView"
+//    var clickView:(()->Void)?
+//    
+//    lazy var moreView: UIView = {
+//        let moreView = UIView()
+//        moreView.backgroundColor = .white.withAlphaComponent(0.1)
+//        moreView.cornerRadius = 10.0
+//        let textLabel = UILabel.createLabel(text: "more".localized,font: .font(size: 12),textColor: .white.withAlphaComponent(0.6))
+//        moreView.addSubview(textLabel)
+//        
+//        let imageView = UIImageView.createImageView(imageName: "gary_right_arrow")
+//        moreView.addSubview(imageView)
+//        
+//        textLabel.snp.makeConstraints { make in
+//            make.leading.equalTo(8)
+//            make.centerY.equalToSuperview()
+//        }
+//        
+//        imageView.snp.makeConstraints { make in
+//            make.centerY.equalToSuperview()
+//            make.leading.equalTo(textLabel.snp.trailing).offset(2)
+//            make.width.height.equalTo(12)
+//            make.trailing.equalTo(-4)
+//        }
+//        moreView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(clickMoreView)))
+//        return moreView
+//    }()
+//    
+//    
+//    
+//    override init(frame: CGRect) {
+//        super.init(frame: frame)
+//        
+//        addSubview(moreView)
+//        moreView.snp.makeConstraints { make in
+//            make.center.equalToSuperview()
+//            make.height.equalTo(20)
+//        }
+//    }
+//    
+//    required init?(coder: NSCoder) {
+//        fatalError("init(coder:) has not been implemented")
+//    }
+//    
+//    @objc func clickMoreView() {
+//        clickView?()
+//    }
+//}

+ 1 - 1
AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/ViewModel/TSAIRintoneVM.swift

@@ -51,7 +51,7 @@ class TSAIRintoneVM {
 
     //每日推荐的歌曲
     lazy var recommendRingtonesModel: TSAIRintoneHistoryModel = {
-        let model = TSAIRintoneHistoryModel(title: "Recommend Ringtones", list:[],type: .recommend)
+        let model = TSAIRintoneHistoryModel(title: "🔥 Recommend Ringtones", list:[],type: .recommend)
         return model
     }()
 

+ 9 - 2
AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVC.swift

@@ -41,7 +41,9 @@ class TSGeneralRintoneVC: TSBottomAlertVC {
     //############################## 生成动画 ##############################
     lazy var generateInView : TSCommonloadingView = {
         let generateInView = TSCommonloadingView()
-        generateInView.cancelBtn.addTarget(self, action: #selector(closePage), for: .touchUpInside)
+        generateInView.timeLabel.text = "~ 4min"
+//        generateInView.cancelBtn.addTarget(self, action: #selector(closePage), for: .touchUpInside)
+        generateInView.backstageBtn.addTarget(self, action: #selector(clickBackstageBtn), for: .touchUpInside)
         return generateInView
     }()
 
@@ -77,6 +79,11 @@ class TSGeneralRintoneVC: TSBottomAlertVC {
         }
     }
     
+    @objc func clickBackstageBtn() {
+        viewModel.cancelAllRequest()
+        self.dismiss(animated: true, completion: nil)
+    }
+    
     @objc override func closePage() {
         viewModel.cancelAllRequest()
         self.dismiss(animated: true, completion: nil)
@@ -118,7 +125,7 @@ class TSGeneralRintoneVC: TSBottomAlertVC {
             guard let self = self else { return }
             self.upDateView(state: state, model: model)
         }.store(in: &cancellable)
-
+    
         ringView.monitorPlayStateDefaultHandle()
     }
 }

+ 22 - 10
AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVM.swift

@@ -36,17 +36,25 @@ class TSGeneralRintoneVM {
         stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
 
         kDelayOnMainThread(0.2) {
+            self.stateDatauPblished = (.progressString(self.generating(progress: 0.2)),nil)
+        }
+        
+        kDelayOnMainThread(0.5) {
             self.stateDatauPblished = (.progressString(self.generating(progress: 0.5)),nil)
         }
-
-        kDelayOnMainThread(1.0) {
-            if Bool.random() {
-                let infoModel = TSActionInfoModel(JSON: actionInfoDict)
-                self.stateDatauPblished = (.success(nil),infoModel)
-            }else{
-                self.stateDatauPblished = (.failed("error?.localizedDescription"),nil)
-            }
+        
+        kDelayOnMainThread(0.8) {
+            self.stateDatauPblished = (.progressString(self.generating(progress: 0.8)),nil)
         }
+
+//        kDelayOnMainThread(2.0) {
+//            if Bool.random() {
+//                let infoModel = TSActionInfoModel(JSON: actionInfoDict)
+//                self.stateDatauPblished = (.success(nil),infoModel)
+//            }else{
+//                self.stateDatauPblished = (.failed("error?.localizedDescription"),nil)
+//            }
+//        }
     }
     
  
@@ -113,7 +121,7 @@ class TSGeneralRintoneVM {
         var progressInt = Int(progress*100)
 
         if generatingProgress >= progressInt{
-            return "Generating \(generatingProgress)%"
+            return generatingString
         }
 
         if progressInt > 99 {
@@ -121,6 +129,10 @@ class TSGeneralRintoneVM {
         }
         
         generatingProgress = progressInt
-        return "Generating \(progressInt)%"
+        return generatingString
+    }
+    
+    var generatingString:String {
+        return "Working on your ringtone \(generatingProgress)% ..."
     }
 }

+ 6 - 5
AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/TSTextGeneralRintoneVC.swift

@@ -13,7 +13,7 @@ class TSTextGeneralRintoneVC: TSBaseVC {
             if cusStackView.viewH > 0{
                 return cusStackView.viewH
             }
-            return 455.0
+            return 400.0
         }
     }
     
@@ -30,11 +30,13 @@ class TSTextGeneralRintoneVC: TSBaseVC {
     
     //###################################### cusStackView ######################################
     lazy var cusStackView: TSCustomStackView = {
-        let cusStackView = TSCustomStackView(axis: .vertical,spacing: 8)
+        let cusStackView = TSCustomStackView(axis: .vertical,spacing: 0)
+        cusStackView.scrollView.isScrollEnabled = false
         return cusStackView
     }()
     
     //###################################### 输入框 ######################################
+
     lazy var promptTextView: TSPromptTextView = {
         let promptTextView = TSPromptTextView(randomTextArray: kRandomTextToRintone) { [weak self] text in
             guard let self = self else { return }
@@ -85,13 +87,12 @@ class TSTextGeneralRintoneVC: TSBaseVC {
         
         contentView.addSubview(cusStackView)
         cusStackView.snp.makeConstraints { make in
-            make.top.leading.bottom.trailing.equalTo(0)
+            make.leading.bottom.trailing.equalTo(0)
+            make.top.equalTo(16)
         }
 
         cusStackView.addSubviewToStack(promptTextView)
-        
         cusStackView.addSubviewToStack(promptStyleView)
-
         cusStackView.addSubviewToStack(creatBtnView)
         creatBtnView.snp.makeConstraints { make in
             make.height.equalTo(creatBtnView.viewH)

+ 4 - 4
AIRingtone/Business/TSAIRintoneVC/TSTextGeneralRintoneVC/VM/text_rintone_style.json

@@ -13,14 +13,14 @@
     },
     {
         "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",
+        "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_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",
+        "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
     },
     {

+ 167 - 8
AIRingtone/Business/VIewTool/TSCommonloadingView.swift

@@ -32,17 +32,23 @@ class TSCommonloadingView: TSBaseView {
         return animatedImageView
     }()
     
+    
+    lazy var timeLabel: UILabel = {
+        let timeLabel = UILabel.createLabel(text: "~ 1min",font: .font(size: 20,weight: .bold),textColor: .fromHex("#FFFFFF"),textAlignment: .center)
+        return timeLabel
+    }()
+    
     lazy var textLabel: UILabel = {
         let textLabel = UILabel.createLabel(font: .font(size: 12),textColor: .fromHex("#FFFFFF",alpha: 0.6),textAlignment: .center)
         return textLabel
     }()
     
     
-    lazy var cancelBtn: UIButton = {
-        let textColor = UIColor.white.withAlphaComponent(0.4)
-        let cancelBtn = UIButton.createButton(title:"Cancel".localized,backgroundColor: "#171717".uiColor,font: UIFont.font(size: 16,weight: .regular),titleColor:textColor,corner: 24)
+    lazy var backstageBtn: UIButton = {
+        let textColor = UIColor.themeColor
+        let cancelBtn = UIButton.createButton(title:"Generate in the background".localized,backgroundColor: "#171717".uiColor,font: UIFont.font(size: 16,weight: .regular),titleColor:textColor,corner: 24)
         cancelBtn.layer.borderWidth = 1
-        cancelBtn.layer.borderColor = UIColor.white.withAlphaComponent(0.15).cgColor
+        cancelBtn.layer.borderColor = textColor.cgColor
         return cancelBtn
     }()
     private var targetView: UIView = UIView()
@@ -66,6 +72,13 @@ class TSCommonloadingView: TSBaseView {
             make.centerY.equalToSuperview().offset(-60)
         }
   
+        contentView.addSubview(timeLabel)
+        timeLabel.snp.makeConstraints { make in
+            make.height.equalTo(18.0)
+            make.top.equalTo(imageView.snp.bottom).offset(-8)
+            make.leading.trailing.equalToSuperview()
+        }
+        
         contentView.addSubview(textLabel)
         textLabel.snp.makeConstraints { make in
             make.height.equalTo(18.0)
@@ -73,11 +86,12 @@ class TSCommonloadingView: TSBaseView {
             make.leading.trailing.equalToSuperview()
         }
         
-        contentView.addSubview(cancelBtn)
-        cancelBtn.snp.makeConstraints { make in
+        contentView.addSubview(backstageBtn)
+        backstageBtn.snp.makeConstraints { make in
             make.height.equalTo(48.0)
-            make.top.equalTo(textLabel.snp.bottom).offset(36)
-            make.width.equalTo(200.0)
+//            make.top.equalTo(textLabel.snp.bottom).offset(36)
+            make.bottom.equalTo(-40)
+            make.width.equalTo(312.0)
             make.centerX.equalToSuperview()
         }
     }
@@ -150,3 +164,148 @@ class TSCommonloadingView: TSBaseView {
         isRotating = isRotating
     }
 }
+
+
+//class TSCommonloadingView: TSBaseView {
+//    
+//    lazy var imageView: UIImageView = {
+//        let imageView = UIImageView.createImageView(imageName: "failed_big")
+//        imageView.isHidden = true
+//        return imageView
+//    }()
+//    
+//    lazy var animatedImageView: AnimatedImageView = {
+//        let animatedImageView = AnimatedImageView()
+//        animatedImageView.autoPlayAnimatedImage = false
+//        if let gifURL = Bundle.main.url(forResource: "rotatingAnimation", withExtension: "gif") {
+//            animatedImageView.kf.setImage(with: gifURL, options: [.cacheOriginalImage]) { result in
+//                switch result {
+//                case .success(let value):
+//                    print("GIF 加载成功: \(value.source.url?.absoluteString ?? "")")
+//                case .failure(let error):
+//                    print("GIF 加载失败: \(error.localizedDescription)")
+//                }
+//            }
+//        }
+//        
+//        return animatedImageView
+//    }()
+//    
+//    lazy var textLabel: UILabel = {
+//        let textLabel = UILabel.createLabel(font: .font(size: 12),textColor: .fromHex("#FFFFFF",alpha: 0.6),textAlignment: .center)
+//        return textLabel
+//    }()
+//    
+//    
+//    lazy var cancelBtn: UIButton = {
+//        let textColor = UIColor.white.withAlphaComponent(0.4)
+//        let cancelBtn = UIButton.createButton(title:"Cancel".localized,backgroundColor: "#171717".uiColor,font: UIFont.font(size: 16,weight: .regular),titleColor:textColor,corner: 24)
+//        cancelBtn.layer.borderWidth = 1
+//        cancelBtn.layer.borderColor = UIColor.white.withAlphaComponent(0.15).cgColor
+//        return cancelBtn
+//    }()
+//    private var targetView: UIView = UIView()
+//    
+//    override func creatUI() {
+//        
+//        let blurEffect = createBlurEffectView(style: .dark)
+//        contentView.addSubview(blurEffect)
+//        
+//        contentView.addSubview(imageView)
+//        imageView.snp.makeConstraints { make in
+//            make.width.height.equalTo(200.0)
+//            make.centerX.equalToSuperview()
+//            make.centerY.equalToSuperview().offset(-60)
+//        }
+//        
+//        contentView.addSubview(animatedImageView)
+//        animatedImageView.snp.makeConstraints { make in
+//            make.width.height.equalTo(200.0)
+//            make.centerX.equalToSuperview()
+//            make.centerY.equalToSuperview().offset(-60)
+//        }
+//  
+//        contentView.addSubview(textLabel)
+//        textLabel.snp.makeConstraints { make in
+//            make.height.equalTo(18.0)
+//            make.top.equalTo(imageView.snp.bottom).offset(16)
+//            make.leading.trailing.equalToSuperview()
+//        }
+//        
+//        contentView.addSubview(cancelBtn)
+//        cancelBtn.snp.makeConstraints { make in
+//            make.height.equalTo(48.0)
+//            make.top.equalTo(textLabel.snp.bottom).offset(36)
+//            make.width.equalTo(200.0)
+//            make.centerX.equalToSuperview()
+//        }
+//    }
+//    
+//    
+//    override func dealThings() {
+//        // 监听应用生命周期事件
+//        NotificationCenter.default.addObserver(
+//            self,
+//            selector: #selector(handleAppDidEnterBackground),
+//            name: UIApplication.didEnterBackgroundNotification,
+//            object: nil
+//        )
+//        
+//        NotificationCenter.default.addObserver(
+//            self,
+//            selector: #selector(handleAppWillEnterForeground),
+//            name: UIApplication.willEnterForegroundNotification,
+//            object: nil
+//        )
+//    }
+//    
+//    
+//    lazy var isRotating = false{
+//        didSet{
+//            if isRotating == true{
+//                startRotating(view: imageView)
+//            }else{
+//                stopRotating(view: imageView)
+//            }
+//        }
+//    }
+//    
+//    
+//    /// 开始旋转
+//    func startRotating(view:UIView,duration: Double = 2.0) {
+//        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
+//            self.animatedImageView.startAnimating()
+//        }
+//    }
+//
+//    /// 停止旋转
+//    func stopRotating(view:UIView) {
+//        animatedImageView.stopAnimating()
+//    }
+//    
+//    func showLoading(text:String){
+//        animatedImageView.isHidden = false
+//        imageView.isHidden = true
+//        
+//        textLabel.text = text
+//        isRotating = true
+//    }
+//    
+//    func showError(text:String){
+//        animatedImageView.isHidden = true
+//        
+//        imageView.isHidden = false
+//        imageView.image = UIImage(named: "failed_big")
+//        
+//        textLabel.text = text
+//        isRotating = false
+//    }
+//    
+//    @objc private func handleAppDidEnterBackground() {
+//        stopRotating(view: targetView)
+//    }
+//
+//    @objc private func handleAppWillEnterForeground() {
+//        isRotating = isRotating
+//    }
+//}

+ 125 - 0
AIRingtone/Business/VIewTool/TSRingLoadingView.swift

@@ -0,0 +1,125 @@
+//
+//  TSRingLoadingView.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/21.
+//
+
+import Kingfisher
+
+class TSRingLoadingView: TSBaseView {
+    
+    lazy var animatedImageView: AnimatedImageView = {
+        let animatedImageView = AnimatedImageView()
+        animatedImageView.autoPlayAnimatedImage = false
+        if let gifURL = Bundle.main.url(forResource: "ringAnimation", withExtension: "gif") {
+            animatedImageView.kf.setImage(with: gifURL, options: [.cacheOriginalImage]) { result in
+                switch result {
+                case .success(let value):
+                    print("GIF 加载成功: \(value.source.url?.absoluteString ?? "")")
+                case .failure(let error):
+                    print("GIF 加载失败: \(error.localizedDescription)")
+                }
+            }
+        }
+        
+        return animatedImageView
+    }()
+    
+    lazy var textLabel: UILabel = {
+        let textLabel = UILabel.createLabel(text:"loading...".localized, font: .font(size: 12),textColor: .fromHex("#FFFFFF").withAlphaComponent(0.8) ,textAlignment: .center)
+        return textLabel
+    }()
+    
+    
+    private var targetView: UIView = UIView()
+    
+    override func creatUI() {
+        contentView.backgroundColor = .black
+        contentView.cornerRadius = 16
+        contentView.snp.remakeConstraints { make in
+            make.width.height.equalTo(100)
+            make.center.equalToSuperview()
+        }
+        
+        contentView.addSubview(animatedImageView)
+        animatedImageView.snp.makeConstraints { make in
+            make.width.height.equalTo(60)
+            make.centerX.equalToSuperview()
+            make.top.equalTo(12)
+        }
+  
+        contentView.addSubview(textLabel)
+        textLabel.snp.makeConstraints { make in
+            make.height.equalTo(18.0)
+            make.top.equalTo(animatedImageView.snp.bottom).offset(2)
+            make.leading.trailing.equalToSuperview()
+        }
+        
+    }
+    
+    
+    override func dealThings() {
+        // 监听应用生命周期事件
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(handleAppDidEnterBackground),
+            name: UIApplication.didEnterBackgroundNotification,
+            object: nil
+        )
+        
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(handleAppWillEnterForeground),
+            name: UIApplication.willEnterForegroundNotification,
+            object: nil
+        )
+    }
+    
+    
+    lazy var isRotating = false{
+        didSet{
+            if isRotating == true{
+                startRotating(view: animatedImageView)
+            }else{
+                stopRotating(view: animatedImageView)
+            }
+        }
+    }
+    
+    
+    /// 开始旋转
+    func startRotating(view:UIView) {
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
+            self.animatedImageView.startAnimating()
+        }
+    }
+
+    /// 停止旋转
+    func stopRotating(view:UIView) {
+        animatedImageView.stopAnimating()
+    }
+    
+    func showLoading(text:String){
+        animatedImageView.isHidden = false
+
+        textLabel.text = text
+        isRotating = true
+    }
+    
+    func showError(text:String){
+        animatedImageView.isHidden = true
+
+        
+        textLabel.text = text
+        isRotating = false
+    }
+    
+    @objc private func handleAppDidEnterBackground() {
+        stopRotating(view: targetView)
+    }
+
+    @objc private func handleAppWillEnterForeground() {
+        isRotating = isRotating
+    }
+}

binární
AIRingtone/Common/Res/ringAnimation.gif


+ 0 - 0
AIRingtone/Common/Tool/TSAudioAVPlayer.swift → AIRingtone/Common/Tool/NotUse/TSAudioAVPlayer.swift


+ 0 - 0
AIRingtone/Common/Tool/TSAudioPlayerFileTool.swift → AIRingtone/Common/Tool/NotUse/TSAudioPlayerFileTool.swift


+ 0 - 0
AIRingtone/Common/Tool/TSDownloadManager.swift → AIRingtone/Common/Tool/NotUse/TSDownloadManager.swift


+ 34 - 147
AIRingtone/Common/Tool/OperationQueue/TSBaseOperation.swift

@@ -8,17 +8,24 @@
 import Foundation
 
 class TSBaseOperation: Operation , @unchecked Sendable{
-    typealias TaskCompletionHandler = (Error?) -> Void
-    typealias TaskBlock = (@escaping TaskCompletionHandler) -> Void
     
-    private let task: TaskBlock
+    let uuid:String
+    
+    enum TSBaseOperationState {
+        case executing(Bool)
+        case finished(Bool)
+        case cancelled(Bool)
+    }
+    
+    @Published var operationStatePblished:TSBaseOperationState = .executing(false)
+    
     private var _executing = false
     private var _finished = false
     private var _cancelled = false
     private var _error: Error?
     
-    init(task: @escaping TaskBlock) {
-        self.task = task
+    required init(uuid:String) {
+        self.uuid = uuid
         super.init()
     }
     
@@ -45,23 +52,11 @@ class TSBaseOperation: Operation , @unchecked Sendable{
             completeOperation()
             return
         }
-        
-        willChangeValue(forKey: "isExecuting")
-        _executing = true
-        didChangeValue(forKey: "isExecuting")
-        
-        task { [weak self] error in
-            guard let self = self else { return }
-            self._error = error
-            self.completeOperation()
-        }
+        setExecutingValue(value: true)
     }
     
     override func cancel() {
-        willChangeValue(forKey: "isCancelled")
-        _cancelled = true
-        didChangeValue(forKey: "isCancelled")
-        
+        setCancelValue(value: true)
         if isExecuting {
             completeOperation()
         }
@@ -69,18 +64,32 @@ class TSBaseOperation: Operation , @unchecked Sendable{
     
     private func completeOperation() {
         if _executing {
-            willChangeValue(forKey: "isExecuting")
-            _executing = false
-            didChangeValue(forKey: "isExecuting")
+            setExecutingValue(value: false)
         }
         
         if !_finished {
-            willChangeValue(forKey: "isFinished")
-            _finished = true
-            didChangeValue(forKey: "isFinished")
+            setFinishedValue(value: true)
         }
     }
     
+    func setCancelValue(value:Bool){
+        willChangeValue(forKey: "isCancelled")
+        _cancelled = value
+        didChangeValue(forKey: "isCancelled")
+    }
+    
+    func setExecutingValue(value:Bool){
+        willChangeValue(forKey: "isExecuting")
+        _executing = value
+        didChangeValue(forKey: "isExecuting")
+    }
+    
+    func setFinishedValue(value:Bool){
+        willChangeValue(forKey: "isFinished")
+        _finished = value
+        didChangeValue(forKey: "isFinished")
+    }
+    
     // MARK: - Error Handling
     
     var error: Error? {
@@ -103,125 +112,3 @@ class TSBaseOperation: Operation , @unchecked Sendable{
         super.removeDependency(operation)
     }
 }
-
-
-
-
-
-//import Foundation
-//
-//final class TaskOperation: Operation, @unchecked Sendable {
-//    typealias TaskCompletionHandler = (Error?) -> Void
-//    typealias TaskBlock = (@escaping TaskCompletionHandler) -> Void
-//    
-//    private let task: TaskBlock
-//    private var _executing = false
-//    private var _finished = false
-//    private var _cancelled = false
-//    private var _error: Error?
-//    
-//    private let stateLock = NSLock() // 用于线程安全的状态管理
-//    
-//    init(task: @escaping TaskBlock) {
-//        self.task = task
-//        super.init()
-//    }
-//    
-//    // MARK: - State Management
-//    
-//    override var isExecuting: Bool {
-//        stateLock.lock()
-//        defer { stateLock.unlock() }
-//        return _executing
-//    }
-//    
-//    override var isFinished: Bool {
-//        stateLock.lock()
-//        defer { stateLock.unlock() }
-//        return _finished
-//    }
-//    
-//    override var isCancelled: Bool {
-//        stateLock.lock()
-//        defer { stateLock.unlock() }
-//        return _cancelled
-//    }
-//    
-//    override var isAsynchronous: Bool {
-//        return true
-//    }
-//    
-//    override func start() {
-//        stateLock.lock()
-//        if isCancelled {
-//            stateLock.unlock()
-//            completeOperation()
-//            return
-//        }
-//        
-//        willChangeValue(forKey: "isExecuting")
-//        _executing = true
-//        didChangeValue(forKey: "isExecuting")
-//        stateLock.unlock()
-//        
-//        task { [weak self] error in
-//            guard let self = self else { return }
-//            self.stateLock.lock()
-//            self._error = error
-//            self.stateLock.unlock()
-//            self.completeOperation()
-//        }
-//    }
-//    
-//    override func cancel() {
-//        stateLock.lock()
-//        willChangeValue(forKey: "isCancelled")
-//        _cancelled = true
-//        didChangeValue(forKey: "isCancelled")
-//        stateLock.unlock()
-//        
-//        if isExecuting {
-//            completeOperation()
-//        }
-//    }
-//    
-//    private func completeOperation() {
-//        stateLock.lock()
-//        if _executing {
-//            willChangeValue(forKey: "isExecuting")
-//            _executing = false
-//            didChangeValue(forKey: "isExecuting")
-//        }
-//        
-//        if !_finished {
-//            willChangeValue(forKey: "isFinished")
-//            _finished = true
-//            didChangeValue(forKey: "isFinished")
-//        }
-//        stateLock.unlock()
-//    }
-//    
-//    // MARK: - Error Handling
-//    
-//    var error: Error? {
-//        stateLock.lock()
-//        defer { stateLock.unlock() }
-//        return _error
-//    }
-//    
-//    // MARK: - Convenience Methods
-//    
-//    func waitUntilFinished() {
-//        while !isFinished {
-//            RunLoop.current.run(mode: .default, before: .distantFuture)
-//        }
-//    }
-//    
-//    func addDependency(_ operation: TaskOperation) {
-//        super.addDependency(operation)
-//    }
-//    
-//    func removeDependency(_ operation: TaskOperation) {
-//        super.removeDependency(operation)
-//    }
-//}

+ 60 - 34
AIRingtone/Common/Tool/OperationQueue/TSBaseOperationQueue.swift

@@ -6,56 +6,82 @@
 //
 
 import Foundation
-
-class TaskQueueManager {
-    private let queue: OperationQueue
+import Combine
+class TSBaseOperationQueue {
     
+    private(set) var queue: OperationQueue = OperationQueue()
     
+    private var activeOperations:[String:TSBaseOperation] = [:]
+    // 存储每个操作的 AnyCancellable
+    private var cancellables: [String: AnyCancellable] = [:]
+    // 存储 KVO 观察者
+    private var operationCountObservation: NSKeyValueObservation?
     
-    var isAvailability:Bool {
-        get {
-            if queue.operationCount <= queue.maxConcurrentOperationCount {
-                return true
-            }
-            return false
+    @Published var isAvailability:Bool = true
+    private func upDateAvailability(){
+        if queue.operationCount <= queue.maxConcurrentOperationCount {
+            isAvailability = true
         }
+        isAvailability = false
     }
     
-    init(maxConcurrentOperationCount: Int = OperationQueue.defaultMaxConcurrentOperationCount) {
-        queue = OperationQueue()
+    init(maxConcurrentOperationCount: Int = 1) {
         queue.maxConcurrentOperationCount = maxConcurrentOperationCount
+        
+        // 监听 operationCount 的变化
+           operationCountObservation = queue.observe(\.operationCount, options: [.new]) { [weak self] (queue, change) in
+               guard let self = self else { return }
+               if let newValue = change.newValue {
+                   upDateAvailability()
+               }
+           }
     }
     
-    func addTask(_ task: @escaping TSBaseOperation.TaskBlock) -> TSBaseOperation {
-        let operation = TSBaseOperation(task: task)
-        queue.addOperation(operation)
-        return operation
+    // 获取或创建操作
+    func getOperation<T: TSBaseOperation>(uuid: String) -> T {
+        if let existingOperation = activeOperations[uuid] as? T {
+            return existingOperation
+        } else {
+            let operation = T(uuid: uuid)
+            activeOperations[uuid] = operation
+            queue.addOperation(operation)
+            cancellables[uuid] = operation.$operationStatePblished.sink { [weak self] state in
+                guard let self = self else { return }
+                
+                switch state {
+                case .finished(let finished):
+                    if finished == true {
+                        cancelOperations(uuid: uuid)
+                    }
+                case .cancelled(let cancelled):
+                    if cancelled == true {
+                        cancelOperations(uuid: uuid)
+                    }
+                default: break
+                }
+            }
+            return operation
+        }
     }
     
+    /// 清理所有下载任务
     func cancelAllOperations() {
         queue.cancelAllOperations()
+        activeOperations = [:]
+    }
+    
+    /// 清理某个下载任务
+    /// - Parameter url: 下载任务的 URL
+    func cancelOperations(uuid: String) {
+        if let operation = activeOperations[uuid] {
+            operation.cancel()
+            activeOperations.removeValue(forKey: uuid)
+            cancellables.removeValue(forKey: uuid)
+        }
     }
     
     func waitUntilAllOperationsAreFinished() {
         queue.waitUntilAllOperationsAreFinished()
     }
-    
-    
-    
-    
-    //// 监听 operationCount 属性
-    //queue.addObserver(self, forKeyPath: "operationCount", options: [.new], context: nil)
-    //override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
-    //    if keyPath == "operationCount" {
-    //        if queue.operationCount == 0 {
-    //            print("所有任务已完成")
-    //        } else {
-    //            print("队列中还有 \(queue.operationCount) 个任务在执行")
-    //        }
-    //    }
-    //}
-    //
-    //deinit {
-    //  queue.removeObserver(self, forKeyPath: "operationCount")
-    //}
+
 }

+ 96 - 0
AIRingtone/Common/Tool/OperationQueue/TSGenerateRintoneOperation/TSGenerateRintoneOperation.swift

@@ -5,3 +5,99 @@
 //  Created by 100Years on 2025/3/21.
 //
 
+import Combine
+import Alamofire
+class TSGenerateRintoneOperation: TSBaseOperation , @unchecked Sendable{
+    
+    @Published var stateDatauPblished:(TSProgressState,TSActionInfoModel?) = (TSProgressState.none,nil){
+        didSet{
+            dePrint("stateDatauPblished didSet = \(stateDatauPblished)")
+            
+        }
+    }
+    
+    private var creatRequest:Request?
+    private var queryRequest:Request?
+    private var stopNetwork = false
+    private var generatingProgress = 0
+    private var aiText:String = ""
+    private var action_id:Int = 0    
+    
+   func creatRintone(text:String) {
+       generatingProgress = 0
+       aiText = text
+       let postDict:[String : Any] = [
+           "prompt":text,
+           "duration":20
+       ]
+       stateDatauPblished = (.start,nil)
+       stateDatauPblished = (.progressString(generating(progress: 0.0)),nil)
+       creatRequest = TSNetworkShared.post(urlType: .musicCreate,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){
+       self.action_id = action_id
+       queryRequest = TSNetworkShared.get(urlType: .actionInfo,parameters: ["action_id":action_id]) { [weak self] data,error in
+           guard let self = self else { return }
+           if 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 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)%"
+    }
+    
+    
+    
+    func cancelAllRequest(){
+        creatRequest?.cancel()
+        queryRequest?.cancel()
+        stopNetwork = true
+    }
+    
+    
+}

+ 3 - 1
AIRingtone/Common/Tool/OperationQueue/TSGenerateRintoneOperation/TSGenerateRintoneOperationQueue.swift

@@ -5,4 +5,6 @@
 //  Created by 100Years on 2025/3/21.
 //
 
-TSGenerateRintoneOperation
+class TSGenerateRintoneOperationQueue: TSBaseOperationQueue {
+    let shared:TSGenerateRintoneOperationQueue = TSGenerateRintoneOperationQueue()
+}

+ 0 - 0
AIRingtone/Common/Tool/TSBusinessAudioPlayer.swift → AIRingtone/Common/Tool/TSAudioPlayer/TSBusinessAudioPlayer.swift


+ 15 - 37
AIRingtone/Common/Tool/TSBandRingTool/TSBandRingTool.swift

@@ -13,6 +13,10 @@ class TSBandRingTool:NSObject {
     private lazy var playContentView = UIView(frame: UIScreen.main.bounds)
     private lazy var audioConvertTool = AudioTool()
     
+    lazy var ringLoadingView: TSRingLoadingView = {
+        let ringLoadingView = TSRingLoadingView(frame: CGRectMake(0, 0, k_ScreenWidth, k_ScreenHeight))
+        return ringLoadingView
+    }()
     weak var targetVC:UIViewController?
 //    init(targetVC: UIViewController) {
 //        self.targetVC = targetVC
@@ -61,9 +65,17 @@ class TSBandRingTool:NSObject {
         }
         self.targetVC = vc
         if fileURLString.contains("http") {
-            TSLoadingAnimation.showLoading(in: self.targetVC?.view)
-            TSCommonTool.downloadAndCacheFile(from: fileURLString) { path, error in
-                TSLoadingAnimation.hideLoading()
+            
+//            TSLoadingAnimation.showLoading(in: self.targetVC?.view)
+            if let window = WindowHelper.getKeyWindow() {
+                window.addSubview(ringLoadingView)
+                ringLoadingView.isRotating = true
+            }
+
+            TSCommonTool.downloadAndCacheFile(from: fileURLString) { [weak self] path, error in
+                guard let self = self else { return }
+//                TSLoadingAnimation.hideLoading()
+                ringLoadingView.removeFromSuperview()
                 if let path = path,let url = URL(string: path) {
                     self.createBand(with: url, fileName: fileName) { bandURL in
                         if let url = bandURL {
@@ -87,40 +99,6 @@ class TSBandRingTool:NSObject {
        
     }
     
-//    func shareBand(with fileURLString: String,
-//                   fileName:String?,
-//                   completion: ((Bool) -> Void)? = nil) {
-//        
-//        if checkGarageBandInstallation() == false {
-//            completion?(false)
-//            return
-//        }
-//        
-//        if fileURLString.contains("http") {
-//            TSLoadingAnimation.showLoading(in: self.targetVC?.view)
-//            TSCommonTool.downloadAndCacheFile(from: fileURLString) { path, error in
-//                TSLoadingAnimation.hideLoading()
-//                if let path = path,let url = URL(string: path) {
-//                    self.createBand(with: url, fileName: fileName) { bandURL in
-//                        if let url = bandURL {
-//                            completion?(true)
-//                            self.shareRing(fileUrl: url)
-//                        }else{
-//                            completion?(false)
-//                            dePrint("Failed to set, please try another")
-//                        }
-//                    }
-//                }else{
-//                    dePrint("downloadAndCacheFile = \(error?.localizedDescription)")
-//                    completion?(false)
-//                }
-//            }
-//        }else{
-//            dePrint("ringtone no http")
-//            completion?(false)
-//        }
-//    }
-    
     // 创建用于分享库乐队的band文件
     func createBand(with fileURL: URL?, fileName: String?,
                     completion: ((URL?) -> Void)?) {

+ 0 - 12
AIRingtone/Common/Tool/TSSetContactAvatar.swift

@@ -1,12 +0,0 @@
-//
-//  TSSetContactAvatar.swift
-//  AIRingtone
-//
-//  Created by 100Years on 2025/3/3.
-//
-
-class TSSetContactAvatar {
-    
-
-    
-}