完善对话
authorliangzhenying <867174124@qq.com>
Fri, 19 Sep 2025 10:14:39 +0000 (18:14 +0800)
committerliangzhenying <867174124@qq.com>
Fri, 19 Sep 2025 10:14:39 +0000 (18:14 +0800)
38 files changed:
ShenYin/Podfile.lock
ShenYin/ShenYin.xcodeproj/project.pbxproj
ShenYin/ShenYin/Api/HttpClient.swift
ShenYin/ShenYin/Api/ResponseBaseModel.swift
ShenYin/ShenYin/AppLaunch.swift
ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Group_2437@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Group_2437@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Group_2435@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Group_2435@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.imageset/分屏_2@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.imageset/分屏_2@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Ble/BleManager.swift
ShenYin/ShenYin/SceneDelegate.swift
ShenYin/ShenYin/UI/Base/BaseNC.swift
ShenYin/ShenYin/UI/Base/BaseVC.swift
ShenYin/ShenYin/UI/Home/CallingRecordVC.swift
ShenYin/ShenYin/UI/Home/Chat/ChatVC.swift
ShenYin/ShenYin/UI/Home/Chinese2English/Chinese2EnglishVC.swift
ShenYin/ShenYin/UI/Home/Dialog/DialogRecordBar.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Home/Dialog/DialogTranlateVC.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Home/Dialog/DialogTranslateCell.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Home/FieldRecording/FieldRecordBar.swift
ShenYin/ShenYin/UI/Home/FieldRecording/FieldRecordingVC.swift
ShenYin/ShenYin/UI/Home/FieldRecording/RecordBar.swift
ShenYin/ShenYin/UI/Home/RecordDetail/RecordDetailVC.swift
ShenYin/ShenYin/UI/Home/RecordTranslateVC.swift
ShenYin/ShenYin/UI/Home/Root/HomeFunctionView.swift
ShenYin/ShenYin/UI/Home/TextTranslate/TextTranslateVC.swift
ShenYin/ShenYin/UI/Mine/Login/ViewModel/LoginVM.swift
ShenYin/ShenYin/UI/common/CustomAlert.swift
ShenYin/ShenYin/UI/common/LoadingButton.swift
ShenYin/ShenYin/UI/common/PlaceHolderTextView.swift
ShenYin/ShenYin/UI/common/ScrollView+Bottom.swift [new file with mode: 0644]
ShenYin/podfile
document/JOYGEM_AI_IOS_V1.0.19/JoyGemAIDemo-swift/JoyGemAIDemo/DialogueViewController.swift

index 3e86ec9..7cb6391 100644 (file)
@@ -71,7 +71,6 @@ PODS:
     - TZImagePickerController/Location (= 3.8.9)
   - TZImagePickerController/Basic (3.8.9)
   - TZImagePickerController/Location (3.8.9)
-  - TZScrollViewPopGesture (1.0.6)
   - YYModel (1.0.4)
   - YYText (1.0.7)
 
@@ -95,7 +94,6 @@ DEPENDENCIES:
   - swiftScan
   - TabPageViewController
   - TZImagePickerController
-  - TZScrollViewPopGesture
   - YYModel
   - YYText
 
@@ -129,7 +127,6 @@ SPEC REPOS:
     - swiftScan
     - TabPageViewController
     - TZImagePickerController
-    - TZScrollViewPopGesture
     - YYModel
     - YYText
 
@@ -162,10 +159,9 @@ SPEC CHECKSUMS:
   swiftScan: 0849e7d7c1c641384767a573ee8cb90b88d1ddd9
   TabPageViewController: 8bd4104909754416b35a98f3b72a5b674ab20dd5
   TZImagePickerController: 456f470b5dea97b37226ec7a694994a8663340b2
-  TZScrollViewPopGesture: d36355038259e89372a1f4a2db7e9ca675de2278
   YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
   YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
 
-PODFILE CHECKSUM: bc7d3a8004029604d5620b967136223e19d8a67d
+PODFILE CHECKSUM: 57796390fdd051e53f61c569309d2caa20f804e9
 
 COCOAPODS: 1.16.2
index 229bec3..aeed467 100644 (file)
                        );
                        mainGroup = 3F887B932E38D8DC00C98658;
                        minimizedProjectReferenceProxies = 1;
-                       packageReferences = (
-                       );
                        preferredProjectObjectVersion = 77;
                        productRefGroup = 3F887B9D2E38D8DC00C98658 /* Products */;
                        projectDirPath = "";
index 41cef86..3d88d08 100644 (file)
@@ -12,7 +12,8 @@ import HandyJSON
 // 相关api
 enum CommomApi
 {
-    case sms(phone:String)
+    case sms(phone:String,type:SmsType)
+    case countryList
     case list(pageNO: Int = 1, pageSize: Int = 10)
     case login(phone:String,code:String)
 }
