完善UI
authorliangzhenying <867174124@qq.com>
Fri, 26 Sep 2025 03:50:51 +0000 (11:50 +0800)
committerliangzhenying <867174124@qq.com>
Fri, 26 Sep 2025 03:50:51 +0000 (11:50 +0800)
42 files changed:
ShenYin/ShenYin/Assets.xcassets/home/lvdong.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/lvdong.imageset/lvdong@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Group 2095@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Group 2095@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Group 2290@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Group 2290@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Group 2291@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Group 2291@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/分屏_2@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/分屏_2@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/语音发送中@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/语音发送中@3x.png [new file with mode: 0644]
ShenYin/ShenYin/MixApi/MixApi.swift [deleted file]
ShenYin/ShenYin/Tools/YLTools.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Home/CallingRecordVC.swift
ShenYin/ShenYin/UI/Home/Chinese2English/Chinese2EnglishVC.swift
ShenYin/ShenYin/UI/Home/Dialog/DialogRecordBar.swift
ShenYin/ShenYin/UI/Home/Dialog/DialogSplitView.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Home/Dialog/DialogTranlateVC.swift
ShenYin/ShenYin/UI/Home/Dialog/DialogTranslateCell.swift
ShenYin/ShenYin/UI/Home/Dialog/Untitled.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Home/FieldRecording/FieldRecordingVC.swift
ShenYin/ShenYin/UI/Home/FieldRecording/RhythView.swift
ShenYin/ShenYin/UI/Home/Root/HomeFunctionView.swift
ShenYin/ShenYin/UI/Home/Root/HomeHeadView.swift
ShenYin/ShenYin/UI/Home/TextTranslate/TextTranslateVC.swift
ShenYin/ShenYin/UI/Launch/AiSupportLanguage.swift [moved from ShenYin/ShenYin/UI/common/AiSupportLanguage.swift with 100% similarity]
ShenYin/ShenYin/UI/Launch/AppDelegate.swift [moved from ShenYin/ShenYin/AppDelegate.swift with 100% similarity]
ShenYin/ShenYin/UI/Launch/AppLaunch.swift [moved from ShenYin/ShenYin/AppLaunch.swift with 99% similarity]
ShenYin/ShenYin/UI/Launch/AppManager.swift [moved from ShenYin/ShenYin/UI/common/AppManager.swift with 93% similarity]
ShenYin/ShenYin/UI/Launch/BleManager.swift [moved from ShenYin/ShenYin/Ble/BleManager.swift with 96% similarity]
ShenYin/ShenYin/UI/Launch/CacheManager.swift [moved from ShenYin/ShenYin/UI/common/cache/CacheManager.swift with 100% similarity]
ShenYin/ShenYin/UI/Launch/JoySdkManager.swift [moved from ShenYin/ShenYin/JoySdkManager.swift with 100% similarity]
ShenYin/ShenYin/UI/Launch/SceneDelegate.swift [moved from ShenYin/ShenYin/SceneDelegate.swift with 100% similarity]
ShenYin/ShenYin/UI/common/BrokenLineView.swift
ShenYin/ShenYin/UI/common/LoadingButton.swift
ShenYin/ShenYin/UI/common/NotificationManager.swift [new file with mode: 0644]

