对话请求加了loading
authorliangzhenying <867174124@qq.com>
Fri, 12 Sep 2025 07:08:05 +0000 (15:08 +0800)
committerliangzhenying <867174124@qq.com>
Fri, 12 Sep 2025 07:08:05 +0000 (15:08 +0800)
20 files changed:
ShenYin/Podfile.lock
ShenYin/ShenYin.xcodeproj/project.pbxproj
ShenYin/ShenYin.xcworkspace/xcshareddata/swiftpm/Package.resolved [new file with mode: 0644]
ShenYin/ShenYin/AppLaunch.swift
ShenYin/ShenYin/Assets.xcassets/AppIcon.appiconset/20250911-142330.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/AppIcon.appiconset/Contents.json
ShenYin/ShenYin/Ble/BleManager.swift
ShenYin/ShenYin/SceneDelegate.swift
ShenYin/ShenYin/UI/Base/BaseTC.swift
ShenYin/ShenYin/UI/Home/Chat/ChatCell.swift
ShenYin/ShenYin/UI/Home/Chat/ChatVC.swift
ShenYin/ShenYin/UI/Home/FieldRecording/FieldRecordBar.swift
ShenYin/ShenYin/UI/Home/FieldRecording/FieldRecordingVC.swift
ShenYin/ShenYin/UI/Home/FieldRecording/RhythView.swift
ShenYin/ShenYin/UI/Mode/CustomEqVC.swift
ShenYin/ShenYin/UI/Scan/BleScanVC.swift
ShenYin/ShenYin/UI/common/LoadingButton.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/common/cache/CacheManager.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/common/pop/ConnectPopView.swift [new file with mode: 0644]
ShenYin/podfile

index be12f21..3e86ec9 100644 (file)
@@ -52,8 +52,6 @@ PODS:
     - Moya/Core (= 15.0.0)
   - Moya/Core (15.0.0):
     - Alamofire (~> 5.0)
-  - MultiSlider (2.2.0):
-    - SweeterSwift
   - netfox (1.21.0)
   - Realm (20.0.3):
     - Realm/Headers (= 20.0.3)
@@ -65,7 +63,6 @@ PODS:
   - SVProgressHUD (2.3.1):
     - SVProgressHUD/Core (= 2.3.1)
   - SVProgressHUD/Core (2.3.1)
-  - SweeterSwift (1.2.6)
   - SwiftDate (7.0.0)
   - swiftScan (1.2.1)
   - TabPageViewController (0.2.8)
@@ -89,7 +86,6 @@ DEPENDENCIES:
   - Kingfisher (~> 6.0)
   - MJRefresh
   - Moya
-  - MultiSlider
   - netfox
   - RealmSwift
   - SnapKit
@@ -123,14 +119,12 @@ SPEC REPOS:
     - Kingfisher
     - MJRefresh
     - Moya
-    - MultiSlider
     - netfox
     - Realm
     - RealmSwift
     - SnapKit
     - SocketRocket
     - SVProgressHUD
-    - SweeterSwift
     - SwiftDate
     - swiftScan
     - TabPageViewController
@@ -158,14 +152,12 @@ SPEC CHECKSUMS:
   Kingfisher: 016c8b653a35add51dd34a3aba36b580041acc74
   MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
   Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
-  MultiSlider: 9667217199a051fa729bf54986d68fb9b911554c
   netfox: 9d5cc727fe7576c4c7688a2504618a156b7d44b7
   Realm: 853e5089d6042dff807bda000277eadfe2da93d2
   RealmSwift: f33c19577cefcbf681345d721fcbc7b42be4c949
   SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
   SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
   SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22
-  SweeterSwift: 1eca266517c703d7376e723a21926f5cb2ba4d0f
   SwiftDate: bbc26e26fc8c0c33fbee8c140c5e8a68293a148a
   swiftScan: 0849e7d7c1c641384767a573ee8cb90b88d1ddd9
   TabPageViewController: 8bd4104909754416b35a98f3b72a5b674ab20dd5
@@ -174,6 +166,6 @@ SPEC CHECKSUMS:
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
   YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
 
-PODFILE CHECKSUM: 826428f9bd4197f6e9759f68eaf9008f80c0563b
+PODFILE CHECKSUM: bc7d3a8004029604d5620b967136223e19d8a67d
 
 COCOAPODS: 1.16.2
