Selaa lähdekoodia

提测 1.5(1)

100Years 3 viikkoa sitten
vanhempi
commit
99734aff3f
48 muutettua tiedostoa jossa 347 lisäystä ja 161 poistoa
  1. 8 6
      AIRingtone.xcodeproj/project.pbxproj
  2. 3 3
      AIRingtone/AppDelegate.swift
  3. 1 2
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_0.imageset/Contents.json
  4. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_0.imageset/photo_example_0.png
  5. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_0.imageset/photo_example_0@2x.png
  6. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_0.imageset/photo_example_0@3x.png
  7. 1 2
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_1.imageset/Contents.json
  8. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_1.imageset/photo_example_1.png
  9. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_1.imageset/photo_example_1@2x.png
  10. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_1.imageset/photo_example_1@3x.png
  11. 1 2
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_2.imageset/Contents.json
  12. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_2.imageset/photo_example_2.png
  13. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_2.imageset/photo_example_2@2x.png
  14. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_2.imageset/photo_example_2@3x.png
  15. 1 2
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_0.imageset/Contents.json
  16. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_0.imageset/poster_example_0.png
  17. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_0.imageset/poster_example_0@2x.png
  18. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_0.imageset/poster_example_0@3x.png
  19. 1 2
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_1.imageset/Contents.json
  20. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_1.imageset/poster_example_1.png
  21. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_1.imageset/poster_example_1@2x.png
  22. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_1.imageset/poster_example_1@3x.png
  23. 1 2
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_2.imageset/Contents.json
  24. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_2.imageset/poster_example_2.png
  25. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_2.imageset/poster_example_2@2x.png
  26. BIN
      AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_2.imageset/poster_example_2@3x.png
  27. 188 0
      AIRingtone/Business/Data/TSUserDefaultData1.swift
  28. 1 1
      AIRingtone/Business/TSAIPhotoVC/TSGeneralPicVC/TSGenneralPicVM.swift
  29. 27 37
      AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/TSAIRintoneVC.swift
  30. 9 45
      AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/View/TSAIRintoneHistoryCell.swift
  31. 1 1
      AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVM.swift
  32. 25 13
      AIRingtone/Business/TSAIRintoneVC/TSGenerateHistoryVC/TSGenerateHistoryVC.swift
  33. 1 1
      AIRingtone/Business/TSCollectionViewVM/TSCollectionViewVM.swift
  34. 2 3
      AIRingtone/Business/TSDiscoverVC/TSDiscoverListVC/TSDiscoverListVC.swift
  35. 3 4
      AIRingtone/Business/TSDiscoverVC/TSRingDownVC/TSRingDownVC.swift
  36. 1 1
      AIRingtone/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift
  37. 9 1
      AIRingtone/Business/TSSetingVC/SetingVC/TSSetingVC.swift
  38. 1 0
      AIRingtone/Business/TSSetingVC/SetingVC/TSSetingViewModel.swift
  39. 2 2
      AIRingtone/Business/TSSetingVC/SetingVC/View/SettingPurchaseTopView.swift
  40. 3 3
      AIRingtone/Business/TSSetingVC/SetingVC/View/TSSettingListView.swift
  41. 3 2
      AIRingtone/Business/VIewTool/TSRingToneCellView.swift
  42. 5 3
      AIRingtone/Common/Config/GlobalImports.swift
  43. 2 0
      AIRingtone/Common/Ex/Notification+TSEx.swift
  44. 14 11
      AIRingtone/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGenerateBaseOperation.swift
  45. 2 3
      AIRingtone/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGeneratePhotoOperation.swift
  46. 3 4
      AIRingtone/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGeneratePosterOperation.swift
  47. 18 4
      AIRingtone/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGenerateRintoneOperation.swift
  48. 10 1
      AIRingtone/Common/Tool/TSAudioPlayer/TSAudioPlayer.swift

+ 8 - 6
AIRingtone.xcodeproj/project.pbxproj

@@ -197,6 +197,7 @@
 		A840A7F92D916D9A0044B8B9 /* TSGeneratePosterOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGeneratePosterOperation.swift; sourceTree = "<group>"; };
 		A840A7F92D916D9A0044B8B9 /* TSGeneratePosterOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGeneratePosterOperation.swift; sourceTree = "<group>"; };
 		A840A7FD2D916DB40044B8B9 /* TSGeneratePhotoOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGeneratePhotoOperation.swift; sourceTree = "<group>"; };
 		A840A7FD2D916DB40044B8B9 /* TSGeneratePhotoOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGeneratePhotoOperation.swift; sourceTree = "<group>"; };
 		A840A8022D9194590044B8B9 /* TSGenerateBaseOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGenerateBaseOperation.swift; sourceTree = "<group>"; };
 		A840A8022D9194590044B8B9 /* TSGenerateBaseOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSGenerateBaseOperation.swift; sourceTree = "<group>"; };
+		A840A8042D925E910044B8B9 /* TSUserDefaultData1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSUserDefaultData1.swift; sourceTree = "<group>"; };
 		A868A8992D75505800F6D884 /* TSThemeBannerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSThemeBannerCell.swift; 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>"; };
 		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>"; };
 		A868A89D2D7560B900F6D884 /* TSPageNullView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPageNullView.swift; sourceTree = "<group>"; };
@@ -623,6 +624,7 @@
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
 				A83F871C2D79409300D29B1B /* TSUserDefaultData.swift */,
 				A83F871C2D79409300D29B1B /* TSUserDefaultData.swift */,
+				A840A8042D925E910044B8B9 /* TSUserDefaultData1.swift */,
 			);
 			);
 			path = Data;
 			path = Data;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -1323,11 +1325,11 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 5;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				GENERATE_INFOPLIST_FILE = YES;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = AIRingtone/Info.plist;
 				INFOPLIST_FILE = AIRingtone/Info.plist;
-				INFOPLIST_KEY_CFBundleDisplayName = "AI Ringtone";
+				INFOPLIST_KEY_CFBundleDisplayName = Ringtones;
 				INFOPLIST_KEY_NSContactsUsageDescription = "Allow \"Contacts\" permission to set contact photo";
 				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_NSPhotoLibraryUsageDescription = "Allow us to access Photos in order to save wallpapers to your device.";
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@@ -1342,7 +1344,7 @@
 					"$(inherited)",
 					"$(inherited)",
 					"$(PROJECT_DIR)/AIRingtone/Common/Tool/TSBandRingTool/libmp3",
 					"$(PROJECT_DIR)/AIRingtone/Common/Tool/TSBandRingTool/libmp3",
 				);
 				);
-				MARKETING_VERSION = 1.4;
+				MARKETING_VERSION = 1.5;
 				PRODUCT_BUNDLE_IDENTIFIER = ai.ringtones.com;
 				PRODUCT_BUNDLE_IDENTIFIER = ai.ringtones.com;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
@@ -1365,11 +1367,11 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 5;
+				CURRENT_PROJECT_VERSION = 1;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				DEVELOPMENT_TEAM = 65UD255J84;
 				GENERATE_INFOPLIST_FILE = YES;
 				GENERATE_INFOPLIST_FILE = YES;
 				INFOPLIST_FILE = AIRingtone/Info.plist;
 				INFOPLIST_FILE = AIRingtone/Info.plist;
-				INFOPLIST_KEY_CFBundleDisplayName = "AI Ringtone";
+				INFOPLIST_KEY_CFBundleDisplayName = Ringtones;
 				INFOPLIST_KEY_NSContactsUsageDescription = "Allow \"Contacts\" permission to set contact photo";
 				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_NSPhotoLibraryUsageDescription = "Allow us to access Photos in order to save wallpapers to your device.";
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
 				INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
