- 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)
- swiftScan
- TabPageViewController
- TZImagePickerController
- - TZScrollViewPopGesture
- YYModel
- YYText
- swiftScan
- TabPageViewController
- TZImagePickerController
- - TZScrollViewPopGesture
- YYModel
- YYText
swiftScan: 0849e7d7c1c641384767a573ee8cb90b88d1ddd9
TabPageViewController: 8bd4104909754416b35a98f3b72a5b674ab20dd5
TZImagePickerController: 456f470b5dea97b37226ec7a694994a8663340b2
- TZScrollViewPopGesture: d36355038259e89372a1f4a2db7e9ca675de2278
YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
-PODFILE CHECKSUM: bc7d3a8004029604d5620b967136223e19d8a67d
+PODFILE CHECKSUM: 57796390fdd051e53f61c569309d2caa20f804e9
COCOAPODS: 1.16.2
);
mainGroup = 3F887B932E38D8DC00C98658;
minimizedProjectReferenceProxies = 1;
- packageReferences = (
- );
preferredProjectObjectVersion = 77;
productRefGroup = 3F887B9D2E38D8DC00C98658 /* Products */;
projectDirPath = "";
// 相关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)
}
// 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(_,_):
/// 请求方式
var method: Moya.Method {
switch self {
- case .sms(_):
+ case .sms(_,_):
return .get
case .login(_,_):
return .post
// 收集参数
switch self {
+ case let .sms(phone, type):
+ params["phone"] = phone
+ params["type"] = type
case let .list(pageNO, pageSize):
params["pageNO"] = pageNO
params["pageSize"] = pageSize
required public init() { }
public var code = -1
- public var status = 0
public var msg = "请求失败"
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()
+ }
}
}
--- /dev/null
+{
+ "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
+ }
+}
--- /dev/null
+{
+ "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
+ }
+}
--- /dev/null
+{
+ "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
+ }
+}
}
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)
}
App.shared.window = window
window?.rootViewController = BaseTC()
- window?.rootViewController = UINavigationController(rootViewController: RecordTranslateVC())
+// window?.rootViewController = UINavigationController(rootViewController: DialogTranslateVC())
AppLaunch.start()
}
//
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
}
}
import UIKit
import Kingfisher
-open class BaseVC:UIViewController, UIGestureRecognizerDelegate {
+open class BaseVC:UIViewController {
let logBtn = UIButton(type: .custom)
let navBar = BaseNavigationBar()
let rhythView = RhythView()
var messageList : [(String,UInt)] = []
var recordFilePath : String?
-
+
override func viewDidLoad() {
super.viewDidLoad()
toolBar.hasRightItem = false
textView.do { v in
+ v.backgroundColor = .hexString("#F7F7F7")
v.isEditable = false
v.font = .regular(14)
v.text = ""
}
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() {
}
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 = {
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) {
}
func callManager(_ manager: JoyGemCallManager, stateChange code: JoyGemStateCode) {
- debugPrint("code: \(code)")
+ Logger.debug("code: \(code)")
}
func callManager(_ manager: JoyGemCallManager, onError code: JoyGemErrorCode) {
}
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;
})
textView.text = messageList.compactMap({ (str,idx) in
return str
}).joined(separator: "\n")
+ refreshData()
}
}
var isTtsPlaying = false
deinit {
+ PcmSound.sharedInstance().stopAudioUnit()
+ PcmSound.sharedInstance().cleanup()
JoyGemChatManager.shared().removeObserver(self, forKeyPath: "isActive")
}
}
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)
}
model.content = ""
model.id = -1
dataList.append(model)
- tableView.reloadData()
- scrollToBottom()
+ refreshData()
JoyGemChatManager.shared().stopChat()
JoyGemChatManager.shared().startSingleChat()
model.id = Int(index)
dataList.append(model)
}
- tableView.reloadData()
- scrollToBottom()
+ refreshData()
}
func chatManager(_ manager: JoyGemChatManager, responseText text: String?, index: UInt, finish isFinish: Bool) {
model.id = Int(index)
dataList.append(model)
}
- tableView.reloadData()
- scrollToBottom()
+ refreshData()
}
}
}
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)
// 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()
}
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()
--- /dev/null
+//
+// 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)
+ }
+ }
+ }
+}
--- /dev/null
+//
+// 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)]");
+ }
+}
--- /dev/null
+//
+// 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()
+ }
+ }
+}
class FieldRecordBar: BaseView {
- let recordBtn = LoadingButton()
+ let recordBtn = LoadingButton()
let leftItem = RecordBarItem()
let rightItem = RecordBarButton()
var state:RecordSate = .stop
var hasRightItem:Bool = true
override func setupViews() {
- backgroundColor = .white
+ backgroundColor = .hexString("#F7F7F7")
addSubviews([leftItem,rightItem,recordBtn])
recordBtn.do { v in
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}
return
}
@objc func recordBtnAction(){
+ if recordBtn.activeView.animating {
+ return
+ }
recordBtn.isSelected = !recordBtn.isSelected
rightItem.state = .start
rightItem.isHidden = !recordBtn.isSelected
var messageList : [(String,UInt)] = []
var recordFilePath : String?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- }
+
override func setupViews() {
navBar.title = "现场录音"
toolBar.delegate = self
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)
}
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))
}
}
}
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()
var delegate:RecordBarDelegate?
override func setupViews() {
- backgroundColor = .white
+ backgroundColor = .hexString("#F7F7F7")
addSubviews([leftItem,rightItem,recordBtn])
recordBtn.do { v in
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
}
}
}
@objc func rightAction(){
+ if recordBtn.activeView.animating {
+ return
+ }
if recordBtn.isSelected {
return
}
}
func scrollToBottom(){
-
+ let range = NSMakeRange(textView.text.count - 1, 1)
+ textView.scrollRangeToVisible(range)
}
}
extension RecordDetailVC:RecordDetailTopBarDelegate{
// Created by liangshi on 2025/8/6.
//
-
import UIKit
import JoyGemAI
import AVFoundation
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() {
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
}
}
case .recordTranslate:
App.shared.goToPage(RecordTranslateVC())
case .dialogTranslate:
- App.shared.goToPage(DialogTranlateVC())
+ App.shared.goToPage(DialogTranslateVC())
case .textTranslate:
App.shared.goToPage(TextTranlateVC())
}
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)
}
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
guard let self = self else{return}
if !finish{
dataList.last!.response = dataList.last!.response + result
- tableView.reloadData()
- scrollToBottom()
+ refreshData()
}
} error: { error in
// 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 = ""
}
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)
}
}
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)
}
-
}
//
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()
}
}
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()
}
}
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()
+ }
+}
}
}
-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
- }
- }
- }
-
-
}
--- /dev/null
+//
+// ScrollView+Bottom.swift
+// ShenYin
+//
+// Created by liangshi on 2025/9/19.
+//
+
+extension UITableView {
+
+
+}
pod 'SnapKit'#布局
pod 'YYText'#富文本
pod 'FDFullscreenPopGesture'#侧滑返回
- pod 'TZScrollViewPopGesture'#侧滑返回
+# pod 'TZScrollViewPopGesture'#侧滑返回
pod 'IQKeyboardManagerSwift'#键盘
pod 'MJRefresh'#刷新
pod 'YYModel'#model解析
// 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