index de54e87..52afbf1 100644 (file)
@@ -9,6 +9,8 @@
 /* Begin PBXBuildFile section */
                3F79C6142E6055E500EC38B9 /* JoyGemAI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */; };
                3F79C6152E6055E500EC38B9 /* JoyGemAI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+               3FF8A4622E72CBBA00271F9E /* DSWaveformImage in Frameworks */ = {isa = PBXBuildFile; productRef = 3FF8A4612E72CBBA00271F9E /* DSWaveformImage */; };
+               3FF8A4642E72CBBA00271F9E /* DSWaveformImageViews in Frameworks */ = {isa = PBXBuildFile; productRef = 3FF8A4632E72CBBA00271F9E /* DSWaveformImageViews */; };
                F2E449CAD5874BE652A69B50 /* Pods_ShenYin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3862D5561144E20721225B96 /* Pods_ShenYin.framework */; };
 /* End PBXBuildFile section */
 
@@ -63,7 +65,9 @@
                        buildActionMask = 2147483647;
                        files = (
                                F2E449CAD5874BE652A69B50 /* Pods_ShenYin.framework in Frameworks */,
+                               3FF8A4622E72CBBA00271F9E /* DSWaveformImage in Frameworks */,
                                3F79C6142E6055E500EC38B9 /* JoyGemAI.framework in Frameworks */,
+                               3FF8A4642E72CBBA00271F9E /* DSWaveformImageViews in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        mainGroup = 3F887B932E38D8DC00C98658;
                        minimizedProjectReferenceProxies = 1;
+                       packageReferences = (
+                               3FF8A4602E72CBBA00271F9E /* XCRemoteSwiftPackageReference "DSWaveformImage" */,
+                       );
                        preferredProjectObjectVersion = 77;
                        productRefGroup = 3F887B9D2E38D8DC00C98658 /* Products */;
                        projectDirPath = "";
                        inputFileListPaths = (
                                "${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-input-files.xcfilelist",
                        );
+                       inputPaths = (
+                       );
                        name = "[CP] Embed Pods Frameworks";
                        outputFileListPaths = (
                                "${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-output-files.xcfilelist",
                        );
+                       outputPaths = (
+                       );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
                        shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks.sh\"\n";
                        defaultConfigurationName = Release;
                };
 /* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+               3FF8A4602E72CBBA00271F9E /* XCRemoteSwiftPackageReference "DSWaveformImage" */ = {
+                       isa = XCRemoteSwiftPackageReference;
+                       repositoryURL = "https://github.com/dmrschmidt/DSWaveformImage";
+                       requirement = {
+                               kind = upToNextMajorVersion;
+                               minimumVersion = 14.2.2;
+                       };
+               };
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+               3FF8A4612E72CBBA00271F9E /* DSWaveformImage */ = {
+                       isa = XCSwiftPackageProductDependency;
+                       package = 3FF8A4602E72CBBA00271F9E /* XCRemoteSwiftPackageReference "DSWaveformImage" */;
+                       productName = DSWaveformImage;
+               };
+               3FF8A4632E72CBBA00271F9E /* DSWaveformImageViews */ = {
+                       isa = XCSwiftPackageProductDependency;
+                       package = 3FF8A4602E72CBBA00271F9E /* XCRemoteSwiftPackageReference "DSWaveformImage" */;
+                       productName = DSWaveformImageViews;
+               };
+/* End XCSwiftPackageProductDependency section */
        };
        rootObject = 3F887B942E38D8DC00C98658 /* Project object */;
 }