@@ -1384,7 +1386,7 @@
 					"$(inherited)",
 					"$(inherited)",
 					"$(PROJECT_DIR)/AIRingtone/Common/Tool/TSBandRingTool/libmp3",
 					"$(PROJECT_DIR)/AIRingtone/Common/Tool/TSBandRingTool/libmp3",
 				);
 				);
-				MARKETING_VERSION = 1.4;
+				MARKETING_VERSION = 1.5;
 				PRODUCT_BUNDLE_IDENTIFIER = ai.ringtones.com;
 				PRODUCT_BUNDLE_IDENTIFIER = ai.ringtones.com;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
 				SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";

+ 3 - 3
AIRingtone/AppDelegate.swift

@@ -56,6 +56,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
 
 
     func initPlatform() {
     func initPlatform() {
         TSColorConfigShared.naviMianTextColor = .white
         TSColorConfigShared.naviMianTextColor = .white
+        checkAppConfig()
     }
     }
 
 
 }
 }
@@ -147,13 +148,12 @@ extension AppDelegate {
     }
     }
     
     
     func checkAppConfig(){
     func checkAppConfig(){
-        _ = TSNetworkShared.get(urlType: .config) { [weak self] data,error in
-            guard let self = self else { return }
+        _ = TSNetworkShared.get(urlType: .config) { data,error in
             
             
             if let result = kNetWorkResultSuccess(data: data) {
             if let result = kNetWorkResultSuccess(data: data) {
                 kAppNewVerison = result.safeString(forKey: "version")
                 kAppNewVerison = result.safeString(forKey: "version")
+                NotificationCenter.default.post(name: .kRefreshSettingView, object: nil)
             }
             }
-     
         }
         }
     }
     }
     
     

+ 1 - 2
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_0.imageset/Contents.json

@@ -5,12 +5,11 @@
       "scale" : "1x"
       "scale" : "1x"
     },
     },
     {
     {
-      "filename" : "photo_example_0@2x.png",
+      "filename" : "photo_example_0.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "2x"
       "scale" : "2x"
     },
     },
     {
     {
-      "filename" : "photo_example_0@3x.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "3x"
       "scale" : "3x"
     }
     }

BIN
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_0.imageset/photo_example_0.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_0.imageset/photo_example_0@2x.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_0.imageset/photo_example_0@3x.png


+ 1 - 2
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_1.imageset/Contents.json

@@ -5,12 +5,11 @@
       "scale" : "1x"
       "scale" : "1x"
     },
     },
     {
     {
-      "filename" : "photo_example_1@2x.png",
+      "filename" : "photo_example_1.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "2x"
       "scale" : "2x"
     },
     },
     {
     {
-      "filename" : "photo_example_1@3x.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "3x"
       "scale" : "3x"
     }
     }

BIN
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_1.imageset/photo_example_1.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_1.imageset/photo_example_1@2x.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_1.imageset/photo_example_1@3x.png


+ 1 - 2
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_2.imageset/Contents.json

@@ -5,12 +5,11 @@
       "scale" : "1x"
       "scale" : "1x"
     },
     },
     {
     {
-      "filename" : "photo_example_2@2x.png",
+      "filename" : "photo_example_2.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "2x"
       "scale" : "2x"
     },
     },
     {
     {
-      "filename" : "photo_example_2@3x.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "3x"
       "scale" : "3x"
     }
     }

BIN
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_2.imageset/photo_example_2.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_2.imageset/photo_example_2@2x.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/photo_example_2.imageset/photo_example_2@3x.png


+ 1 - 2
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_0.imageset/Contents.json

@@ -5,12 +5,11 @@
       "scale" : "1x"
       "scale" : "1x"
     },
     },
     {
     {
-      "filename" : "poster_example_0@2x.png",
+      "filename" : "poster_example_0.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "2x"
       "scale" : "2x"
     },
     },
     {
     {
-      "filename" : "poster_example_0@3x.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "3x"
       "scale" : "3x"
     }
     }

BIN
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_0.imageset/poster_example_0.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_0.imageset/poster_example_0@2x.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_0.imageset/poster_example_0@3x.png


+ 1 - 2
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_1.imageset/Contents.json

@@ -5,12 +5,11 @@
       "scale" : "1x"
       "scale" : "1x"
     },
     },
     {
     {
-      "filename" : "poster_example_1@2x.png",
+      "filename" : "poster_example_1.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "2x"
       "scale" : "2x"
     },
     },
     {
     {
-      "filename" : "poster_example_1@3x.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "3x"
       "scale" : "3x"
     }
     }

BIN
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_1.imageset/poster_example_1.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_1.imageset/poster_example_1@2x.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_1.imageset/poster_example_1@3x.png


+ 1 - 2
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_2.imageset/Contents.json

@@ -5,12 +5,11 @@
       "scale" : "1x"
       "scale" : "1x"
     },
     },
     {
     {
-      "filename" : "poster_example_2@2x.png",
+      "filename" : "poster_example_2.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "2x"
       "scale" : "2x"
     },
     },
     {
     {
-      "filename" : "poster_example_2@3x.png",
       "idiom" : "universal",
       "idiom" : "universal",
       "scale" : "3x"
       "scale" : "3x"
     }
     }

BIN
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_2.imageset/poster_example_2.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_2.imageset/poster_example_2@2x.png


BIN
AIRingtone/Assets.xcassets/AIPhoto/example/poster_example_2.imageset/poster_example_2@3x.png


+ 188 - 0
AIRingtone/Business/Data/TSUserDefaultData1.swift