diff --git a/ShenYin/ShenYin/Assets.xcassets/home/lvdong.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/home/lvdong.imageset/Contents.json
new file mode 100644 (file)
index 0000000..4feb1b9
--- /dev/null
@@ -0,0 +1,21 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "lvdong@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/lvdong.imageset/lvdong@2x.png b/ShenYin/ShenYin/Assets.xcassets/home/lvdong.imageset/lvdong@2x.png
new file mode 100644 (file)
index 0000000..aeac888
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/lvdong.imageset/lvdong@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Contents.json
new file mode 100644 (file)
index 0000000..4591384
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Group 2095@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Group 2095@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Group 2095@2x.png b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Group 2095@2x.png
new file mode 100644 (file)
index 0000000..6417b96
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Group 2095@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Group 2095@3x.png b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Group 2095@3x.png
new file mode 100644 (file)
index 0000000..9444543
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_1.imageset/Group 2095@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Contents.json
new file mode 100644 (file)
index 0000000..c31e30f
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Group 2290@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Group 2290@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Group 2290@2x.png b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Group 2290@2x.png
new file mode 100644 (file)
index 0000000..b90caf4
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Group 2290@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Group 2290@3x.png b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Group 2290@3x.png
new file mode 100644 (file)
index 0000000..3fe6ff1
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_2.imageset/Group 2290@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Contents.json
new file mode 100644 (file)
index 0000000..ba69c16
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Group 2291@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Group 2291@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Group 2291@2x.png b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Group 2291@2x.png
new file mode 100644 (file)
index 0000000..78d610c
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Group 2291@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Group 2291@3x.png b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Group 2291@3x.png
new file mode 100644 (file)
index 0000000..a1f0cb6
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/play_animate_white_3.imageset/Group 2291@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/Contents.json
new file mode 100644 (file)
index 0000000..5446c99
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "分屏_2@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "分屏_2@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/分屏_2@2x.png b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/分屏_2@2x.png
new file mode 100644 (file)
index 0000000..0a43345
Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/\345\210\206\345\261\217_2@2x.png" differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/分屏_2@3x.png b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/分屏_2@3x.png
new file mode 100644 (file)
index 0000000..5cbb614
Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_2.imageset/\345\210\206\345\261\217_2@3x.png" differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/Contents.json
new file mode 100644 (file)
index 0000000..884debb
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "语音发送中@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "语音发送中@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/语音发送中@2x.png b/ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/语音发送中@2x.png
new file mode 100644 (file)
index 0000000..de5c375
Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/\350\257\255\351\237\263\345\217\221\351\200\201\344\270\255@2x.png" differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/语音发送中@3x.png b/ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/语音发送中@3x.png
new file mode 100644 (file)
index 0000000..60cb958
Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/home/translate_bg.imageset/\350\257\255\351\237\263\345\217\221\351\200\201\344\270\255@3x.png" differ
diff --git a/ShenYin/ShenYin/MixApi/MixApi.swift b/ShenYin/ShenYin/MixApi/MixApi.swift
deleted file mode 100644 (file)
index 177778b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-//  MixApi.swift
-//  Magpie
-//
-//  Created by incar on 2024/1/6.
-//
-
-import Foundation
-import CoreBluetooth
-
-public class MixDevice{
-    
-    /// 设备
-     var peripheral: CBPeripheral!
-    
-    /// 广播信息
-     var advertisementData: [String : AnyObject]?
-    
-    /// 信号
-     var RSSI: Int32?
-}
-
-public protocol MixApi  {
-    
-    /// 单利
-    static var manager: MixApi { get }
-    
-    /// 发现设备
-    var discoverDevice:((_ devices:[MixDevice]) -> Void)? { get }
-    
-    /// 收到sdk传数过来的数据,具体请阅读每条指令参数说明
-    var receiveData:((_ data:Any) -> Void)? { get  }
-    
-    /// 扫描
-    /// - Parameters:
-    ///   - uuid: 指定设备
-    ///   - duration: 超时
-    func scanWithServices(_ uuid: [String]?, duration: TimeInterval)
-    
-    /// 停止扫描
-    func stopScan()
-    
-    /// 连接设备
-    /// - Parameters:
-    ///   - device: 扫描到的涉笔
-    ///   - duration: 超时时间
-    ///   - success: 连接成功
-    ///   - fail: 连接失败
-    func connect(device : MixDevice, duration: TimeInterval, success: @escaping (() -> Void), fail: @escaping ((_ error:[String:Any]) -> Void))
-    
-    /// 连接设备
-    /// - Parameters:
-    ///   - identifier: 设备标识符
-    ///   - duration: 超时时间
-    ///   - success: 连接成功
-    ///   - fail: 连接失败
-    func connect(identifier : String, duration: TimeInterval, success: @escaping (() -> Void), fail: @escaping ((_ error:[String:Any]) -> Void))
-    
-    
-    /// 取消当前连接
-    func cancelConnect()
-    
-    /// 发送指令
-    /// - Parameters:
-    ///   - parameters: 无参传nil,具体key-value请阅读每条指令参数说明
-    ///   - success: 发送成功
-    ///   - failure: 发送失败
-    func sendCommand(parameters: [String : Any]?, success:@escaping (() -> Void), failure:@escaping ((_ error:[String:Any]) -> Void))
-}
diff --git a/ShenYin/ShenYin/Tools/YLTools.swift b/ShenYin/ShenYin/Tools/YLTools.swift
new file mode 100644 (file)
index 0000000..03dacb5
--- /dev/null
@@ -0,0 +1,16 @@
+//
+//  YLTools.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/22.
+//
+import Foundation
+
+class YLToos {
+    static func formatSeconds(_ totalSeconds: Int) -> String {
+        let hours = totalSeconds / 3600
+        let minutes = (totalSeconds % 3600) / 60
+        let seconds = totalSeconds % 60
+        return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
+    }
+}
index d27735f..e8f88d5 100644 (file)
@@ -38,7 +38,6 @@ class CallingRecordVC:BaseVC{
     override func setupLayout() {
         rhythView.snp.makeConstraints { make in
             make.width.centerX.equalToSuperview()
-            make.height.equalTo(100)
             make.top.equalToSuperview().inset(kNavBtm)
         }
         toolBar.snp.makeConstraints { make in
@@ -66,11 +65,12 @@ class CallingRecordVC:BaseVC{
     }
     override func navleftViewTapped() {
         if toolBar.recordBtn.isSelected {
-            CustomAlert.showWith(title: "提示", messgage: "当前正在录音,确定放弃当前录音吗?", cancelCallback: nil) {
+            CustomAlert.showWith(title: "提示", messgage: "当前正在录音,确定放弃当前录音吗?", cancelCallback: nil) {[unowned self] in
+                self.rhythView.stopTimer()
                 JoyGemCallManager.shared().stop()
                 PcmSound.sharedInstance().stopAudioUnit()
                 PcmSound.sharedInstance().cleanup()
-                super.navleftViewTapped()
+                self.navigationController?.popViewController(animated: true)
             }
         }
         else{
@@ -105,9 +105,11 @@ extension CallingRecordVC:FieldRecordBarDelegate{
         if state == .start {
             textView.text = ""
             messageList.removeAll()
+            rhythView.startTimer()
             JoyGemCallManager.shared().start()
         }
         else if state == .stop{
+            rhythView.stopTimer()
             JoyGemCallManager.shared().stop()
             bar.startAnimating {[weak self] in
                 guard let self = self else{return}
index 138ff35..0c3e100 100644 (file)
@@ -11,12 +11,17 @@ import AVFAudio
 class Chinese2EnglishVC:BaseVC{
     let toolBar = RecordBar()
     let tableView = UITableView(frame: CGRectZero, style: .plain)
+    let bg = UIImageView()
     var dataList:[(Chinese2EnglishCellModel,UInt)] = []
     var pcmData = Data()
 
     override func setupViews() {
         navBar.title = "中英互译"
         navBar.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
+        view.addSubview(tableView)
+        view.addSubview(toolBar)
+        view.addSubview(bg)
+        
         toolBar.delegate = self
         
         tableView.backgroundColor = .clear
@@ -25,8 +30,9 @@ class Chinese2EnglishVC:BaseVC{
         tableView.estimatedRowHeight = 60
         tableView.separatorStyle = .none
         tableView.register(Chinese2EnglishCell.self, forCellReuseIdentifier: Chinese2EnglishCell.reuseID)
-        view.addSubview(tableView)
-        view.addSubview(toolBar)
+        
+        bg.image = UIImage(named: "translate_bg")
+
         
     }
     override func setupLayout() {
@@ -40,6 +46,10 @@ class Chinese2EnglishVC:BaseVC{
             make.left.right.equalToSuperview()
             make.bottom.equalTo(toolBar.snp.top)
         }
+        bg.snp.makeConstraints { make in
+            make.size.equalTo(90)
+            make.center.equalTo(tableView)
+        }
     }
     override func setupData() {
         JoyGemSIDeviceManager.shared().delegate = self
@@ -81,6 +91,10 @@ class Chinese2EnglishVC:BaseVC{
         tableView.reloadData()
         if dataList.count > 0 {
             tableView.scrollToRow(at: IndexPath(row: dataList.count - 1, section: 0), at: .none, animated: true)
+            bg.isHidden = true
+        }
+        else{
+            bg.isHidden = false
         }
     }
 }
index fd644a5..23b82ff 100644 (file)
@@ -23,180 +23,228 @@ protocol DialogRecordBarDelegate {
 }
 
 class DialogRecordBar: BaseView {
-    let switchBtn = UIButton()
-    let leftItem = RecordBarItem()
-    let rightItem = RecordBarItem()
+    let recordView = DialogRecordView()
+    let languageView = DialogLanguageView()
     var delegate:DialogRecordBarDelegate?
+    var navBar:BaseNavigationBar = BaseNavigationBar()
     
     override func setupViews() {
-        backgroundColor = .white
-        addSubviews([leftItem,rightItem,switchBtn])
+        backgroundColor = .clear
+        addSubviews([recordView,languageView])
         
-        switchBtn.do { v in
-            v.setImage(UIImage(named: "split_screen_1"), for: .normal)
-            v.setImage(UIImage(named: "split_screen_1"), for: .selected)
-            v.addTarget(self, action: #selector(switchBtnAction), for: .touchUpInside)
+        recordView.do { v in
+//            v.backgroundColor = .green
+            v.switchBtn.addTarget(self, action: #selector(switchBtnAction), for: .touchUpInside)
+            v.leftRecord.addTarget(self, action: #selector(leftRecordBtnAction), for: .touchUpInside)
+            v.rightRecord.addTarget(self, action: #selector(rightRecordBtnAction), for: .touchUpInside)
         }
-        leftItem.do { (v) in
-            v.recordBtn.setImage(UIImage(named: "dialog_device_ear"), for: .normal)
-            v.recordBtn.setImage(UIImage(named: "dialog_device_ear"), for: .selected)
-            v.languageItem.language = AiSupportLanguage.chinse
-            v.languageItem.yc.addTap(target: self, action: #selector(leftLanguageAction))
-            v.recordBtn.addTarget(self, action: #selector(leftRecordBtnAction), for: .touchUpInside)
-            v.language = .chinse
 
-        }
-        rightItem.do { (v) in
-            v.recordBtn.setImage(UIImage(named: "dialog_device_phone"), for: .normal)
-            v.recordBtn.setImage(UIImage(named: "dialog_device_phone"), for: .selected)
-            v.languageItem.language = AiSupportLanguage.english
-            v.languageItem.yc.addTap(target: self, action: #selector(rightLanguageAction))
-            v.recordBtn.addTarget(self, action: #selector(rightRecordBtnAction), for: .touchUpInside)
-            v.language = .english
+        languageView.do { (v) in
+            v.leftItem.yc.addTap(target: self, action: #selector(leftLanguageAction))
+            v.rightItem.yc.addTap(target: self, action: #selector(rightLanguageAction))
         }
     }
     
     override func setupLayout() {
-        switchBtn.snp.makeConstraints { make in
-            make.size.equalTo(56)
-            make.center.equalToSuperview()
-        }
-        leftItem.snp.makeConstraints { make in
-            make.height.equalTo(100)
-            make.centerY.equalTo(switchBtn)
-            make.right.equalToSuperview().offset(-(kScreenWid/2 + 60))
+        recordView.snp.makeConstraints { make in
+            make.width.equalToSuperview()
+            make.height.equalTo(34)
+            make.top.equalToSuperview().inset(10)
+            make.left.equalToSuperview()
         }
-        rightItem.snp.makeConstraints { make in
-            make.height.equalTo(100)
-            make.centerY.equalTo(switchBtn)
-            make.left.equalToSuperview().offset(kScreenWid/2 + 60)
+        languageView.snp.makeConstraints { make in
+            make.width.equalToSuperview()
+            make.top.equalTo(recordView.snp.bottom)
+            make.left.equalToSuperview()
+//            make.height.equalTo(60)
         }
     }
     
-    func stopRecord(){
-        if leftItem.recordBtn.isSelected {
-            leftItem.recordBtn.isSelected = false
-            leftItem.stopAnimating()
+    func stopRecord(_ type:DialogRecordDeviceType){
+        if type == .earphone {
+            recordView.leftRecord.isSelected = false
+            recordView.leftRecord.stopAnimating(finished: { [weak self] in
+                guard let self = self else { return  }
+                recordView.leftRecord.alpha = 1
+                languageView.leftItem.alpha = 1
+                recordView.rightRecord.alpha = 1
+                languageView.rightItem.alpha = 1
+            })
         }
-        if rightItem.recordBtn.isSelected {
-            rightItem.recordBtn.isSelected = false
-            rightItem.stopAnimating()
+        else{
+            recordView.rightRecord.isSelected = false
+            recordView.rightRecord.stopAnimating(finished: { [weak self] in
+                guard let self = self else { return  }
+                recordView.leftRecord.alpha = 1
+                languageView.leftItem.alpha = 1
+                recordView.rightRecord.alpha = 1
+                languageView.rightItem.alpha = 1
+            })
         }
-        leftItem.alpha = 1
-        rightItem.alpha = 1
     }
 
     @objc func switchBtnAction(){
-        delegate?.recordBar(self, layoutChange: .normal)
+        recordView.switchBtn.isSelected = !recordView.switchBtn.isSelected
+        let type:DialogRecordLayoutType = recordView.switchBtn.isSelected ?  .spolit:.normal
+        delegate?.recordBar(self, layoutChange: type)
+        
+        if type == .normal {
+            navBar.titleLabel.isHidden = false
+            recordView.addSubview(recordView.rightRecord)
+            recordView.setupLayout()
+        }
+        else{
+            recordView.splitLayout()
+            
+            navBar.titleLabel.isHidden = true
+            navBar.addSubview(recordView.rightRecord)
+            recordView.rightRecord.snp.makeConstraints { make in
+                make.center.equalTo(navBar.titleLabel)
+            }
+        }
     }
     
     @objc func leftRecordBtnAction(){
-        if  rightItem.recordBtn.activeView.animating {
-            return
-        }
-        if rightItem.recordBtn.isSelected {
+        if  recordView.rightRecord.activeView.animating || recordView.rightRecord.loadView.animating {
             return
         }
-        leftItem.recordBtn.isSelected = !leftItem.recordBtn.isSelected
-        if leftItem.recordBtn.isSelected {
-            rightItem.recordBtn.alpha = 1
-            leftItem.languageItem.alpha = 0.3
-            rightItem.recordBtn.alpha = 0.3
-            rightItem.languageItem.alpha = 0.3
+
+        recordView.leftRecord.isSelected = !recordView.leftRecord.isSelected
+        if  recordView.leftRecord.isSelected {
+            recordView.leftRecord.alpha = 1
+            recordView.rightRecord.alpha = 0.3
+            languageView.leftItem.alpha = 0.3
+            languageView.rightItem.alpha = 0.3
             
-            leftItem.startAnimating()
+            recordView.leftRecord.startAnimating()
             delegate?.recordBar(self, device: .earphone,stateChange: .start)
         }
         else{
-            leftItem.recordBtn.alpha = 1
-            leftItem.languageItem.alpha = 1
-            rightItem.recordBtn.alpha = 1
-            rightItem.languageItem.alpha = 1
-            
-            leftItem.stopAnimating()
+            stopRecord(.earphone)
             delegate?.recordBar(self, device: .earphone,stateChange: .stop)
         }
 
     }
     @objc func rightRecordBtnAction(){
-        if  leftItem.recordBtn.activeView.animating {
+        if  recordView.leftRecord.activeView.animating || recordView.leftRecord.loadView.animating {
             return
         }
-        if leftItem.recordBtn.isSelected {
-            return
-        }
-        rightItem.recordBtn.isSelected = !rightItem.recordBtn.isSelected
         
-        if rightItem.recordBtn.isSelected {
-            leftItem.recordBtn.alpha = 0.3
-            leftItem.languageItem.alpha = 0.3
-            rightItem.recordBtn.alpha = 1
-            rightItem.languageItem.alpha = 0.3
+        recordView.rightRecord.isSelected = !recordView.rightRecord.isSelected
+        
+        if  recordView.rightRecord.isSelected {
+            recordView.leftRecord.alpha = 0.3
+            recordView.rightRecord.alpha = 1
+            languageView.leftItem.alpha = 0.3
+            languageView.rightItem.alpha = 0.3
             
-            rightItem.startAnimating()
+            recordView.rightRecord.startAnimating()
             delegate?.recordBar(self, device: .phone,stateChange: .start)
         }
         else{
-            leftItem.recordBtn.alpha = 1
-            leftItem.languageItem.alpha = 1
-            rightItem.recordBtn.alpha = 1
-            rightItem.languageItem.alpha = 1
-            
-            rightItem.stopAnimating()
+            stopRecord(.phone)
             delegate?.recordBar(self, device: .phone,stateChange: .stop)
         }
     }
     
     @objc func leftLanguageAction(){
-        if leftItem.recordBtn.isSelected || rightItem.recordBtn.isSelected {
+        if recordView.isBusy {
             return
         }
-        let v = LanguagePickerView(languages: AiSupportLanguage.translate,isLeft: true,left: leftItem.language,right: rightItem.language)
-        v.selectedIndex = v.list.firstIndex(where: {$0.title == leftItem.language.title}) ?? 0
+        let v = LanguagePickerView(languages: AiSupportLanguage.translate,isLeft: true,left: languageView.leftItem.language,right: languageView.rightItem.language)
+        v.selectedIndex = v.list.firstIndex(where: {$0.title == languageView.leftItem.language.title}) ?? 0
         v.show()
         v.didSelected = {[weak self] (index,value) in
             guard let self = self else { return  }
             if index == 0 {
-                leftItem.language = value
+                languageView.leftItem.language = value
             }
             else{
-                rightItem.language = value
+                languageView.rightItem.language = value
             }
         }
     }
     @objc func rightLanguageAction(){
-        if leftItem.recordBtn.isSelected || rightItem.recordBtn.isSelected{
+        if recordView.isBusy{
             return
         }
-        let v = LanguagePickerView(languages: AiSupportLanguage.translate,isLeft: false,left: leftItem.language,right: rightItem.language)
-        v.selectedIndex = v.list.firstIndex(where: {$0.title == rightItem.language.title}) ?? 0
+        let v = LanguagePickerView(languages: AiSupportLanguage.translate,isLeft: false,left: languageView.leftItem.language,right: languageView.rightItem.language)
+        v.selectedIndex = v.list.firstIndex(where: {$0.title == languageView.rightItem.language.title}) ?? 0
         v.show()
         v.didSelected = {[weak self] (index,value) in
             guard let self = self else { return  }
             if index == 0 {
-                leftItem.language = value
+                languageView.leftItem.language = value
             }
             else{
-                rightItem.language = value
+                languageView.rightItem.language = value
             }
         }
     }
-    class RecordBarItem: UIView {
-        let recordBtn = RecordingButton()
-        let languageItem = RecordLanguageItem()
+    class DialogRecordView:BaseView{
+        let leftRecord = DialogRecordingButton()
+        let rightRecord = DialogRecordingButton()
+        let switchBtn = UIButton()
+        var isBusy:Bool{
+            return leftRecord.activeView.animating || leftRecord.loadView.animating || rightRecord.activeView.animating || rightRecord.loadView.animating
+        }
         
-        var language:AiSupportLanguage = AiSupportLanguage.chinse{
-            didSet{
-                languageItem.language = language
+        override func setupViews() {
+            addSubviews([leftRecord,rightRecord,switchBtn])
+            switchBtn.do { v in
+                v.setImage(UIImage(named: "split_screen_1"), for: .normal)
+                v.setImage(UIImage(named: "split_screen_2"), for: .selected)
+//                v.backgroundColor = .red
+                
+            }
+            leftRecord.do { v in
+                v.setImage(UIImage(named: "dialog_device_ear"), for: .normal)
+                v.setImage(UIImage(named: "dialog_device_ear"), for: .selected)
+            }
+            rightRecord.do { v in
+                v.setImage(UIImage(named: "dialog_device_phone"), for: .normal)
+                v.setImage(UIImage(named: "dialog_device_phone"), for: .selected)
+                v.activeView.tintColor = UIColor.hexString("#0092E1")
+                v.activeView.yc.setBorder(width: 2, color: .hexString("#0092E1"), radius: 17)
+                v.loadView.tintColor = UIColor.hexString("#0092E1")
             }
         }
-        
-        func startAnimating(){
-            recordBtn.startAnimating()
+        override func setupLayout() {
+            switchBtn.snp.remakeConstraints { make in
+                make.size.equalTo(34)
+                make.centerX.equalToSuperview()
+                make.top.equalToSuperview()
+            }
+            leftRecord.snp.remakeConstraints { make in
+                make.width.equalTo(66)
+                make.height.equalTo(34)
+                make.top.equalToSuperview().inset(0)
+                make.right.equalToSuperview().offset(-(kScreenWid/2 + 60))
+            }
+            rightRecord.snp.remakeConstraints { make in
+                make.width.equalTo(66)
+                make.height.equalTo(34)
+                make.top.equalToSuperview().inset(0)
+                make.left.equalToSuperview().offset(kScreenWid/2 + 60)
+            }
         }
-        func stopAnimating(){
-            recordBtn.stopAnimating()
+        func splitLayout(){
+            switchBtn.snp.remakeConstraints { make in
+                make.size.equalTo(34)
+                make.right.equalToSuperview().inset(36)
+                make.top.equalToSuperview()
+            }
+            leftRecord.snp.remakeConstraints { make in
+                make.width.equalTo(66)
+                make.height.equalTo(34)
+                make.top.equalToSuperview().inset(0)
+                make.right.equalToSuperview().offset(-(kScreenWid/2 - 33))
+            }
         }
+    }
+    class DialogLanguageView: UIView {
+        let leftItem = RecordLanguageItem()
+        let rightItem = RecordLanguageItem()
 
         override init(frame: CGRect) {
             super.init(frame: frame)
@@ -210,25 +258,33 @@ class DialogRecordBar: BaseView {
         
         func setupViews() {
 //            backgroundColor = .red
-            addSubviews([recordBtn,languageItem])
-            recordBtn.do { v in
-//                v.yc.setBorder(width: 1, color: .color(.theme), radius: 17)
+            addSubviews([leftItem,rightItem])
+
+            leftItem.do { (v) in
+                v.language = AiSupportLanguage.chinse
+                v.yc.addTap(target: self, action: #selector(leftLanguageAction))
+                v.language = .chinse
+                v.valueLabel.text = "耳机"
+            }
+            rightItem.do { (v) in
+                v.language = AiSupportLanguage.english
+                v.yc.addTap(target: self, action: #selector(rightLanguageAction))
+                v.language = .english
+                v.valueLabel.text = "手机"
             }
         }
         
         func setupLayout() {
-            recordBtn.snp.makeConstraints { make in
-                make.width.equalTo(66)
-                make.height.equalTo(34)
-                make.top.equalToSuperview().inset(0)
-                make.centerX.equalToSuperview()
+            leftItem.snp.makeConstraints { make in
+                make.height.equalTo(60)
+                make.top.equalToSuperview()
+                make.right.equalToSuperview().offset(-(kScreenWid/2 + 60))
             }
-            languageItem.snp.makeConstraints { make in
-                make.right.equalToSuperview()
-                make.top.equalTo(recordBtn.snp.bottom).offset(0)
-                make.centerX.equalToSuperview()
+            rightItem.snp.makeConstraints { make in
+                make.height.equalTo(leftItem)
+                make.centerY.equalTo(leftItem)
+                make.left.equalToSuperview().offset(kScreenWid/2 + 60)
             }
-
         }
     }
     class RecordLanguageItem: BaseView {
@@ -255,7 +311,6 @@ class DialogRecordBar: BaseView {
             valueLabel.do { v in
                 v.textColor = .rgb(0x666666)
                 v.font = .regular(10)
-                v.text = "耳机"
             }
         }
         
diff --git a/ShenYin/ShenYin/UI/Home/Dialog/DialogSplitView.swift b/ShenYin/ShenYin/UI/Home/Dialog/DialogSplitView.swift
new file mode 100644 (file)
index 0000000..8c99724
--- /dev/null
@@ -0,0 +1,214 @@
+//
+//  Dialog.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/25.
+//
+
+import UIKit
+
+class DialogSplitView: BaseView {
+    let line = UIView()
+    let tableView1 = UITableView(frame: CGRectZero, style: .plain)
+    var dataList1:[DialogTranslateCellModel] = []
+
+    let tableView2 = UITableView(frame: CGRectZero, style: .plain)
+    var dataList2:[DialogTranslateCellModel] = []
+    
+    var dataList:[DialogTranslateCellModel] = []{
+        didSet{
+            dataList1 = dataList
+            dataList2 = dataList
+            tableView1.reloadData()
+            tableView2.reloadData()
+            
+            if dataList.count > 0 {
+                tableView1.scrollToRow(at: IndexPath(row: dataList.count - 1, section: 0), at: .none, animated: true)
+                tableView2.scrollToRow(at: IndexPath(row: dataList.count - 1, section: 0), at: .none, animated: true)
+            }
+
+        }
+    }
+    
+    override func setupViews() {
+        addSubviews([tableView1,tableView2,line])
+        
+//        backgroundColor = .red
+        tableView1.do { v in
+            v.backgroundColor = .hexString("#F7F7F7")
+//            v.backgroundColor = .green
+            v.delegate = self
+            v.dataSource = self
+            v.estimatedRowHeight = 60
+            v.separatorStyle = .none
+            v.register(DialogSplitCell.self, forCellReuseIdentifier: DialogSplitCell.reuseID)
+            v.transform = CGAffineTransform(rotationAngle: .pi)
+        }
+        tableView2.do { v in
+            v.backgroundColor = .hexString("#F7F7F7")
+//            v.backgroundColor = .yellow
+            v.delegate = self
+            v.dataSource = self
+            v.estimatedRowHeight = 60
+            v.separatorStyle = .none
+            v.register(DialogSplitCell.self, forCellReuseIdentifier: DialogSplitCell.reuseID)
+        }
+        line.backgroundColor = .hexString("#E9E9E9")
+    }
+    override func setupLayout() {
+        tableView1.snp.makeConstraints { make in
+            make.top.equalToSuperview()
+            make.left.equalToSuperview()
+            make.width.equalTo(kScreenWid)
+            make.height.equalToSuperview().multipliedBy(0.5)
+        }
+        tableView2.snp.makeConstraints { make in
+            make.top.equalTo(tableView1.snp.bottom)
+            make.left.equalToSuperview()
+            make.width.equalTo(kScreenWid)
+            make.height.equalToSuperview().multipliedBy(0.5)
+        }
+        line.snp.makeConstraints { make in
+            make.left.right.equalToSuperview().inset(36)
+            make.top.equalTo(tableView2.snp.top )
+            make.height.equalTo(1)
+        }
+    }
+
+}
+extension DialogSplitView:UITableViewDelegate,UITableViewDataSource {
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        if tableView == tableView1 {
+            return dataList1.count
+        }
+        else {
+            return dataList2.count
+        }
+    }
+    
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        let cell = DialogSplitCell.cell(withTableView: tableView, indexPath: indexPath)
+        if tableView == tableView1 {
+            cell.config(data: dataList1[indexPath.row], isLeft: false)
+        }
+        else{
+            cell.config(data: dataList1[indexPath.row], isLeft: true)
+        }
+        return cell
+    }
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        
+    }
+}
+
+class DialogSplitCell:BaseTableViewCell{
+    let bgView = UIView()
+    let originalLabel = UILabel()
+    let copyIcon = UIImageView()
+    
+    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+        super.init(style: style, reuseIdentifier: reuseIdentifier)
+        
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    override func setupViews() {
+        contentView.backgroundColor = .hexString("#F7F7F7")
+        
+        bgView.do { v in
+            v.yc.setCornerRadius(12)
+            v.backgroundColor = .white
+        }
+        originalLabel.do { v in
+            v.font = .regular(14)
+            v.textColor = .hexString("#121212")
+            v.numberOfLines = 0
+            v.textAlignment = .left
+        }
+        copyIcon.do { v in
+            v.image = UIImage(named: "play_animate_3")
+            v.animationImages = [UIImage(named: "play_animate_1")!,UIImage(named: "play_animate_2")!,UIImage(named: "play_animate_3")!]
+            v.animationDuration = 0.6
+            v.animationRepeatCount = 0
+            v.yc.addTap(target: self, action: #selector(copyAction))
+        }
+        contentView.addSubview(bgView)
+        bgView.addSubviews([originalLabel,copyIcon])
+    }
+    
+    override func setupLayout() {
+        originalLabel.snp.makeConstraints { make in
+            make.top.equalToSuperview().inset(14)
+            make.height.greaterThanOrEqualTo(15)
+            make.left.equalToSuperview().inset(12)
+            make.width.lessThanOrEqualTo(kScreenWid - 120)
+            make.right.equalToSuperview().inset(50)
+            make.bottom.equalToSuperview().inset(14)
+        }
+        copyIcon.snp.makeConstraints { make in
+            make.right.equalToSuperview().inset(12)
+            make.size.equalTo(24)
+            make.top.equalToSuperview().inset(12)
+        }
+    }
+    
+    
+    func config(data:DialogTranslateCellModel,isLeft:Bool){
+        
+        //            translationLabel.text = data.response
+        if isLeft {
+            if data.isPhone {
+                originalLabel.text = data.response
+                bgView.snp.remakeConstraints { make in
+                    make.top.bottom.equalToSuperview().inset(10)
+                    make.right.equalToSuperview().inset(18)
+                }
+                bgView.backgroundColor = .color(.theme)
+                originalLabel.textColor = .white
+            }
+            else{
+                originalLabel.text = data.send
+                bgView.snp.remakeConstraints { make in
+                    make.top.bottom.equalToSuperview().inset(10)
+                    make.left.equalToSuperview().inset(18)
+                }
+                bgView.backgroundColor = .white
+                originalLabel.textColor = .hexString("#606D80")
+            }
+        }
+        else{
+            if data.isPhone {
+                originalLabel.text = data.send
+                bgView.snp.remakeConstraints { make in
+                    make.top.bottom.equalToSuperview().inset(10)
+                    make.right.equalToSuperview().inset(18)
+                }
+                bgView.backgroundColor = .color(.theme)
+                originalLabel.textColor = .white
+            }
+            else{
+                originalLabel.text = data.response
+                bgView.snp.remakeConstraints { make in
+                    make.top.bottom.equalToSuperview().inset(10)
+                    make.left.equalToSuperview().inset(18)
+                }
+                bgView.backgroundColor = .white
+                originalLabel.textColor = .hexString("#606D80")
+            }
+        }
+    }
+
+    @objc func copyAction(){
+        //        UIPasteboard.general.string = data.send + "\n" + data.response
+        //        YLprogressHUD.showAutoHiden("已拷贝")
+        if copyIcon.isAnimating {
+            copyIcon.stopAnimating()
+        }
+        else{
+            copyIcon.startAnimating()
+        }
+    }
+}
index 7f8263d..90333d7 100644 (file)
@@ -12,6 +12,7 @@ class DialogTranslateVC:BaseVC{
     let toolBar = DialogRecordBar()
     var recordFilePath : String?
     
+    let splitView = DialogSplitView()
     let tableView = UITableView(frame: CGRectZero, style: .plain)
     var dataList:[DialogTranslateCellModel] = []
     
@@ -23,14 +24,15 @@ class DialogTranslateVC:BaseVC{
         super.viewDidLoad()
     }
     override func setupViews() {
-        view.addSubviews([toolBar,tableView])
+        view.addSubviews([toolBar,tableView,splitView])
         
         navBar.title = "对话翻译"
         navBar.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
         
         toolBar.do { v in
-            v.backgroundColor = .clear
+//            v.backgroundColor = .clear
             v.delegate = self
+            v.navBar = navBar
         }
         view.backgroundColor = .hexString("#F7F7F7")
         
@@ -42,12 +44,14 @@ class DialogTranslateVC:BaseVC{
             v.separatorStyle = .none
             v.register(DialogTranslateCell.self, forCellReuseIdentifier: DialogTranslateCell.reuseID)
         }
+        splitView.isHidden = true
+        
     }
     override func setupLayout() {
         toolBar.snp.makeConstraints { make in
             make.width.centerX.equalToSuperview()
             make.height.equalTo(120)
-            make.bottom.equalToSuperview().inset(20)
+            make.bottom.equalToSuperview()
         }
         tableView.snp.makeConstraints { make in
             make.top.equalToSuperview().inset(kNavBtm)
@@ -55,8 +59,17 @@ class DialogTranslateVC:BaseVC{
             make.width.equalTo(kScreenWid)
             make.bottom.equalTo(toolBar.snp.top)
         }
+        splitView.snp.makeConstraints { make in
+            make.edges.equalTo(tableView)
+        }
     }
     override func setupData() {
+//        dataList = [
+//            DialogTranslateCellModel(send: "你好", response: "hello",isPhone: false),
+//            DialogTranslateCellModel(send: "Nice to meet you", response: "很高兴认识你",isPhone: true),
+//            DialogTranslateCellModel(send: "深圳今天下雨吗", response: "ShenZhen is raining today?",isPhone: false),
+//            DialogTranslateCellModel(send: "YES", response: "是的",isPhone: true),
+//        ]        
 
         JoyGemSIManager.shared().delegate = self
         JoyGemSIDeviceManager.shared().delegate = self
@@ -83,18 +96,11 @@ class DialogTranslateVC:BaseVC{
         navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = true
     }
     override func navleftViewTapped() {
-        if toolBar.leftItem.recordBtn.isSelected || toolBar.rightItem.recordBtn.isSelected {
-            CustomAlert.showWith(title: "提示", messgage: "当前正在录音,确定放弃当前录音吗?", cancelCallback: nil) {
-                JoyGemSIManager.shared().stop()
-                JoyGemSIDeviceManager.shared().stop()
-                PcmSound.sharedInstance().stopAudioUnit()
-                PcmSound.sharedInstance().cleanup()
-                super.navleftViewTapped()
-            }
-        }
-        else{
-            super.navleftViewTapped()
-        }
+        JoyGemSIManager.shared().stop()
+        JoyGemSIDeviceManager.shared().stop()
+        PcmSound.sharedInstance().stopAudioUnit()
+        PcmSound.sharedInstance().cleanup()
+        super.navleftViewTapped()
     }
     
     func refreshData(){
@@ -102,6 +108,7 @@ class DialogTranslateVC:BaseVC{
         if dataList.count > 0 {
             tableView.scrollToRow(at: IndexPath(row: dataList.count - 1, section: 0), at: .none, animated: true)
         }
+        splitView.dataList = dataList
     }
 }
 
@@ -122,7 +129,13 @@ extension DialogTranslateVC:UITableViewDelegate,UITableViewDataSource {
 
 extension DialogTranslateVC:DialogRecordBarDelegate{
     func recordBar(_ bar: DialogRecordBar, layoutChange: DialogRecordLayoutType) {
-        
+        if  layoutChange == .spolit{
+            splitView.isHidden = false
+            splitView.dataList = dataList
+        }
+        else{
+            splitView.isHidden = true
+        }
     }
     
     func recordBar(_ bar: DialogRecordBar, device: DialogRecordDeviceType, stateChange state: RecordBarSate) {
@@ -152,8 +165,8 @@ extension DialogTranslateVC:DialogRecordBarDelegate{
         dataList.append(model)
         refreshData()
         
-        JoyGemSIManager.shared().originalLanguage = toolBar.rightItem.language.value
-        JoyGemSIManager.shared().targetLanguage = toolBar.leftItem.language.value
+        JoyGemSIManager.shared().originalLanguage = toolBar.languageView.rightItem.language.value
+        JoyGemSIManager.shared().targetLanguage = toolBar.languageView.leftItem.language.value
         JoyGemSIManager.shared().start()
     }
     
@@ -169,8 +182,8 @@ extension DialogTranslateVC:DialogRecordBarDelegate{
         dataList.append(model)
         refreshData()
         
-        JoyGemSIDeviceManager.shared().originalLanguage = toolBar.leftItem.language.value
-        JoyGemSIDeviceManager.shared().targetLanguage = toolBar.rightItem.language.value
+        JoyGemSIManager.shared().originalLanguage = toolBar.languageView.leftItem.language.value
+        JoyGemSIManager.shared().targetLanguage = toolBar.languageView.rightItem.language.value
         JoyGemSIDeviceManager.shared().start()
         otherPcm = Data()
         do {
@@ -188,7 +201,10 @@ extension DialogTranslateVC:DialogRecordBarDelegate{
 
 extension DialogTranslateVC : JoyGemSIManagerDelegate {
     func siManagerStopped(_ manager: JoyGemSIManager, reason code: JoyGemRecordStopCode) {
-        
+        if let model = dataList.last,model.send.isEmpty{
+            dataList.removeLast()
+            refreshData()
+        }
     }
     
     func siManager(_ manager: JoyGemSIManager, didUpdateRaw model: JoyGemAsrModel) {
@@ -203,6 +219,7 @@ extension DialogTranslateVC : JoyGemSIManagerDelegate {
         
         ///监听到一句话结束,自动结束当前录音
         if (model.definite == true) {
+            toolBar.stopRecord(.phone)
             stopPhoneRecord()
         }
         
@@ -261,7 +278,10 @@ extension DialogTranslateVC : JoyGemSIManagerDelegate {
 extension DialogTranslateVC : JoyGemSIDeviceManagerDelegate {
     
     func siDeviceManagerStopped(_ manager: JoyGemSIDeviceManager, reason code: JoyGemRecordStopCode) {
-        
+        if let model = dataList.last,model.send.isEmpty{
+            dataList.removeLast()
+            refreshData()
+        }
     }
     
     func siDeviceManager(_ manager: JoyGemSIDeviceManager, didUpdateRaw model: JoyGemAsrModel) {
@@ -277,6 +297,7 @@ extension DialogTranslateVC : JoyGemSIDeviceManagerDelegate {
         
         ///监听到一句话结束,自动结束当前录音
         if (model.definite == true) {
+            toolBar.stopRecord(.earphone)
             stopEarRecord()
         }
         
index 952387e..b98a949 100644 (file)
@@ -10,9 +10,10 @@ class DialogTranslateCellModel{
     var response = ""
     var isPhone : Bool = false //是否手机收音
     
-    init(send: String = "", response: String = "") {
+    init(send: String = "", response: String = "",isPhone : Bool = false) {
         self.send = send
         self.response = response
+        self.isPhone = isPhone
     }
 }
 
@@ -55,7 +56,7 @@ class DialogTranslateCell:BaseTableViewCell{
             v.textAlignment = .left
         }
         line.do { v in
-            //            v.backgroundColor = .hexString("#93C6EC")
+            v.backgroundColor = .hexString("#93C6EC")
         }
         copyIcon.do { v in
             v.image = UIImage(named: "play_animate_3")
@@ -69,17 +70,18 @@ class DialogTranslateCell:BaseTableViewCell{
     }
     
     override func setupLayout() {
-        bgView.snp.makeConstraints { make in
-            make.top.bottom.equalToSuperview().inset(10)
-            make.width.lessThanOrEqualTo(kScreenWid - 58)
-            make.left.equalToSuperview().inset(18)
-        }
-        
+//        bgView.snp.makeConstraints { make in
+//            make.top.bottom.equalToSuperview().inset(10)
+//            make.width.lessThanOrEqualTo(kScreenWid - 58)
+//            make.left.equalToSuperview().inset(18)
+//        }
+//        
         originalLabel.snp.makeConstraints { make in
             make.top.equalToSuperview().inset(14)
-            make.left.equalToSuperview().inset(12)
             make.height.greaterThanOrEqualTo(15)
-            make.width.lessThanOrEqualTo(kScreenWid - 110)
+            make.left.equalToSuperview().inset(12)
+            make.right.equalToSuperview().inset(50)
+            make.width.lessThanOrEqualTo(kScreenWid - 120)
         }
         line.snp.makeConstraints { make in
             make.left.right.equalToSuperview().inset(12)
@@ -90,7 +92,7 @@ class DialogTranslateCell:BaseTableViewCell{
         translationLabel.snp.makeConstraints { make in
             make.top.equalTo(line.snp.bottom).offset(15)
             make.left.equalToSuperview().inset(12)
-            make.width.lessThanOrEqualTo(kScreenWid - 110)
+            make.right.equalToSuperview().inset(12)
             make.height.greaterThanOrEqualTo(15)
             make.bottom.equalToSuperview().inset(14)
         }
@@ -107,26 +109,27 @@ class DialogTranslateCell:BaseTableViewCell{
             translationLabel.text = data.response
             
             if data.isPhone {
-//                bgView.snp.remakeConstraints { make in
-//                    make.top.bottom.equalToSuperview().inset(10)
-//                    make.width.lessThanOrEqualTo(kScreenWid - 58)
-//                    make.left.equalToSuperview().inset(18)
-//                }
+                bgView.snp.remakeConstraints { make in
+                    make.top.bottom.equalToSuperview().inset(10)
+//                    make.width.equalTo(kScreenWid - 78)
+                    make.right.equalToSuperview().inset(18)
+                }
                 bgView.backgroundColor = .color(.theme)
                 originalLabel.textColor = .white
                 translationLabel.textColor = .white
             }
             else{
+                bgView.snp.remakeConstraints { make in
+                    make.top.bottom.equalToSuperview().inset(10)
+//                    make.width.equalTo(kScreenWid - 78)
+                    make.left.equalToSuperview().inset(18)
+                }
                 bgView.backgroundColor = .white
-                originalLabel.textColor = .hexString("606D80")
+                originalLabel.textColor = .hexString("#606D80")
                 translationLabel.textColor = .hexString("#121212")
-//                bgView.snp.remakeConstraints { make in
-//                    make.top.bottom.equalToSuperview().inset(10)
-//                    make.width.lessThanOrEqualTo(kScreenWid - 58)
-//                    make.right.equalToSuperview().inset(18)
-//                }
-
             }
+            line.setNeedsLayout()
+            line.layoutIfNeeded()
         }
     }
     @objc func copyAction(){
diff --git a/ShenYin/ShenYin/UI/Home/Dialog/Untitled.swift b/ShenYin/ShenYin/UI/Home/Dialog/Untitled.swift
new file mode 100644 (file)
index 0000000..c7b5846
--- /dev/null
@@ -0,0 +1,7 @@
+//
+//  Untitled.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/25.
+//
+
index d8ba505..8c65613 100644 (file)
@@ -34,7 +34,6 @@ class FieldRecordingVC:BaseVC{
     override func setupLayout() {
         rhythView.snp.makeConstraints { make in
             make.width.centerX.equalToSuperview()
-            make.height.equalTo(100)
             make.top.equalToSuperview().inset(kNavBtm)
         }
         toolBar.snp.makeConstraints { make in
@@ -71,11 +70,12 @@ class FieldRecordingVC:BaseVC{
     }
     override func navleftViewTapped() {
         if toolBar.recordBtn.isSelected {
-            CustomAlert.showWith(title: "提示", messgage: "当前正在录音,确定放弃当前录音吗?", cancelCallback: nil) {
+            CustomAlert.showWith(title: "提示", messgage: "当前正在录音,确定放弃当前录音吗?", cancelCallback: nil) {[unowned self] in
+                self.rhythView.stopTimer()
                 JoyGemRecordManager.shared().stop()
                 PcmSound.sharedInstance().stopAudioUnit()
                 PcmSound.sharedInstance().cleanup()
-                super.navleftViewTapped()
+                self.navigationController?.popViewController(animated: true)
             }
         }
         else{
@@ -98,14 +98,18 @@ extension FieldRecordingVC:FieldRecordBarDelegate{
             textView.text = ""
             messageList.removeAll()
             JoyGemRecordManager.shared().start()
+            rhythView.startTimer()
         }
         if state == .resume{
+            rhythView.startTimer()
             JoyGemRecordManager.shared().resume()
         }
         else if state == .pause{
             JoyGemRecordManager.shared().pause()
+            rhythView.stopTimer()
         }
         else if state == .stop{
+            rhythView.stopTimer()
             JoyGemRecordManager.shared().stop()
             bar.startAnimating {[weak self] in
                 guard let self = self else{return}
index 2b837ad..1ea5b00 100644 (file)
@@ -2,16 +2,46 @@ import UIKit
 //import DSWaveformImage
 
 class RhythView: BaseView {
+    let lable = UILabel()
+    let wave = UIView()
+    var timer:Timer?
+    var num = 0
 //   let wave = WaveformLiveView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 50))
-//    
-//    override func setupViews() {
+
+    override func setupViews() {
+        addSubviews([lable,wave])
+        lable.do { v in
+            v.textColor = .hexString("#121212")
+            v.font = .bold(32)
+            v.textAlignment = .center
+            v.text = "00:00:00"
+        }
 //        backgroundColor = .red
-//        wave.backgroundColor = .green
-//        addSubview(wave)
-//
-//    }
-//    override func setupLayout() {
-//        
-//    }
-    
+        wave.backgroundColor = .lightGray
+    }
+    override func setupLayout() {
+        lable.snp.makeConstraints { make in
+            make.top.equalToSuperview().inset(10)
+            make.centerX.equalToSuperview()
+        }
+        wave.snp.makeConstraints { make in
+            make.top.equalToSuperview().inset(40)
+            make.left.right.equalToSuperview()
+            make.height.equalTo(58)
+            make.bottom.equalToSuperview()
+        }
+    }
+    @objc func timerAction(){
+        num += 1
+        lable.text = YLToos.formatSeconds(num)
+    }
+    func startTimer(){
+        if let timer = timer,timer.isValid{
+            timer.invalidate()
+        }
+        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
+    }
+    func stopTimer(){
+        timer?.invalidate()
+    }
 }
index fd4d4f6..49557e2 100644 (file)
@@ -78,6 +78,7 @@ class HomeFunctionView: BaseView {
         var y = 0.0
         for (index, value) in list.enumerated() {
             let view = HomeCell()
+            view.enable = App.shared.deviceValid
             addSubview(view)
             
             view.type = value
@@ -93,10 +94,14 @@ class HomeFunctionView: BaseView {
                 }
             }
         }
+        NotificationManager.add(self, selector: #selector(deviceChange(_:)), forName: .deviceValidChange)
     }
-    
-    override func setupLayout() {
-        
+    @objc func deviceChange(_ noti:Notification){
+        for item in self.subviews{
+            if let view = item as? HomeCell  {
+                view.enable = App.shared.deviceValid
+            }
+        }
     }
 }
 class HomeCell: BaseView {
@@ -111,6 +116,16 @@ class HomeCell: BaseView {
             icon.image = UIImage(named: type.icon)
         }
     }
+    var enable:Bool = false{
+        didSet{
+            if enable {
+                alpha = 1
+            }
+            else{
+                alpha = 0.3
+            }
+        }
+    }
     
     override func setupViews() {
         addSubview(bgView)
@@ -155,6 +170,9 @@ class HomeCell: BaseView {
         }
     }
     @objc func tapAction(){
+        if !App.shared.deviceValid {
+            return
+        }
         switch type {
         case .fileRecord:
             App.shared.goToPage(FieldRecordingVC())
index 655a7d1..a940d84 100644 (file)
@@ -14,6 +14,17 @@ class HomeHeadView: BaseView {
     let titleLabel = UILabel()
     let valueLabel = UILabel()
     
+    var enable:Bool = false{
+        didSet{
+            if enable {
+                bottonView.alpha = 1
+            }
+            else{
+                bottonView.alpha = 0.3
+            }
+        }
+    }
+    
     override func setupViews() {
         addSubviews([icon,bottonView])
         bottonView.addSubviews([titleLabel,valueLabel,tipsIcon])
@@ -39,6 +50,8 @@ class HomeHeadView: BaseView {
             v.font = .regular(14)
             v.text = "随时随地 一键开录"
         }
+        self.enable = App.shared.deviceValid
+        NotificationManager.add(self, selector: #selector(deviceChange(_:)), forName: .deviceValidChange)
     }
     
     override func setupLayout() {
@@ -66,7 +79,12 @@ class HomeHeadView: BaseView {
         }
     }
     @objc func chatAction(){
-        App.shared.goToPage(ChatVC())
+        if App.shared.deviceValid {
+            App.shared.goToPage(ChatVC())
+        }
+    }
+    @objc func deviceChange(_ noti:Notification){
+        self.enable = App.shared.deviceValid
     }
 }
 
index bacf365..ae05b9e 100644 (file)
@@ -84,9 +84,10 @@ extension TextTranlateVC:UITableViewDelegate,UITableViewDataSource {
 }
 extension TextTranlateVC:SendToolBarDelegate{
     func sendToolBar(_ toolBar: SendToolBar, _ text: String) {
-//        toolBar.textField.resignFirstResponder()
+        toolBar.textField.resignFirstResponder()
         dataList.append(TranslateCellModel(send: text,response: ""))
         refreshData()
+        toolBar.textField.text = ""
         
         let from = languageItem.leftLabel.language.value
         let to = languageItem.rightLabel.language.value
similarity index 99%
rename from ShenYin/ShenYin/AppLaunch.swift
rename to ShenYin/ShenYin/UI/Launch/AppLaunch.swift
index d021252..50f4af0 100644 (file)
@@ -8,7 +8,6 @@
 import UIKit
 import IQKeyboardManagerSwift
 
-
 class AppLaunch:NSObject{
     @MainActor static func start(){
         JoySdkManager.shared.setupSdk()
similarity index 93%
rename from ShenYin/ShenYin/UI/common/AppManager.swift
rename to ShenYin/ShenYin/UI/Launch/AppManager.swift
index 9edb7d6..f06e6f1 100644 (file)
@@ -9,7 +9,6 @@ class App{
     static let shared = App()
     var window:UIWindow?
     
-    
     func topVC()->UIViewController!{
         guard let vc = window?.rootViewController else{
             Logger.debug("页面异常!!!")
@@ -42,3 +41,9 @@ extension App{
         }
     }
 }
+
+extension App{
+    var deviceValid:Bool{
+        return BleManager.shared.isConnetd
+    }
+}
similarity index 96%
rename from ShenYin/ShenYin/Ble/BleManager.swift
rename to ShenYin/ShenYin/UI/Launch/BleManager.swift
index 2d28d4c..6f3c078 100644 (file)
@@ -25,6 +25,7 @@ class BleManager: NSObject {
     }
     
     static let shared = BleManager()
+    var isConnetd:Bool = false
     
     func setupJoySdk(){
         JoyGemAIManager.shared().delegate = self;
@@ -84,7 +85,10 @@ extension BleManager:CBCentralManagerDelegate{
     }
     func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
         Logger.debug("蓝牙已断开 \(peripheral)")
+        self.isConnetd = false
+        NotificationManager.post(type: .deviceValidChange, objtect: nil)
         disConnectDeviceCallback?(peripheral)
+        checkConnect()
     }
 }
 
@@ -102,7 +106,6 @@ extension BleManager: CBPeripheralDelegate {
     }
     
     func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
-        //MARK: 需要配置服务对象
         if (service.uuid.uuidString == kJoyGemAIServiceUUID) {
             let success = JoyGemAIManager.shared().configService(service) { chars in
                 for char in chars {
@@ -121,6 +124,7 @@ extension BleManager: CBPeripheralDelegate {
             //MARK: 使能成功时需要
             Logger.debug("特征使能成功")
             JoyGemAIManager.shared().bleConnected()
+
         }
     }
     
@@ -177,7 +181,6 @@ extension BleManager{
     func connectPeripheral(_ peripheral: CBPeripheral) {
         Logger.debug("连接中...")
         centralManager.connect(peripheral, options: [CBConnectPeripheralOptionEnableTransportBridgingKey:true])
-        YLprogressHUD.showLoading()
     }
     
     func cancel() {
@@ -193,6 +196,8 @@ extension BleManager : JoyGemAIManagerDelegate {
     }
     
     func joyGemAuthSuccessCallback() {
+        self.isConnetd = true
+        NotificationManager.post(type: .deviceValidChange, objtect: nil)
         ConnectPopView().showAutoHide {
             App.shared.enter()
         }
index e96c8f2..faf8df4 100644 (file)
@@ -6,22 +6,22 @@
 //
 
 class BrokenLineView: UIView {
-    override func draw(_ rect: CGRect) {
-        super.draw(rect)
-        let path = UIBezierPath()
-        let lineWidth: CGFloat = 0.5
-        let dashLength: CGFloat = 5.0
-        let spaceLength: CGFloat = 3.0
-        let startPoint = CGPoint(x: 0, y: bounds.midY)
-        let endPoint = CGPoint(x: bounds.width, y: bounds.midY)
-        path.move(to: startPoint)
-        path.addLine(to: endPoint)
-        let shapeLayer = CAShapeLayer()
-        shapeLayer.path = path.cgPath
-        shapeLayer.strokeColor = UIColor.hexString("#93C6EC").cgColor
-        shapeLayer.fillColor = UIColor.clear.cgColor
-        shapeLayer.lineWidth = lineWidth
-        shapeLayer.lineDashPattern = [NSNumber(value: dashLength), NSNumber(value: spaceLength)]
-        layer.addSublayer(shapeLayer)
-    }
+//    override func draw(_ rect: CGRect) {
+//        super.draw(rect)
+//        let path = UIBezierPath()
+//        let lineWidth: CGFloat = 0.5
+//        let dashLength: CGFloat = 5.0
+//        let spaceLength: CGFloat = 3.0
+//        let startPoint = CGPoint(x: 0, y: bounds.midY)
+//        let endPoint = CGPoint(x: bounds.width, y: bounds.midY)
+//        path.move(to: startPoint)
+//        path.addLine(to: endPoint)
+//        let shapeLayer = CAShapeLayer()
+//        shapeLayer.path = path.cgPath
+//        shapeLayer.strokeColor = UIColor.hexString("#93C6EC").cgColor
+//        shapeLayer.fillColor = UIColor.clear.cgColor
+//        shapeLayer.lineWidth = lineWidth
+//        shapeLayer.lineDashPattern = [NSNumber(value: dashLength), NSNumber(value: spaceLength)]
+//        layer.addSublayer(shapeLayer)
+//    }
 }
index 8bec230..7565b2b 100644 (file)
@@ -26,7 +26,7 @@ class LoadingButton:UIButton{
         loading = true
         activeView.backgroundColor = .hexString("#F7F7F7")
         activeView.startAnimating()
-        DispatchQueue.main.asyncAfter(deadline:.now() + 3) {
+        DispatchQueue.main.asyncAfter(deadline:.now() + 2) {
             self.stopAnimating()
             finished?()
         }
@@ -88,29 +88,43 @@ class RecordingView: UIView {
         activeView.stopAnimating()
     }
 }
-class RecordingButton:UIButton{
-    let activeView = DGActivityIndicatorView(type: .lineScalePulseOut,tintColor: UIColor.hexString("#0092E1"))!
+class DialogRecordingButton:UIButton{
+    let activeView = DGActivityIndicatorView(type: .lineScalePulseOut,tintColor: UIColor.hexString("#919191"),size: 20)!
+    let loadView = DGActivityIndicatorView(type: .ballClipRotate,tintColor: UIColor.hexString("#919191"))!
     
     override init(frame: CGRect) {
         super.init(frame: frame)
         activeView.backgroundColor = .hexString("#F7F7F7")
+        activeView.yc.setBorder(width: 2, color: .hexString("#919191"), radius: 17)
         addSubview(activeView)
         activeView.snp.remakeConstraints { make in
             make.edges.equalToSuperview()
         }
+        
+        addSubview(loadView)
+        loadView.snp.remakeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        loadView.backgroundColor = .hexString("#F7F7F7")
     }
     
     required init?(coder: NSCoder) {
         fatalError("init(coder:) has not been implemented")
     }
     func startAnimating(finished:(()->Void)? = nil){
+        loadView.isHidden = true
+        activeView.isHidden = false
         activeView.startAnimating()
-//        DispatchQueue.main.asyncAfter(deadline:.now() + 3) {
-//            self.stopAnimating()
-//            finished?()
-//        }
     }
-    func stopAnimating(){
+    func stopAnimating(finished:@escaping (()->Void)){
         activeView.stopAnimating()
+        activeView.isHidden = true
+
+        loadView.isHidden = false
+        loadView.startAnimating()
+        DispatchQueue.main.asyncAfter(deadline:.now() + 2) { [weak self] in
+            self?.loadView.stopAnimating()
+            finished()
+        }
     }
 }
diff --git a/ShenYin/ShenYin/UI/common/NotificationManager.swift b/ShenYin/ShenYin/UI/common/NotificationManager.swift
new file mode 100644 (file)
index 0000000..50771da
--- /dev/null
@@ -0,0 +1,38 @@
+//
+//  Untitled.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/26.
+//
+
+import Foundation
+
+enum NotificationType:String{
+    case deviceValidChange
+    
+    var value:String{
+        switch self {
+        case .deviceValidChange:
+            return "deviceValidChange"
+        default:
+            return "unknown"
+        }
+    }
+}
+
+
+class NotificationManager {
+    static func add(_ observer: Any, selector aSelector: Selector, forName name: NotificationType) {
+        NotificationCenter.default.addObserver(observer, selector: aSelector, name:  Notification.Name(name.value), object: nil)
+    }
+    
+    static func post(type:NotificationType,objtect:Any?){
+        NotificationCenter.default.post(name: Notification.Name(type.value), object: objtect, userInfo:nil)
+    }
+
+    @objc func handleNotification(_ notification: Notification) {
+        if let data = notification.userInfo?["data"] as? String {
+            print("Received data: \(data)")
+        }
+    }
+}