diff --git a/ShenYin/ShenYin.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ShenYin/ShenYin.xcworkspace/xcshareddata/swiftpm/Package.resolved
new file mode 100644 (file)
index 0000000..6851bcf
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "originHash" : "eb3e6467aa3b79663b371a20cbe7f1b7c7a6a3c9f98e6945bc9704361b5ae42d",
+  "pins" : [
+    {
+      "identity" : "dswaveformimage",
+      "kind" : "remoteSourceControl",
+      "location" : "https://github.com/dmrschmidt/DSWaveformImage",
+      "state" : {
+        "revision" : "4c56578ee10128ee2b2c04c9c5aa73812de722db",
+        "version" : "14.2.2"
+      }
+    }
+  ],
+  "version" : 3
+}
index 4004d61..eb00957 100644 (file)
@@ -13,6 +13,7 @@ class AppLaunch:NSObject{
     @MainActor static func start(){
         JoySdkManager.shared.setupSdk()
         setupKeyboard()
+        loadCache()
     }
     
     @MainActor static func setupKeyboard(){
@@ -23,4 +24,13 @@ class AppLaunch:NSObject{
         IQKeyboardManager.shared.isEnabled = true
         IQKeyboardManager.shared.resignOnTouchOutside = true
     }
+    static func loadCache(){
+        let list = DeviceCache.shared.getDeviceList()
+        Logger.debug("缓存设备",list)
+        if list.count > 0 {
+            CacheManager.shared.currentDevice = list.first
+            BleManager.shared.startScanDevice()
+            App.shared.enter()
+        }
+    }
 }
diff --git a/ShenYin/ShenYin/Assets.xcassets/AppIcon.appiconset/20250911-142330.png b/ShenYin/ShenYin/Assets.xcassets/AppIcon.appiconset/20250911-142330.png
new file mode 100644 (file)
index 0000000..1484aa2
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/AppIcon.appiconset/20250911-142330.png differ
index 2305880..ba8a194 100644 (file)
@@ -1,28 +1,7 @@
 {
   "images" : [
     {
-      "idiom" : "universal",
-      "platform" : "ios",
-      "size" : "1024x1024"
-    },
-    {
-      "appearances" : [
-        {
-          "appearance" : "luminosity",
-          "value" : "dark"
-        }
-      ],
-      "idiom" : "universal",
-      "platform" : "ios",
-      "size" : "1024x1024"
-    },
-    {
-      "appearances" : [
-        {
-          "appearance" : "luminosity",
-          "value" : "tinted"
-        }
-      ],
+      "filename" : "20250911-142330.png",
       "idiom" : "universal",
       "platform" : "ios",
       "size" : "1024x1024"
index 17c8cc3..88d6639 100644 (file)
@@ -8,7 +8,6 @@
 import UIKit
 import CoreBluetooth
 import JoyGemAI
-import SVProgressHUD
 import AVFAudio
 class BleManager: NSObject {
     var discoverDeviceCallback: (([CBPeripheral]) -> Void)?
@@ -66,24 +65,25 @@ extension BleManager:CBCentralManagerDelegate{
         }
         
         devices.append(peripheral)
-        print(peripheral)
+        Logger.debug(peripheral)
         discoverDeviceCallback?(devices)
+        checkConnect()
     }
     
     func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
         stopScanDevice()
-        print("蓝牙已连接 \(peripheral)")
+        Logger.debug("蓝牙已连接 \(peripheral)")
         connectPeripheral = peripheral
         peripheral.delegate = self
         peripheral.discoverServices([CBUUID(string: kJoyGemAIServiceUUID)]);
         didConnectDeviceCallback?(connectPeripheral!)
     }
     func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
-        print("peripheral: %@ failed to connect", peripheral)
-        SVProgressHUD.dismiss()
+        Logger.debug("peripheral: %@ failed to connect", peripheral)
+        YLprogressHUD.hidden()
     }
     func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
-        print("蓝牙已断开 \(peripheral)")
+        Logger.debug("蓝牙已断开 \(peripheral)")
         disConnectDeviceCallback?(peripheral)
     }
 }
@@ -93,9 +93,9 @@ extension BleManager: CBPeripheralDelegate {
     
     func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
         
-        print("发现服务成功")
+        Logger.debug("发现服务成功")
         for service in peripheral.services! {
-            print("peripheral service: %@", service)
+            Logger.debug("peripheral service: %@", service)
             peripheral.discoverCharacteristics(nil, for: service)
         }
         
@@ -119,7 +119,7 @@ extension BleManager: CBPeripheralDelegate {
     func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: (any Error)?) {
         if (characteristic.isNotifying == true && characteristic.service?.uuid.uuidString == kJoyGemAIServiceUUID && characteristic.uuid.uuidString == kJoyGemAICharacteristicNotifyUUID) {
             //MARK: 使能成功时需要
-            print("特征使能成功")
+            Logger.debug("特征使能成功")
             JoyGemAIManager.shared().bleConnected()
         }
     }
@@ -136,26 +136,38 @@ extension BleManager: CBPeripheralDelegate {
     func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: (any Error)?) {
         
     }
-    
 }
 
 extension BleManager{
-    
     // MARK: - Public Methods
     func startScanDevice() {
-        print("扫描中...")
+        centralManager.stopScan()
+        Logger.debug("扫描中...")
         devices = []
         
         centralManager.scanForPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
+        discoverDeviceCallback?(devices)
+    }
+    
+    func checkConnect(){
         let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)])
         for item in list {
             devices.append(item)
             break
         }