@@ -0,0 +1,188 @@
+//
+//  TSUserDefaultData1.swift
+//  AIRingtone
+//
+//  Created by 100Years on 2025/3/24.
+//
+
+
+import Foundation
+import ObjectMapper
+
+// MARK: - 基类
+class HistoryManager<T: Mappable> {
+    private let userDefaultsKey: String
+    private var historyString: String {
+        get {
+            return UserDefaults.standard.string(forKey: userDefaultsKey) ?? ""
+        }
+        set {
+            UserDefaults.standard.set(newValue, forKey: userDefaultsKey)
+        }
+    }
+    
+    var listModelArray: [T] {
+        get {
+            if let listModelArray = Mapper<T>().mapArray(JSONString: historyString) {
+                return listModelArray
+            }
+            return []
+        }
+        set {
+            if let jsonString = newValue.toJSONString() {
+                historyString = jsonString
+            }
+        }
+    }
+    
+    init(userDefaultsKey: String) {
+        self.userDefaultsKey = userDefaultsKey
+    }
+    
+    func saveModel(model: T) {
+        var models = listModelArray
+        if let index = models.firstIndex(where: { $0.toJSONString() == model.toJSONString() }) {
+            models[index] = model
+        } else {
+            models.insert(model, at: 0)
+        }
+        listModelArray = models
+    }
+    
+    func removeModel(model: T) {
+        var models = listModelArray
+        models.removeAll { $0.toJSONString() == model.toJSONString() }
+        listModelArray = models
+    }
+    
+    func removeIndex(index: Int) {
+        var models = listModelArray
+        models.remove(at: index)
+        listModelArray = models
+    }
+    
+    func replaceModel(oldID: Int, newModel: T) {
+        var models = listModelArray
+        if let index = models.firstIndex(where: { ($0 as? TSActionInfoModel)?.id == oldID }) {
+            models[index] = newModel
+        } else {
+            models.insert(newModel, at: 0)
+        }
+        listModelArray = models
+    }
+}
+
+// MARK: - 子类实现
+// 海报历史记录
+class TSPosterHistory: HistoryManager<TSActionInfoModel> {
+    static let shared = TSPosterHistory(userDefaultsKey: "kPosterTextPicHistoryListString")
+    
+    private override init(userDefaultsKey: String) {
+        super.init(userDefaultsKey: userDefaultsKey)
+        if UserDefaults.standard.string(forKey: "insertPosterExampleData") == nil {
+            insertExampleData()
+            UserDefaults.standard.set("1", forKey: "insertPosterExampleData")
+            UserDefaults.standard.synchronize()
+        }
+    }
+    
+    private func insertExampleData() {
+        let array = [
+            createExampleModel(imageName: "poster_example_0"),
+            createExampleModel(imageName: "poster_example_1"),
+            createExampleModel(imageName: "poster_example_2")
+        ]
+        if let jsonString = array.toJSONString() {
+            listModelArray = Mapper<TSActionInfoModel>().mapArray(JSONString: jsonString) ?? []
+        }
+    }
+    
+    private func createExampleModel(imageName: String) -> TSActionInfoModel {
+        let model = TSActionInfoModel()
+        model.modelType = .example
+        model.request.prompt = "Example"
+        model.request.promptSort = "Example"
+        model.request.width = kTextPicW
+        model.request.height = kTextPicH
+        model.response.resultUrl = imageName
+        return model
+    }
+}
+
+// 头像历史记录
+class TSPhotoHistory: HistoryManager<TSActionInfoModel> {
+    static let shared = TSPhotoHistory(userDefaultsKey: "kPhotoTextPicHistoryListString")
+    
+    private override init(userDefaultsKey: String) {
+        super.init(userDefaultsKey: userDefaultsKey)
+        if UserDefaults.standard.string(forKey: "insertPhotoExampleData") == nil {
+            insertExampleData()
+            UserDefaults.standard.set("1", forKey: "insertPhotoExampleData")
+            UserDefaults.standard.synchronize()
+        }
+    }
+    
+    private func insertExampleData() {
+        let array = [
+            createExampleModel(imageName: "photo_example_0"),
+            createExampleModel(imageName: "photo_example_1"),
+            createExampleModel(imageName: "photo_example_2")
+        ]
+        if let jsonString = array.toJSONString() {
+            listModelArray = Mapper<TSActionInfoModel>().mapArray(JSONString: jsonString) ?? []
+        }
+    }
+    
+    private func createExampleModel(imageName: String) -> TSActionInfoModel {
+        let model = TSActionInfoModel()
+        model.modelType = .example
+        model.request.prompt = "Example"
+        model.request.promptSort = "Example"
+        model.request.width = kTextPicW
+        model.request.height = kTextPicW
+        model.response.resultUrl = imageName
+        return model
+    }
+}
+
+// AI铃声历史记录
+class TSAIRintoneHistory: HistoryManager<TSActionInfoModel> {
+    static let shared = TSAIRintoneHistory(userDefaultsKey: "kRintoneTextMusicHistoryListString")
+    
+    private override init(userDefaultsKey: String) {
+        super.init(userDefaultsKey: userDefaultsKey)
+        if UserDefaults.standard.string(forKey: "insertRintoneExampleData") == nil {
+            insertExampleData()
+            UserDefaults.standard.set("1", forKey: "insertRintoneExampleData")
+            UserDefaults.standard.synchronize()
+        }
+    }
+    
+    private func insertExampleData() {
+        let array = [
+            createExampleModel()
+        ]
+        if let jsonString = array.toJSONString() {
+            listModelArray = Mapper<TSActionInfoModel>().mapArray(JSONString: jsonString) ?? []
+        }
+    }
+    
+    private func createExampleModel() -> TSActionInfoModel {
+        let model = TSActionInfoModel()
+        model.modelType = .example
+        model.request.duration = 30
+        model.request.prompt = "Example"
+        model.request.promptSort = "Example"
+        model.response.coverUrl = "http://example.com/cover"
+        model.response.title = "Glass"
+        model.response.musicUrl = "http://example.com/music"
+        return model
+    }
+}
+
+// 我的下载铃声历史记录
+class TSMineRintoneHistory: HistoryManager<TSRingModel> {
+    static let shared = TSMineRintoneHistory(userDefaultsKey: "kMineRintoneHistoryListString")
+    
+    var isHaveNew: Bool = false
+}

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