@@ -23,14 +24,17 @@ extension CommomApi: TargetType
     // url
     var baseURL: URL
     {
-        return URL(string: "https://app-api.raisound.com")!
+//        return URL(string: "https://app-api.raisound.com")!
+        return URL(string: "https://app-api.deepchords.com")!
     }
 
     /// 请求路径
     var path: String {
         switch self {
-        case .sms(let phone):
-            return "/sys/sms/reg-login/\(phone)"
+        case .sms(let phone,let type):
+            return "/uc/sms"
+        case .countryList:
+            return "/uc/country/list"
         case .list:
             return "list"
         case .login(_,_):
@@ -41,7 +45,7 @@ extension CommomApi: TargetType
     /// 请求方式
     var method: Moya.Method {
         switch self {
-        case .sms(_):
+        case .sms(_,_):
             return .get
         case .login(_,_):
             return .post
@@ -62,6 +66,9 @@ extension CommomApi: TargetType
         
         // 收集参数
         switch self {
+        case let .sms(phone, type):
+            params["phone"] = phone
+            params["type"] = type
         case let .list(pageNO, pageSize):
             params["pageNO"] = pageNO
             params["pageSize"] = pageSize
index a56f0d2..e887c13 100644 (file)
@@ -11,7 +11,6 @@ public class ResponseBaseModel: HandyJSON {
     required public init() { }
 
     public var code = -1
-    public var status = 0
     public var msg = "请求失败"
     
 
index 1fa4370..d021252 100644 (file)
@@ -27,10 +27,10 @@ class AppLaunch:NSObject{
     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()
-//        }
+        if list.count > 0 {
+            CacheManager.shared.currentDevice = list.first
+            BleManager.shared.startScanDevice()
+            App.shared.enter()
+        }
     }
 }
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Contents.json
new file mode 100644 (file)
index 0000000..6d169ae
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Group_2437@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Group_2437@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Group_2437@2x.png b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Group_2437@2x.png
new file mode 100644 (file)
index 0000000..275aaab
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Group_2437@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Group_2437@3x.png b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Group_2437@3x.png
new file mode 100644 (file)
index 0000000..752bfa3
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_ear.imageset/Group_2437@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Contents.json
new file mode 100644 (file)
index 0000000..b7db985
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Group_2435@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Group_2435@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Group_2435@2x.png b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Group_2435@2x.png
new file mode 100644 (file)
index 0000000..1fe725e
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Group_2435@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Group_2435@3x.png b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Group_2435@3x.png
new file mode 100644 (file)
index 0000000..62a8eab
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/home/dialog_device_phone.imageset/Group_2435@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.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_1.imageset/分屏_2@2x.png b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.imageset/分屏_2@2x.png
new file mode 100644 (file)
index 0000000..e647e2e
Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.imageset/\345\210\206\345\261\217_2@2x.png" differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.imageset/分屏_2@3x.png b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.imageset/分屏_2@3x.png
new file mode 100644 (file)
index 0000000..e947155
Binary files /dev/null and "b/ShenYin/ShenYin/Assets.xcassets/home/split_screen_1.imageset/\345\210\206\345\261\217_2@3x.png" differ
index 88d6639..2d28d4c 100644 (file)
@@ -226,6 +226,7 @@ extension BleManager : JoyGemAIManagerDelegate {
 }
 extension BleManager : JoyGemAIManagerDataSource {
     func joyGemSend(_ data: Data, with characteristic: CBCharacteristic) {
+//        print("发送",data.map { String($0) }.joined(separator: ""))
         if let connectPeripheral = connectPeripheral{
             connectPeripheral.writeValue(data, for: characteristic, type:.withoutResponse)
         }
index cdba428..d49cccf 100644 (file)
@@ -20,7 +20,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
         
         App.shared.window = window
         window?.rootViewController = BaseTC()
-        window?.rootViewController = UINavigationController(rootViewController: RecordTranslateVC())
+//        window?.rootViewController = UINavigationController(rootViewController: DialogTranslateVC())
         AppLaunch.start()
     }
 
index 22ca3c8..8ad6814 100644 (file)
@@ -6,11 +6,16 @@
 //
 
 import UIKit
+import FDFullscreenPopGesture
 
-class BaseNC:UINavigationController{
+class BaseNC: UINavigationController {
+    override init(rootViewController: UIViewController) {
+        super.init(rootViewController: rootViewController)
+        fd_fullscreenPopGestureRecognizer?.isEnabled = true
+    }
     
-    override func viewDidLoad() {
-        super.viewDidLoad()
-        
+    required init?(coder aDecoder: NSCoder) {
+        super.init(coder: aDecoder)
+        fd_fullscreenPopGestureRecognizer?.isEnabled = true
     }
 }
index da69642..ae612d9 100644 (file)
@@ -8,7 +8,7 @@
 import UIKit
 import Kingfisher
 
-open class BaseVC:UIViewController, UIGestureRecognizerDelegate {
+open class BaseVC:UIViewController {
     
     let logBtn = UIButton(type: .custom)
     let navBar = BaseNavigationBar()
index 40e4993..d27735f 100644 (file)
@@ -14,7 +14,7 @@ class CallingRecordVC:BaseVC{
     let rhythView = RhythView()
     var messageList : [(String,UInt)] = []
     var recordFilePath : String?
-    
+
     
     override func viewDidLoad() {
         super.viewDidLoad()
@@ -25,6 +25,7 @@ class CallingRecordVC:BaseVC{
         toolBar.hasRightItem = false
         
         textView.do { v in
+            v.backgroundColor = .hexString("#F7F7F7")
             v.isEditable = false
             v.font = .regular(14)
             v.text = ""
@@ -53,10 +54,32 @@ class CallingRecordVC:BaseVC{
     }
     override func setupData() {
         JoyGemCallManager.shared().delegate = self
-//        JoyGemCallManager.shared().stereoDelegate = self//双声道
     }
-    func scrollToBottom(){
-        
+
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = false
+    }
+    override func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+        navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = true
+    }
+    override func navleftViewTapped() {
+        if toolBar.recordBtn.isSelected {
+            CustomAlert.showWith(title: "提示", messgage: "当前正在录音,确定放弃当前录音吗?", cancelCallback: nil) {
+                JoyGemCallManager.shared().stop()
+                PcmSound.sharedInstance().stopAudioUnit()
+                PcmSound.sharedInstance().cleanup()
+                super.navleftViewTapped()
+            }
+        }
+        else{
+            super.navleftViewTapped()
+        }
+    }
+    func refreshData(){
+        let range = NSMakeRange(textView.text.count - 1, 1)
+        textView.scrollRangeToVisible(range)
     }
     ///播放最后一次录音文件
     @objc func playRecord() {
@@ -86,9 +109,9 @@ extension CallingRecordVC:FieldRecordBarDelegate{
         }
         else if state == .stop{
             JoyGemCallManager.shared().stop()
-            bar.recordBtn.startAnimating {[weak self] in
+            bar.startAnimating {[weak self] in
                 guard let self = self else{return}
-                //                toolBar.recordBtn.stopCli()
+                //toolBar.recordBtn.stopCli()
                 let v = PopTextField()
                 v.show()
                 v.cancelTap = {
@@ -105,15 +128,15 @@ extension CallingRecordVC : JoyGemCallManagerDelegate {
     
     func callManagerStopped(_ manager: JoyGemCallManager, reason code: JoyGemRecordStopCode) {
         if (code == .actively) {
-            YLprogressHUD.showAutoHiden( "用户主动结束")
+            Logger.debug( "用户主动结束")
         } else {
-            YLprogressHUD.showAutoHiden( "自动结束")
-            ///判断当前蓝牙是否连接从而确定是否因为蓝牙断开造成的录音断开
+            Logger.debug( "自动结束")
+            toolBar.recordBtn.isSelected = false
         }
     }
     
     func callManagerNotonCall(_ manager: JoyGemCallManager) {
-        YLprogressHUD.showAutoHiden("未处于通话状态")
+        Logger.debug("未处于通话状态")
     }
     
     func callManager(_ manager: JoyGemCallManager, saveFile path: String) {
@@ -122,7 +145,7 @@ extension CallingRecordVC : JoyGemCallManagerDelegate {
     }
     
     func callManager(_ manager: JoyGemCallManager, stateChange code: JoyGemStateCode) {
-        debugPrint("code: \(code)")
+        Logger.debug("code: \(code)")
     }
     
     func callManager(_ manager: JoyGemCallManager, onError code: JoyGemErrorCode) {
@@ -130,7 +153,7 @@ extension CallingRecordVC : JoyGemCallManagerDelegate {
     }
     
     func callManager(_ manager: JoyGemCallManager, didUpdateAsr model: JoyGemAsrModel) {
-        debugPrint("text: \(model.text),index: \(model.index)")
+        Logger.debug("text: \(model.text),index: \(model.index)")
         let msg = messageList.firstIndex (where: { (str,idx) in
             return idx == model.index;
         })
@@ -143,6 +166,7 @@ extension CallingRecordVC : JoyGemCallManagerDelegate {
         textView.text = messageList.compactMap({ (str,idx) in
             return str
         }).joined(separator: "\n")
+        refreshData()
     }
     
 }
index 1534d1e..f271ff9 100644 (file)
@@ -20,6 +20,8 @@ class ChatVC:BaseVC{
     var isTtsPlaying = false
     
     deinit {
+        PcmSound.sharedInstance().stopAudioUnit()
+        PcmSound.sharedInstance().cleanup()
         JoyGemChatManager.shared().removeObserver(self, forKeyPath: "isActive")
     }
     
@@ -116,7 +118,8 @@ class ChatVC:BaseVC{
         }
         App.shared.goToPage(vc)
     }
-    func scrollToBottom(){
+    func refreshData(){
+        tableView.reloadData()
         if dataList.count > 0 {
             tableView.scrollToRow(at: IndexPath(row: dataList.count - 1, section: 0), at: .none, animated: true)
         }
@@ -140,8 +143,7 @@ extension ChatVC:ChatRecordBarDelegate{
         model.content = ""
         model.id = -1
         dataList.append(model)
-        tableView.reloadData()
-        scrollToBottom()
+        refreshData()
         
         JoyGemChatManager.shared().stopChat()
         JoyGemChatManager.shared().startSingleChat()
@@ -231,8 +233,7 @@ extension ChatVC : JoyGemChatManagerDelegate {
             model.id = Int(index)
             dataList.append(model)
         }
-        tableView.reloadData()
-        scrollToBottom()
+        refreshData()
     }
     
     func chatManager(_ manager: JoyGemChatManager, responseText text: String?, index: UInt, finish isFinish: Bool) {
@@ -249,8 +250,7 @@ extension ChatVC : JoyGemChatManagerDelegate {
                 model.id = Int(index)
                 dataList.append(model)
             }
-            tableView.reloadData()
-            scrollToBottom()
+            refreshData()
         }
     }
 }
index 14fdfae..138ff35 100644 (file)
@@ -13,9 +13,7 @@ class Chinese2EnglishVC:BaseVC{
     let tableView = UITableView(frame: CGRectZero, style: .plain)
     var dataList:[(Chinese2EnglishCellModel,UInt)] = []
     var pcmData = Data()
-    override func viewDidLoad() {
-        super.viewDidLoad()
-    }
+
     override func setupViews() {
         navBar.title = "中英互译"
         navBar.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
@@ -54,6 +52,27 @@ class Chinese2EnglishVC:BaseVC{
 //            print(error)
 //        }
     }
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = false
+    }
+    override func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+        navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = true
+    }
+    override func navleftViewTapped() {
+        if toolBar.recordBtn.isSelected {
+            CustomAlert.showWith(title: "提示", messgage: "当前正在录音,确定放弃当前录音吗?", cancelCallback: nil) {
+                JoyGemSIDeviceManager.shared().stop()
+                PcmSound.sharedInstance().stopAudioUnit()
+                PcmSound.sharedInstance().cleanup()
+                super.navleftViewTapped()
+            }
+        }
+        else{
+            super.navleftViewTapped()
+        }
+    }
     override func navRightViewTapped() {
         let tip = RecordTipsView(type: .chinese2english)
         tip.show()
@@ -85,7 +104,7 @@ extension Chinese2EnglishVC:RecordBarDelegate{
         }
         else if state == .stop{
             JoyGemSIDeviceManager.shared().stop()
-            bar.recordBtn.startAnimating {[weak self] in
+            bar.startAnimating {[weak self] in
                 guard let self = self else{return}
                 //                toolBar.recordBtn.stopCli()
                 let v = PopTextField()
diff --git a/ShenYin/ShenYin/UI/Home/Dialog/DialogRecordBar.swift b/ShenYin/ShenYin/UI/Home/Dialog/DialogRecordBar.swift
new file mode 100644 (file)
index 0000000..fd644a5
--- /dev/null
@@ -0,0 +1,280 @@
+//
+//  DialogRecordBar.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/16.
+//
+
+enum DialogRecordDeviceType{
+    case earphone
+    case phone
+}
+enum DialogRecordDeviceState{
+    case start
+    case stop
+}
+enum DialogRecordLayoutType{
+    case normal
+    case spolit
+}
+protocol DialogRecordBarDelegate {
+    func recordBar(_ bar:DialogRecordBar,layoutChange :DialogRecordLayoutType)
+    func recordBar(_ bar:DialogRecordBar, device:DialogRecordDeviceType,stateChange state:RecordBarSate)
+}
+
+class DialogRecordBar: BaseView {
+    let switchBtn = UIButton()
+    let leftItem = RecordBarItem()
+    let rightItem = RecordBarItem()
+    var delegate:DialogRecordBarDelegate?
+    
+    override func setupViews() {
+        backgroundColor = .white
+        addSubviews([leftItem,rightItem,switchBtn])
+        
+        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)
+        }
+        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
+        }
+    }
+    
+    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))
+        }
+        rightItem.snp.makeConstraints { make in
+            make.height.equalTo(100)
+            make.centerY.equalTo(switchBtn)
+            make.left.equalToSuperview().offset(kScreenWid/2 + 60)
+        }
+    }
+    
+    func stopRecord(){
+        if leftItem.recordBtn.isSelected {
+            leftItem.recordBtn.isSelected = false
+            leftItem.stopAnimating()
+        }
+        if rightItem.recordBtn.isSelected {
+            rightItem.recordBtn.isSelected = false
+            rightItem.stopAnimating()
+        }
+        leftItem.alpha = 1
+        rightItem.alpha = 1
+    }
+
+    @objc func switchBtnAction(){
+        delegate?.recordBar(self, layoutChange: .normal)
+    }
+    
+    @objc func leftRecordBtnAction(){
+        if  rightItem.recordBtn.activeView.animating {
+            return
+        }
+        if rightItem.recordBtn.isSelected {
+            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
+            
+            leftItem.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()
+            delegate?.recordBar(self, device: .earphone,stateChange: .stop)
+        }
+
+    }
+    @objc func rightRecordBtnAction(){
+        if  leftItem.recordBtn.activeView.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
+            
+            rightItem.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()
+            delegate?.recordBar(self, device: .phone,stateChange: .stop)
+        }
+    }
+    
+    @objc func leftLanguageAction(){
+        if leftItem.recordBtn.isSelected || rightItem.recordBtn.isSelected {
+            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
+        v.show()
+        v.didSelected = {[weak self] (index,value) in
+            guard let self = self else { return  }
+            if index == 0 {
+                leftItem.language = value
+            }
+            else{
+                rightItem.language = value
+            }
+        }
+    }
+    @objc func rightLanguageAction(){
+        if leftItem.recordBtn.isSelected || rightItem.recordBtn.isSelected{
+            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
+        v.show()
+        v.didSelected = {[weak self] (index,value) in
+            guard let self = self else { return  }
+            if index == 0 {
+                leftItem.language = value
+            }
+            else{
+                rightItem.language = value
+            }
+        }
+    }
+    class RecordBarItem: UIView {
+        let recordBtn = RecordingButton()
+        let languageItem = RecordLanguageItem()
+        
+        var language:AiSupportLanguage = AiSupportLanguage.chinse{
+            didSet{
+                languageItem.language = language
+            }
+        }
+        
+        func startAnimating(){
+            recordBtn.startAnimating()
+        }
+        func stopAnimating(){
+            recordBtn.stopAnimating()
+        }
+
+        override init(frame: CGRect) {
+            super.init(frame: frame)
+            setupViews()
+            setupLayout()
+        }
+        
+        @MainActor required init?(coder: NSCoder) {
+            fatalError("init(coder:) has not been implemented")
+        }
+        
+        func setupViews() {
+//            backgroundColor = .red
+            addSubviews([recordBtn,languageItem])
+            recordBtn.do { v in
+//                v.yc.setBorder(width: 1, color: .color(.theme), radius: 17)
+            }
+        }
+        
+        func setupLayout() {
+            recordBtn.snp.makeConstraints { make in
+                make.width.equalTo(66)
+                make.height.equalTo(34)
+                make.top.equalToSuperview().inset(0)
+                make.centerX.equalToSuperview()
+            }
+            languageItem.snp.makeConstraints { make in
+                make.right.equalToSuperview()
+                make.top.equalTo(recordBtn.snp.bottom).offset(0)
+                make.centerX.equalToSuperview()
+            }
+
+        }
+    }
+    class RecordLanguageItem: BaseView {
+        let icon = UIImageView()
+        let titleLabel = UILabel()
+        let valueLabel = UILabel()
+        
+        var language:AiSupportLanguage = AiSupportLanguage.chinse{
+            didSet{
+                titleLabel.text = language.title
+            }
+        }
+        
+        override func setupViews() {
+//                        backgroundColor = .green
+            addSubviews([titleLabel,valueLabel,icon])
+            icon.do { v in
+                v.image = UIImage(named: "polygon")
+            }
+            titleLabel.do { v in
+                v.textColor = .rgb(0x121212)
+                v.font = .bold(16)
+            }
+            valueLabel.do { v in
+                v.textColor = .rgb(0x666666)
+                v.font = .regular(10)
+                v.text = "耳机"
+            }
+        }
+        
+        override func setupLayout() {
+            icon.snp.makeConstraints { make in
+                make.size.equalTo(12)
+                make.top.equalToSuperview().inset(10)
+                make.right.equalToSuperview()
+            }
+            titleLabel.snp.makeConstraints { make in
+                make.right.equalTo(icon.snp.left).offset(-5)
+                make.centerY.equalTo(icon)
+                make.left.equalToSuperview()
+            }
+            valueLabel.snp.makeConstraints { make in
+                make.right.equalTo(titleLabel)
+                make.top.equalTo(titleLabel.snp.bottom).offset(5)
+                make.bottom.equalToSuperview().inset(10)
+            }
+        }
+    }
+}
diff --git a/ShenYin/ShenYin/UI/Home/Dialog/DialogTranlateVC.swift b/ShenYin/ShenYin/UI/Home/Dialog/DialogTranlateVC.swift
new file mode 100644 (file)
index 0000000..7f8263d
--- /dev/null
@@ -0,0 +1,341 @@
+//
+//  DialogTranslateVC.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/8/6.
+//
+
+import UIKit
+import JoyGemAI
+import AVFoundation
+class DialogTranslateVC:BaseVC{
+    let toolBar = DialogRecordBar()
+    var recordFilePath : String?
+    
+    let tableView = UITableView(frame: CGRectZero, style: .plain)
+    var dataList:[DialogTranslateCellModel] = []
+    
+    var tmpList : [(String,UInt)] = []
+    var tmpOtherList : [(String,UInt)] = []
+    var otherPcm = Data()
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+    }
+    override func setupViews() {
+        view.addSubviews([toolBar,tableView])
+        
+        navBar.title = "对话翻译"
+        navBar.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
+        
+        toolBar.do { v in
+            v.backgroundColor = .clear
+            v.delegate = self
+        }
+        view.backgroundColor = .hexString("#F7F7F7")
+        
+        tableView.do { v in
+            v.backgroundColor = .hexString("#F7F7F7")
+            v.delegate = self
+            v.dataSource = self
+            v.estimatedRowHeight = 60
+            v.separatorStyle = .none
+            v.register(DialogTranslateCell.self, forCellReuseIdentifier: DialogTranslateCell.reuseID)
+        }
+    }
+    override func setupLayout() {
+        toolBar.snp.makeConstraints { make in
+            make.width.centerX.equalToSuperview()
+            make.height.equalTo(120)
+            make.bottom.equalToSuperview().inset(20)
+        }
+        tableView.snp.makeConstraints { make in
+            make.top.equalToSuperview().inset(kNavBtm)
+            make.left.equalToSuperview()
+            make.width.equalTo(kScreenWid)
+            make.bottom.equalTo(toolBar.snp.top)
+        }
+    }
+    override func setupData() {
+
+        JoyGemSIManager.shared().delegate = self
+        JoyGemSIDeviceManager.shared().delegate = self
+        
+        PcmSound.sharedInstance().delegate = self;
+        PcmSound.sharedInstance().setup(16000, withchannels: 1)
+        do {
+            try AVAudioSession.sharedInstance().setActive(true)
+        } catch {
+            print(error)
+        }
+        PcmSound.sharedInstance().setup(16000, withchannels: 1)
+    }
+    override func navRightViewTapped() {
+        let tip = RecordTipsView(type: .tongchuan)
+        tip.show()
+    }
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = false
+    }
+    override func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+        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()
+        }
+    }
+    
+    func refreshData(){
+        tableView.reloadData()
+        if dataList.count > 0 {
+            tableView.scrollToRow(at: IndexPath(row: dataList.count - 1, section: 0), at: .none, animated: true)
+        }
+    }
+}
+
+extension DialogTranslateVC:UITableViewDelegate,UITableViewDataSource {
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+        return dataList.count
+    }
+    
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+        let cell = DialogTranslateCell.cell(withTableView: tableView, indexPath: indexPath)
+        cell.data = dataList[indexPath.row]
+        return cell
+    }
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        
+    }
+}
+
+extension DialogTranslateVC:DialogRecordBarDelegate{
+    func recordBar(_ bar: DialogRecordBar, layoutChange: DialogRecordLayoutType) {
+        
+    }
+    
+    func recordBar(_ bar: DialogRecordBar, device: DialogRecordDeviceType, stateChange state: RecordBarSate) {
+        if device == .earphone {
+            if state == .start {
+                startEarRecord()
+            }
+            else{
+                stopEarRecord()
+            }
+        }
+        else if device == .phone{
+            if state == .start {
+                startPhoneRecord()
+            }
+            
+            else{
+                stopPhoneRecord()
+            }
+        }
+    }
+    @objc func startPhoneRecord() {
+        tmpList.removeAll()
+        tmpOtherList.removeAll()
+        let model = DialogTranslateCellModel()
+        model.isPhone = true
+        dataList.append(model)
+        refreshData()
+        
+        JoyGemSIManager.shared().originalLanguage = toolBar.rightItem.language.value
+        JoyGemSIManager.shared().targetLanguage = toolBar.leftItem.language.value
+        JoyGemSIManager.shared().start()
+    }
+    
+    @objc func stopPhoneRecord() {
+        JoyGemSIManager.shared().stop()
+    }
+    
+    @objc func startEarRecord() {
+        tmpList.removeAll()
+        tmpOtherList.removeAll()
+        let model = DialogTranslateCellModel()
+        model.isPhone = false
+        dataList.append(model)
+        refreshData()
+        
+        JoyGemSIDeviceManager.shared().originalLanguage = toolBar.leftItem.language.value
+        JoyGemSIDeviceManager.shared().targetLanguage = toolBar.rightItem.language.value
+        JoyGemSIDeviceManager.shared().start()
+        otherPcm = Data()
+        do {
+            try AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: [.defaultToSpeaker])
+            try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
+        } catch {
+            print(error)
+        }
+    }
+    
+    @objc func stopEarRecord() {
+        JoyGemSIDeviceManager.shared().stop()
+    }
+}
+
+extension DialogTranslateVC : JoyGemSIManagerDelegate {
+    func siManagerStopped(_ manager: JoyGemSIManager, reason code: JoyGemRecordStopCode) {
+        
+    }
+    
+    func siManager(_ manager: JoyGemSIManager, didUpdateRaw model: JoyGemAsrModel) {
+        let msg = tmpList.firstIndex (where: { (str,idx) in
+            return idx == model.index;
+        })
+        if (msg == nil) {
+            tmpList.append((model.text,model.index))
+        } else {
+            tmpList[msg!] = (model.text,model.index)
+        }
+        
+        ///监听到一句话结束,自动结束当前录音
+        if (model.definite == true) {
+            stopPhoneRecord()
+        }
+        
+        guard let model = dataList.last else {
+            return
+        }
+        
+        model.send = tmpList.compactMap({ (str,idx) in
+            return str
+        }).joined(separator: "\n")
+        refreshData()
+    }
+    
+    func siManager(_ manager: JoyGemSIManager, didUpdateTranslate model: JoyGemAsrModel) {
+        let msg = tmpOtherList.firstIndex (where: { (str,idx) in
+            return idx == model.index;
+        })
+        if (msg == nil) {
+            tmpOtherList.append((model.text,model.index))
+        } else {
+            tmpOtherList[msg!] = (model.text,model.index)
+        }
+        
+        guard let model = dataList.last else {
+            return
+        }
+        
+        model.response = tmpOtherList.compactMap({ (str,idx) in
+            return str
+        }).joined(separator: "\n")
+        refreshData()
+    }
+    
+    func siManager(_ manager: JoyGemSIManager, saveFile path: String) {
+        
+    }
+    
+    
+    func siManager(_ manager: JoyGemSIManager, stateChange code: JoyGemStateCode) {
+        
+    }
+    
+    func siManagerStopped(_ manager: JoyGemSIManager) {
+        
+    }
+    
+    func siManager(_ manager: JoyGemSIManager, didUpdateAudioData data: Data) {
+        PcmSound.sharedInstance().feed(data)
+    }
+    
+    func siManager(_ manager: JoyGemSIManager, onError code: JoyGemErrorCode) {
+        
+    }
+}
+
+extension DialogTranslateVC : JoyGemSIDeviceManagerDelegate {
+    
+    func siDeviceManagerStopped(_ manager: JoyGemSIDeviceManager, reason code: JoyGemRecordStopCode) {
+        
+    }
+    
+    func siDeviceManager(_ manager: JoyGemSIDeviceManager, didUpdateRaw model: JoyGemAsrModel) {
+        debugPrint("text: \(model.text),index: \(model.index)")
+        let msg = tmpList.firstIndex (where: { (str,idx) in
+            return idx == model.index;
+        })
+        if (msg == nil) {
+            tmpList.append((model.text,model.index))
+        } else {
+            tmpList[msg!] = (model.text,model.index)
+        }
+        
+        ///监听到一句话结束,自动结束当前录音
+        if (model.definite == true) {
+            stopEarRecord()
+        }
+        
+        guard let model = dataList.last else {
+            return
+        }
+        
+        model.send = tmpList.compactMap({ (str,idx) in
+            return str
+        }).joined(separator: "\n")
+        refreshData()
+    }
+    
+    func siDeviceManager(_ manager: JoyGemSIDeviceManager, didUpdateTranslate model: JoyGemAsrModel) {
+        let msg = tmpOtherList.firstIndex (where: { (str,idx) in
+            return idx == model.index;
+        })
+        if (msg == nil) {
+            tmpOtherList.append((model.text,model.index))
+        } else {
+            tmpOtherList[msg!] = (model.text,model.index)
+        }
+        
+        guard let model = dataList.last else {
+            return
+        }
+        
+        model.response = tmpOtherList.compactMap({ (str,idx) in
+            return str
+        }).joined(separator: "\n")
+        refreshData()
+    }
+    
+    func siDeviceManager(_ manager: JoyGemSIDeviceManager, didUpdateAudioData data: Data) {
+        //otherPcm.append(data)
+        PcmSound.sharedInstance().feed(data)
+    }
+    
+    func siDeviceManager(_ manager: JoyGemSIDeviceManager, update mode: JoyGemRecordMode) {
+        
+    }
+    
+    func siDeviceManager(_ manager: JoyGemSIDeviceManager, saveFile path: String) {
+        debugPrint("path: \(path)")
+    }
+    
+    func siDeviceManager(_ manager: JoyGemSIDeviceManager, stateChange code: JoyGemStateCode) {
+        debugPrint("code: \(code)")
+    }
+    
+    func siDeviceManager(_ manager: JoyGemSIDeviceManager, onError code: JoyGemErrorCode) {
+        
+    }
+}
+
+
+extension DialogTranslateVC : PcmSoundDelegate {
+    
+    func remaining(_ frames: UInt) {
+        debugPrint("[frame:\(frames)]");
+    }
+}
diff --git a/ShenYin/ShenYin/UI/Home/Dialog/DialogTranslateCell.swift b/ShenYin/ShenYin/UI/Home/Dialog/DialogTranslateCell.swift
new file mode 100644 (file)
index 0000000..952387e
--- /dev/null
@@ -0,0 +1,142 @@
+//
+//  DialogTranslateCell.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/17.
+//
+
+class DialogTranslateCellModel{
+    var send = ""
+    var response = ""
+    var isPhone : Bool = false //是否手机收音
+    
+    init(send: String = "", response: String = "") {
+        self.send = send
+        self.response = response
+    }
+}
+
+
+
+
+class DialogTranslateCell:BaseTableViewCell{
+    let bgView = UIView()
+    let line = BrokenLineView()
+    let originalLabel = UILabel()
+    let translationLabel = 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("#606D80")
+            v.numberOfLines = 0
+            v.textAlignment = .left
+        }
+        translationLabel.do { v in
+            v.font = .regular(14)
+            v.textColor = .hexString("#121212")
+            v.numberOfLines = 0
+            v.textAlignment = .left
+        }
+        line.do { v in
+            //            v.backgroundColor = .hexString("#93C6EC")
+        }
+        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,translationLabel,line,copyIcon])
+    }
+    
+    override func setupLayout() {
+        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)
+        }
+        line.snp.makeConstraints { make in
+            make.left.right.equalToSuperview().inset(12)
+            make.height.equalTo(1)
+            make.top.equalTo(originalLabel.snp.bottom).offset(15)
+        }
+        
+        translationLabel.snp.makeConstraints { make in
+            make.top.equalTo(line.snp.bottom).offset(15)
+            make.left.equalToSuperview().inset(12)
+            make.width.lessThanOrEqualTo(kScreenWid - 110)
+            make.height.greaterThanOrEqualTo(15)
+            make.bottom.equalToSuperview().inset(14)
+        }
+        copyIcon.snp.makeConstraints { make in
+            make.right.equalToSuperview().inset(12)
+            make.size.equalTo(24)
+            make.top.equalToSuperview().inset(12)
+        }
+    }
+    
+    var data:DialogTranslateCellModel!{
+        didSet{
+            originalLabel.text = data.send
+            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.backgroundColor = .color(.theme)
+                originalLabel.textColor = .white
+                translationLabel.textColor = .white
+            }
+            else{
+                bgView.backgroundColor = .white
+                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)
+//                }
+
+            }
+        }
+    }
+    @objc func copyAction(){
+        //        UIPasteboard.general.string = data.send + "\n" + data.response
+        //        YLprogressHUD.showAutoHiden("已拷贝")
+        if copyIcon.isAnimating {
+            copyIcon.stopAnimating()
+        }
+        else{
+            copyIcon.startAnimating()
+        }
+    }
+}
index bc6c279..fc0689c 100644 (file)
@@ -19,7 +19,7 @@ protocol FieldRecordBarDelegate {
 
 
 class FieldRecordBar: BaseView {
-    let recordBtn = LoadingButton()
+     let recordBtn = LoadingButton()
     let leftItem = RecordBarItem()
     let rightItem = RecordBarButton()
     var state:RecordSate = .stop
@@ -27,7 +27,7 @@ class FieldRecordBar: BaseView {
     var hasRightItem:Bool = true
     
     override func setupViews() {
-        backgroundColor = .white
+        backgroundColor = .hexString("#F7F7F7")
         addSubviews([leftItem,rightItem,recordBtn])
         
         recordBtn.do { v in
@@ -61,8 +61,18 @@ class FieldRecordBar: BaseView {
             make.left.equalToSuperview().offset(kScreenWid/2 + 60)
         }
     }
+    
+    func startAnimating(finished:(()->Void)? = nil){
+        leftItem.alpha = 0.3
+        recordBtn.startAnimating {[weak self] in
+            guard let self = self else{return}
+            leftItem.alpha = 1
+           finished?()
+            
+        }
+    }
     @objc func leftAction(){
-        if recordBtn.isSelected {
+        if recordBtn.isSelected || recordBtn.activeView.animating {
             return
         }
         let list = AiSupportLanguage.record.map{$0.title}
@@ -78,6 +88,9 @@ class FieldRecordBar: BaseView {
         return
     }
     @objc func recordBtnAction(){
+        if recordBtn.activeView.animating {
+            return
+        }
         recordBtn.isSelected = !recordBtn.isSelected
         rightItem.state = .start
         rightItem.isHidden = !recordBtn.isSelected
index dc2c896..d8ba505 100644 (file)
@@ -15,10 +15,7 @@ class FieldRecordingVC:BaseVC{
     var messageList : [(String,UInt)] = []
     var recordFilePath : String?
     
-    
-    override func viewDidLoad() {
-        super.viewDidLoad()
-    }
+
     override func setupViews() {
         navBar.title = "现场录音"
         toolBar.delegate = self
@@ -27,6 +24,7 @@ class FieldRecordingVC:BaseVC{
             v.isEditable = false
             v.font = .regular(14)
             v.text = ""
+            v.backgroundColor = .hexString("#F7F7F7")
             v.textColor = .hexString("#121212")
             v.contentInset = UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 18)
         }
@@ -62,7 +60,30 @@ class FieldRecordingVC:BaseVC{
             Logger.debug(error)
         }
     }
+
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = false
+    }
+    override func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+        navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = true
+    }
+    override func navleftViewTapped() {
+        if toolBar.recordBtn.isSelected {
+            CustomAlert.showWith(title: "提示", messgage: "当前正在录音,确定放弃当前录音吗?", cancelCallback: nil) {
+                JoyGemRecordManager.shared().stop()
+                PcmSound.sharedInstance().stopAudioUnit()
+                PcmSound.sharedInstance().cleanup()
+                super.navleftViewTapped()
+            }
+        }
+        else{
+            super.navleftViewTapped()
+        }
+    }
     func scrollToBottom(){
+        textView.scrollRangeToVisible(NSMakeRange(textView.text.count - 1, 1))        
 
     }
 }
@@ -86,7 +107,7 @@ extension FieldRecordingVC:FieldRecordBarDelegate{
         }
         else if state == .stop{
             JoyGemRecordManager.shared().stop()
-            bar.recordBtn.startAnimating {[weak self] in
+            bar.startAnimating {[weak self] in
                 guard let self = self else{return}
 //                toolBar.recordBtn.stopCli()
                 let v = PopTextField()
index 1ffbbde..b748df4 100644 (file)
@@ -22,7 +22,7 @@ class RecordBar: BaseView {
     var delegate:RecordBarDelegate?
     
     override func setupViews() {
-        backgroundColor = .white
+        backgroundColor = .hexString("#F7F7F7")
         addSubviews([leftItem,rightItem,recordBtn])
         
         recordBtn.do { v in
@@ -57,27 +57,43 @@ class RecordBar: BaseView {
             make.left.equalToSuperview().offset(kScreenWid/2 + 60)
         }
     }
-    
+    func startAnimating(finished:(()->Void)? = nil){
+        leftItem.alpha = 0.3
+        rightItem.alpha = 0.3
+        recordBtn.startAnimating {[weak self] in
+            guard let self = self else{return}
+            leftItem.alpha = 1
+            rightItem.alpha = 1
+            finished?()
+            
+        }
+    }
     @objc func recordBtnAction(){
+        if recordBtn.activeView.animating {
+            return
+        }
         recordBtn.isSelected = !recordBtn.isSelected
         if recordBtn.isSelected {
-            delegate?.recordBar(self, stateChange: .start)
+            leftItem.alpha = 0.3
+            rightItem.alpha = 0.3
         }
         else{
-            delegate?.recordBar(self, stateChange: .stop)
+            leftItem.alpha = 1
+            rightItem.alpha = 1
         }
         
         if recordBtn.isSelected {
-            leftItem.alpha = 0.3
-            rightItem.alpha = 0.3
+            delegate?.recordBar(self, stateChange: .start)
         }
         else{
-            leftItem.alpha = 1
-            rightItem.alpha = 1
+            delegate?.recordBar(self, stateChange: .stop)
         }
     }
     
     @objc func leftAction(){
+        if recordBtn.activeView.animating {
+            return
+        }
         if recordBtn.isSelected {
             return
         }
@@ -95,6 +111,9 @@ class RecordBar: BaseView {
         }
     }
     @objc func rightAction(){
+        if recordBtn.activeView.animating {
+            return
+        }
         if recordBtn.isSelected {
             return
         }
index 479fdd5..8624305 100644 (file)
@@ -78,7 +78,8 @@ class RecordDetailVC:BaseVC{
         
     }
     func scrollToBottom(){
-        
+        let range = NSMakeRange(textView.text.count - 1, 1)
+        textView.scrollRangeToVisible(range)
     }
 }
 extension RecordDetailVC:RecordDetailTopBarDelegate{
index 86e9c8d..fc60166 100644 (file)
@@ -5,7 +5,6 @@
 //  Created by liangshi on 2025/8/6.
 //
 
-
 import UIKit
 import JoyGemAI
 import AVFoundation
@@ -17,41 +16,30 @@ class RecordTranslateVC:BaseVC{
     var translateList : [(String,UInt)] = []
     var recordFilePath : String?
     
-    override func viewDidLoad() {
-        super.viewDidLoad()
-    }
+
     override func setupViews() {
-        navBar.title = "同传听译"
-        navBar.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
         view.addSubviews([toolBar,textView,translateTextView])
         
-        toolBar.delegate = self
+        navBar.title = "同传听译"
+        navBar.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
         
-        textView.do { v in
-            v.isEditable = false
-            v.font = .regular(14)
-            v.text = ""
-            v.textColor = .hexString("#121212")
-            v.contentInset = UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 18)
+        toolBar.do { v in
+            v.backgroundColor = .clear
+            v.delegate = self
+            v.recordBtn.activeView.backgroundColor = .hexString("#F7F7F7")
         }
+        view.backgroundColor = .hexString("#F7F7F7")
+        
         textView.do { v in
-            v.isEditable = false
-            v.font = .regular(14)
-            v.text = ""
-            v.textColor = .hexString("#121212")
-            v.contentInset = UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 18)
-            v.yc.setBorder(width: 1, color: .black)
+            v.placeHolde = "此处将显示原文"
+            v.textView.textColor = .hexString("#666666")
         }
         translateTextView.do { v in
-            v.isEditable = false
-            v.font = .regular(14)
-            v.text = ""
-            v.textColor = .hexString("#121212")
-//            v.yc.addgradientLayer(colors: [.hexString("#0092E1").withAlphaComponent(0.1),.white], direction: .top2down,rect: CGRect(x: 0, y: 0, width: kScreenWid, height: (kScreenHei - kNavBtm - 120 - 10)/2))
-//            v.contentInset = UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 18)
-            v.yc.setBorder(width: 1, color: .black)
-//            v.yc.setCorners(withRoundedRect: CGRect(x: 0, y: 0, width: kScreenWid, height: (kScreenHei - kNavBtm - 120 - 10)/2), roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 20, height: 20))
-
+            v.textView.textColor = .hexString("#121212")
+            v.placeHolde = "此处将显示原文译文"
+            v.bgView.yc.addgradientLayer(colors: [.hexString("#0092E1"),.hexString("#F7F7F7")], direction: .top2down,rect: CGRect(x: 0, y: 0, width: kScreenWid, height: (kScreenHei - kNavBtm - 120 - 10)/2))
+            v.bgView.alpha = 0.1
+            v.yc.setCorners(withRoundedRect: CGRect(x: 0, y: 0, width: kScreenWid, height: (kScreenHei - kNavBtm - 120 - 10)/2), roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 20, height: 20))
         }
     }
     override func setupLayout() {
@@ -87,68 +75,84 @@ class RecordTranslateVC:BaseVC{
         let tip = RecordTipsView(type: .tongchuan)
         tip.show()
     }
-    func scrollToBottom(){
-        let range = NSMakeRange(textView.text.count - 1, 1)
-        textView.scrollRangeToVisible(range)
+
+    override func viewDidAppear(_ animated: Bool) {
+        super.viewDidAppear(animated)
+        navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = false
+    }
+    override func viewDidDisappear(_ animated: Bool) {
+        super.viewDidDisappear(animated)
+        navigationController?.fd_fullscreenPopGestureRecognizer?.isEnabled = true
+    }
+    override func navleftViewTapped() {
+        if toolBar.recordBtn.isSelected {
+            CustomAlert.showWith(title: "提示", messgage: "当前正在录音,确定放弃当前录音吗?", cancelCallback: nil) {
+                JoyGemSIDeviceManager.shared().stop()
+                PcmSound.sharedInstance().stopAudioUnit()
+                PcmSound.sharedInstance().cleanup()
+                super.navleftViewTapped()
+            }
+        }
+        else{
+            super.navleftViewTapped()
+        }
     }
 }
 
 extension RecordTranslateVC:RecordBarDelegate{
-
+    
     func recordBar(_ bar: RecordBar, stateChange state: RecordBarSate) {
-        textView.text = "123"
-        
-//        if state == .start {
-//            messageList.removeAll()
-//            translateList.removeAll()
-//            textView.text = nil
-//            translateTextView.text = nil
-//            
-//            if Thread.isMainThread {
-//                do {
-//                    try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [])
-//                    try AVAudioSession.sharedInstance().setActive(true)
-//                } catch let error as NSError {
-//                    Logger.debug("An error occurred setting the audio session category: \(error.localizedDescription)")
-//                }
-//            } else {
-//                DispatchQueue.main.sync {
-//                    do {
-//                        try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [])
-//                        try AVAudioSession.sharedInstance().setActive(true)
-//                    } catch let error as NSError {
-//                        Logger.debug("An error occurred setting the audio session category: \(error.localizedDescription)")
-//                    }
-//                }
-//            }
-//            JoyGemSIManager.shared().originalLanguage = toolBar.leftItem.language.value
-//            JoyGemSIManager.shared().targetLanguage = toolBar.rightItem.language.value
-//            JoyGemSIManager.shared().start()
-//        }
-//        else if state == .stop{
-//            JoyGemSIManager.shared().stop()
-//            bar.recordBtn.startAnimating {[weak self] in
-//                guard let self = self else{return}
-//                //                toolBar.recordBtn.stopCli()
-//                let v = PopTextField()
-//                v.show()
-//                v.cancelTap = {
-//                    
-//                }
-//                v.okTap = {
-//                    
-//                }
-//            }
-//        }
+        if state == .start {
+            messageList.removeAll()
+            translateList.removeAll()
+            textView.text = nil
+            translateTextView.text = nil
+            
+            if Thread.isMainThread {
+                do {
+                    try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [])
+                    try AVAudioSession.sharedInstance().setActive(true)
+                } catch let error as NSError {
+                    Logger.debug("An error occurred setting the audio session category: \(error.localizedDescription)")
+                }
+            } else {
+                DispatchQueue.main.sync {
+                    do {
+                        try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [])
+                        try AVAudioSession.sharedInstance().setActive(true)
+                    } catch let error as NSError {
+                        Logger.debug("An error occurred setting the audio session category: \(error.localizedDescription)")
+                    }
+                }
+            }
+            JoyGemSIManager.shared().originalLanguage = toolBar.leftItem.language.value
+            JoyGemSIManager.shared().targetLanguage = toolBar.rightItem.language.value
+            JoyGemSIManager.shared().start()
+        }
+        else if state == .stop{
+            JoyGemSIManager.shared().stop()
+            bar.startAnimating {[weak self] in
+                guard let self = self else{return}
+                //                toolBar.recordBtn.stopCli()
+                let v = PopTextField()
+                v.show()
+                v.cancelTap = {
+                    
+                }
+                v.okTap = {
+                    
+                }
+            }
+        }
     }
 }
 
 extension RecordTranslateVC : JoyGemSIManagerDelegate {
     func siManagerStopped(_ manager: JoyGemSIManager, reason code: JoyGemRecordStopCode) {
         if (code == .actively) {
-            YLprogressHUD.showAutoHiden("用户主动结束")
+//            YLprogressHUD.showAutoHiden("用户主动结束")
         } else {
-            YLprogressHUD.showAutoHiden("用户被动结束")
+            toolBar.recordBtn.isSelected = false
         }
     }
     
index 69513b0..fd4d4f6 100644 (file)
@@ -165,7 +165,7 @@ class HomeCell: BaseView {
         case .recordTranslate:
             App.shared.goToPage(RecordTranslateVC())
         case .dialogTranslate:
-            App.shared.goToPage(DialogTranlateVC())
+            App.shared.goToPage(DialogTranslateVC())
         case .textTranslate:
             App.shared.goToPage(TextTranlateVC())
         }
index 8a9417f..bacf365 100644 (file)
@@ -61,7 +61,8 @@ class TextTranlateVC:BaseVC{
             make.bottom.equalToSuperview()
         }
     }
-    func scrollToBottom(){
+    func refreshData(){
+        tableView.reloadData()
         if dataList.count > 0 {
             tableView.scrollToRow(at: IndexPath(row: dataList.count - 1, section: 0), at: .none, animated: true)
         }
@@ -85,8 +86,7 @@ extension TextTranlateVC:SendToolBarDelegate{
     func sendToolBar(_ toolBar: SendToolBar, _ text: String) {
 //        toolBar.textField.resignFirstResponder()
         dataList.append(TranslateCellModel(send: text,response: ""))
-        tableView.reloadData()
-        scrollToBottom()
+        refreshData()
         
         let from = languageItem.leftLabel.language.value
         let to = languageItem.rightLabel.language.value
@@ -95,8 +95,7 @@ extension TextTranlateVC:SendToolBarDelegate{
             guard let self = self else{return}
             if !finish{
                 dataList.last!.response = dataList.last!.response + result
-                tableView.reloadData()
-                scrollToBottom()
+                refreshData()
             }
 
         } error: { error in
index b90049f..551f367 100644 (file)
@@ -5,6 +5,27 @@
 //  Created by liangshi on 2025/7/30.
 //
 
+enum SmsType
+{
+    case reg
+    case forget
+    case update
+    case login
+    
+    var value:String{
+        switch self {
+        case .reg:
+            return "reg"
+        case .forget:
+            return "forget"
+        case .update:
+            return "update"
+        case .login:
+            return "login"
+        }
+    }
+}
+
 class LoginModel:ResponseBaseModel {
      var data:String = ""
 }
@@ -12,7 +33,7 @@ class LoginModel:ResponseBaseModel {
 
 class LoginVM:BaseVM{
     static public func sendCode(phone:String, completion:@escaping (_ result:ResponseBaseModel) ->Void) {
-        HttpClient.instance.request(CommomApi.sms(phone: phone)) { (model:ResponseBaseModel, res) in
+        HttpClient.instance.request(CommomApi.sms(phone: phone,type: .login)) { (model:ResponseBaseModel, res) in
             completion(model)
         }
     }
index 6054d7e..8e46a35 100644 (file)
@@ -8,17 +8,29 @@
 
 class CustomAlert {
     
+//    static func showWith(title:String,messgage:String,cancel:String = "取消",ok:String = "确定",cancelCallback: (()->Void)?,okCallback: (()->Void)?){
+//        let vc = UIAlertController(title: "音量警告", message: "为保护听力,请勿在佩戴耳机时使用此功能。", preferredStyle: .alert)
+//        let action0 = UIAlertAction(title: "取消", style: .cancel) { action in
+//            cancelCallback?()
+//        }
+//        let action1 = UIAlertAction(title: "播放", style: .default) { action in
+//            okCallback?()
+//        }
+//        vc.addAction(action0)
+//        vc.addAction(action1)
+//        App.shared.topVC()?.present(vc, animated: true)
+//    }
+   
     static func showWith(title:String,messgage:String,cancel:String = "取消",ok:String = "确定",cancelCallback: (()->Void)?,okCallback: (()->Void)?){
-        let vc = UIAlertController(title: "音量警告", message: "为保护听力,请勿在佩戴耳机时使用此功能。", preferredStyle: .alert)
-        let action0 = UIAlertAction(title: "取消", style: .cancel) { action in
+        let vc = UIAlertController(title: title, message: messgage, preferredStyle: .alert)
+        let action0 = UIAlertAction(title: cancel, style: .cancel) { action in
             cancelCallback?()
         }
-        let action1 = UIAlertAction(title: "播放", style: .default) { action in
+        let action1 = UIAlertAction(title: ok, style: .default) { action in
             okCallback?()
         }
         vc.addAction(action0)
         vc.addAction(action1)
         App.shared.topVC()?.present(vc, animated: true)
     }
-    
 }
index 464b106..8bec230 100644 (file)
@@ -6,14 +6,15 @@
 //
 import DGActivityIndicatorView
 import UIKit
+
 class LoadingButton:UIButton{
-    let loadingView = DGActivityIndicatorView(type: .ballClipRotate,tintColor: UIColor.hexString("#0092E1"))!
+    let activeView = DGActivityIndicatorView(type: .ballClipRotate,tintColor: UIColor.hexString("#0092E1"))!
+    var loading = false
     
     override init(frame: CGRect) {
         super.init(frame: frame)
-        loadingView.backgroundColor = .white
-        addSubview(loadingView)
-        loadingView.snp.remakeConstraints { make in
+        addSubview(activeView)
+        activeView.snp.remakeConstraints { make in
             make.edges.equalToSuperview()
         }
     }
@@ -22,14 +23,17 @@ class LoadingButton:UIButton{
         fatalError("init(coder:) has not been implemented")
     }
     func startAnimating(finished:(()->Void)? = nil){
-        loadingView.startAnimating()
+        loading = true
+        activeView.backgroundColor = .hexString("#F7F7F7")
+        activeView.startAnimating()
         DispatchQueue.main.asyncAfter(deadline:.now() + 3) {
             self.stopAnimating()
             finished?()
         }
     }
     func stopAnimating(){
-        loadingView.stopAnimating()
+        loading = false
+        activeView.stopAnimating()
     }
 }
 
@@ -58,3 +62,55 @@ class LoadingView: UIView {
         activeView.stopAnimating()
     }
 }
+class RecordingView: UIView {
+    let activeView = DGActivityIndicatorView(type: .lineScalePulseOut,tintColor: UIColor.hexString("#0092E1"))!
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        activeView.backgroundColor = .hexString("#F7F7F7")
+        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){
+        bringSubviewToFront(activeView)
+        activeView.startAnimating()
+    }
+    func stopAnimating(){
+        activeView.stopAnimating()
+    }
+}
+class RecordingButton:UIButton{
+    let activeView = DGActivityIndicatorView(type: .lineScalePulseOut,tintColor: UIColor.hexString("#0092E1"))!
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        activeView.backgroundColor = .hexString("#F7F7F7")
+        addSubview(activeView)
+        activeView.snp.remakeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    func startAnimating(finished:(()->Void)? = nil){
+        activeView.startAnimating()
+//        DispatchQueue.main.asyncAfter(deadline:.now() + 3) {
+//            self.stopAnimating()
+//            finished?()
+//        }
+    }
+    func stopAnimating(){
+        activeView.stopAnimating()
+    }
+}
index 1662bc5..8e08442 100644 (file)
@@ -13,54 +13,62 @@ extension UITextView {
     }
 }
 
-class PlaceHolderTextView: UITextView {
+class PlaceHolderTextView: BaseView {
+    let bgView = UIView()
+    let textView = UITextView()
     let label = UILabel()
     
-    var placeHolde:String = ""{
+    var placeHolde:String?{
         didSet{
             label.text = placeHolde
         }
     }
+    var text:String?{
+        didSet{
+            textView.text = text
+            if let text = text,text.isNotEmpty {
+                label.isHidden = true
+                return
+            }
+            label.isHidden = false
+        }
+    }
 
-    
-    override init(frame: CGRect, textContainer: NSTextContainer?) {
-        super.init(frame: frame, textContainer: textContainer)
-        
-        self.addObserver(self, forKeyPath: "observedText", options: [.new,.old], context: nil)
-
-        
+    override func setupViews() {
+//        yc.setBorder(width: 1, color: .black)
         label.do { v in
-            v.text = "此处将显示原文"
+            v.backgroundColor = .clear
             v.textAlignment = .center
             v.textColor = .hexString("#666666")
             v.font = .regular(16)
         }
-        addSubview(label)
+        textView.do { v in
+            v.isEditable = false
+            v.font = .regular(14)
+            v.textColor = .hexString("#121212")
+            v.backgroundColor = .clear
+            v.contentInset = UIEdgeInsets(top: 18, left: 18, bottom: 18, right: 18)
+        }
+        addSubviews([bgView])
+        addSubviews([textView,label])
+
+    }
+    override func setupLayout() {
+        bgView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
         label.snp.makeConstraints { make in
             make.center.equalToSuperview()
         }
+        textView.snp.makeConstraints { make in
+//            make.left.right.equalToSuperview().inset(18)
+//            make.top.bottom.equalToSuperview().inset(18)
+            make.edges.equalToSuperview()
+        }
     }
     
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
+    func scrollToBottom(){
+        let range = NSMakeRange(textView.text.count - 1, 1)
+        textView.scrollRangeToVisible(range)
     }
-    
-    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
-        if keyPath == "observedText", let textView = object as? UITextView {
-            if let newText = change?[.newKey] as? String {
-                Logger.debug("Text changed to: \(newText)")
-                if newText.isNotEmpty {
-                    label.isHidden = true
-                }
-                else{
-                    label.isHidden = false
-                }
-            }
-            else{
-                label.isHidden = false
-            }
-        }
-    }
-
-
 }
diff --git a/ShenYin/ShenYin/UI/common/ScrollView+Bottom.swift b/ShenYin/ShenYin/UI/common/ScrollView+Bottom.swift
new file mode 100644 (file)
index 0000000..99dd61c
--- /dev/null
@@ -0,0 +1,11 @@
+//
+//  ScrollView+Bottom.swift
+//  ShenYin
+//
+//  Created by liangshi on 2025/9/19.
+//
+
+extension UITableView {
+    
+    
+}
index fee0b8d..426028d 100644 (file)
@@ -10,7 +10,7 @@ target 'ShenYin' do
   pod 'SnapKit'#布局
   pod 'YYText'#富文本
   pod 'FDFullscreenPopGesture'#侧滑返回
-  pod 'TZScrollViewPopGesture'#侧滑返回
+#  pod 'TZScrollViewPopGesture'#侧滑返回
   pod 'IQKeyboardManagerSwift'#键盘
   pod 'MJRefresh'#刷新
   pod 'YYModel'#model解析
index 8a43f05..f34e346 100644 (file)
@@ -97,10 +97,10 @@ class DialogueViewController: UIViewController {
 //        earStopButton.addTarget(self, action: #selector(stopEarRecord), for: .touchUpInside)
         
         JoyGemSIManager.shared().originalLanguage = kJoyGemAILocalizationZH
-        JoyGemSIManager.shared().targetLanguage = kJoyGemAILocalizationJA
+        JoyGemSIManager.shared().targetLanguage = kJoyGemAILocalizationEN
         JoyGemSIManager.shared().delegate = self
         
-        JoyGemSIDeviceManager.shared().originalLanguage = kJoyGemAILocalizationJA
+        JoyGemSIDeviceManager.shared().originalLanguage = kJoyGemAILocalizationEN
         JoyGemSIDeviceManager.shared().targetLanguage = kJoyGemAILocalizationZH
         JoyGemSIDeviceManager.shared().delegate = self