-        if list.count > 0 {
-            print("缓存",list)
+
+        for item in devices{
+            if let current = CacheManager.shared.currentDevice,current.uuid == item.identifier.uuidString {
+                connectPeripheral(item)
+                return
+            }
+        }
+        
+        if connectPeripheral == nil || connectPeripheral?.state == .disconnected {
+            DispatchQueue.main.asyncAfter(deadline:.now() + 3) {
+                self.checkConnect()
+            }
         }
-        discoverDeviceCallback?(devices)
     }
     
     func stopScanDevice() {
@@ -163,13 +175,9 @@ extension BleManager{
     }
     
     func connectPeripheral(_ peripheral: CBPeripheral) {
-        print("连接中...")
-//        YLprogressHUD.showLoading()
+        Logger.debug("连接中...")
         centralManager.connect(peripheral, options: [CBConnectPeripheralOptionEnableTransportBridgingKey:true])
-        SVProgressHUD.show(withStatus: "连接中")
-        //        DispatchQueue.main.asyncAfter(deadline: .now() + 15){[weak self] in
-        //            self?.cancel()
-        //        }
+        YLprogressHUD.showLoading()
     }
     
     func cancel() {
@@ -185,32 +193,32 @@ extension BleManager : JoyGemAIManagerDelegate {
     }
     
     func joyGemAuthSuccessCallback() {
-        YLprogressHUD.showAutoHiden(text: "鉴权成功"){
+        ConnectPopView().showAutoHide {
             App.shared.enter()
         }
-        
+        CacheManager.shared.saveDevice(DeviceModel(name: connectPeripheral?.name ?? "", uuid: connectPeripheral?.identifier.uuidString ?? ""))
         PcmSound.sharedInstance().setup(16000, withchannels: 1)
         let options: AVAudioSession.CategoryOptions = [.allowBluetooth]
         do {
             try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
             try AVAudioSession.sharedInstance().setActive(true)
         } catch {
-            print(error)
+            Logger.debug(error)
         }
     }
     
     func joyGemAction(_ action: JoyGemActionMode) {
         switch action {
         case .cancel:
-            SVProgressHUD.showInfo(withStatus: "请求关闭录音功能/通知关闭了对话")
+            YLprogressHUD.showAutoHiden("请求关闭录音功能/通知关闭了对话")
         case .recordLive:
-            SVProgressHUD.showInfo(withStatus: "请求开启现场录音")
+            YLprogressHUD.showAutoHiden("请求开启现场录音")
         case .recordCall:
-            SVProgressHUD.showInfo(withStatus: "请求开启通话录音")
+            YLprogressHUD.showAutoHiden("请求开启通话录音")
         case .si:
-            SVProgressHUD.showInfo(withStatus: "请求开启同传听译")
+            YLprogressHUD.showAutoHiden( "请求开启同传听译")
         case .chat:
-            SVProgressHUD.showInfo(withStatus: "通知开启了AI对话")
+            YLprogressHUD.showAutoHiden( "通知开启了AI对话")
         @unknown default:
             break
         }
index a191bc1..c891392 100644 (file)
@@ -20,7 +20,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
         
         App.shared.window = window
         window?.rootViewController = BaseTC()
-        window?.rootViewController = UINavigationController(rootViewController: CustomEqVC())
+        window?.rootViewController = UINavigationController(rootViewController: BleScanVC())
         AppLaunch.start()
     }
 
index 0ef49d6..06eddf7 100644 (file)
@@ -55,6 +55,6 @@ class BaseTC:UITabBarController{
         self.tabBar.backgroundColor = .white
         view.backgroundColor = .color(.bgColor)
 
-        self.selectedIndex = 1
+        self.selectedIndex = 0
     }
 }
index 71cb86f..cfb25ea 100644 (file)
@@ -8,11 +8,11 @@
 public class ChatCellModel {
     public var type: Int = 0//1发,0收
     public var content: String = ""
-    public var id:UInt = 0
+    public var id:Int = 0
 }
 
 class ChatCell:BaseTableViewCell{
-    let bgView = UIView()
+    let bgView = LoadingView()
     let originalLabel = UILabel()
     
     override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
@@ -54,13 +54,20 @@ class ChatCell:BaseTableViewCell{
             make.top.bottom.equalToSuperview().inset(14)
             make.left.right.equalToSuperview().inset(12)
             make.width.lessThanOrEqualTo(kScreenWid - 60)
+            make.width.greaterThanOrEqualTo(60)
+            make.height.greaterThanOrEqualTo(19)
         }
     }
     
     var data:ChatCellModel!{
         didSet{
             if data.content.isEmpty{
-                data.content = "..."
+                originalLabel.text = ""
+                bgView.startAnimating()
+            }
+            else{
+                bgView.stopAnimating()
+                originalLabel.text = data.content
             }
             if data.type == 1 {
                 bgView.backgroundColor = .color(.theme)
@@ -80,7 +87,6 @@ class ChatCell:BaseTableViewCell{
                     make.left.equalToSuperview().inset(20)
                 }
             }
-            originalLabel.text = data.content
         }
     }
 }
index fda5200..bd3982b 100644 (file)
@@ -134,7 +134,15 @@ class ChatVC:BaseVC{
 
 extension ChatVC:ChatRecordBarDelegate{
     func recordBarStart(_ toolBar: ChatRecordBar) {
-//        JoyGemChatManager.shared().playAudioEnd()
+        
+        let model = ChatCellModel()
+        model.type = 1
+        model.content = ""
+        model.id = -1
+        dataList.append(model)
+        tableView.reloadData()
+        scrollToBottom()
+        
         JoyGemChatManager.shared().stopChat()
         JoyGemChatManager.shared().startSingleChat()
     }
@@ -199,20 +207,27 @@ extension ChatVC : JoyGemChatManagerDelegate {
     
     func chatManager(_ manager: JoyGemChatManager, requestText text: String?, index: UInt) {
         Logger.debug(text,index)
-        if let text = text {
-            if let model = dataList.last,model.id == index,model.type == 1 {
-                model.content = text
-            }
-            else{
-                let model = ChatCellModel()
-                model.type = 1
-                model.content = text
-                model.id = index
-                dataList.append(model)
-            }
-            tableView.reloadData()
-            scrollToBottom()
+        guard let text = text else{
+            return
+        }
+        if text.isEmpty {
+            return
+        }
+        if dataList.last?.id == -1 {
+            dataList.removeLast()
+        }
+        if let model = dataList.last,model.id == index,model.type == 1 {
+            model.content = text
+        }
+        else{
+            let model = ChatCellModel()
+            model.type = 1
+            model.content = text
+            model.id = Int(index)
+            dataList.append(model)
         }
+        tableView.reloadData()
+        scrollToBottom()
     }
     
     func chatManager(_ manager: JoyGemChatManager, responseText text: String?, index: UInt, finish isFinish: Bool) {
@@ -226,7 +241,7 @@ extension ChatVC : JoyGemChatManagerDelegate {
                 let model = ChatCellModel()
                 model.type = 0
                 model.content = text
-                model.id = index
+                model.id = Int(index)
                 dataList.append(model)
             }
             tableView.reloadData()
index 575baca..018aaaf 100644 (file)
@@ -19,7 +19,7 @@ protocol FieldRecordBarDelegate {
 
 
 class FieldRecordBar: BaseView {
-    let recordBtn = UIButton()
+    let recordBtn = LoadingButton()
     let leftItem = RecordBarItem()
     let rightItem = RecordBarButton()
     var state:RecordSate = .stop
index b7cc559..75a807a 100644 (file)
@@ -86,14 +86,17 @@ extension FieldRecordingVC:FieldRecordBarDelegate{
         }
         else if state == .stop{
             JoyGemRecordManager.shared().stop()
-            
-            let v = PopTextField()
-            v.show()
-            v.cancelTap = {
-                
-            }
-            v.okTap = {
-                
+            bar.recordBtn.startAnimating {[weak self] in
+                guard let self = self else{return}
+//                toolBar.recordBtn.stopCli()
+                let v = PopTextField()
+                v.show()
+                v.cancelTap = {
+                    
+                }
+                v.okTap = {
+                    
+                }
             }
         }
     }
@@ -144,12 +147,21 @@ extension FieldRecordingVC : JoyGemRecordManagerDelegate {
     
     
     func recordManagerStopped(_ manager: JoyGemRecordManager, reason code: JoyGemRecordStopCode) {
-//        if (code == .actively) {
+        if (code == .actively) {
 //            YLprogressHUD.showAutoHiden("用户主动结束")
-//        } else {
-//            YLprogressHUD.showAutoHiden("自动结束")
-//            ///判断当前蓝牙是否连接从而确定是否因为蓝牙断开造成的录音断开
-//        }
+//            toolBar.recordBtn.stopLoading()
+//            let v = PopTextField()
+//            v.show()
+//            v.cancelTap = {
+//                
+//            }
+//            v.okTap = {
+//                
+//            }
+        } else {
+            YLprogressHUD.showAutoHiden("自动结束")
+            ///判断当前蓝牙是否连接从而确定是否因为蓝牙断开造成的录音断开
+        }
     }
     
     func recordManager(_ manager: JoyGemRecordManager, onError code: JoyGemErrorCode) {
index 76371dd..2b837ad 100644 (file)
@@ -1,5 +1,17 @@
 import UIKit
+//import DSWaveformImage
 
-class RhythView: UIView {
-   
+class RhythView: BaseView {
+//   let wave = WaveformLiveView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 50))
+//    
+//    override func setupViews() {
+//        backgroundColor = .red
+//        wave.backgroundColor = .green
+//        addSubview(wave)
+//
+//    }
+//    override func setupLayout() {
+//        
+//    }
+    
 }
index 184680f..870c17b 100644 (file)
@@ -7,7 +7,6 @@
 
 import UIKit
 import JoyGemAI
-import MultiSlider
 class CustomEqVC:BaseVC{
     private let bgView = UIView()
     private let sliderBgView = UIView()
index 37dc8ea..aa11e6a 100644 (file)
@@ -8,7 +8,15 @@
 import UIKit
 import CoreBluetooth
 import DGActivityIndicatorView
+
+enum BleScanState{
+    case scan
+    case has
+    case none
+}
+
 class BleScanVC: BaseVC{
+    let headerView = BleScanHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 280))
     let tableView = UITableView(frame: .zero, style: .plain)
     var list:[CBPeripheral] = []
     
@@ -25,7 +33,7 @@ class BleScanVC: BaseVC{
             v.estimatedRowHeight = 76
             v.separatorStyle = .none
             v.register(BleScanCell.self, forCellReuseIdentifier: BleScanCell.reuseID)
-            v.tableHeaderView = BleScanHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 280))
+            v.tableHeaderView = headerView
         }
         view.addSubview(tableView)
     }
@@ -39,6 +47,12 @@ class BleScanVC: BaseVC{
         BleManager.shared.discoverDeviceCallback = {[weak self] devices in
             self?.list = devices
             self?.tableView.reloadData()
+            if devices.count > 0 {
+                self?.headerView.stateView.state = .has
+            }
+            else{
+                self?.headerView.stateView.state = .none
+            }
         }
         startScan()
     }
@@ -48,7 +62,7 @@ class BleScanVC: BaseVC{
     func startScan(){
         list = []
         tableView.reloadData()
-        BleManager.shared.startScanDevice()
+        BleManager.shared.startScanDevice()        
     }
 }
 
@@ -72,10 +86,11 @@ extension BleScanVC:UITableViewDelegate,UITableViewDataSource {
 class BleScanHeaderView: BaseView {
     let rippleView = DGActivityIndicatorView(type: .triplePulse,tintColor: UIColor.hexString("#0092E1"),size: 250)!
     var radarImageView = UIImageView()
+    var stateView = ScanView()
     override func setupViews() {
         backgroundColor = .clear
 //        rippleView.backgroundColor = .red
-        addSubviews([rippleView,radarImageView])
+        addSubviews([rippleView,radarImageView,stateView])
         rippleView.startAnimating()
         
         radarImageView.do { v in
@@ -101,6 +116,58 @@ class BleScanHeaderView: BaseView {
             make.size.equalTo(250)
             make.center.equalToSuperview()
         }
+        stateView.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalTo(rippleView.snp.bottom).offset(30)
+        }
+    }
+    
+
+    
+    class ScanView: BaseView {
+        let titleLabel = UILabel()
+        let desLabel = UILabel()
+        var state:BleScanState = .scan{
+            didSet{
+                self.isHidden = state == .has
+                if state == .none {
+//                    titleLabel.text = "正在扫描"
+//                    desLabel.text = "请确保智能设备已连接电源,且位于手机附近"
+                }
+                else{
+                    titleLabel.text = "正在扫描"
+                    desLabel.text = "请确保智能设备已连接电源,且位于手机附近"
+                }
+            }
+        }
+        override func setupViews() {
+            backgroundColor = .clear
+            addSubviews([titleLabel,desLabel])
+            titleLabel.do { (v) in
+                v.textColor = .rgb(0x121212)
+                v.font = .regular(14)
+                v.textAlignment = .center
+                v.numberOfLines = 0
+            }
+            desLabel.do { (v) in
+                v.textColor = .rgb(0x8D8D8D)
+                v.font = .regular(14)
+                v.textAlignment = .center
+                v.numberOfLines = 0
+            }
+        }
+        override func setupLayout() {
+            titleLabel.snp.makeConstraints { make in
+                make.top.equalToSuperview()
+                make.centerX.equalToSuperview()
+            }
+            desLabel.snp.makeConstraints { make in
+                make.top.equalTo(titleLabel.snp.bottom).offset(10)
+                make.centerX.equalToSuperview()
+            }
+        }
+        
+        
     }
 }
 
diff --git a/ShenYin/ShenYin/UI/common/LoadingButton.swift b/ShenYin/ShenYin/UI/common/LoadingButton.swift
new file mode 100644 (file)
index 0000000..464b106
--- /dev/null
@@ -0,0 +1,60 @@
+//
+//  LoadingButton.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/11.
+//
+import DGActivityIndicatorView
+import UIKit
+class LoadingButton:UIButton{
+    let loadingView = DGActivityIndicatorView(type: .ballClipRotate,tintColor: UIColor.hexString("#0092E1"))!
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        loadingView.backgroundColor = .white
+        addSubview(loadingView)
+        loadingView.snp.remakeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    func startAnimating(finished:(()->Void)? = nil){
+        loadingView.startAnimating()
+        DispatchQueue.main.asyncAfter(deadline:.now() + 3) {
+            self.stopAnimating()
+            finished?()
+        }
+    }
+    func stopAnimating(){
+        loadingView.stopAnimating()
+    }
+}
+
+class LoadingView: UIView {
+    let activeView = DGActivityIndicatorView(type: .ballPulse,tintColor: .white)!
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        activeView.backgroundColor = .clear
+        addSubview(activeView)
+        activeView.snp.makeConstraints { make in
+            make.center.equalToSuperview()
+            make.width.equalTo(60)
+            make.height.equalTo(40)
+        }
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    func startAnimating(finished:(()->Void)? = nil){
+        activeView.startAnimating()
+    }
+    func stopAnimating(){
+        activeView.stopAnimating()
+    }
+}
diff --git a/ShenYin/ShenYin/UI/common/cache/CacheManager.swift b/ShenYin/ShenYin/UI/common/cache/CacheManager.swift
new file mode 100644 (file)
index 0000000..5f2f202
--- /dev/null
@@ -0,0 +1,62 @@
+//
+//  c.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/11.
+//
+import CoreBluetooth
+
+class CacheManager{
+    static let shared = CacheManager()
+    var currentDevice:DeviceModel?
+    
+    func saveDevice(_ device: DeviceModel) {
+        self.currentDevice = device
+        DeviceCache.shared.saveDevice(device)
+    }
+}
+
+class DeviceModel: NSObject, NSCoding {
+    var name = ""
+    var uuid = ""
+    
+    init(name: String, uuid: String) {
+        self.name = name
+        self.uuid = uuid
+    }
+    
+    func encode(with aCoder: NSCoder) {
+        aCoder.encode(name, forKey: "name")
+        aCoder.encode(uuid, forKey: "uuid")
+    }
+    
+    required init?(coder aDecoder: NSCoder) {
+        name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
+        uuid = aDecoder.decodeObject(forKey: "uuid") as? String ?? ""
+    }
+}
+
+class DeviceCache {
+    static let shared = DeviceCache()
+    private let userDefaults = UserDefaults.standard
+    private let deviceListKey = "deviceListKey"
+    
+    func saveDevice(_ device: DeviceModel) {
+        var deviceList = getDeviceList()
+        if let index = deviceList.firstIndex(where: { $0.uuid == device.uuid }) {
+            deviceList[index] = device
+        } else {
+            deviceList.append(device)
+        }
+        let encoder = NSKeyedArchiver.archivedData(withRootObject: deviceList)
+        userDefaults.set(encoder, forKey: deviceListKey)
+    }
+    
+    func getDeviceList() -> [DeviceModel] {
+        if let data = userDefaults.data(forKey: deviceListKey),
+           let deviceList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [DeviceModel] {
+            return deviceList
+        }
+        return []
+    }
+}
diff --git a/ShenYin/ShenYin/UI/common/pop/ConnectPopView.swift b/ShenYin/ShenYin/UI/common/pop/ConnectPopView.swift
new file mode 100644 (file)
index 0000000..82879e3
--- /dev/null
@@ -0,0 +1,86 @@
+//
+//  ConnectPopView.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/11.
+//
+
+import UIKit
+
+class ConnectPopView: BasePresentView2 {
+    let contentView = UIView()
+    private let titleLabel = UILabel()
+    private let imageView = UIImageView()
+    private let desLabel = UILabel()
+
+    
+    init() {
+        super.init()
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    override func setupSubView() {
+        super.setupSubView()
+        addSubview(contentView)
+        contentView.addSubviews([titleLabel,imageView,desLabel])
+    }
+    override func setupLayout() {
+        super.setupLayout()
+
+        contentView.snp.makeConstraints { make in
+            make.left.right.equalToSuperview().inset(18)
+            make.height.equalTo(315)
+            make.center.equalToSuperview()
+        }
+        titleLabel.snp.makeConstraints { (m) in
+            m.top.equalToSuperview().inset(30)
+            m.left.right.equalToSuperview()
+        }
+        imageView.snp.makeConstraints { (m) in
+            m.centerX.equalToSuperview()
+            m.top.equalToSuperview().inset(76)
+            m.width.equalTo(190)
+            m.height.equalTo(156)
+        }
+        desLabel.snp.makeConstraints { (m) in
+            m.top.equalTo(imageView.snp.bottom).offset(20)
+            m.left.right.equalToSuperview()
+//            m.bottom.equalToSuperview().inset(30)
+        }
+    }
+    
+    override func setupStyle() {
+        super.setupStyle()
+        contentView.do { (v) in
+            v.backgroundColor = .white
+            v.yc.setCornerRadius(20)
+        }
+        imageView.do { v in
+            v.image = UIImage(named: "home_header")
+        }
+        titleLabel.do { (v) in
+            v.textColor = .rgb(0x121212)
+            v.font = .regular(20)
+            v.textAlignment = .center
+            v.text = "Deep Gen2 Max"
+        }
+        desLabel.do { (v) in
+            v.textColor = .rgb(0x121212)
+            v.font = .regular(24)
+            v.textAlignment = .center
+            v.text = "连接成功"
+        }
+    }
+    
+    func showAutoHide(finished: (() -> Void)? = nil){
+        show()
+        DispatchQueue.main.asyncAfter(deadline:.now() + 0.5) {
+            self.hide()
+            finished?()
+        }
+    }
+}
+
index 55c4a07..fee0b8d 100644 (file)
@@ -32,7 +32,9 @@ target 'ShenYin' do
 
   pod 'SocketRocket'#socket,AI用到
   pod 'DGActivityIndicatorView'#扫描雷达
-  pod 'MultiSlider'
+#  pod 'MultiSlider'
+#  pod 'DSWaveformImage'
+  
 #  pod 'NVActivityIndicatorView', '~> 5.1.1'  # 最新稳定版
 #  pod 'EZAudio', '~> 1.1.0'
 end