@@ -67,7 +67,7 @@ class TSGenneralPicVM {
 
 
 
 
 //        kDelayOnMainThread(2.0) {
 //        kDelayOnMainThread(2.0) {
-//            if Bool.random() {
+//            if kRandomBool() {
 //                let infoModel = TSActionInfoModel(JSON: self.gennerateType == .poster ? actionInfoDictPoster : actionInfoDictPhoto)
 //                let infoModel = TSActionInfoModel(JSON: self.gennerateType == .poster ? actionInfoDictPoster : actionInfoDictPhoto)
 //                self.stateDatauPblished = (.success(nil),infoModel)
 //                self.stateDatauPblished = (.success(nil),infoModel)
 //            }else{
 //            }else{

+ 27 - 37
AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/TSAIRintoneVC.swift

@@ -120,7 +120,7 @@ class TSAIRintoneVC: TSBaseVC {
             if let userInfo = notification.userInfo as? [String: Any], let uuid = userInfo["uuid"] as? String,let state = userInfo["state"] as? TSProgressState {
             if let userInfo = notification.userInfo as? [String: Any], let uuid = userInfo["uuid"] as? String,let state = userInfo["state"] as? TSProgressState {
                 dePrint("TSBaseOperation stateDatauPblished 收到 = \(state)")
                 dePrint("TSBaseOperation stateDatauPblished 收到 = \(state)")
                 switch state {
                 switch state {
-                case .start:
+                case .start, .success(_),.failed(_),.none:
                     self.viewModel.updateRecentData()
                     self.viewModel.updateRecentData()
                     self.updateGeneratedHistory()
                     self.updateGeneratedHistory()
 //                case .start, .success(_),.failed(_):
 //                case .start, .success(_),.failed(_):
@@ -137,6 +137,7 @@ class TSAIRintoneVC: TSBaseVC {
     func updateListView(){
     func updateListView(){
         collectionView.reloadData()
         collectionView.reloadData()
     }
     }
+    
     func updateGeneratedHistory(){
     func updateGeneratedHistory(){
         if collectionView.numberOfSections != viewModel.modelList.count {
         if collectionView.numberOfSections != viewModel.modelList.count {
             collectionView.reloadData()
             collectionView.reloadData()
@@ -147,30 +148,6 @@ class TSAIRintoneVC: TSBaseVC {
         }
         }
         
         
     }
     }
-    func updateGeneratedList(num:Int){
-//        ​**reloadData()**:简单易用,适合数据量小且不需要动画的场景。
-//        ​**performBatchUpdates**:更高效且支持动画,适合数据量大或需要动画的场景。
-//        ​**UICollectionViewDiffableDataSource**:iOS 13 及以上版本的最佳选择,自动处理数据变化并支持动画。
-//        let maxNum = num > 2 ? 2 : num
-        
-        if collectionView.numberOfSections != viewModel.modelList.count {
-            collectionView.reloadData()
-        }
-        if let historyModel = viewModel.modelList.first,historyModel.type == .history{
-            UIView.performWithoutAnimation {
-                collectionView.reloadSections(IndexSet(integer: 0))
-            }
-        }
-//        var array:[IndexPath] = []
-//        for i in 0..<1 {
-//            array.append(IndexPath(item: i, section: 0))
-//        }
-//        
-//        UIView.performWithoutAnimation {
-//            collectionView.reloadItems(at: array)
-//        }
-    }
-    
 }
 }
 
 
 extension TSAIRintoneVC: UICollectionViewDataSource ,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout {
 extension TSAIRintoneVC: UICollectionViewDataSource ,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout {
@@ -195,15 +172,13 @@ extension TSAIRintoneVC: UICollectionViewDataSource ,UICollectionViewDelegate,UI
            let cell = cell as? TSAIRintoneHistoryCell
            let cell = cell as? TSAIRintoneHistoryCell
         {
         {
             cell.delegate = self
             cell.delegate = self
-            
+            cell.setRingBtn.indexPath = indexPath
+            cell.setRingBtn.addTarget(self, action: #selector(clickSetRingBtn(_ :)), for: .touchUpInside)
             if let model = itemModel as? TSActionInfoModel {
             if let model = itemModel as? TSActionInfoModel {
                 cell.model = model
                 cell.model = model
             }else if let ringModel = itemModel as? TSRingModel {
             }else if let ringModel = itemModel as? TSRingModel {
                 cell.ringModel = ringModel
                 cell.ringModel = ringModel
             }
             }
-            
-            cell.setRingBtn.indexPath = indexPath
-            cell.setRingBtn.addTarget(self, action: #selector(clickSetRingBtn(_ :)), for: .touchUpInside)
         }
         }
         
         
         return cell
         return cell
@@ -303,6 +278,17 @@ extension TSAIRintoneVC: SwipeCollectionViewCellDelegate {
             return nil
             return nil
         }
         }
         
         
+        if let sectionModel = self.viewModel.modelList.safeObj(At: indexPath.section),
+        let model = sectionModel.list.safeObj(At: indexPath.item){
+            if let model = model as? TSActionInfoModel {
+                switch model.actionStatus {
+                case .pending,.running:
+                    return nil
+                default:break
+                }
+            }
+        }
+        
         // 删除操作
         // 删除操作
         let deleteAction = SwipeAction(style: .destructive, title: nil) {[weak self] action, indexPath in
         let deleteAction = SwipeAction(style: .destructive, title: nil) {[weak self] action, indexPath in
             guard let self = self else { return }
             guard let self = self else { return }
@@ -310,14 +296,18 @@ extension TSAIRintoneVC: SwipeCollectionViewCellDelegate {
                 if let sectionModel = self.viewModel.modelList.safeObj(At: indexPath.section),
                 if let sectionModel = self.viewModel.modelList.safeObj(At: indexPath.section),
                 let model = sectionModel.list.safeObj(At: indexPath.item){
                 let model = sectionModel.list.safeObj(At: indexPath.item){
                     if let model = model as? TSActionInfoModel {
                     if let model = model as? TSActionInfoModel {
-                        collectionView.performBatchUpdates({
-                            self.viewModel.removeModel(model: model)
-                            if sectionModel.list.count == 0 {
-                                collectionView.deleteSections([indexPath.section])
-                            }else{
-                                collectionView.deleteItems(at: [indexPath])
-                            }
-                        })
+//                        collectionView.performBatchUpdates({
+//                            self.viewModel.removeModel(model: model)
+//                            if sectionModel.list.count == 0 {
+//                                collectionView.deleteSections([indexPath.section])
+//                            }else{
+//                                collectionView.deleteItems(at: [indexPath])
+//                            }
+//                        })
+                        
+                        self.viewModel.removeModel(model: model)
+                        collectionView.reloadData()
+                        
                         TSBusinessAudioPlayer.shared.stop()
                         TSBusinessAudioPlayer.shared.stop()
                     }
                     }
                 }
                 }

+ 9 - 45
AIRingtone/Business/TSAIRintoneVC/TSAIRintoneVC/View/TSAIRintoneHistoryCell.swift

@@ -101,27 +101,17 @@ class TSAIRintoneHistoryCell: SwipeCollectionViewCell  {
     var model:TSActionInfoModel?{
     var model:TSActionInfoModel?{
         didSet{
         didSet{
             guard let model = model else { return }
             guard let model = model else { return }
-//            cancellable.removeAll()
             if let rintoneOperation = TSGenerateRintoneOperationQueue.shared.findOperation(uuid: model.uuid) as? TSGenerateRintoneOperation {
             if let rintoneOperation = TSGenerateRintoneOperationQueue.shared.findOperation(uuid: model.uuid) as? TSGenerateRintoneOperation {
-                DispatchQueue.main.async {
-                    rintoneOperation.currentActionInfoModelChanged =
-                    //                rintoneOperation.$currentActionInfoModel.sink
-                    { [weak self] actionInfoModel in
+                    rintoneOperation.currentActionInfoModelChanged = { [weak self] actionInfoModel in
                         guard let self = self else { return }
                         guard let self = self else { return }
                         DispatchQueue.main.async {
                         DispatchQueue.main.async {
                             self.updataActionInfoModelView(model: actionInfoModel)
                             self.updataActionInfoModelView(model: actionInfoModel)
                         }
                         }
                     }
                     }
-                    //                .store(in: &cancellable)
-                }
             }
             }
-            
+
             updataActionInfoModelView(model: model)
             updataActionInfoModelView(model: model)
-            
             dePrint("model actionStatus 收到=\(model.actionStatus)")
             dePrint("model actionStatus 收到=\(model.actionStatus)")
-            
-           
-
         }
         }
     }
     }
     
     
@@ -136,7 +126,6 @@ class TSAIRintoneHistoryCell: SwipeCollectionViewCell  {
             generateView.isHidden = false
             generateView.isHidden = false
             generateView.setProgress(progress: model.percent)
             generateView.setProgress(progress: model.percent)
         case .success:
         case .success:
-//            cancellable.removeAll()
             generateView.isHidden = true
             generateView.isHidden = true
             
             
             ringView.timeLab.text = Float(model.request.duration).floatToMinuteSecond()
             ringView.timeLab.text = Float(model.request.duration).floatToMinuteSecond()
@@ -148,7 +137,6 @@ class TSAIRintoneHistoryCell: SwipeCollectionViewCell  {
             self.changePlayerState(state: TSBusinessAudioPlayer.shared.currentPlayerState)
             self.changePlayerState(state: TSBusinessAudioPlayer.shared.currentPlayerState)
             
             
         case .failed:
         case .failed:
-//            cancellable.removeAll()
             generateView.isHidden = false
             generateView.isHidden = false
             generateView.setFail()
             generateView.setFail()
         }
         }
@@ -157,9 +145,7 @@ class TSAIRintoneHistoryCell: SwipeCollectionViewCell  {
     var ringModel:TSRingModel?{
     var ringModel:TSRingModel?{
         didSet{
         didSet{
             guard let ringModel = ringModel else { return }
             guard let ringModel = ringModel else { return }
-            
-//            cancellable.removeAll()
-            
+
             ringView.timeLab.text = Float(ringModel.duration).floatToMinuteSecond()
             ringView.timeLab.text = Float(ringModel.duration).floatToMinuteSecond()
             ringView.nameLab.text = ringModel.title
             ringView.nameLab.text = ringModel.title
             ringView.setCoverImageView(urlString: "")
             ringView.setCoverImageView(urlString: "")
@@ -229,28 +215,17 @@ class TSAIRintoneHistoryCell: SwipeCollectionViewCell  {
                 }
                 }
             }
             }
         }
         }
-        
-//        NotificationCenter.default.addObserver(forName: .kGenerateRintoneOperationChanged, object: nil, queue: nil) { notification in
-//            if let model = self.model,
-//               let userInfo = notification.userInfo as? [String: Any],
-//               let uuid = userInfo["uuid"] as? String,
-//               model.uuid == uuid,
-//               let state = userInfo["state"] as? TSProgressState,
-//               let actionInfo = userInfo["actionInfo"] as? TSActionInfoModel
-//            {
-//                self.updataActionInfoModelView(model: actionInfo)
-//            }
-//        }
     }
     }
     
     
     override func prepareForReuse() {
     override func prepareForReuse() {
         super.prepareForReuse()
         super.prepareForReuse()
 //        cancellable.removeAll()
 //        cancellable.removeAll()
     }
     }
+    
     func changePlayerState(state:TSBusinessAudioPlayer.PlayerState){
     func changePlayerState(state:TSBusinessAudioPlayer.PlayerState){
-            if playSelf == false {
-            self.ringView.isPlay = false
-            backgroundColor = .cardColor
+        dePrint("changePlayerState = \(state)")
+        if playSelf == false {
+            ringView.handelAudioPlayerStateChange(state: .stop)
             return
             return
         }
         }
         ringView.handelAudioPlayerStateChange(state: state)
         ringView.handelAudioPlayerStateChange(state: state)
@@ -259,20 +234,9 @@ class TSAIRintoneHistoryCell: SwipeCollectionViewCell  {
     deinit {
     deinit {
         NotificationCenter.default.removeObserver(self)
         NotificationCenter.default.removeObserver(self)
     }
     }
-
+    
     var indexPath:IndexPath? {
     var indexPath:IndexPath? {
-        guard let collectionView = self.superview as? UICollectionView else {
-//            print("Cell 的 indexPath 无法获取 UICollectionView")
-            return nil
-        }
-        
-        if let indexPath = collectionView.indexPath(for: self) {
-//            print("Cell 的 indexPath: \(indexPath)")
-            return indexPath
-        } else {
-//            print("Cell 的 indexPath 无法获取")
-            return nil
-        }
+        return setRingBtn.indexPath
     }
     }
 }
 }
 
 

+ 1 - 1
AIRingtone/Business/TSAIRintoneVC/TSGeneralRintoneVC/TSGeneralRintoneVM.swift

@@ -49,7 +49,7 @@ class TSGeneralRintoneVM {
         }
         }
 
 
 //        kDelayOnMainThread(2.0) {
 //        kDelayOnMainThread(2.0) {
-//            if Bool.random() {
+//            if kRandomBool() {
 //                let infoModel = TSActionInfoModel(JSON: actionInfoDict)
 //                let infoModel = TSActionInfoModel(JSON: actionInfoDict)
 //                self.stateDatauPblished = (.success(nil),infoModel)
 //                self.stateDatauPblished = (.success(nil),infoModel)
 //            }else{
 //            }else{

+ 25 - 13
AIRingtone/Business/TSAIRintoneVC/TSGenerateHistoryVC/TSGenerateHistoryVC.swift

@@ -77,7 +77,7 @@ class TSGenerateHistoryVC: TSBaseVC {
         NotificationCenter.default.addObserver(forName: .kGenerateRintoneOperationChanged, object: nil, queue: nil) { notification in
         NotificationCenter.default.addObserver(forName: .kGenerateRintoneOperationChanged, object: nil, queue: nil) { notification in
             if let userInfo = notification.userInfo as? [String: Any],let state = userInfo["state"] as? TSProgressState {
             if let userInfo = notification.userInfo as? [String: Any],let state = userInfo["state"] as? TSProgressState {
                 switch state {
                 switch state {
-                case .start, .success(_),.failed(_):
+                case .start, .success(_),.failed(_),.none:
                     self.viewModel.updateRecentData()
                     self.viewModel.updateRecentData()
                     self.updateListView()
                     self.updateListView()
                 default:break
                 default:break
@@ -118,15 +118,13 @@ extension TSGenerateHistoryVC: UICollectionViewDataSource ,UICollectionViewDeleg
            let cell = cell as? TSAIRintoneHistoryCell
            let cell = cell as? TSAIRintoneHistoryCell
         {
         {
             cell.delegate = self
             cell.delegate = self
-            
+            cell.setRingBtn.indexPath = indexPath
+            cell.setRingBtn.addTarget(self, action: #selector(clickSetRingBtn(_ :)), for: .touchUpInside)
             if let model = itemModel as? TSActionInfoModel {
             if let model = itemModel as? TSActionInfoModel {
                 cell.model = model
                 cell.model = model
             }else if let ringModel = itemModel as? TSRingModel {
             }else if let ringModel = itemModel as? TSRingModel {
                 cell.ringModel = ringModel
                 cell.ringModel = ringModel
             }
             }
-            
-            cell.setRingBtn.indexPath = indexPath
-            cell.setRingBtn.addTarget(self, action: #selector(clickSetRingBtn(_ :)), for: .touchUpInside)
         }
         }
         
         
         return cell
         return cell
@@ -165,6 +163,17 @@ extension TSGenerateHistoryVC: SwipeCollectionViewCellDelegate {
             return nil
             return nil
         }
         }
         
         
+        if let sectionModel = self.viewModel.modelList.safeObj(At: indexPath.section),
+        let model = sectionModel.list.safeObj(At: indexPath.item){
+            if let model = model as? TSActionInfoModel {
+                switch model.actionStatus {
+                case .pending,.running:
+                    return nil
+                default:break
+                }
+            }
+        }
+        
         // 删除操作
         // 删除操作
         let deleteAction = SwipeAction(style: .destructive, title: nil) {[weak self] action, indexPath in
         let deleteAction = SwipeAction(style: .destructive, title: nil) {[weak self] action, indexPath in
             guard let self = self else { return }
             guard let self = self else { return }
@@ -172,14 +181,17 @@ extension TSGenerateHistoryVC: SwipeCollectionViewCellDelegate {
                 if let sectionModel = self.viewModel.modelList.safeObj(At: indexPath.section),
                 if let sectionModel = self.viewModel.modelList.safeObj(At: indexPath.section),
                 let model = sectionModel.list.safeObj(At: indexPath.item){
                 let model = sectionModel.list.safeObj(At: indexPath.item){
                     if let model = model as? TSActionInfoModel {
                     if let model = model as? TSActionInfoModel {
-                        collectionView.performBatchUpdates({
-                            self.viewModel.removeModel(model: model)
-                            if sectionModel.list.count == 0 {
-                                collectionView.deleteSections([indexPath.section])
-                            }else{
-                                collectionView.deleteItems(at: [indexPath])
-                            }
-                        })
+//                        collectionView.performBatchUpdates({
+//                            self.viewModel.removeModel(model: model)
+//                            if sectionModel.list.count == 0 {
+//                                collectionView.deleteSections([indexPath.section])
+//                            }else{
+//                                collectionView.deleteItems(at: [indexPath])
+//                            }
+//                        })
+                        self.viewModel.removeModel(model: model)
+                        collectionView.reloadData()
+                        
                         TSBusinessAudioPlayer.shared.stop()
                         TSBusinessAudioPlayer.shared.stop()
                     }
                     }
                 }
                 }

+ 1 - 1
AIRingtone/Business/TSCollectionViewVM/TSCollectionViewVM.swift

@@ -17,7 +17,7 @@ enum TSColVVMStyple : Int {
     case photoHistory    //生成头像的历史记录
     case photoHistory    //生成头像的历史记录
     
     
     case ringCategories    //铃声分类
     case ringCategories    //铃声分类
-    case ringList       //铃声列表
+//    case ringList       //铃声列表
     
     
     var config:TSColVVMSizeConfig {
     var config:TSColVVMSizeConfig {
         switch self {
         switch self {

+ 2 - 3
AIRingtone/Business/TSDiscoverVC/TSDiscoverListVC/TSDiscoverListVC.swift

@@ -136,14 +136,13 @@ extension TSDiscoverListVC: UICollectionViewDataSource ,UICollectionViewDelegate
             let itemModel = sectionModel.list.safeObj(At: indexPath.item),
             let itemModel = sectionModel.list.safeObj(At: indexPath.item),
            let cell = cell as? TSAIRintoneHistoryCell
            let cell = cell as? TSAIRintoneHistoryCell
         {
         {
+            cell.setRingBtn.indexPath = indexPath
+            cell.setRingBtn.addTarget(self, action: #selector(clickSetRingBtn(_ :)), for: .touchUpInside)
             if let model = itemModel as? TSActionInfoModel {
             if let model = itemModel as? TSActionInfoModel {
                 cell.model = model
                 cell.model = model
             }else if let ringModel = itemModel as? TSRingModel {
             }else if let ringModel = itemModel as? TSRingModel {
                 cell.ringModel = ringModel
                 cell.ringModel = ringModel
             }
             }
-            
-            cell.setRingBtn.indexPath = indexPath
-            cell.setRingBtn.addTarget(self, action: #selector(clickSetRingBtn(_ :)), for: .touchUpInside)
         }
         }
         
         
         return cell
         return cell

+ 3 - 4
AIRingtone/Business/TSDiscoverVC/TSRingDownVC/TSRingDownVC.swift

@@ -124,15 +124,14 @@ extension TSRingDownVC: UICollectionViewDataSource ,UICollectionViewDelegate,UIC
            let cell = cell as? TSAIRintoneHistoryCell
            let cell = cell as? TSAIRintoneHistoryCell
         {
         {
             cell.delegate = self
             cell.delegate = self
-            
+            cell.setRingBtn.indexPath = indexPath
+            cell.setRingBtn.addTarget(self, action: #selector(clickSetRingBtn(_ :)), for: .touchUpInside)
             if let model = itemModel as? TSActionInfoModel {
             if let model = itemModel as? TSActionInfoModel {
                 cell.model = model
                 cell.model = model
             }else if let ringModel = itemModel as? TSRingModel {
             }else if let ringModel = itemModel as? TSRingModel {
                 cell.ringModel = ringModel
                 cell.ringModel = ringModel
             }
             }
-            
-            cell.setRingBtn.indexPath = indexPath
-            cell.setRingBtn.addTarget(self, action: #selector(clickSetRingBtn(_ :)), for: .touchUpInside)
+
         }
         }
         
         
         return cell
         return cell

+ 1 - 1
AIRingtone/Business/TSPurchaseMembershipVC/TSPurchaseVC.swift

@@ -217,7 +217,7 @@ struct PurchaseView :View {
             VStack {
             VStack {
                 Image("vip_big_icon").resizable().frame(width: 163, height: 163)
                 Image("vip_big_icon").resizable().frame(width: 163, height: 163)
       
       
-                Text(" AI Ringtone Pro")
+                Text(" Ringtones Pro")
                     .font(.font(name: .PoppinsBlackItalic,size: 30))
                     .font(.font(name: .PoppinsBlackItalic,size: 30))
                     .gradientForeground(
                     .gradientForeground(
                         colors: [Color.white, "#F7B7FF".uiColor.color],
                         colors: [Color.white, "#F7B7FF".uiColor.color],

+ 9 - 1
AIRingtone/Business/TSSetingVC/SetingVC/TSSetingVC.swift

@@ -61,7 +61,7 @@ class TSSetingVC: TSBaseVC {
     }
     }
     
     
     override func dealThings() {
     override func dealThings() {
-        
+        refreshView()
         publisher.enterPurchasePublisher.receive(on: DispatchQueue.main).sink { [weak self] _ in
         publisher.enterPurchasePublisher.receive(on: DispatchQueue.main).sink { [weak self] _ in
             guard let self = self else { return }
             guard let self = self else { return }
             viewModel.pushVipPurchase(parent: self)
             viewModel.pushVipPurchase(parent: self)
@@ -94,6 +94,7 @@ class TSSetingVC: TSBaseVC {
         }.store(in: &cancellable)
         }.store(in: &cancellable)
         
         
         NotificationCenter.default.addObserver(self, selector: #selector(vipInfoChanged), name: .kPurchaseDidChanged, object: nil)
         NotificationCenter.default.addObserver(self, selector: #selector(vipInfoChanged), name: .kPurchaseDidChanged, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(refreshView), name: .kRefreshSettingView, object: nil)
     }
     }
     
     
     @objc func vipInfoChanged() {
     @objc func vipInfoChanged() {
@@ -101,4 +102,11 @@ class TSSetingVC: TSBaseVC {
             self.viewModel.isViper = kPurchaseToolShared.isVip
             self.viewModel.isViper = kPurchaseToolShared.isVip
         }
         }
     }
     }
+    
+    @objc func refreshView() {
+        if let newVerison = Float(kAppNewVerison),
+           let oldVerison = Float(appShortVersion()){
+            self.viewModel.isHaveNewVersion = newVerison > oldVerison
+        }
+    }
 }
 }

+ 1 - 0
AIRingtone/Business/TSSetingVC/SetingVC/TSSetingViewModel.swift

@@ -11,6 +11,7 @@ class TSSetingViewModel: ObservableObject {
     
     
     @Published var settingTypes: [SettingType] = SettingType.allCases
     @Published var settingTypes: [SettingType] = SettingType.allCases
     @Published var isViper: Bool = kPurchaseToolShared.isVip
     @Published var isViper: Bool = kPurchaseToolShared.isVip
+    @Published var isHaveNewVersion: Bool = false
     
     
     var appid = "6741563341"
     var appid = "6741563341"
     // todo.kailen-privacy
     // todo.kailen-privacy

+ 2 - 2
AIRingtone/Business/TSSetingVC/SetingVC/View/SettingPurchaseTopView.swift

@@ -16,7 +16,7 @@ struct SettingPurchaseTopView: View {
                     Spacer().frame(width:20)
                     Spacer().frame(width:20)
                     VStack(alignment: .leading,spacing: 16) {
                     VStack(alignment: .leading,spacing: 16) {
                         HStack {
                         HStack {
-                            customText(text: " AI Ringtone Pro")
+                            customText(text: " Ringtones Pro")
                             Spacer()
                             Spacer()
                         }
                         }
                         
                         
@@ -71,7 +71,7 @@ struct SettingPurchaseTopView: View {
     // 定义一个返回 View 的方法
     // 定义一个返回 View 的方法
     func customText(text:String) -> some View {
     func customText(text:String) -> some View {
         let gorgeousColor = "#F7B7FF".uiColor.color
         let gorgeousColor = "#F7B7FF".uiColor.color
-        return Text(" AI Ringtone Pro")
+        return Text(" Ringtones Pro")
             .font(.font(name: .PoppinsBlackItalic,size: 20))
             .font(.font(name: .PoppinsBlackItalic,size: 20))
             .gradientForeground(
             .gradientForeground(
                 colors: [Color.white, gorgeousColor],
                 colors: [Color.white, gorgeousColor],

+ 3 - 3
AIRingtone/Business/TSSetingVC/SetingVC/View/TSSettingListView.swift

@@ -27,7 +27,7 @@ struct TSSettingListView: View {
                 
                 
                 ForEach(viewModel.settingTypes, id:\.self) { type in
                 ForEach(viewModel.settingTypes, id:\.self) { type in
                     Spacer().frame(height: 16)
                     Spacer().frame(height: 16)
-                    SettingListItemView(type: type)
+                    SettingListItemView(type: type,viewModel: viewModel)
                     .onTapGesture {
                     .onTapGesture {
                         publisher.settingPublisher.send(type)
                         publisher.settingPublisher.send(type)
                     }
                     }
@@ -45,8 +45,8 @@ struct TSSettingListView: View {
 
 
 struct SettingListItemView: View {
 struct SettingListItemView: View {
     var type : SettingType
     var type : SettingType
+    var viewModel: TSSetingViewModel
     var body: some View {
     var body: some View {
-        
         ZStack {
         ZStack {
             Color.white.opacity(0.1)
             Color.white.opacity(0.1)
             HStack {
             HStack {
@@ -58,7 +58,7 @@ struct SettingListItemView: View {
 //                    Text(appVersion()).foregroundColor(.hex("#FFFFFF").opacity(0.4)).font(.font(size: 16))
 //                    Text(appVersion()).foregroundColor(.hex("#FFFFFF").opacity(0.4)).font(.font(size: 16))
 //                }
 //                }
                 if type == .update {
                 if type == .update {
-                    if kAppNewVerison != appVersion() {
+                    if viewModel.isHaveNewVersion {
                         Color.hex("#E661F6").frame(width: 4, height: 4).cornerRadius(2)
                         Color.hex("#E661F6").frame(width: 4, height: 4).cornerRadius(2)
                         Spacer().frame(width: 4)
                         Spacer().frame(width: 4)
                     }
                     }

+ 3 - 2
AIRingtone/Business/VIewTool/TSRingToneCellView.swift

@@ -135,13 +135,14 @@ extension TSRingToneCellView {
             }
             }
         case .play:
         case .play:
             self.isPlay = true
             self.isPlay = true
-//            backgroundColor = "#3C213F".uiColor
         case .stop:
         case .stop:
             self.isloading = false
             self.isloading = false
             self.isPlay = false
             self.isPlay = false
+            self.progressView.isHidden = true
             self.progressView.progress = 0.0
             self.progressView.progress = 0.0
-//            backgroundColor = .cardColor
         case .currentTime(_):
         case .currentTime(_):
+            self.isPlay = true
+            self.progressView.isHidden = false
             self.progressView.progress =  CGFloat(TSBusinessAudioPlayer.shared.playProgress)
             self.progressView.progress =  CGFloat(TSBusinessAudioPlayer.shared.playProgress)
         default:
         default:
             break
             break

+ 5 - 3
AIRingtone/Common/Config/GlobalImports.swift

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

+ 2 - 0
AIRingtone/Common/Ex/Notification+TSEx.swift

@@ -17,6 +17,8 @@ extension Notification.Name {
     static let kGeneratePosterOperationChanged = Notification.Name("kGeneratePosterOperationChanged") //生成海报任务发生变化
     static let kGeneratePosterOperationChanged = Notification.Name("kGeneratePosterOperationChanged") //生成海报任务发生变化
     static let kGeneratePhotoOperationChanged = Notification.Name("kGeneratePhotoOperationChanged") //生成图片任务发生变化
     static let kGeneratePhotoOperationChanged = Notification.Name("kGeneratePhotoOperationChanged") //生成图片任务发生变化
     
     
+    static let kRefreshSettingView = Notification.Name("kRefreshSettingView")   //刷新设置按钮
+    
 }
 }
 
 
 
 

+ 14 - 11
AIRingtone/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGenerateBaseOperation.swift

@@ -48,17 +48,7 @@ class TSGenerateBaseOperationQueue: TSBaseOperationQueue {
 class TSGenerateBaseOperation: TSBaseOperation , @unchecked Sendable{
 class TSGenerateBaseOperation: TSBaseOperation , @unchecked Sendable{
     
     
     var actionInfoDict:[String:Any]{
     var actionInfoDict:[String:Any]{
-        return [
-            "actionType":"music_create",
-            "comments": "Success",
-            "costTime":15,
-            "createdTimestamp":1741338454,
-            "id":1536,
-            "percent":1,
-            "request":"{\"prompt\": \"Create a Techno ringtone with a repetitive bassline, crisp hi-hats, and subtle synth textures. Use a BPM of 125-130 for a sleek, modern sound., 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\", \"duration\": 5}",
-            "response":"{\"coverUrl\": \"https://be-aigc.s3-accelerate.amazonaws.com/f0fb7739-a5cc-4805-9b68-b4a5890eb285.png\", \"title\": \"Neon Pulse\\\"  \\n\\\"Horizon Glow\", \"musicUrl\": \"https://be-aigc.s3-accelerate.amazonaws.com/c47d40dd-d07c-4edc-a6d9-8382438149d1.wav\"}",
-            "status":"success"
-        ]
+        return [:]
     }
     }
     
     
     @Published var stateDatauPblished:(TSProgressState,TSActionInfoModel?) = (TSProgressState.none,nil){
     @Published var stateDatauPblished:(TSProgressState,TSActionInfoModel?) = (TSProgressState.none,nil){
@@ -140,3 +130,16 @@ class TSGenerateBaseOperation: TSBaseOperation , @unchecked Sendable{
      }
      }
      
      
 }
 }
+ var kRandomBoolLastResult:Bool = true
+func kRandomBool() -> Bool {
+    if !kRandomBoolLastResult {
+        // 如果上一次是 false,这次必须返回 true
+        kRandomBoolLastResult = true
+        return true
+    } else {
+        // 如果上一次是 true,随机返回 true 或 false
+        let randomResult = Bool.random()
+        kRandomBoolLastResult = randomResult
+        return randomResult
+    }
+}

+ 2 - 3
AIRingtone/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGeneratePhotoOperation.swift

@@ -53,7 +53,6 @@ class TSGeneratePhotoOperation: TSGenerateBaseOperation , @unchecked Sendable{
     
     
     //模拟数据
     //模拟数据
     func creatPhoto(oldModel:TSActionInfoModel? = nil,prompt:String,promptSort:String) {
     func creatPhoto(oldModel:TSActionInfoModel? = nil,prompt:String,promptSort:String) {
-        stateDatauPblished = (.start,nil)
         if let model = oldModel {
         if let model = oldModel {
             currentActionInfoModel = model
             currentActionInfoModel = model
         }else {
         }else {
@@ -70,7 +69,7 @@ class TSGeneratePhotoOperation: TSGenerateBaseOperation , @unchecked Sendable{
         
         
         for i in 0..<Int(time){
         for i in 0..<Int(time){
             kDelayOnMainThread(Double(i)) {
             kDelayOnMainThread(Double(i)) {
-                let progress = Float(i)/100.0
+                let progress = Float(i)*10/100.0
                 self.currentActionInfoModel.percent = progress
                 self.currentActionInfoModel.percent = progress
                 self.currentActionInfoModel.actionStatus = .running
                 self.currentActionInfoModel.actionStatus = .running
                 self.currentActionInfoModel.status = "running"
                 self.currentActionInfoModel.status = "running"
@@ -80,7 +79,7 @@ class TSGeneratePhotoOperation: TSGenerateBaseOperation , @unchecked Sendable{
         }
         }
 
 
         kDelayOnMainThread(time+1.0) {
         kDelayOnMainThread(time+1.0) {
-            if Bool.random(), let infoModel = TSActionInfoModel(JSON: self.actionInfoDict){
+            if kRandomBool(), let infoModel = TSActionInfoModel(JSON: self.actionInfoDict){
                 infoModel.id = Int.uuid
                 infoModel.id = Int.uuid
                 self.replaceSaveInfoModel(model: infoModel)
                 self.replaceSaveInfoModel(model: infoModel)
                 self.stateDatauPblished = (.success(nil),self.currentActionInfoModel)
                 self.stateDatauPblished = (.success(nil),self.currentActionInfoModel)

+ 3 - 4
AIRingtone/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGeneratePosterOperation.swift

@@ -54,7 +54,6 @@ class TSGeneratePosterOperation: TSGenerateBaseOperation , @unchecked Sendable{
 
 
     //模拟数据
     //模拟数据
     func creatPoster(oldModel:TSActionInfoModel? = nil,prompt:String,promptSort:String) {
     func creatPoster(oldModel:TSActionInfoModel? = nil,prompt:String,promptSort:String) {
-        stateDatauPblished = (.start,nil)
         if let model = oldModel {
         if let model = oldModel {
             currentActionInfoModel = model
             currentActionInfoModel = model
         }else {
         }else {
@@ -67,11 +66,11 @@ class TSGeneratePosterOperation: TSGenerateBaseOperation , @unchecked Sendable{
         
         
         replaceSaveInfoModel(model: currentActionInfoModel)
         replaceSaveInfoModel(model: currentActionInfoModel)
         stateDatauPblished = (.start,currentActionInfoModel)
         stateDatauPblished = (.start,currentActionInfoModel)
-        let time = 100.0
+        let time = 5.0
         
         
         for i in 0..<Int(time){
         for i in 0..<Int(time){
             kDelayOnMainThread(Double(i)) {
             kDelayOnMainThread(Double(i)) {
-                let progress = Float(i)/100.0
+                let progress = Float(i)*10/100.0
                 self.currentActionInfoModel.percent = progress
                 self.currentActionInfoModel.percent = progress
                 self.currentActionInfoModel.actionStatus = .running
                 self.currentActionInfoModel.actionStatus = .running
                 self.currentActionInfoModel.status = "running"
                 self.currentActionInfoModel.status = "running"
@@ -81,7 +80,7 @@ class TSGeneratePosterOperation: TSGenerateBaseOperation , @unchecked Sendable{
         }
         }
 
 
         kDelayOnMainThread(time+1.0) {
         kDelayOnMainThread(time+1.0) {
-            if Bool.random(), let infoModel = TSActionInfoModel(JSON: self.actionInfoDict){
+            if kRandomBool(), let infoModel = TSActionInfoModel(JSON: self.actionInfoDict){
                 infoModel.id = Int.uuid
                 infoModel.id = Int.uuid
                 self.replaceSaveInfoModel(model: infoModel)
                 self.replaceSaveInfoModel(model: infoModel)
                 self.stateDatauPblished = (.success(nil),self.currentActionInfoModel)
                 self.stateDatauPblished = (.success(nil),self.currentActionInfoModel)

+ 18 - 4
AIRingtone/Common/Tool/OperationQueue/TSGenerateBaseOperation/TSGenerateRintoneOperation.swift

@@ -30,6 +30,20 @@ class TSGenerateRintoneOperationQueue: TSGenerateBaseOperationQueue {
 
 
 class TSGenerateRintoneOperation: TSGenerateBaseOperation , @unchecked Sendable{
 class TSGenerateRintoneOperation: TSGenerateBaseOperation , @unchecked Sendable{
     
     
+    override var actionInfoDict:[String:Any]{
+        return [
+            "actionType":"music_create",
+            "comments": "Success",
+            "costTime":15,
+            "createdTimestamp":1741338454,
+            "id":1536,
+            "percent":1,
+            "request":"{\"prompt\": \"Create a Techno ringtone with a repetitive bassline, crisp hi-hats, and subtle synth textures. Use a BPM of 125-130 for a sleek, modern sound., 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\", \"duration\": 5}",
+            "response":"{\"coverUrl\": \"https://be-aigc.s3-accelerate.amazonaws.com/f0fb7739-a5cc-4805-9b68-b4a5890eb285.png\", \"title\": \"Neon Pulse\\\"  \\n\\\"Horizon Glow\", \"musicUrl\": \"https://be-aigc.s3-accelerate.amazonaws.com/c47d40dd-d07c-4edc-a6d9-8382438149d1.wav\"}",
+            "status":"success"
+        ]
+    }
+    
     func replaceSaveInfoModel(model:TSActionInfoModel){
     func replaceSaveInfoModel(model:TSActionInfoModel){
         model.uuid = uuid
         model.uuid = uuid
         TSAIRintoneHistory.replaceModel(oldID: currentActionInfoModel.id, newModel: model)
         TSAIRintoneHistory.replaceModel(oldID: currentActionInfoModel.id, newModel: model)
@@ -41,7 +55,7 @@ class TSGenerateRintoneOperation: TSGenerateBaseOperation , @unchecked Sendable{
 
 
     //模拟数据
     //模拟数据
     func creatRintone(oldModel:TSActionInfoModel? = nil,prompt:String,promptSort:String) {
     func creatRintone(oldModel:TSActionInfoModel? = nil,prompt:String,promptSort:String) {
-        stateDatauPblished = (.start,nil)
+//        stateDatauPblished = (.start,nil)
         if let model = oldModel {
         if let model = oldModel {
             currentActionInfoModel = model
             currentActionInfoModel = model
         }else {
         }else {
@@ -54,11 +68,11 @@ class TSGenerateRintoneOperation: TSGenerateBaseOperation , @unchecked Sendable{
         
         
         replaceSaveInfoModel(model: currentActionInfoModel)
         replaceSaveInfoModel(model: currentActionInfoModel)
         stateDatauPblished = (.start,currentActionInfoModel)
         stateDatauPblished = (.start,currentActionInfoModel)
-        let time = 2.0
+        let time = 8.0
         
         
         for i in 0..<Int(time){
         for i in 0..<Int(time){
             kDelayOnMainThread(Double(i)) {
             kDelayOnMainThread(Double(i)) {
-                let progress = Float(i)/100.0
+                let progress = Float(i)*10.0/100.0
                 self.currentActionInfoModel.percent = progress
                 self.currentActionInfoModel.percent = progress
                 self.currentActionInfoModel.actionStatus = .running
                 self.currentActionInfoModel.actionStatus = .running
                 self.currentActionInfoModel.status = "running"
                 self.currentActionInfoModel.status = "running"
@@ -68,7 +82,7 @@ class TSGenerateRintoneOperation: TSGenerateBaseOperation , @unchecked Sendable{
         }
         }
 
 
         kDelayOnMainThread(time+1.0) {
         kDelayOnMainThread(time+1.0) {
-            if Bool.random(), let infoModel = TSActionInfoModel(JSON: self.actionInfoDict){
+            if kRandomBool(), let infoModel = TSActionInfoModel(JSON: self.actionInfoDict){
                 infoModel.id = Int.uuid
                 infoModel.id = Int.uuid
                 self.replaceSaveInfoModel(model: infoModel)
                 self.replaceSaveInfoModel(model: infoModel)
                 self.stateDatauPblished = (.success(nil),self.currentActionInfoModel)
                 self.stateDatauPblished = (.success(nil),self.currentActionInfoModel)

+ 10 - 1
AIRingtone/Common/Tool/TSAudioPlayer/TSAudioPlayer.swift

@@ -17,7 +17,16 @@ class TSAudioPlayer: NSObject {
     }
     }
     
     
     var isPlaying: Bool {
     var isPlaying: Bool {
-        return player?.rate != 0 && player?.error == nil
+//        return player?.rate != 0 && player?.error == nil
+        
+        if let player = player {
+            if #available(iOS 10.0, *) {
+                return player.timeControlStatus == .playing
+            } else {
+                return player.rate > 0
+            }
+        }
+        return false
     }
     }
     
     
     var duration: Double {
     var duration: Double {