- JXSegmentedView (1.4.1)
- Kingfisher (6.3.1)
- MJRefresh (3.7.9)
- - netfox (1.21.0)
- - Realm (20.0.3):
- - Realm/Headers (= 20.0.3)
- - Realm/Headers (20.0.3)
- - RealmSwift (20.0.3):
- - Realm (= 20.0.3)
- SnapKit (5.7.1)
- SocketRocket (0.7.1)
- SVProgressHUD (2.3.1):
- JXSegmentedView
- Kingfisher (~> 6.0)
- MJRefresh
- - netfox
- - RealmSwift
- SnapKit
- SocketRocket
- SVProgressHUD
- JXSegmentedView
- Kingfisher
- MJRefresh
- - netfox
- - Realm
- - RealmSwift
- SnapKit
- SocketRocket
- SVProgressHUD
JXSegmentedView: cd73555ce2134d1656db2cb383ba9c2f36fb5078
Kingfisher: 016c8b653a35add51dd34a3aba36b580041acc74
MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
- netfox: 9d5cc727fe7576c4c7688a2504618a156b7d44b7
- Realm: 853e5089d6042dff807bda000277eadfe2da93d2
- RealmSwift: f33c19577cefcbf681345d721fcbc7b42be4c949
SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22
YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
ZipArchive: e25a4373192673e3229ac8d6e9f64a3e5713c966
-PODFILE CHECKSUM: 06f9ef8c019046f938158cfb86472b866db8d248
+PODFILE CHECKSUM: 3a7a732ff076ffc1ffadc01ed95542ab50a068f8
COCOAPODS: 1.16.2
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>NSPrivacyTracking</key>
+ <false/>
+ <key>NSPrivacyTrackingDomains</key>
+ <array/>
+ <key>NSPrivacyAccessedAPITypes</key>
+ <array>
+ <dict>
+ <key>NSPrivacyAccessedAPIType</key>
+ <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
+ <key>NSPrivacyAccessedAPITypeReasons</key>
+ <array>
+ <string>E174.1</string>
+ </array>
+ </dict>
+ </array>
+ <key>NSPrivacyCollectedDataTypes</key>
+ <array/>
+</dict>
+</plist>
/* Begin PBXBuildFile section */
3F79C6142E6055E500EC38B9 /* JoyGemAI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */; };
3F79C6152E6055E500EC38B9 /* JoyGemAI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ 3F8F58292EBCA2B800FFC00B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */; };
F2E449CAD5874BE652A69B50 /* Pods_ShenYin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3862D5561144E20721225B96 /* Pods_ShenYin.framework */; };
/* End PBXBuildFile section */
3862D5561144E20721225B96 /* Pods_ShenYin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShenYin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3F79C4902E603B4700EC38B9 /* JoyGemAI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JoyGemAI.framework; sourceTree = "<group>"; };
3F887B9C2E38D8DC00C98658 /* ShenYin.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShenYin.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
5F5DE5910965D53C2B3405B0 /* Pods-ShenYin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShenYin.debug.xcconfig"; path = "Target Support Files/Pods-ShenYin/Pods-ShenYin.debug.xcconfig"; sourceTree = "<group>"; };
CB933A7969ADF81D59503790 /* Pods-LingQi.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LingQi.debug.xcconfig"; path = "Target Support Files/Pods-LingQi/Pods-LingQi.debug.xcconfig"; sourceTree = "<group>"; };
CE98543C79FAAB6CEF4CBFCA /* Pods-LingQi.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-LingQi.release.xcconfig"; path = "Target Support Files/Pods-LingQi/Pods-LingQi.release.xcconfig"; sourceTree = "<group>"; };
3F887B932E38D8DC00C98658 = {
isa = PBXGroup;
children = (
+ 3F8F58282EBCA2B800FFC00B /* PrivacyInfo.xcprivacy */,
3F887B9E2E38D8DC00C98658 /* ShenYin */,
3F887B9D2E38D8DC00C98658 /* Products */,
34A14A83ECF09370871C891F /* Pods */,
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 3F8F58292EBCA2B800FFC00B /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
// Created by liangshi on 2025/10/15.
//
-class Config{
-
-
- static var appLanguage = AppSupportLanguage.chinse
+class DCConfig{
+ static var appLanguage = AppSupportLanguage.china
}
-class DCGlobal {
-
+class DCGlobal {
/// 微信开发平台 App ID
static let wxAppID = "wxf19317f23b00d8ab"
static let wxUniversalLink = "https://www.thisiot.com/flychat"
case uploadVoiceFile(param:[String:Any])
/// 创建录音记录
case voiceRecord(param:[String:Any])
+ /// 录音文本记录上报
+ case voiceRecordText(param:[String:Any])
/// 获取录音记录
case getVoiceRecord(recordId:String)
+ /// 获取录音文本记录上报
+ case getVoiceRecordText(param:[String:Any])
/// 更新录音
case updateVoiceRecord(param:[String:Any])
/// 删除录音
case .storageSize:
return "/res/voice-file/storage-size"
case .musicCategory:
- return "/res/music-category/list"
+ return "/res/music-category/list?languageCode=\(DCConfig.appLanguage.lanCode)"
case .musicCategoryList(let categoryId,let page):
- return "/res/sleep-music/list/\(page)?categoryId=\(categoryId)"
+ return "/res/sleep-music/list/\(page)?categoryId=\(categoryId)&languageCode=\(DCConfig.appLanguage.lanCode)"
case .musicUrl( let id):
return "/res/music-file/path/\(id)"
case .recordUrl( let id):
case .feedbackHistory:
return "/uc/feedback"
- case .productInfo(let name):
+ case .productInfo(_):
return "/dev/product-info/by-name"
case .deviceList:
return "/dev/device/list"
case .voiceRecord(_):
return "/res/voice-record"
+ case .voiceRecordText(_):
+ return "/res/voice-record-txt"
case .getVoiceRecord(let recordId):
return "/res/voice-record/\(recordId)"
+ case .getVoiceRecordText(_):
+ return "/res/voice-record-txt/list"
case .updateVoiceRecord(let param):
return "/res/voice-record/\(param["id"]!)"
case .deleteVoiceRecord(let recordId):
var method:RequestMethod{
switch self {
- case .register(_),.phoneCodeLogin(_),.emailCodeLogin(_),.appleLogin(_),.login(_),.commitFeedback(_),.voiceRecord(_):
+ case .register(_),.phoneCodeLogin(_),.emailCodeLogin(_),.appleLogin(_),.login(_),.commitFeedback(_),.voiceRecord(_),.voiceRecordText(_):
return .post
case .updatePwd(_),.updateUserInfo(_),.updatePhone(_),.updateEmail(_),.bindDevice(_),.otaUpdateVersion(_),.voiceRecordCollection(_),.updateVoiceRecord(_):
return .put
break
case let .voiceRecord(para):
params += para
+ case let .voiceRecordText(para):
+ params += para
+ case let .getVoiceRecordText(para):
+ params += para
case let .voiceRecordList(para):
params += para
case let .updateVoiceRecord(para):
let url = target.url
let params = target.param
Logger.debug("request => ",url)
- Logger.debug(params)
+ Logger.debug(YLToos.jsonToString(params))
if target.method == .get {
HTTP.GET(url,parameters: params,requestSerializer: JSONParameterSerializer()){ response in
return
}
let responseStr = response.data.string ?? ""
- if let code = dict["code"] as? Int,code == 50000{
- YLprogressHUD.showAutoHiden(text: "当前账号已经退出登录"){
- CacheManager.shared.user.logout()
- }
- }
+// if let code = dict["code"] as? Int,code == 50000{
+// YLprogressHUD.showAutoHiden(text: "当前账号已经退出登录"){
+// CacheManager.shared.user.logout()
+// }
+// }
if let res = T.deserialize(from: dict){
completionHandler(res,responseStr)
return
}
}
-extension Data {
- var string: String? { String(data: self, encoding: .utf8) }
- func jsonObject(options: JSONSerialization.ReadingOptions = [.mutableContainers]) -> Any? {
- do { return try JSONSerialization.jsonObject(with: self, options: options) }
- catch { Logger.debug(error) }
- return nil
- }
-}
-extension String {
- var data: Data? { self.data(using: .utf8) }
-}
--- /dev/null
+{
+ "images" : [
+ {
+ "filename" : "server_qr.png",
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
}
static func createFolder(_ foldPath:String){
- Logger.debug("路径 " ,foldPath)
let fileManager = FileManager.default
if !fileManager.fileExists(atPath: foldPath) {
do {
--- /dev/null
+//
+// DeviceCache.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/8.
+//
+
+class DeviceCache {
+ static let shared = DeviceCache()
+ private let userDefaults = UserDefaults.standard
+ private let deviceListKey = "DeviceCache"
+
+ func add(_ uuid: String,mac:String) {
+ var deviceList = getList()
+ deviceList[uuid] = mac
+ userDefaults.set(deviceList, forKey: deviceListKey)
+ userDefaults.synchronize()
+ }
+ func getMac(_ uuid:String)->String?{
+ let deviceList = getList()
+ Logger.debug(deviceList)
+ return deviceList[uuid]
+ }
+ func getList() -> [String:String] {
+ if let data = userDefaults.value(forKey: deviceListKey) as? [String:String]{
+ return data
+ }
+ return [:]
+ }
+}
+
+
+extension DeviceCache{
+ static func saveLastConnected(mac:String){
+ UserDefaults.standard.set(mac, forKey: "LastConnect")
+ UserDefaults.standard.synchronize()
+ }
+ static func getLastConnected()->String?{
+ if let value = UserDefaults.standard.value(forKey: "LastConnect"),let obj = value as? String {
+ return obj
+ }
+ return nil
+ }
+}
+++ /dev/null
-//
-// FontCache.swift
-// ShenYin
-//
-// Created by liangshi on 2025/10/24.
-//
-
-class FontCache{
- static func saveFont(type:FontType){
- UserDefaults.standard.set(type.rawValue, forKey: "FontCache")
- UserDefaults.standard.synchronize()
- }
- static func getFont()->FontType{
- if let value = UserDefaults.standard.value(forKey: "FontCache"),let font = value as? Int {
- return FontType(rawValue: font) ?? .stand
- }
- return FontType.stand
- }
-}
return true
}
}
+
+class FontCache{
+ static func saveFont(type:FontType){
+ UserDefaults.standard.set(type.rawValue, forKey: "FontCache")
+ UserDefaults.standard.synchronize()
+ }
+ static func getFont()->FontType{
+ if let value = UserDefaults.standard.value(forKey: "FontCache"),let font = value as? Int {
+ return FontType(rawValue: font) ?? .stand
+ }
+ return FontType.stand
+ }
+}
+
+class RoleCache{
+ static let key = "RoleCache"
+ static func save(type:String){
+ UserDefaults.standard.set(type, forKey: key)
+ UserDefaults.standard.synchronize()
+ }
+ static func get()->String?{
+ if let value = UserDefaults.standard.value(forKey: key),let text = value as? String {
+ return text
+ }
+ return nil
+ }
+}
var gender = GenderType.unnkown
var countryName = ""
var countryId = ""
+
+ var cacheCountryName:String{
+ for item in LoginVM.shared.countryList {
+ if item.id == self.countryId{
+ return item.name
+ }
+ }
+ return ""
+ }
}
self.info = model.data
UserCache.shared.save(self.info)
}
-// else{
-// logout()
-// }
+ else{
+ if let dict = YLToos.stringToJson(res),let code = dict["code"] as? Int,code == 50000{
+ logout()
+ }
+ }
finished?()
}
}
<string>bluetooth-central</string>
<string>audio</string>
</array>
+ <key>NSLocationWhenInUseUsageDescription</key>
+ <string>允许APP使用定位方便查找耳机</string>
</dict>
</plist>
// Created by apple on 2020/12/16.
//
-import Foundation
-import MapKit
-
-struct MapTool {
- /// Info plist
- /// LSApplicationQueriesSchemes 需要添加 iosamap
- private static let aMapScheme = "iosamap://"
- private static let aMapSchemeUrl = URL(string: aMapScheme)
- private static var canOpenAmap: Bool {
- if let url = aMapSchemeUrl {
- return UIApplication.shared.canOpenURL(url)
- } else {
- return false
- }
- }
-
- private static let mapsScheme = "http://maps.apple.com/"
- private static let mapsSchemeUrl = URL(string: mapsScheme)
- private static var canOpenMaps: Bool {
- if let url = mapsSchemeUrl {
- return UIApplication.shared.canOpenURL(url)
- } else {
- return false
- }
- }
-
- /// Info plist
- /// LSApplicationQueriesSchemes 需要添加 baidumap
- private static let bMapScheme = "baidumap://"
- private static let bMapSchemeUrl = URL(string: bMapScheme)
- private static var canOpenbMap: Bool {
- if let url = bMapSchemeUrl {
- return UIApplication.shared.canOpenURL(url)
- } else {
- return false
- }
- }
-
- /// 导航功能方法封装
- /// @param lat 纬度
- /// @param lng 经度
- /// @param address 地图显示目的地
- /// @param currentController 在哪个VC弹出
-// static func mapNavigation(lat: Double, lng: Double, address: String, currentVC: UIViewController) {
-// let urlScheme = ""
-// let appName = ""
-// var address = address
-// let coordiante = CLLocationCoordinate2DMake(lat, lng)
-// if address.isEmpty {
-// address = "目的地"
-// }
-// let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
-// if canOpenMaps {
-// let action = UIAlertAction(title: "苹果地图", style: .default) { (action) in
-// let currentLocation = MKMapItem.forCurrentLocation()
-// let toLocation = MKMapItem(placemark: MKPlacemark(coordinate: coordiante))
-// toLocation.name = address
-// MKMapItem.openMaps(with: [currentLocation, toLocation],
-// launchOptions: [
-// MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
-// MKLaunchOptionsShowsTrafficKey:true]
-// )
-// }
-// alert.addAction(action)
+//import Foundation
+//import MapKit
+//
+//struct MapTool {
+// /// Info plist
+// /// LSApplicationQueriesSchemes 需要添加 iosamap
+// private static let aMapScheme = "iosamap://"
+// private static let aMapSchemeUrl = URL(string: aMapScheme)
+// private static var canOpenAmap: Bool {
+// if let url = aMapSchemeUrl {
+// return UIApplication.shared.canOpenURL(url)
+// } else {
+// return false
// }
-// if canOpenbMap {
-// let action = UIAlertAction(title: "百度地图", style: .default) { (action) in
-// let bstr = "baidumap://map/direction?origin={{我的位置}}&destination=name:\(address)|latlng:\(coordiante.latitude),\(coordiante.longitude)&mode=driving&coord_type=gcj02"
-// let urlStr = bstr.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
-// guard let urlStr2 = urlStr else { return }
-// guard let url = urlStr2.url else { return }
-// UIApplication.shared.open(url, options: [:]) { (success) in
-// SNLog("scheme try end")
-// }
-// }
-// alert.addAction(action)
+// }
+//
+// private static let mapsScheme = "http://maps.apple.com/"
+// private static let mapsSchemeUrl = URL(string: mapsScheme)
+// private static var canOpenMaps: Bool {
+// if let url = mapsSchemeUrl {
+// return UIApplication.shared.canOpenURL(url)
+// } else {
+// return false
// }
-// if canOpenAmap {
-// let action = UIAlertAction(title: "高德地图", style: .default) { (action) in
-// let bstr = "iosamap://path?sourceApplication=\(appName)&backScheme=\(urlScheme)&dlat=\(coordiante.latitude)&dlon=\(coordiante.longitude)&dname=\(address)&dev=0&t=0"
-// let urlStr = bstr.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
-// guard let urlStr2 = urlStr else { return }
-// guard let url = urlStr2.url else { return }
-// UIApplication.shared.open(url, options: [:]) { (success) in
-// SNLog("scheme try end")
-// }
-// }
-// alert.addAction(action)
+// }
+//
+// /// Info plist
+// /// LSApplicationQueriesSchemes 需要添加 baidumap
+// private static let bMapScheme = "baidumap://"
+// private static let bMapSchemeUrl = URL(string: bMapScheme)
+// private static var canOpenbMap: Bool {
+// if let url = bMapSchemeUrl {
+// return UIApplication.shared.canOpenURL(url)
+// } else {
+// return false
// }
-// let action = UIAlertAction(title: "取消", style: .cancel, handler: nil)
-// alert.addAction(action)
-//
-// currentVC.present(alert, animated: true, completion: nil)
// }
-}
+//
+// /// 导航功能方法封装
+// /// @param lat 纬度
+// /// @param lng 经度
+// /// @param address 地图显示目的地
+// /// @param currentController 在哪个VC弹出
+//// static func mapNavigation(lat: Double, lng: Double, address: String, currentVC: UIViewController) {
+//// let urlScheme = ""
+//// let appName = ""
+//// var address = address
+//// let coordiante = CLLocationCoordinate2DMake(lat, lng)
+//// if address.isEmpty {
+//// address = "目的地"
+//// }
+//// let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
+//// if canOpenMaps {
+//// let action = UIAlertAction(title: "苹果地图", style: .default) { (action) in
+//// let currentLocation = MKMapItem.forCurrentLocation()
+//// let toLocation = MKMapItem(placemark: MKPlacemark(coordinate: coordiante))
+//// toLocation.name = address
+//// MKMapItem.openMaps(with: [currentLocation, toLocation],
+//// launchOptions: [
+//// MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving,
+//// MKLaunchOptionsShowsTrafficKey:true]
+//// )
+//// }
+//// alert.addAction(action)
+//// }
+//// if canOpenbMap {
+//// let action = UIAlertAction(title: "百度地图", style: .default) { (action) in
+//// let bstr = "baidumap://map/direction?origin={{我的位置}}&destination=name:\(address)|latlng:\(coordiante.latitude),\(coordiante.longitude)&mode=driving&coord_type=gcj02"
+//// let urlStr = bstr.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
+//// guard let urlStr2 = urlStr else { return }
+//// guard let url = urlStr2.url else { return }
+//// UIApplication.shared.open(url, options: [:]) { (success) in
+//// SNLog("scheme try end")
+//// }
+//// }
+//// alert.addAction(action)
+//// }
+//// if canOpenAmap {
+//// let action = UIAlertAction(title: "高德地图", style: .default) { (action) in
+//// let bstr = "iosamap://path?sourceApplication=\(appName)&backScheme=\(urlScheme)&dlat=\(coordiante.latitude)&dlon=\(coordiante.longitude)&dname=\(address)&dev=0&t=0"
+//// let urlStr = bstr.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
+//// guard let urlStr2 = urlStr else { return }
+//// guard let url = urlStr2.url else { return }
+//// UIApplication.shared.open(url, options: [:]) { (success) in
+//// SNLog("scheme try end")
+//// }
+//// }
+//// alert.addAction(action)
+//// }
+//// let action = UIAlertAction(title: "取消", style: .cancel, handler: nil)
+//// alert.addAction(action)
+////
+//// currentVC.present(alert, animated: true, completion: nil)
+//// }
+//}
let t = CMTimeGetSeconds(duration)
return Int(t)
}
+ static func stringToJson(_ text:String)->[String:Any]?{
+ guard let data = text.data(using: .utf8) else{
+ return nil
+ }
+ return dataToJson(data)
+ }
+ static func dataToJson(_ data:Data)->[String:Any]?{
+ do {
+ let jsonData = try JSONSerialization.jsonObject(with: data, options: .fragmentsAllowed)
+ return jsonData as? [String:Any]
+ } catch {
+ return nil
+ }
+ }
+ static func jsonToString(_ json:[String:Any])->String{
+ if let data = jsonToData(json){
+ return String(data: data, encoding: .utf8) ?? ""
+ }
+ return ""
+ }
+ static func jsonToData(_ json:[String:Any])->Data?{
+ do {
+ let jsonData = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
+ return jsonData
+ } catch {
+ return nil
+ }
+ }
+
+ static func readFile(from path:String) ->Data?{
+ let fileURL = URL(fileURLWithPath: path)
+ do {
+ let data = try Data(contentsOf:fileURL)
+ return data
+ } catch {
+ return nil
+ }
+ }
+
+ static func saveToFile(data:Data,path:String)->Bool{
+ let url = URL(fileURLWithPath: path)
+ do {
+ try data.write(to: url, options: .atomic)
+ return true
+ }
+ catch{
+ Logger.debug(error)
+ return false
+ }
+ }
+
+ static func base64ToImage(_ base64String: String) -> UIImage? {
+ if let data = Data(base64Encoded: base64String),
+ let image = UIImage(data: data) {
+ return image
+ }
+ return nil
+ }
+
+ static func generateRandomString(length: Int = 16) -> String {
+ let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+ var randomString: String = ""
+ for _ in 0..<length {
+ let randomValue = Int.random(in: 0...letters.count - 1)
+ randomString.append(letters[letters.index(letters.startIndex, offsetBy: randomValue)])
+ }
+ return randomString
+ }
+ static func generateRandomString2(length: Int = 16) -> String {
+ let letters = "abcdef0123456789"
+ var randomString: String = ""
+ for _ in 0..<length {
+ let randomValue = Int.random(in: 0...letters.count - 1)
+ randomString.append(letters[letters.index(letters.startIndex, offsetBy: randomValue)])
+ }
+ return randomString
+ }
+}
+
+extension Data {
+ var string: String? { String(data: self, encoding: .utf8) }
+ func jsonObject(options: JSONSerialization.ReadingOptions = [.mutableContainers]) -> Any? {
+ do { return try JSONSerialization.jsonObject(with: self, options: options) }
+ catch { Logger.debug(error) }
+ return nil
+ }
+}
+
+extension String {
+ var data: Data? { self.data(using: .utf8) }
}
}
func show(animate:Bool = true) -> Void {
self.layer.opacity = 1
- App.shared.window?.addSubview(self)
-
+// App.shared.window?.addSubview(self)
+ App.shared.topVC().view.addSubview(self)
}
@objc func hide() -> Void {
self.tabBar.backgroundColor = .white
view.backgroundColor = .color(.bgColor)
-// self.selectedIndex = 4
+// self.selectedIndex = 2
}
}
bgView.addSubview(label)
totalHeight = label.bottom + 12
- if item !== vm.list.last {
- let line = UIView()
- line.backgroundColor = .hexString("#F2F2F2")
- line.height = 1
- line.width = kScreenWid - 2*70
- line.left = 10
- line.top = totalHeight - 6
- bgView.addSubview(line)
- }
+// if item !== vm.list.last {
+// let line = UIView()
+// line.backgroundColor = .hexString("#F2F2F2")
+// line.height = 1
+// line.width = kScreenWid - 2*70
+// line.left = 10
+// line.top = totalHeight - 6
+// bgView.addSubview(line)
+// }
label.add(target: self, action: #selector(tapAction(_:)))
}
let toolBar = SendToolBar()
let qaView = CustomerHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 195))
let tableView = UITableView(frame: CGRectZero, style: .plain)
- var dataList:[FeedbackContentModel] = []
+ var dataList:[Any] = []
override func viewDidLoad() {
super.viewDidLoad()
}
v.separatorStyle = .none
v.tableHeaderView = qaView
v.register(FeedbackContentViewCell.self, forCellReuseIdentifier: FeedbackContentViewCell.reuseID)
+ v.register(FeedbackContentImageCell.self, forCellReuseIdentifier: FeedbackContentImageCell.reuseID)
}
toolBar.do { v in
v.textField.text = ""
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = FeedbackContentViewCell.cell(withTableView: tableView, indexPath: indexPath)
- cell.data = dataList[indexPath.row]
- return cell
+ let data = dataList[indexPath.row]
+ if let model = data as? FeedbackContentModel {
+ let cell = FeedbackContentViewCell.cell(withTableView: tableView, indexPath: indexPath)
+ cell.data = model
+ return cell
+ }
+ else if let model = data as? UIImage{
+ let cell = FeedbackContentImageCell.cell(withTableView: tableView, indexPath: indexPath)
+ cell.imgView.image = model
+ return cell
+ }
+ return UITableViewCell()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
func sendToolBar(_ toolBar: SendToolBar, _ text: String) {
toolBar.textField.resignFirstResponder()
dataList.append(FeedbackContentModel(content: text,isSend: true))
- dataList.append(FeedbackContentModel(content: "请加企业微信:123456",isSend: false))
+ dataList.append(FeedbackContentModel(content: "请加企业客服微信具体解答您的问题!",isSend: false))
+ dataList.append(UIImage(named: "server_qr")!)
+
refreshData()
toolBar.textField.text = ""
var messageList : [(String,UInt)] = []
var recordFilePath : String?
+ var autoStart = false
+ init(autoStart :Bool = false) {
+ self.autoStart = autoStart
+ super.init()
+ }
override func viewDidLoad() {
super.viewDidLoad()
}
}
override func setupData() {
JoyGemCallManager.shared().delegate = self
+ if autoStart{
+ startRecord()
+ }
}
override func viewDidAppear(_ animated: Bool) {
// debugPrint("播放音频时发生错误: \(error.localizedDescription)")
// }
}
+ func startRecord(){
+ toolBar.recordBtnAction()
+ }
+ func stopRecord(){
+ toolBar.recordBtnAction()
+ }
}
extension CallingRecordVC:FieldRecordBarDelegate{
let v = PopTextField()
v.show()
v.cancelTap = {
-
+ App.shared.popPage()
}
v.okTap = { [weak self] text in
guard let self = self else{return}
var role:JoyGemSpeaker!{
didSet{
-// titleLabel.text = role.name
+ titleLabel.text = "嗨!我是" + role.name
icon.image = UIImage(named: "role_" + role.role)
}
}
make.bottom.equalToSuperview().inset(30)
}
tableView.snp.makeConstraints { make in
- make.top.equalToSuperview().inset(80)
+ make.top.equalToSuperview().inset(kNavBtm)
make.left.right.equalToSuperview()
make.bottom.equalTo(toolBar.snp.top)
}
guard let self = self,speakers.count > 0 else{return}
self.roleList = speakers
self.roleList.insert(xiaoYinRole(), at: 0)
- self.roleItem.role = roleList.first
- self.headerView.role = roleList.first
+
+ var currentRole = roleList.first
+ if let cacheRole = RoleCache.get(){
+ for item in roleList{
+ if item.role == cacheRole {
+ currentRole = item
+ break
+ }
+ }
+ }
+ self.roleItem.role = currentRole
+ self.headerView.role = currentRole
JoyGemChatManager.shared().setSpeaker(self.roleItem.role)
}
}
v.textColor = .rgb(0x121212)
v.font = .bold(14)
v.text = "智能体"
- v.isHidden = true
+
}
+ isHidden = true
}
override func setupLayout() {
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let data = list[indexPath.row]
+ RoleCache.save(type: data.role)
didSelected?(data)
navigationController?.popViewController(animated: true)
}
toolBar.delegate = self
toolBar.isChienseEnglish = true
+ toolBar.leftItem.valueLabel.text = "左耳"
+ toolBar.rightItem.valueLabel.text = "右耳"
tableView.backgroundColor = .clear
tableView.delegate = self
func reloadData() {
DeviceVM.shared.refresh {[weak self] result in
self?.collectionView.reloadData()
- if !BleManager.shared.isConnetd,let model = DeviceVM.shared.dataList.first{
- self?.startConectBle(model)
+ if !BleManager.shared.isConnetd,let lastMac = DeviceCache.getLastConnected(){
+ for item in DeviceVM.shared.dataList {
+ if item.mac == lastMac{
+ self?.startConectBle(item)
+ }
+ }
}
}
CacheManager.shared.user.tokenIsValid(){[weak self] in
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
-// let model = DeviceVM.shared.dataList[indexPath.row]
-// if BleManager.shared.isConected(mac: model.mac) {
-// App.shared.goToPage(HomeVC(device: model))
-// return
-// }
-// ConnectPopView.shared.stateDidChange(.connecting)
-// startConectBle(model,autoJump: true)
-
let model = DeviceVM.shared.dataList[indexPath.row]
if !BleManager.shared.isConected(mac: model.mac) {
startConectBle(model,autoJump: false)
}
}
override func navRightViewTapped() {
- let tip = RecordTipsView(type: .tongchuan)
+ let tip = RecordTipsView(type: .dialog)
tip.show()
}
override func viewDidAppear(_ animated: Bool) {
let rhythView = RhythView()
var messageList : [(String,UInt)] = []
var recordFilePath : String?
+ var autoStart = false
+ init(autoStart :Bool = false) {
+ self.autoStart = autoStart
+ super.init()
+ }
override func setupViews() {
navBar.title = "现场录音"
v.contentInset = UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 18)
}
view.addSubviews([rhythView,textView,toolBar])
-
}
override func setupLayout() {
rhythView.snp.makeConstraints { make in
} catch {
Logger.debug(error)
}
+ if autoStart{
+ startRecord()
+ }
}
override func viewDidAppear(_ animated: Bool) {
textView.scrollRangeToVisible(NSMakeRange(textView.text.count - 1, 1))
}
+ func startRecord(){
+ toolBar.recordBtnAction()
+ }
+ func stopRecord(){
+ toolBar.recordBtnAction()
+ }
}
extension FieldRecordingVC:FieldRecordBarDelegate{
let v = PopTextField()
v.show()
v.cancelTap = {
-
+ App.shared.popPage()
}
v.okTap = { [weak self] text in
guard let self = self else{return}
func recordManager(_ manager: JoyGemRecordManager, update mode: JoyGemRecordMode) {
- Logger.debug("mode: \(mode)")
+ Logger.debug("update mode: \(mode)")
}
func recordManager(_ manager: JoyGemRecordManager, saveFile path: String) {
}
func recordManager(_ manager: JoyGemRecordManager, stateChange code: JoyGemStateCode) {
- Logger.debug("code: \(code)")
+ Logger.debug("stateChange: \(code)")
}
func recordManagerStopped(_ manager: JoyGemRecordManager, reason code: JoyGemRecordStopCode) {
+ Logger.debug("stop reason: \(code)")
if (code == .actively) {
// YLprogressHUD.showAutoHiden("用户主动结束")
// toolBar.recordBtn.stopLoading()
}
func recordManager(_ manager: JoyGemRecordManager, onError code: JoyGemErrorCode) {
-
+ Logger.debug("onError: \(code)")
}
}
for fileURL in files {
if !zipArchive.addFile(toZip: fileURL, newname: URL(fileURLWithPath: fileURL).lastPathComponent ) {
+ if !FileManager.default.fileExists(atPath: fileURL){
+ Logger.debug("文件不存在",fileURL)
+ }
Logger.debug("Failed to add file: \(fileURL)")
zipArchive.closeZipFile2()
return nil
didSet{
guard let localModel = localModel else { return }
titleLabel.text = localModel.name
- dateLabel.text = localModel.createTime
+ if localModel.createTime.count > 20{
+ dateLabel.text = String(localModel.createTime.prefix(19))
+ }
+ else{
+ dateLabel.text = localModel.createTime
+ }
typeLabel.text = localModel.type.title
durationLabel.text = YLToos.formatSeconds(localModel.duration)
titleLabel.textColor = localModel.favorite == "0" ? UIColor.hexString("#121212"):.color(.theme)
v.text = "2025-06-02 10:28"
}
collectionIcon.do { v in
+// v.backgroundColor = .red
+ v.contentMode = .center
v.yc.addTap(target: self, action: #selector(collectionAction))
}
playIcon.do { v in
m.right.lessThanOrEqualTo(typeLabel.snp.left).offset(-50)
}
collectionIcon.snp.makeConstraints { (m) in
- m.size.equalTo(16)
- m.left.equalTo(titleLabel.snp.right).offset(8)
+ m.size.equalTo(32)
+ m.left.equalTo(titleLabel.snp.right)
m.centerY.equalTo(titleLabel)
}
@objc func collectionAction(){
if let model = model {
model.favorite = model.favorite == "0" ? "1":"0"
- collectionIcon.image = UIImage(named: model.favorite == "0" ? "collection_normal":"collection_selected")
+ self.model = model
var params:[String:Any] = [:]
params["recordId"] = model.id
}
}
else if let localModel = localModel{
+
localModel.favorite = localModel.favorite == "0" ? "1":"0"
- collectionIcon.image = UIImage(named: localModel.favorite == "0" ? "collection_normal":"collection_selected")
+ self.localModel = localModel
RecordCache.shared.add(localModel)
}
}
required public init() { }
}
+
+
class RecordHistorySelectedModel:HandyJSON{
var isSelcted = false
var model = RecordDetailModel()
required public init() { }
}
+
+class CloudSelectedModel:HandyJSON{
+ var isSelcted = false
+ var model = RecordHistoryModel()
+
+ required public init() { }
+}
+
+
+/// 录音详情
+class CloudRecordDetailRoot:ResponseBaseModel {
+ var data = CloudRecordDetailData()
+}
+class CloudRecordDetailData:HandyJSON {
+ var list = [CloudRecordDetail]()
+ var total = 0
+ var pageSize = 0
+ var currentPage = 0
+ var totalPage = 0
+ var hasNext = false
+ var hasPre = false
+
+ required public init() { }
+}
+
+class CloudRecordDetail:HandyJSON{
+ var type:RecordType = .present
+ var id = ""
+ var recordId = ""
+ var text = ""
+ var speakerName = ""
+ var translateText = ""
+ var sourceLanguage = ""
+ var targetLanguage = ""
+ var left = false
+ var clientTime = 0
+ var createTime = ""
+ var updateTime = ""
+ required public init() { }
+}
class CloudRecordVC: BaseVC{
let tableView = UITableView(frame: .zero, style: .plain)
let vm = HistoryRecordVM()
- var list = [RecordHistoryModel]()
+// var list = [RecordHistoryModel]()
override func viewDidLoad() {
super.viewDidLoad()
override func setupViews() {
navBar.do { v in
v.title = "云存储空间"
- let items = [NavigationRightItem(image: UIImage(named: "filter"),target: self, action: #selector(filterAction)),NavigationRightItem(image: UIImage(named: "search"), target: self,action: #selector(searchAction))]
+// let items = [NavigationRightItem(image: UIImage(named: "filter"),target: self, action: #selector(filterAction)),NavigationRightItem(image: UIImage(named: "search"), target: self,action: #selector(searchAction))]
+ let items = [NavigationRightItem(image: UIImage(named: "filter"),target: self, action: #selector(filterAction))]
v.setupRightViews(items)
}
}
}
}
+ func longpressAction(cell:HistoryRecordCell){
+ let window = App.shared.window
+ let rect = cell.superview!.convert(cell.frame, to: window)
+ let top = CGRectGetMaxY(rect)
+ Logger.debug(rect,top)
+
+ let model = cell.model!
+
+ let v = RecordPopView()
+ v.contentTop = top
+ v.show()
+ v.hidenCallback = {
+ cell.bgView.backgroundColor = .white
+ }
+ v.shareCallback = {
+ App.shared.goToPage(RecordShareVC(cloudList: [model]))
+ }
+ v.renameCallback = {[weak self] in
+ let v = PopTextField()
+ v.titleLabel.text = "重命名"
+ v.textFiled.text = model.name
+ v.cancelButton.setTitle("取消", for: .normal)
+ v.show()
+ v.cancelTap = {
+
+ }
+ v.okTap = { [weak self] text in
+ guard let self = self else{return}
+ model.name = text
+ tableView.reloadData()
+ var params:[String:Any] = [:]
+ params["id"] = model.id
+ params["name"] = model.name
+ let api = CommomApi.updateVoiceRecord(param: params)
+ HttpClient.request(api) {(model:ResponseBaseModel,res) in
+
+ }
+ }
+ }
+ v.deleteCallback = {[weak self] in
+ self?.deleteAction(model)
+ }
+ v.selectedCallback = { [weak self] in
+ guard let self = self else{return}
+ let vc = CloudSelectedVC(data: vm.list)
+ vc.deleteCallback = { [weak self] deleteList in
+ guard let self = self else{return}
+ for item in deleteList{
+ vm.list.removeAll(where: {$0.id == item.id})
+ }
+ tableView.reloadData()
+ }
+ App.shared.goToPage(vc,animated: false)
+ }
+ }
+ func deleteAction(_ model:RecordHistoryModel){
+ CustomAlert.showWith(title: "您要删除这条录音吗?", messgage: "删除后,此记录将无法恢复。", cancelCallback: {}) {[weak self] in
+ guard let self = self else{return}
+ YLprogressHUD.hidden()
+ vm.list.removeAll(where: {$0.id == model.id})
+ tableView.reloadData()
+ HttpClient.request( CommomApi.deleteVoiceRecord(recordId: model.id)) {(result:ResponseBaseModel,res) in
+ }
+ }
+ }
+ func deleteAction(indexPath:IndexPath){
+ CustomAlert.showWith(title: "您要删除这条录音吗?", messgage: "删除后,此记录将无法恢复。", cancelCallback: {}) {[weak self] in
+ guard let self = self else{return}
+ let model = vm.list[indexPath.row]
+ vm.list.removeAll(where: {$0.id == model.id})
+ tableView.deleteRows(at: [indexPath], with:.fade)
+ HttpClient.request(CommomApi.deleteVoiceRecord(recordId: model.id)) {(result:ResponseBaseModel,res) in
+ }
+ }
+ }
}
extension CloudRecordVC:UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = HistoryRecordCell.cell(withTableView: tableView, indexPath: indexPath)
cell.model = vm.list[indexPath.row]
+ cell.longPressCallback = {[weak self] cell in
+ self?.longpressAction(cell: cell)
+ }
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// 实现滑动删除功能
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
- // 从数据源中移除对应数据
- vm.list.remove(at: indexPath.row)
- // 从表格中删除对应行
- tableView.deleteRows(at: [indexPath], with:.fade)
+ deleteAction(indexPath: indexPath)
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
+ func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
+ return "删除"
+ }
}
override func setupViews() {
navBar.do { v in
v.title = "历史记录"
- let items = [NavigationRightItem(image: UIImage(named: "filter"),target: self, action: #selector(filterAction)),NavigationRightItem(image: UIImage(named: "search"), target: self,action: #selector(searchAction))]
+// let items = [NavigationRightItem(image: UIImage(named: "filter"),target: self, action: #selector(filterAction)),NavigationRightItem(image: UIImage(named: "search"), target: self,action: #selector(searchAction))]
+ let items = [NavigationRightItem(image: UIImage(named: "filter"),target: self, action: #selector(filterAction))]
v.setupRightViews(items)
}
}
v.renameCallback = {[weak self] in
let v = PopTextField()
+ v.titleLabel.text = "重命名"
v.textFiled.text = model.name
v.cancelButton.setTitle("取消", for: .normal)
v.show()
let data = list[indexPath.row]
App.shared.goToPage(RecordDetailVC(record: data,needFrontVC:true))
}
- // 实现滑动删除功能
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
- // 从数据源中移除对应数据
- list.remove(at: indexPath.row)
- // 从表格中删除对应行
- tableView.deleteRows(at: [indexPath], with:.fade)
+ CustomAlert.showWith(title: "您要删除这条录音吗?", messgage: "删除后,此记录将无法恢复。", cancelCallback: {}) {[weak self] in
+ guard let self = self else{return}
+ RecordCache.shared.remove(list[indexPath.row])
+ list.remove(at: indexPath.row)
+ tableView.deleteRows(at: [indexPath], with:.fade)
+ }
+
}
}
-
- // 允许编辑
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
+ func tableView(_ tableView: UITableView, titleForDeleteConfirmationButtonForRowAt indexPath: IndexPath) -> String? {
+ return "删除"
+ }
+
}
--- /dev/null
+//
+// CloudSelectedCell.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/7.
+//
+
+class CloudSelectedCell: BaseTableViewCell {
+ let selectedIcon = UIImageView()
+ let bgView = UIView()
+ let playIcon = UIImageView()
+ let titleLabel = UILabel()
+ let collectionIcon = UIImageView()
+ let durationLabel = UILabel()
+ let dateLabel = UILabel()
+ let typeLabel = UILabel()
+ var selectedCallback:((_ cell:CloudSelectedCell)->Void)?
+
+ var cloudModel:CloudSelectedModel?{
+ didSet{
+ guard let model = cloudModel?.model else { return }
+ titleLabel.text = model.name
+ dateLabel.text = model.createTime
+ typeLabel.text = model.type.title
+ durationLabel.text = YLToos.formatSeconds(model.duration)
+ titleLabel.textColor = model.favorite == "0" ? UIColor.hexString("#121212"):.color(.theme)
+ collectionIcon.image = UIImage(named: model.favorite == "0" ? "collection_normal":"collection_selected")
+ selectedIcon.image = UIImage(named: cloudModel!.isSelcted ? "btn_selected":"btn_normal")
+ }
+ }
+// var localModel:RecordHistorySelectedModel?{
+// didSet{
+// guard let localModel = localModel else { return }
+// titleLabel.text = localModel.model.name
+// dateLabel.text = localModel.model.createTime
+// typeLabel.text = localModel.model.type.title
+// durationLabel.text = YLToos.formatSeconds(localModel.model.duration)
+// titleLabel.textColor = localModel.model.favorite == "0" ? UIColor.hexString("#121212"):.color(.theme)
+// collectionIcon.image = UIImage(named: localModel.model.favorite == "0" ? "collection_normal":"collection_selected")
+// selectedIcon.image = UIImage(named: localModel.isSelcted ? "btn_selected":"btn_normal")
+// }
+// }
+
+ 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.addSubviews([selectedIcon,bgView])
+ bgView.addSubviews([playIcon,titleLabel,durationLabel,collectionIcon,typeLabel,dateLabel])
+
+ backgroundColor = .rgb(0xF7F7F7)
+ contentView.backgroundColor = .clear
+ selectionStyle = .none
+ bgView.do { v in
+ v.backgroundColor = UIColor.white
+ v.layer.cornerRadius = 12
+ v.layer.masksToBounds = true
+ }
+ titleLabel.do { (v) in
+ v.textColor = .rgb(0x121212)
+ v.font = .bold(16)
+ v.textAlignment = .left
+ v.text = "周一会议总结"
+ }
+ durationLabel.do { (v) in
+ v.textColor = .rgb(0x666666)
+ v.font = .regular(12)
+ v.textAlignment = .left
+ v.text = "00:32:27"
+ }
+ typeLabel.do { (v) in
+ v.textColor = .rgb(0x666666)
+ v.font = .regular(12)
+ v.textAlignment = .left
+ v.text = "现场录音"
+ }
+ dateLabel.do { (v) in
+ v.textColor = .rgb(0x666666)
+ v.font = .regular(12)
+ v.textAlignment = .left
+ v.text = "2025-06-02 10:28"
+ }
+ collectionIcon.do { v in
+ v.yc.addTap(target: self, action: #selector(collectionAction))
+ }
+ playIcon.do { v in
+ v.image = UIImage(named: "record_play 2")
+ }
+ selectedIcon.do { v in
+ v.image = UIImage(named: "btn_normal")
+ v.contentMode = .center
+ v.yc.addTap(target: self, action: #selector(selectedAction))
+ }
+ }
+
+ override func setupLayout() {
+ selectedIcon.snp.makeConstraints { (m) in
+ m.size.equalTo(54)
+ m.left.equalToSuperview().inset(0)
+ m.centerY.equalToSuperview()
+ }
+ bgView.snp.makeConstraints { (m) in
+ m.left.equalToSuperview().inset(54)
+ m.right.equalToSuperview().inset(15)
+ m.top.equalToSuperview().inset(5)
+ m.bottom.equalToSuperview().inset(5)
+ m.height.equalTo(74)
+ }
+
+ playIcon.snp.makeConstraints { (m) in
+ m.width.size.equalTo(30)
+ m.left.equalToSuperview().inset(14)
+ m.centerY.equalToSuperview()
+ }
+ titleLabel.snp.makeConstraints { (m) in
+ m.top.equalTo(16)
+ m.left.equalTo(playIcon.snp.right).offset(6)
+ m.right.lessThanOrEqualTo(typeLabel.snp.left).offset(-50)
+ }
+ collectionIcon.snp.makeConstraints { (m) in
+ m.size.equalTo(16)
+ m.left.equalTo(titleLabel.snp.right).offset(8)
+ m.centerY.equalTo(titleLabel)
+ }
+
+ durationLabel.snp.makeConstraints { (m) in
+ m.bottom.equalToSuperview().inset(16)
+ m.left.equalTo(titleLabel)
+ }
+ typeLabel.snp.makeConstraints { (m) in
+ m.top.equalToSuperview().inset(16)
+ m.right.equalToSuperview().inset(14)
+ }
+ dateLabel.snp.makeConstraints { (m) in
+ m.bottom.equalToSuperview().inset(16)
+ m.right.equalTo(typeLabel)
+ }
+ }
+ @objc func collectionAction(){
+ // if let model = model {
+ // model.favorite = model.favorite == "0" ? "1":"0"
+ // collectionIcon.image = UIImage(named: model.favorite == "0" ? "collection_normal":"collection_selected")
+ //
+ // var params:[String:Any] = [:]
+ // params["recordId"] = model.id
+ // params["favorite"] = model.favorite
+ // let api = CommomApi.voiceRecordCollection(param: params)
+ // HttpClient.request(api) { (model:RecordHistoryModelRoot,res) in
+ // }
+ // }
+ // else
+ // if let localModel = localModel{
+ // localModel.model.favorite = localModel.model.favorite == "0" ? "1":"0"
+ // collectionIcon.image = UIImage(named: localModel.model.favorite == "0" ? "collection_normal":"collection_selected")
+ // RecordCache.shared.add(localModel.model)
+ // }
+ }
+ @objc func selectedAction(){
+ if let mode = cloudModel{
+ mode.isSelcted = !mode.isSelcted
+ self.cloudModel = mode
+ }
+ selectedCallback?(self)
+ }
+
+}
--- /dev/null
+//
+// CloudSelectedVC.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/7.
+//
+
+import UIKit
+class CloudSelectedVC: BaseVC{
+ let tableView = UITableView(frame: .zero, style: .plain)
+ let bottomView = HistorySearchBottomView()
+ var list = [CloudSelectedModel]()
+ var deleteList = [RecordHistoryModel]()
+ var remainDeleteList = [RecordHistoryModel]()
+ var deleteCallback:((_ list:[RecordHistoryModel])->Void)?
+
+ init(data:[RecordHistoryModel]) {
+ var tempList = [CloudSelectedModel]()
+ for item in data {
+ let model = CloudSelectedModel()
+ model.model = item
+ tempList.append(model)
+ }
+ list = tempList
+ tableView.reloadData()
+ super.init()
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ // Do any additional setup after loading the view.
+ }
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ tableView.reloadData()
+ }
+ override func setupViews() {
+ navBar.do { v in
+ v.titleLabel.font = .bold(16)
+ v.title = "已选择0项"
+ // v.leftView.backgroundColor = .red
+ v.leftView.setImage(nil, for: .normal)
+ v.rightView.isHidden = false
+ // v.rightView.backgroundColor = .red
+
+ v.leftView.snp.remakeConstraints { (m) in
+ m.leading.equalToSuperview()
+ m.top.equalTo(kNavTop)
+ m.bottom.equalToSuperview()
+ m.width.greaterThanOrEqualTo(58)
+ }
+ v.rightView.snp.remakeConstraints { (m) in
+ m.right.equalToSuperview()
+ m.top.equalTo(kNavTop)
+ m.bottom.equalToSuperview()
+ m.width.greaterThanOrEqualTo(58)
+ }
+
+ let leftLabel = UILabel()
+ leftLabel.text = "全选"
+ leftLabel.textColor = .hexString("#666666")
+ leftLabel.yc.setBorder(width: 1, color: .hexString("#666666"), radius: 11)
+ leftLabel.font = .regular(12)
+ leftLabel.textAlignment = .center
+ leftLabel.yc.addTap(target: self, action: #selector(allSelctedAction))
+ v.leftView.addSubview(leftLabel)
+ leftLabel.snp.remakeConstraints { (m) in
+ m.leading.equalToSuperview().inset(18)
+ m.height.equalTo(22)
+ m.centerY.equalToSuperview()
+ m.width.greaterThanOrEqualTo(40)
+ }
+ let rightLabel = UILabel()
+ rightLabel.textAlignment = .center
+ rightLabel.text = "完成"
+ rightLabel.textColor = .white
+ rightLabel.backgroundColor = .color(.theme)
+ rightLabel.font = .regular(12)
+ rightLabel.yc.setCornerRadius(11)
+ rightLabel.yc.addTap(target: self, action: #selector(doneAction))
+
+ v.rightView.addSubview(rightLabel)
+ rightLabel.snp.remakeConstraints { (m) in
+ m.right.equalToSuperview().inset(18)
+ m.height.equalTo(22)
+ m.centerY.equalTo(v.titleLabel)
+ m.width.greaterThanOrEqualTo(40)
+ }
+ }
+
+ tableView.do { v in
+ v.backgroundColor = .rgb(0xF7F7F7)
+ v.delegate = self
+ v.dataSource = self
+ v.estimatedRowHeight = 84
+ v.separatorStyle = .none
+ // v.isEditing = true
+ v.register(CloudSelectedCell.self, forCellReuseIdentifier: CloudSelectedCell.reuseID)
+ }
+ bottomView.do { v in
+ v.outItem.yc.addTap(target: self, action: #selector(outputAction))
+ v.deleteItem.yc.addTap(target: self, action: #selector(deleteAction))
+ }
+ view.addSubviews([bottomView,tableView])
+ }
+ override func setupLayout() {
+ bottomView.snp.makeConstraints { make in
+ make.left.right.bottom.equalToSuperview()
+ make.height.equalTo(95)
+ }
+ tableView.snp.makeConstraints { make in
+ make.left.right.equalToSuperview()
+ make.top.equalTo(kNavBtm)
+ make.bottom.equalToSuperview().inset(95)
+ }
+ }
+
+
+ @objc func allSelctedAction(){
+ for item in list {
+ item.isSelcted = true
+ }
+ tableView.reloadData()
+ selectedAction()
+ }
+ @objc func doneAction(){
+ App.shared.popPage(animated: false)
+ }
+ func selectedAction(){
+ let selectedList = list.filter({$0.isSelcted})
+ navBar.title = "已选择\(selectedList.count)项"
+ }
+ @objc func outputAction(){
+ var tempList = [RecordHistoryModel]()
+ for item in list {
+ if item.isSelcted {
+ tempList.append(item.model)
+ }
+ }
+ App.shared.goToPage(RecordShareVC(cloudList: tempList))
+ }
+ @objc func deleteAction(){
+ var tempList = [RecordHistoryModel]()
+ for item in list {
+ if item.isSelcted {
+ tempList.append(item.model)
+ }
+ }
+ if tempList.count == 0 {
+ return
+ }
+ deleteList = tempList
+ remainDeleteList = tempList
+ CustomAlert.showWith(title: "您要删除这些录音吗?", messgage: "删除后,这些记录将无法恢复。", cancelCallback: {}) {[weak self] in
+ guard let self = self else{return}
+ YLprogressHUD.showLoading()
+ startDelete()
+ }
+ }
+ func startDelete(){
+ if remainDeleteList.count == 0 {
+ for item in deleteList{
+ list.removeAll(where: {$0.model.id == item.id})
+ }
+ deleteCallback?(deleteList)
+ tableView.reloadData()
+ selectedAction()
+ YLprogressHUD.hidden()
+ return
+ }
+
+ let model = remainDeleteList.last!
+ HttpClient.request( CommomApi.deleteVoiceRecord(recordId: model.id)) {[weak self](result:ResponseBaseModel,res) in
+ guard let self = self else{return}
+ if result.isSuccess{
+
+ }
+ else{
+ Logger.debug("删除失败",model.id)
+ }
+ remainDeleteList.removeLast()
+ startDelete()
+
+ }
+ }
+}
+
+extension CloudSelectedVC:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = CloudSelectedCell.cell(withTableView: tableView, indexPath: indexPath)
+ cell.cloudModel = list[indexPath.row]
+ cell.selectedCallback = {[weak self] cell in
+ self?.selectedAction()
+ }
+ return cell
+ }
+}
RecordCache.shared.remove(list:tempList)
deleteCallback?(tempList)
tableView.reloadData()
-
}
}
}
}
return cell
}
-// func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-// let data = list[indexPath.row]
-//
-// }
-// // 实现滑动删除功能
-// func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
-// if editingStyle == .delete {
-// // 从数据源中移除对应数据
-// list.remove(at: indexPath.row)
-// // 从表格中删除对应行
-// tableView.deleteRows(at: [indexPath], with:.fade)
-// }
-// }
-//
-// // 允许编辑
-// func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
-// return true
-// }
}
HttpClient.request(api) {[weak self] (result:RecordHistoryDetailRoot,res) in
guard let self = self else {return}
if result.isSuccess{
- YLprogressHUD.hidden()
let model = RecordDetailModel()
model.type = result.data.type
model.origin = result.data.summary
model.name = result.data.name
model.createTime = result.data.createTime
self.data = model
- setupViews(data: model)
+ loadDetail(remoteModel: data, localModel: model)
}
else{
YLprogressHUD.hidden()
}
}
}
+ func loadDetail(remoteModel:RecordHistoryModel,localModel:RecordDetailModel){
+ var params:[String:Any] = [:]
+ params["recordId"] = remoteModel.id
+ params["page"] = 1
+ let api = CommomApi.getVoiceRecordText(param: params)
+ HttpClient.request(api) {[weak self] (result:CloudRecordDetailRoot,res) in
+ guard let self = self else {return}
+ if result.isSuccess,let model = result.data.list.first{
+ YLprogressHUD.hidden()
+
+ localModel.origin = model.text
+ localModel.translate = model.translateText
+ localModel.from = AiSupportLanguage(rawValue: model.sourceLanguage) ?? .chinse
+ localModel.to = AiSupportLanguage(rawValue: model.targetLanguage) ?? .english
+ setupViews(data: localModel)
+ }
+ else{
+ YLprogressHUD.hidden()
+ setupViews(data: localModel)
+ }
+ }
+ }
}
extension RecordDetailVC:RecordDetailTopBarDelegate{
func recordDetailTopBarSummaryAction(_ bar: RecordDetailTopBar) {
func recordDetailBarTranstlateAction(_ bar: RecordDetailTopBar) {
updateLayout()
+ if let data = data,data.translate.isEmpty {
+ translateAction()
+ }
}
func recordDetailTopBarOgrinAction(_ bar: RecordDetailTopBar) {
func recordDetailBarRenameAction(_ bar: RecordDetailBar) {
let v = PopTextField()
+ v.titleLabel.text = "重命名"
v.textFiled.text = data?.name ?? ""
v.cancelButton.setTitle("取消", for: .normal)
v.show()
params["favorite"] = "0"
params["duration"] = YLToos.getDuration(data!.path)
params["fileId"] = fileId
- params["summary"] = data!.origin
- params["sourceLanguage"] = data!.from.value
- params["targetLanguage"] = data!.to.value
+ params["summary"] = summaryView.content
+
+// Logger.debug(params)
+ HttpClient.request(.voiceRecord(param: params)) {[weak self](model:CommonDataModel,res) in
+ if model.isSuccess{
+// self?.showUploadSuccess()
+ self?.commitDetail(model.data)
+ }
+ else{
+ YLprogressHUD.showAutoHiden("请求失败")
+ }
+ }
+ }
+ func commitDetail(_ recordId:String){
+ var textList:[String:Any] = [:]
+ textList["text"] = data!.origin
+ textList["translateText"] = data!.translate
+ textList["speakerName"] = CacheManager.shared.user.info.userName
+ textList["sourceLanguage"] = data!.from.value
+ textList["targetLanguage"] = data!.to.value
+ textList["createTime"] = Int(Date().timeIntervalSince1970)
+ textList["left"] = false
+
+ var params:[String:Any] = [:]
+ params["recordId"] = recordId
+ params["textList"] = [
+ textList
+ ]
- Logger.debug(params)
- HttpClient.request(.voiceRecord(param: params)) {[weak self](model:AppUpdateModelRoot,res) in
+// Logger.debug(params)
+ HttpClient.request(.voiceRecordText(param: params)) {[weak self](model:AppUpdateModelRoot,res) in
if model.isSuccess{
self?.showUploadSuccess()
}
v.backgroundColor = .clear
v.delegate = self
v.recordBtn.activeView.backgroundColor = .hexString("#F7F7F7")
+ toolBar.rightItem.valueLabel.text = "手机"
}
view.backgroundColor = .hexString("#F7F7F7")
let v = PopTextField()
v.show()
v.cancelTap = {
-
+ App.shared.popPage()
}
v.okTap = { [weak self] text in
guard let self = self else{return}
titleLabel.do { (v) in
v.textColor = .rgb(0x313230)
v.font = .bold(18)
- v.text = "历史录音"
+ v.text = "历史记录"
}
valueLabel.do { (v) in
v.textColor = .rgb(0x8d8d8d)
let bgView = UIView()
let icon = UIImageView()
let titleLabel = UILabel()
+ let valueLabel = UILabel()
var model:DCPeripheral!{
didSet{
titleLabel.text = model.device.name
- titleLabel.text = titleLabel.text! + "\n" + model.mac
- titleLabel.adjustsFontSizeToFitWidth = true
+// titleLabel.text = titleLabel.text!
+ valueLabel.text = model.mac
+// titleLabel.adjustsFontSizeToFitWidth = true
}
}
}
override func setupViews() {
contentView.addSubview(bgView)
- bgView.addSubviews([titleLabel,icon])
+ bgView.addSubviews([titleLabel,icon,valueLabel])
backgroundColor = .rgb(0xF7F7F7)
contentView.backgroundColor = .clear
selectionStyle = .none
bgView.do { v in
-// v.backgroundColor = UIColor.white
+ v.backgroundColor = UIColor.white
v.layer.cornerRadius = 8
v.layer.masksToBounds = true
}
v.textAlignment = .left
v.numberOfLines = 0
}
+ valueLabel.do { (v) in
+ v.textColor = .rgb(0x666666)
+ v.font = .regular(13)
+ v.textAlignment = .left
+ v.numberOfLines = 0
+ }
icon.image = UIImage(named: "scan_device")
}
m.centerY.equalToSuperview()
}
titleLabel.snp.makeConstraints { (m) in
- m.centerY.equalTo(icon)
+ m.top.equalToSuperview().inset(13)
+ m.left.equalTo(icon.snp.right).offset(15)
+ m.right.equalToSuperview().inset(15)
+ }
+ valueLabel.snp.makeConstraints { (m) in
+ m.bottom.equalToSuperview().inset(13)
m.left.equalTo(icon.snp.right).offset(15)
m.right.equalToSuperview().inset(15)
- m.height.equalToSuperview()
}
-
}
}
import UIKit
import IQKeyboardManagerSwift
-import netfox
+//import netfox
class AppLaunch:NSObject{
@MainActor static func start(){
// NFX.sharedInstance().start()
JoySdkManager.shared.setupSdk()
setupKeyboard()
loadCache()
+ LoginVM.fetchCountryList {result in
+
+ }
// AppUpdateVM.shared.checkedUpdate()
}
}
extension BleManager:CBCentralManagerDelegate{
func centralManagerDidUpdateState(_ central: CBCentralManager) {
+ Logger.debug("蓝牙状态",central.state.rawValue)
switch central.state {
case.unknown:
break
case.poweredOff:
break
case.poweredOn:
- startScanDevice()
+// startScanDevice()
+ checkConnect()
break
@unknown default:
break
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
stopScanDevice()
Logger.debug("蓝牙已连接 \(peripheral)")
+ DeviceCache.saveLastConnected(mac: connectPeripheral!.mac)
+ DeviceCache.shared.add(connectPeripheral!.device.identifier.uuidString, mac: connectPeripheral!.mac)
peripheral.delegate = self
peripheral.discoverServices([CBUUID(string: kJoyGemAIServiceUUID)]);
self.isConnetd = true
// MARK: - Public Methods
func startScanDevice() {
- centralManager.stopScan()
+// centralManager.stopScan()
Logger.debug("扫描中...")
+ Logger.debug("蓝牙状态",centralManager.state.rawValue)
devices = []
+// let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)])
+// Logger.debug("已连接设备",list)
+// for item in list {
+// if let mac = DeviceCache.shared.getMac(item.identifier.uuidString){
+// devices.append(DCPeripheral(device: item,mac: mac))
+// }
+// }
centralManager.scanForPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
discoverDeviceCallback?(devices)
}
func joyGemAction(_ action: JoyGemActionMode) {
+ Logger.debug(action)
+ if !CacheManager.shared.user.isLogin{
+ return
+ }
switch action {
case .cancel:
YLprogressHUD.showAutoHiden("请求关闭录音功能/通知关闭了对话")
+ if let topVC = App.shared.topVC(), let vc = topVC as? FieldRecordingVC {
+ vc.stopRecord()
+ }
+ if let topVC = App.shared.topVC(), let vc = topVC as? CallingRecordVC {
+ vc.stopRecord()
+ }
case .recordLive:
YLprogressHUD.showAutoHiden("请求开启现场录音")
+ if !App.shared.topVC().isKind(of: FieldRecordingVC.self) {
+ App.shared.goToPage(FieldRecordingVC(autoStart: true))
+ }
case .recordCall:
YLprogressHUD.showAutoHiden("请求开启通话录音")
+ if !App.shared.topVC().isKind(of: CallingRecordVC.self) {
+ App.shared.goToPage(CallingRecordVC(autoStart: true))
+ }
case .si:
YLprogressHUD.showAutoHiden( "请求开启同传听译")
case .chat:
YLprogressHUD.showAutoHiden( "通知开启了AI对话")
+ if !App.shared.topVC().isKind(of: ChatVC.self) {
+ App.shared.goToPage(ChatVC())
+ }
@unknown default:
break
}
return false
}
}
+
+// #连接有问题,应当获取设置里面已连接的设备
func connect(mac:String, finished:@escaping ((Bool) -> Void)){
BleManager.shared.cancel()
BleManager.shared.discoverDeviceCallback = { list in
}
BleManager.shared.startScanDevice()
}
-
+// func checkConnected(){
+// if BleManager.shared.isConnetd {
+// return
+// }
+//
+// let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)])
+// for item in list {
+// Logger.debug("当前状态",item.name ?? "",item.state)
+// if let mac = DeviceCache.shared.getMac(item.identifier.uuidString){
+//// devices.append()
+// BleManager.shared.connectPeripheral(DCPeripheral(device: item,mac: mac))
+// break
+// }
+// }
+//
+//
+// }
}
//
enum AppSupportLanguage{
- case chinse
- case english
- case japanese
- case korean
- case french
- case spanish
- case portuguese
- case indonesian
- case russian
- case malay
+ case china
+ case usa
+ case japan
+ case korea
+ case taiwan
+ case spani
+ case vietnam
+ case thailand
+ case malaysia
+ case philippines
+ case frence
+ case singapore
+ case indonesia
+ case russia
static var all:[AppSupportLanguage]{
- return [.chinse,.english,.japanese,.korean,.french,.spanish,.portuguese,.indonesian,.russian,.malay]
+ return [.china,.usa,.japan,.korea,.taiwan,.spani,.vietnam,.thailand,.malaysia,.philippines,.frence,.singapore,.indonesia,.russia]
}
var title:String{
switch self {
- case .chinse:
+ case .china:
return "中文"
- case .english:
- return "英文"
- case .japanese:
+ case .usa:
+ return "美国"
+ case .japan:
return "日文"
- case .korean:
+ case .korea:
return "韩文"
- case .french:
- return "法语"
- case .spanish:
- return "西班牙文"
- case .portuguese:
- return "葡萄牙文"
- case .indonesian:
+ case .taiwan:
+ return "中国台湾"
+ case .spani:
+ return "西班牙"
+ case .vietnam:
+ return "越南"
+ case .thailand:
+ return "泰国"
+ case .malaysia:
+ return "马来西亚"
+ case .philippines:
+ return "菲律宾"
+ case .frence:
+ return "法国"
+ case .singapore:
+ return "新加坡"
+ case .russia:
+ return "俄罗斯"
+ case .indonesia:
return "印度尼西亚文"
- case .russian:
- return "俄文"
- case .malay:
- return "马来文"
+ }
+ }
+ var lanCode:String{
+ switch self {
+ case .china:
+ return "zh_CN"
+ case .usa:
+ return "en_US"
+ case .japan:
+ return "ja"
+ case .korea:
+ return "ko"
+ case .taiwan:
+ return "zh-TW"
+ case .spani:
+ return "es"
+ case .vietnam:
+ return "vi"
+ case .thailand:
+ return "th"
+ case .malaysia:
+ return "ms"
+ case .philippines:
+ return "tl"
+ case .frence:
+ return "fr"
+ case .singapore:
+ return "en"
+ case .russia:
+ return "ru"
+ case .indonesia:
+ return "id"
}
}
var map:[String:String]{
switch self {
- case .chinse:
+ case .china:
+ return englishMap
+ case .usa:
+ return englishMap
+ case .japan:
+ return englishMap
+ case .korea:
+ return englishMap
+ case .taiwan:
+ return englishMap
+ case .spani:
+ return englishMap
+ case .vietnam:
+ return englishMap
+ case .thailand:
return englishMap
- case .english:
+ case .malaysia:
+ return englishMap
+ case .philippines:
+ return englishMap
+ case .frence:
+ return englishMap
+ case .singapore:
+ return englishMap
+ case .russia:
+ return englishMap
+ case .indonesia:
return englishMap
- case .japanese:
- return japaneseMap
- case .korean:
- return koreanMap
- case .french:
- return frenchMap
- case .spanish:
- return spanishMap
- case .portuguese:
- return portugueseMap
- case .indonesian:
- return indonesianMap
- case .russian:
- return russianMap
- case .malay:
- return malayMap
}
}
}
"登录" : "login",
"注册" : "register",
]
-let japaneseMap:[String:String] = [
- "登录" : "login",
- "注册" : "register",
-]
-let koreanMap:[String:String] = [
- "登录" : "login",
- "注册" : "register",
-]
-let frenchMap:[String:String] = [
- "登录" : "login",
- "注册" : "register",
-]
-let spanishMap:[String:String] = [
- "登录" : "login",
- "注册" : "register",
-]
-let portugueseMap:[String:String] = [
- "登录" : "login",
- "注册" : "register",
-]
-let indonesianMap:[String:String] = [
- "登录" : "login",
- "注册" : "register",
-]
-let russianMap:[String:String] = [
- "登录" : "login",
- "注册" : "register",
-]
-let malayMap:[String:String] = [
- "登录" : "login",
- "注册" : "register",
-]
+//let japaneseMap:[String:String] = [
+// "登录" : "login",
+// "注册" : "register",
+//]
+//let koreanMap:[String:String] = [
+// "登录" : "login",
+// "注册" : "register",
+//]
+//let frenchMap:[String:String] = [
+// "登录" : "login",
+// "注册" : "register",
+//]
+//let spanishMap:[String:String] = [
+// "登录" : "login",
+// "注册" : "register",
+//]
+//let portugueseMap:[String:String] = [
+// "登录" : "login",
+// "注册" : "register",
+//]
+//let indonesianMap:[String:String] = [
+// "登录" : "login",
+// "注册" : "register",
+//]
+//let russianMap:[String:String] = [
+// "登录" : "login",
+// "注册" : "register",
+//]
+//let malayMap:[String:String] = [
+// "登录" : "login",
+// "注册" : "register",
+//]
extension String{
var l10n:String{
- if let value = Config.appLanguage.map[self] {
+ if let value = DCConfig.appLanguage.map[self] {
return value
}
else{
contentView.backgroundColor = .rgb(0xF6F6F6)
bgView.do { v in
- v.yc.setCornerRadius(12)
+ v.yc.setCornerRadius(8)
}
originalLabel.do { v in
v.font = .regular(14)
}
}
}
+class FeedbackContentImageCell:BaseTableViewCell{
+ let bgView = UIView()
+ let imgView = UIImageView()
+ let icon = 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 = .rgb(0xF6F6F6)
+
+ bgView.do { v in
+ v.yc.setCornerRadius(8)
+ v.backgroundColor = .white
+ }
+
+ icon.do { v in
+ v.yc.setCornerRadius(18)
+ }
+// imgView.do {v in
+// v.yc.setCornerRadius(12)
+// }
+ contentView.addSubviews([bgView,icon])
+ bgView.addSubviews([imgView])
+ }
+
+ override func setupLayout() {
+ bgView.snp.makeConstraints { make in
+ make.top.equalToSuperview().inset(0)
+ make.bottom.equalToSuperview().inset(10)
+ make.left.right.equalToSuperview().inset(60)
+ make.height.equalTo((kScreenWid-120)*1005/720)
+ }
+
+ imgView.snp.makeConstraints { make in
+ make.top.bottom.equalToSuperview().inset(5)
+ make.left.right.equalToSuperview().inset(5)
+ }
+ }
+}
else{
cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
}
- cell.selectedIcon.isHidden = cell.country.name != currentType.name
+ cell.selectedIcon.isHidden = cell.country.id != currentType.id
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self?.codeView.codeButton.start()
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(model.msg)
}
}
}
}
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(result.msg)
}
}
}
extension LoginVC{
@objc func loginAction(){
+ self.view.endEditing(true)
+ if !agreeView.isAgree {
+ YLprogressHUD.showAutoHiden("请阅读用户协议以及隐私政策并点击同意")
+ return
+ }
guard let phone = phoneView.textField.value else{
YLprogressHUD.showAutoHiden("请输入正确的手机号码")
return
}
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(result.msg)
}
}
}
YLprogressHUD.hidden()
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(model.msg)
}
}
}
@objc func registerAction(){
+ if !agreeView.isAgree {
+ YLprogressHUD.showAutoHiden("请阅读用户协议以及隐私政策并点击同意")
+ return
+ }
guard let phone = phoneView.textField.value else{
YLprogressHUD.showAutoHiden("请输入正确的手机号码")
return
}
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(result.msg)
}
}
}
YLprogressHUD.hidden()
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(model.msg)
}
}
}
}
}
func phoneLogin(){
+ if !agreeView.isAgree {
+ YLprogressHUD.showAutoHiden("请阅读用户协议以及隐私政策并点击同意")
+ return
+ }
guard let phone = phoneView.textField.value else{
YLprogressHUD.showAutoHiden("请输入正确的手机号码")
return
}
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(result.msg)
}
}
}
}
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(result.msg)
}
}
}
}
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(result.msg)
}
}
YLprogressHUD.hidden()
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(model.msg)
}
}
}
}
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(result.msg)
}
}
}
self?.codeView.codeButton.start()
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(model.msg)
}
}
}
}
}
else{
- YLprogressHUD.showAutoHiden("请求失败")
+ YLprogressHUD.showAutoHiden(result.msg)
}
}
}
let agreeValue = UILabel()
let andlabel = UILabel()
let useValue = UILabel()
+ var isAgree:Bool{
+ return agreeBtn.isSelected
+ }
override func setupViews() {
agreeBtn.do { (v) in
v.isSelected = true
}
@objc func wechatAction(){
Logger.debug("wechat action")
+ return
guard IASignWithWeChat.shared.isInstalled else { return }
// guard agreeAgreementBtn.isSelected else { return "请同意《App隐私政策》".asToastShow() }
completion(model)
}
}
+
}
v.font = .regular(14)
v.textColor = .hexString("#666666")
v.numberOfLines = 0
- let text = "请您确保您是有权进行本撤回同意隐私政策操作的相关当事人。撤回同意隐私政策,您将放弃以下资产或者权益:\n\n1.数据清空\n将会停止收集您的个人信息。您使用DeepChords应用过程中产生的数据将被清空;手机中DeepChords应用的缓存数据将被清除。\n\n2.设备解除绑定\nDeepChords账号中,所有设备会与您当前登录的账号解除绑定,并清除设备之前存储在服务器的数据。存储在物理设备中的数据请通过人工本地物理重置来清除。如果您需要重新使用设备,需要您再次进行绑定并且重新授权。\n\n3.其他\n此举还将撤回您对用户协议的同意,并退出DeepChor ds应用。\n\n请您知悉,撤回同意隐私政策不代表撤回同意前的相关行为和责任得到豁免或减轻。若您需要重新在该账号管理设备,需要您重新授权并绑定。请谨慎操作!"
+ let text = "请您确保您是有权进行本撤回同意隐私政策操作的相关当事人。撤回同意隐私政策,您将放弃以下资产或者权益:\n\n1.数据清空\n将会停止收集您的个人信息。您使用DeepChords应用过程中产生的数据将被清空;手机中DeepChords应用的缓存数据将被清除。\n\n2.设备解除绑定\nDeepChords账号中,所有设备会与您当前登录的账号解除绑定,并清除设备之前存储在服务器的数据。存储在物理设备中的数据请通过人工本地物理重置来清除。如果您需要重新使用设备,需要您再次进行绑定并且重新授权。\n\n3.其他\n此举还将撤回您对用户协议的同意,并退出DeepChords应用。\n\n请您知悉,撤回同意隐私政策不代表撤回同意前的相关行为和责任得到豁免或减轻。若您需要重新在该账号管理设备,需要您重新授权并绑定。请谨慎操作!"
let attributedString = NSMutableAttributedString(string: text)
let paragraphStyle = NSMutableParagraphStyle()
cloud.snp.makeConstraints { make in
make.top.equalTo(userInfo.snp.bottom).offset(15)
make.left.right.equalToSuperview().inset(18)
- make.height.equalTo(46)
+ make.height.equalTo(56)
}
banner.snp.makeConstraints { (m) in
m.height.equalTo(126)
m.centerY.equalToSuperview()
}
titleLabel.snp.makeConstraints { (m) in
- m.top.equalToSuperview().inset(6)
+ m.centerY.equalTo(nameLabel)
m.left.equalToSuperview().inset(54)
}
nameLabel.snp.makeConstraints { (m) in
- m.centerY.equalTo(titleLabel)
+ m.top.equalToSuperview().inset(10)
m.right.equalToSuperview().inset(14)
}
progressView.snp.makeConstraints { make in
make.right.equalToSuperview().inset(14)
make.left.equalToSuperview().inset(54)
make.height.equalTo(6)
- make.bottom.equalToSuperview().inset(8)
+ make.bottom.equalToSuperview().inset(12)
}
// PopPlayView().show()
}
import UIKit
class MineVC: BaseVC{
let tableView = UITableView(frame: .zero, style: .plain)
- let list:[MineCellType] = [.instructions,.update,.language,.more,.feeback,.about]
- let headerView = MineHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 317))
+ let list:[MineCellType] = [.instructions,.update,.more,.feeback,.about]
+ let headerView = MineHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 327))
override func viewDidLoad() {
super.viewDidLoad()
HttpClient.request(.otaTaskApp(param: params)) {[weak self](model:AppUpdateModelRoot,res) in
YLprogressHUD.hidden()
guard let self = self else {return}
- if model.isSuccess,model.data.targetVersion.uppercased() > model.data.sourceVersion.uppercased(){
- if model.data.updateType != "0"{
- //可选升级
- optionUpdate()
+ if model.isSuccess{
+ if model.data.targetVersion.uppercased() > model.data.sourceVersion.uppercased(){
+ if model.data.updateType != "0"{
+ //可选升级
+ optionUpdate()
+ }
+ else{
+ //强制升级
+ forceUpdate()
+ }
}
else{
- //强制升级
- forceUpdate()
+ YLprogressHUD.showAutoHiden("已经是最新版本")
}
}
else{
}
UIApplication.shared.open(url)
}
-
+
}
func forceUpdate(){
CustomAlert.showWith(title: nil, messgage: "检测到新版本", ok: "前往更新",cancelCallback: nil) {
override func setupData() {
DeviceVM.getVersion {[weak self] version in
guard let self = self else{return}
- let version = version ?? "--"
+ let version = version ?? " --"
let allText = "当前版本\n" + "V\(version)"
let attributedString = NSMutableAttributedString(string: allText)
let paragraphStyle = NSMutableParagraphStyle()
}
@objc func tapAction(){
if !BleManager.shared.isConnetd{
-// YLprogressHUD.showAutoHiden("")
+ YLprogressHUD.showAutoHiden("请先连接设备")
return
}
BleUpdateVM.shared.checkedUpdate()
valueLabel.text = info.gender.title
}
else if type == .area {
- valueLabel.text = info.countryName
+// valueLabel.text = info.countryName
+ valueLabel.text = info.cacheCountryName
}
else if type == .avatar{
valueIcon.kf.setImage(with:CacheManager.shared.user.info.avatar.yc.asUrl )
}
func areaAction(){
let vc = ContryListVC()
+ vc.currentType = CountryModel()
+ vc.currentType.id = CacheManager.shared.user.info.countryId
vc.didSelected = {[weak self] model in
guard let self = self else{return}
CacheManager.shared.user.info.countryName = model.name
CacheManager.shared.user.tokenIsValid(){[weak self] in
self?.tableView.reloadData()
}
-
+ LoginVM.fetchCountryList {[weak self] result in
+ guard let self = self else{return}
+ self.tableView.reloadData()
+ }
}
}
+++ /dev/null
-//
-// ModeListView.swift
-// ShenYin
-//
-// Created by liangshi on 2025/8/12.
-//
-
-class ModeListView: BaseView {
- let bottonView = UIView()
- let tipsIcon = UIImageView()
- let titleLabel = UILabel()
- let valueLabel = UILabel()
-
- override func setupViews() {
- addSubviews([bottonView])
- bottonView.addSubviews([titleLabel,valueLabel,tipsIcon])
- // backgroundColor = .red
- bottonView.do { v in
- v.backgroundColor = .rgb(0xFAFAFA)
- v.yc.setCornerRadius(30)
- }
- tipsIcon.do { v in
- // v.backgroundColor = .lightGray
- v.image = UIImage(named: "home_recordHistory")
- }
- titleLabel.do { (v) in
- v.textColor = .rgb(0x313230)
- v.font = .bold(18)
- v.text = "历史录音"
- }
- valueLabel.do { (v) in
- v.textColor = .rgb(0x8d8d8d)
- v.font = .regular(14)
- v.text = "随时随地 一键开录"
- }
-
- yc.addTap(target: self, action: #selector(tapAction))
- }
-
- override func setupLayout() {
- bottonView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(15)
- make.top.equalToSuperview()
- make.bottom.equalToSuperview()
- make.height.equalTo(116)
- }
- titleLabel.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(15)
- make.top.equalTo(35)
- }
- valueLabel.snp.makeConstraints { make in
- make.left.equalTo(titleLabel)
- make.top.equalTo(65)
- }
- tipsIcon.snp.makeConstraints { make in
- make.size.equalTo(50)
- make.right.equalToSuperview().inset(15)
- make.centerY.equalToSuperview()
- }
- }
- @objc func tapAction(){
- App.shared.goToPage(HistoryRecordVC())
- }
-}
-
}
override func setupViews() {
- self.navBar.title = "模式"
+ self.navBar.title = BleManager.shared.connectPeripheral?.device.name ?? ""
navBar.backgroundColor = .clear
view.backgroundColor = .color(.bgColor)
formatter.dateFormat = "yyyyMMddHHmmss"
let name = formatter.string(from: Date())
- let filePath = "\(NSHomeDirectory())/Documents/ShenYin_\(name).txt"
+ let filePath = "\(NSHomeDirectory())/Documents/DeepChords_\(name).txt"
let url = URL(fileURLWithPath: filePath)
let data = self.textView.text.data(using:.utf8)
do {
SVProgressHUD.setDefaultStyle(.dark)
SVProgressHUD.setDefaultMaskType(.clear)
SVProgressHUD.setContainerView(App.shared.window)
- SVProgressHUD.show(UIImage(), status: text)
+// SVProgressHUD.show(UIImage(), status: text)
+ SVProgressHUD.showInfo(withStatus: text)
}
/// 显示自动消失的 HUD,并在消失后执行回调
class PopTextField: BasePresentView2 {
let contentView = UIView()
- private let titleLabel = UILabel()
+ let titleLabel = UILabel()
private let textFiledBg = UIView()
let textFiled = UITextField()
let cancelButton = CustomButton()
contentView.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(18)
make.height.equalTo(200)
- make.center.equalToSuperview()
+ make.centerY.equalToSuperview().offset(-60)
}
titleLabel.do { (v) in
v.textColor = .rgb(0x121212)
v.placeholder = "请输入录音名字"
v.font = .bold(16)
v.textColor = .hexString("#121212")
- v.becomeFirstResponder()
+// v.becomeFirstResponder()
}
cancelButton.do { (v) in
- v.setTitle("å\88 é\99¤", for: .normal)
+ v.setTitle("å\8f\96æ¶\88", for: .normal)
v.titleLabel?.font = .bold(16)
v.setTitleColor(.hexString("#121212"), for: .normal)
v.backgroundColor = .hexString("#F7F7F7")
}
}
@objc func okButtonAction(){
+ textFiled.resignFirstResponder()
guard let text = textFiled.text,text.count > 0 else {
return
}
hide()
}
@objc func cancelButtonAction(){
+ textFiled.resignFirstResponder()
cancelTap?()
hide()
}
pod 'MJRefresh'#刷新
pod 'YYModel'#model解析
pod 'HandyJSON'#model解析
- pod 'RealmSwift'#数据库
+# pod 'RealmSwift'#数据库
pod 'SwiftDate'#时间转换
pod 'SVProgressHUD'#蒙版
pod 'Kingfisher', '~> 6.0'#图片下载K
pod 'SwiftHTTP'
pod 'swiftScan'#二维码
pod 'TZImagePickerController'#图片选择
- pod 'netfox'#调试
+# pod 'netfox'#调试
# pod 'DoraemonKit'#调试
pod 'SocketRocket'#socket,AI用到