static var appLanguage = AppSupportLanguage.chinse
}
class DCGlobal {
-
- /// 高德地图 app key
- static let mapKey = "01d0c91a330f94bd5819d617a91d37a0"
-
- /// 腾讯地图 app key
- static let qqmapKey = "FC6BZ-QCJWB-SOTUF-JLGK6-DTFIK-WCBIF"
- /// 腾讯地图 Secret Key
- static let qqmapSecretKey = "ODo3ZcRrsbzB71UTPBbRHeivpxnhSg9X"
+
/// 微信开发平台 App ID
static let wxAppID = "wxf19317f23b00d8ab"
static let wxUniversalLink = "https://www.thisiot.com/flychat"
static let wxSecret = "SECRET"
- static let appStoreLink = "https://itunes.apple.com/cn/app/1542713301?mt=8"
+// static let appStoreLink = "https://itunes.apple.com/cn/app/6738022284?mt=8"
+ static let appStoreLink = "https://itunes.apple.com/cn/app/6752551504?mt=8"
+
/// 版本检测
- static let appStoreVersionURL = "https://itunes.apple.com/cn/lookup?id=1542713301"
+ static let appStoreVersionURL = "https://itunes.apple.com/cn/lookup?id=6752551504"
}
return
}
let responseStr = response.data.string ?? ""
+ 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
}
completionHandler(T(),"请求失败")
- if let code = dict["code"] as? Int,code == 50001{
- YLprogressHUD.showAutoHiden(text: "当前账号已经退出登录"){
- CacheManager.shared.logout()
- }
- }
+
}
}
private static func handleResponse1<T: HandyJSON>(_ data: Data?,error:Error?, completionHandler: @escaping ((T, String) -> Void)) {
return
}
completionHandler(T(),"请求失败")
- if let code = dict["code"] as? Int,code == 50001{
- YLprogressHUD.showAutoHiden(text: "当前账号已经退出登录"){
- CacheManager.shared.logout()
- }
- }
+// if let code = dict["code"] as? Int,code == 50001{
+// YLprogressHUD.showAutoHiden(text: "当前账号已经退出登录"){
+// CacheManager.shared.user.logout()
+// }
+// }
}
}
class CommonDataModel:ResponseBaseModel {
var data = ""
}
+
+class CommonDataIntModel:ResponseBaseModel {
+ var data:Int = 0
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Vector@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Vector@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Group_2287@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Group_2287@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Frame 1938@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Frame 1938@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Frame 1938@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Frame 1938@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Frame@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Frame@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Group_2440@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Group_2440@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+//
+// BannerCache.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/4.
+//
+
+import HandyJSON
+
+class BannerModelRoot:ResponseBaseModel {
+ var data = [BannerModel]()
+}
+
+class BannerModel:NSObject,HandyJSON,NSCoding {
+ var id = ""
+ var title = ""
+ var cover = ""
+ var url = ""
+ required public override init() { }
+
+ func encode(with aCoder: NSCoder) {
+ aCoder.encode(id, forKey: "id")
+ aCoder.encode(title, forKey: "title")
+ aCoder.encode(cover, forKey: "cover")
+ aCoder.encode(url, forKey: "url")
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ id = aDecoder.decodeObject(forKey: "id") as? String ?? ""
+ title = aDecoder.decodeObject(forKey: "title") as? String ?? ""
+ cover = aDecoder.decodeObject(forKey: "cover") as? String ?? ""
+ url = aDecoder.decodeObject(forKey: "url") as? String ?? ""
+ }
+}
+
+
+
+class BannerCache {
+ static let shared = BannerCache()
+ private let userDefaults = UserDefaults.standard
+ private let deviceListKey = "BannerCache"
+
+ func saveList(_ list: [BannerModel]) {
+ let encoder = NSKeyedArchiver.archivedData(withRootObject: list)
+ userDefaults.set(encoder, forKey: deviceListKey)
+ userDefaults.synchronize()
+ }
+
+ func get() -> [BannerModel] {
+ if let data = userDefaults.data(forKey: deviceListKey),
+ let deviceList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [BannerModel] {
+ return deviceList
+ }
+ return []
+ }
+}
--- /dev/null
+//
+// c.swift
+// ShenYin
+//
+// Created by liangshi on 2025/9/11.
+//
+import CoreBluetooth
+
+class CacheManager{
+ static let shared = CacheManager()
+
+ var user = UserModel()
+
+ init(){
+ user.loadCache()
+ }
+}
+
+
+extension CacheManager{
+ static func uuid()->String{
+ if let value = UserDefaults.standard.value(forKey: "uuid"),let uuid = value as? String{
+ return uuid
+ }
+ let uuid = UUID().uuidString
+ UserDefaults.standard.setValue(uuid, forKey: "uuid")
+ UserDefaults.standard.synchronize()
+ return uuid
+ }
+}
+
+
+extension CacheManager{
+ static func saveImg(_ img:UIImage)->String?{
+ guard let data = img.pngData() else{
+ return nil
+ }
+
+ let filePath = DCFolder.getCacheDirectoryPath()! + "/\(Date().timeIntervalSince1970).png"
+ return saveToFile(data: data, filePath: filePath)
+ }
+ static func saveToFile(data:Data,filePath:String)->String?{
+ let url = URL(fileURLWithPath: filePath)
+ do {
+ try data.write(to: url)
+ return filePath
+ } catch {
+ Logger.debug("Error saving compressed data: \(error)")
+ return nil
+ }
+ }
+}
+
--- /dev/null
+//
+// FileManager.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/4.
+//
+
+class DCFolder {
+ static var user:String{
+ let user = CacheManager.shared.user
+ let path = NSHomeDirectory() + "/Documents/" + user.info.id
+ createFolder(path)
+ return path
+ }
+ static var record:String{
+ let path = DCFolder.user + "/record/"
+ createFolder(path)
+ return path
+ }
+
+ static func createFolder(_ foldPath:String){
+ Logger.debug("路径 " ,foldPath)
+ let fileManager = FileManager.default
+ if !fileManager.fileExists(atPath: foldPath) {
+ do {
+ try FileManager.default.createDirectory(atPath: foldPath, withIntermediateDirectories: true, attributes: nil)
+ } catch {
+ Logger.debug("创建文件夹失败!!!",foldPath)
+ }
+ }
+ }
+
+ // 获取应用沙盒中的缓存目录路径
+ static func getCacheDirectoryPath() -> String? {
+ // 获取缓存目录的URL
+ if let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first {
+ // 转换为路径字符串
+ return cacheURL.path
+ }
+ return nil
+ }
+
+ static func moveFile(srcPath:String,desPath:String)->Bool{
+ let fileManager = FileManager.default
+ do {
+ try fileManager.moveItem(atPath: srcPath, toPath: desPath)
+ return true
+ } catch {
+ Logger.debug("文件移动失败: \(error)")
+ return false
+ }
+ }
+ static func recordFileResave(srcPath:String)->String?{
+
+ let desPath = DCFolder.record + (srcPath as NSString).lastPathComponent
+ let fileManager = FileManager.default
+ do {
+ try fileManager.moveItem(atPath: srcPath, toPath: desPath)
+ Logger.debug("文件保存路径: \(desPath)")
+ return desPath
+ } catch {
+ Logger.debug("文件移动失败: \(error)")
+ 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
+ }
+}
--- /dev/null
+//
+// RecordCache.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/24.
+//
+
+class RecordCache {
+ static let shared = RecordCache()
+ private let userDefaults = UserDefaults.standard
+ private let deviceListKey = "deviceListKey"
+
+ func add(_ device: RecordDetailModel) {
+ var deviceList = getList()
+ if let index = deviceList.firstIndex(where: { $0.createTime == device.createTime }) {
+ deviceList[index] = device
+ }
+ else{
+ deviceList.append(device)
+ }
+ let encoder = NSKeyedArchiver.archivedData(withRootObject: deviceList)
+ userDefaults.set(encoder, forKey: deviceListKey)
+ userDefaults.synchronize()
+ }
+ func remove(_ device: RecordDetailModel) {
+ var deviceList = getList()
+ deviceList.removeAll(where: {$0.createTime == device.createTime})
+ let encoder = NSKeyedArchiver.archivedData(withRootObject: deviceList)
+ userDefaults.set(encoder, forKey: deviceListKey)
+ userDefaults.synchronize()
+ }
+ func remove(list: [RecordDetailModel]) {
+ var deviceList = getList()
+ for item in list {
+ deviceList.removeAll(where: {$0.createTime == item.createTime})
+ }
+
+ let encoder = NSKeyedArchiver.archivedData(withRootObject: deviceList)
+ userDefaults.set(encoder, forKey: deviceListKey)
+ userDefaults.synchronize()
+ }
+
+ func getList() -> [RecordDetailModel] {
+ if let data = userDefaults.data(forKey: deviceListKey),
+ let deviceList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [RecordDetailModel] {
+ return deviceList
+ }
+ return []
+ }
+}
--- /dev/null
+//
+// RecordDetailModel.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/23.
+//
+import HandyJSON
+
+enum FiltterRecordType:String,HandyJSONEnum{
+ case present = "present"
+ case phone = "phone"
+ case translate = "translate"
+ case all = "all"
+ case colletion = "colletion"
+
+ var title:String{
+ switch self {
+ case .present:
+ return "现场录音"
+ case .phone:
+ return "通话录音"
+ case .translate:
+ return "同传听译"
+ case .all:
+ return "全部录音"
+ case .colletion:
+ return "收藏录音"
+ }
+ }
+ static var alls:[FiltterRecordType]{
+ return [.all,.colletion,.present,.phone,.translate]
+ }
+}
+
+enum RecordType:String,HandyJSONEnum{
+ case present = "present"
+ case phone = "phone"
+ case translate = "translate"
+
+ var title:String{
+ switch self {
+ case .present:
+ return "现场录音"
+ case .phone:
+ return "通话录音"
+ case .translate:
+ return "同传听译"
+ }
+ }
+}
+
+class RecordDetailModel:NSObject, NSCoding{
+ func encode(with coder: NSCoder) {
+ coder.encode(from.rawValue, forKey: "from")
+ coder.encode(to.rawValue, forKey: "to")
+ coder.encode(type.rawValue, forKey: "type")
+ coder.encode(origin, forKey: "origin")
+ coder.encode(translate, forKey: "translate")
+ coder.encode(summary, forKey: "summary")
+ coder.encode(path, forKey: "path")
+ coder.encode(name, forKey: "name")
+ coder.encode("\(duration)", forKey: "duration")
+ coder.encode(createTime, forKey: "createTime")
+ coder.encode(favorite, forKey: "favorite")
+ }
+ override init() {
+ createTime = Date().format(.full)
+ }
+
+ required init?(coder: NSCoder) {
+ from = AiSupportLanguage(rawValue: coder.decodeObject(forKey: "from") as! String) ?? .chinse
+ to = AiSupportLanguage(rawValue: coder.decodeObject(forKey: "to") as! String) ?? .english
+ type = RecordType(rawValue: coder.decodeObject(forKey: "type") as! String) ?? .present
+ origin = coder.decodeObject(forKey: "origin") as? String ?? ""
+ translate = coder.decodeObject(forKey: "translate") as? String ?? ""
+ summary = coder.decodeObject(forKey: "summary") as? String ?? ""
+ path = coder.decodeObject(forKey: "path") as? String ?? ""
+ name = coder.decodeObject(forKey: "name") as? String ?? ""
+ duration = Int(coder.decodeObject(forKey: "duration") as! String) ?? 0
+ createTime = coder.decodeObject(forKey: "createTime") as? String ?? ""
+ favorite = coder.decodeObject(forKey: "favorite") as? String ?? ""
+ }
+ var type:RecordType = .present
+ var from:AiSupportLanguage = .chinse
+ var to:AiSupportLanguage = .english
+ var path = ""
+ var name = ""
+ var duration = 0
+ var createTime = ""
+ var origin = ""
+
+ var translate = ""
+ var summary = ""
+ var favorite = "0"
+
+
+}
--- /dev/null
+//
+// TipsCache.swift
+// ShenYin
+//
+// Created by liangshi on 2025/9/26.
+//
+
+class TipsCache{
+ static func needShow(type:RecordTipsType,show:Bool){
+ UserDefaults.standard.set(show, forKey: type.title)
+ UserDefaults.standard.synchronize()
+ }
+ static func needShow(type:RecordTipsType)->Bool{
+ if let value = UserDefaults.standard.value(forKey: type.title){
+ return value as? Bool ?? false
+ }
+ return true
+ }
+}
--- /dev/null
+//
+// UserCache.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/5.
+//
+
+import HandyJSON
+
+class UserCacheInfo:NSObject,HandyJSON,NSCoding {
+ var id = ""
+ var avatar = ""
+ var userName = ""
+ var createTime = ""
+ var phone = ""
+ var email = ""
+ var gender = GenderType.unnkown
+ var countryName = ""
+ var countryId = ""
+
+ required public override init() { }
+
+ func encode(with aCoder: NSCoder) {
+ aCoder.encode(id, forKey: "id")
+ aCoder.encode(avatar, forKey: "avatar")
+ aCoder.encode(userName, forKey: "userName")
+ aCoder.encode(createTime, forKey: "createTime")
+ aCoder.encode(phone, forKey: "phone")
+ aCoder.encode(email, forKey: "email")
+ aCoder.encode(gender.rawValue, forKey: "gender")
+ aCoder.encode(countryName, forKey: "countryName")
+ aCoder.encode(countryId, forKey: "countryId")
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ id = aDecoder.decodeObject(forKey: "id") as? String ?? ""
+ avatar = aDecoder.decodeObject(forKey: "avatar") as? String ?? ""
+ userName = aDecoder.decodeObject(forKey: "userName") as? String ?? ""
+ createTime = aDecoder.decodeObject(forKey: "createTime") as? String ?? ""
+ phone = aDecoder.decodeObject(forKey: "phone") as? String ?? ""
+ email = aDecoder.decodeObject(forKey: "email") as? String ?? ""
+ gender = GenderType(rawValue: aDecoder.decodeObject(forKey: "gender") as! String) ?? .unnkown
+ countryName = aDecoder.decodeObject(forKey: "countryName") as? String ?? ""
+ countryId = aDecoder.decodeObject(forKey: "countryId") as? String ?? ""
+ }
+ static func cacheToInfo(_ cache:UserCacheInfo)->UserInfo{
+ let info = UserInfo()
+ info.id = cache.id
+ info.avatar = cache.avatar
+ info.userName = cache.userName
+ info.createTime = cache.createTime
+ info.phone = cache.phone
+ info.email = cache.email
+ info.gender = cache.gender
+ info.countryName = cache.countryName
+ info.countryId = cache.countryId
+ return info
+ }
+ static func infoToCache(_ info:UserInfo)->UserCacheInfo{
+ let cache = UserCacheInfo()
+ cache.id = info.id
+ cache.avatar = info.avatar
+ cache.userName = info.userName
+ cache.createTime = info.createTime
+ cache.phone = info.phone
+ cache.email = info.email
+ cache.gender = info.gender
+ cache.countryName = info.countryName
+ cache.countryId = info.countryId
+ return cache
+ }
+}
+
+
+class UserCache {
+ static let shared = UserCache()
+ private let userDefaults = UserDefaults.standard
+ private let key = "UserCacheInfo"
+
+ func save(_ info: UserInfo) {
+ let cache = UserCacheInfo.infoToCache(info)
+ let encoder = NSKeyedArchiver.archivedData(withRootObject: cache)
+ userDefaults.set(encoder, forKey: key)
+ userDefaults.synchronize()
+ }
+
+ func get() -> UserInfo? {
+ if let data = userDefaults.data(forKey: key),
+ let model = NSKeyedUnarchiver.unarchiveObject(with: data) as? UserCacheInfo {
+ let info = UserCacheInfo.cacheToInfo(model)
+ return info
+ }
+ return nil
+ }
+}
--- /dev/null
+//
+// Untitled.swift
+// ShenYin
+//
+// Created by liangshi on 2025/9/29.
+//
+import HandyJSON
+
+enum GenderType:String,HandyJSONEnum{
+ case man = "1"
+ case female = "0"
+ case unnkown = "2"
+ var title:String{
+ switch self {
+ case .man:
+ return "男"
+ case .female:
+ return "女"
+ case .unnkown:
+ return "保密"
+ }
+ }
+}
+
+
+class UserInfoRoot:ResponseBaseModel {
+ var data = UserInfo()
+}
+
+class UserInfo:ResponseBaseModel {
+ var id = ""
+ var avatar = ""
+ var userName = ""
+ var createTime = ""
+ var phone = ""
+ var email = ""
+ var gender = GenderType.unnkown
+ var countryName = ""
+ var countryId = ""
+}
+
+
+
--- /dev/null
+//
+// UserModel.swift
+// ShenYin
+//
+// Created by liangshi on 2025/7/30.
+//
+
+
+class UserModel {
+ static let cacheKey = "Login"
+ var token:String? {
+ didSet{
+ saveToken(text: token)
+ }
+ }
+ var isLogin:Bool{
+ return token != nil
+ }
+ func loadCache(){
+ self.token = getToken()
+ if let cache = UserCache.shared.get(){
+ self.info = cache
+ }
+
+ if self.token != nil {
+ tokenIsValid()
+ }
+ }
+
+ var storageSize = 0
+ var info = UserInfo()
+}
+
+extension UserModel{
+ func login(token:String){
+ self.token = token
+ NotificationManager.post(type: .login, objtect: nil)
+
+ }
+ func logout(){
+ self.token = nil
+ NotificationManager.post(type: .logout, objtect: nil)
+ App.shared.goToLogin()
+ }
+ func tokenIsValid(finished: (() -> Void)? = nil){
+ HttpClient.request(CommomApi.token) { [weak self](model:UserInfoRoot,res) in
+ guard let self = self else{return}
+ if model.isSuccess{
+ self.info = model.data
+ UserCache.shared.save(self.info)
+ }
+// else{
+// logout()
+// }
+ finished?()
+ }
+ }
+
+ func getStorageSize(completion:@escaping (_ result:CommonDataIntModel) ->Void){
+ HttpClient.request(.storageSize) { [weak self](result:CommonDataIntModel,res) in
+ guard let self = self else{return}
+ if result.isSuccess{
+ storageSize = result.data
+ }
+ completion(result)
+ }
+ }
+
+}
+
+extension UserModel{
+ private func getToken()->String?{
+ if let value = UserDefaults.standard.value(forKey: UserModel.cacheKey),let token = value as? String{
+ return token
+ }
+ return nil
+
+ }
+ private func saveToken(text:String?){
+ if let text = text {
+ UserDefaults.standard.set(text, forKey: UserModel.cacheKey)
+ UserDefaults.standard.synchronize()
+ }
+ else{
+ UserDefaults.standard.removeObject(forKey: UserModel.cacheKey)
+ UserDefaults.standard.synchronize()
+ }
+ }
+}
--- /dev/null
+//
+// UILabel+line.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/3.
+//
+import UIKit
+
+extension UILabel {
+ func setLineSpacing(spacing: CGFloat) {
+ guard let text = text else { return }
+ let attributedString = NSMutableAttributedString(string: text)
+ let paragraphStyle = NSMutableParagraphStyle()
+ paragraphStyle.lineSpacing = spacing
+ attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length))
+ self.attributedText = attributedString
+ }
+}
public let leftView = UIButton()
public let titleLabel = UILabel()
public let separatorLine = UIView()
- public lazy var rightView = setupRightView()
+ public var rightView = UIButton()
private var navTitle: String
public init(title: String = "", delegate: BaseNavigationBarDelegate? = nil) {
v.setImage(UIImage(named: "arrow_back"), for: .normal)
v.addTarget(self, action: #selector(leftViewTapped), for: .touchUpInside)
}
+ setupRightView()
}
- func setupRightView() -> UIButton {
- let rightBtn = UIButton()
- addSubview(rightBtn)
- rightBtn.snp.makeConstraints { (m) in
+ func setupRightView() {
+ rightView.isHidden = true
+ addSubview(rightView)
+ rightView.snp.makeConstraints { (m) in
m.top.equalTo(kNavTop)
m.trailing.bottom.equalToSuperview()
m.width.greaterThanOrEqualTo(48)
}
- rightBtn.do { (v) in
+ rightView.do { (v) in
v.setTitleColor(.rgb(0x222222), for: .normal)
v.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 15)
v.imageView?.contentMode = .right
v.addTarget(self, action: #selector(rightViewTapped), for: .touchUpInside)
}
- return rightBtn
}
@discardableResult
}
return views
}
-// func setupRightViews(_ views:[UIView]){
-// var x = 0
-// for item in views {
-// let w = item.bounds.size.width
-// addSubview(item)
-// item.snp.makeConstraints { (m) in
-// m.top.equalTo(kNavTop)
-// m.bottom.equalToSuperview()
-// m.width.greaterThanOrEqualTo(w)
-// m.right.equalToSuperview().inset(x)
-// }
-//
-// x = x + w
-// }
-// }
+ func setupRightViews(_ views:[UIView]){
+ var x = 0.0
+ for item in views {
+ let w = item.bounds.size.width
+ addSubview(item)
+ item.snp.makeConstraints { (m) in
+ m.top.equalTo(kNavTop)
+ m.bottom.equalToSuperview()
+ m.width.greaterThanOrEqualTo(w)
+ m.right.equalToSuperview().inset(x)
+ }
+
+ x = x + w
+ }
+ }
+
}
self.tabBar.backgroundColor = .white
view.backgroundColor = .color(.bgColor)
- self.selectedIndex = 0
+// self.selectedIndex = 4
}
}
webView.addSubview(progressView)
navBar.title = initData.title
+ navBar.rightView.isHidden = false
navBar.rightView.setTitle("关闭", for: .normal)
view.backgroundColor = .color(.bgColor)
bar.startAnimating {[weak self] in
guard let self = self else{return}
//toolBar.recordBtn.stopCli()
- guard let path = recordFilePath else{return}
+ guard let path = recordFilePath,let wavPath = DCFolder.recordFileResave(srcPath: path) else{return}
let v = PopTextField()
v.show()
v.cancelTap = {
model.from = bar.leftItem.language
model.to = .english
model.name = text
- model.path = path
+ model.path = wavPath
model.duration = YLToos.getDuration(model.path)
model.origin = textView.text
model.translate = ""
v.textAlignment = .left
}
line.do { v in
- // v.backgroundColor = .hexString("#93C6EC")
+// v.backgroundColor = .hexString("#93C6EC")
}
copyIcon.do { v in
v.image = UIImage(named: "play_animate_3")
override func setupViews() {
navBar.title = "中英互译"
+ navBar.rightView.isHidden = false
navBar.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
view.addSubview(tableView)
view.addSubview(toolBar)
bar.startAnimating {[weak self] in
guard let self = self else{return}
// toolBar.recordBtn.stopCli()
- guard let path = recordFilePath else{return}
+ guard let path = recordFilePath,let wavPath = DCFolder.recordFileResave(srcPath: path) else{return}
let v = PopTextField()
v.show()
v.cancelTap = {
model.from = bar.leftItem.language
model.to = bar.rightItem.language
model.name = text
- model.path = path
+ model.path = wavPath
model.duration = YLToos.getDuration(model.path)
model.origin = origin
model.translate = translate
override func setupViews() {
navBar.leftView.isHidden = true
+ navBar.rightView.isHidden = false
navBar.rightView.setImage(UIImage(named: "add_icon"), for: .normal)
self?.startConectBle(model)
}
}
- CacheManager.shared.tokenIsValid(){[weak self] in
+ CacheManager.shared.user.tokenIsValid(){[weak self] in
self?.collectionView.reloadData()
}
}
// v.show(animate: true)
App.shared.goToPage(BleScanVC())
+
}
view.addSubviews([toolBar,tableView,splitView])
navBar.title = "对话翻译"
+ navBar.rightView.isHidden = false
navBar.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
toolBar.do { v in
bar.startAnimating {[weak self] in
guard let self = self else{return}
// toolBar.recordBtn.stopCli()
- guard let path = recordFilePath else{return}
+ guard let path = recordFilePath,let wavPath = DCFolder.recordFileResave(srcPath: path) else{return}
let v = PopTextField()
v.show()
v.cancelTap = {
model.from = bar.leftItem.language
model.to = .english
model.name = text
- model.path = path
+ model.path = wavPath
model.duration = YLToos.getDuration(model.path)
model.origin = textView.text
model.translate = ""
/// - string: 要保存的字符串
/// - fileName: 文件名(不包含扩展名)
/// - Returns: 是否保存成功
- static func saveStringAsTxt(_ string: String) -> String? {
- let fileURL = getDocumentsDirectory().appendingPathComponent("\(Date().format(.full6))").appendingPathExtension("txt")
+ static func saveStringAsTxt(_ string: String,fileName:String = "\(Date().format(.full6))") -> String? {
+ let fileURL = getDocumentsDirectory().appendingPathComponent(fileName).appendingPathExtension("txt")
do {
try string.write(to: fileURL, atomically: true, encoding:.utf8)
return fileURL.path
return nil
}
}
+
}
let durationLabel = UILabel()
let dateLabel = UILabel()
let typeLabel = UILabel()
+ var longPressCallback:((_ cell:HistoryRecordCell)->Void)?
var model:RecordHistoryModel?{
didSet{
v.backgroundColor = UIColor.white
v.layer.cornerRadius = 12
v.layer.masksToBounds = true
+ let longTap = UILongPressGestureRecognizer(target: self, action: #selector(longPressAction(_:)))
+ bgView.addGestureRecognizer(longTap)
}
titleLabel.do { (v) in
v.textColor = .rgb(0x121212)
playIcon.do { v in
v.image = UIImage(named: "record_play 2")
}
+
}
override func setupLayout() {
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)
RecordCache.shared.add(localModel)
}
}
+
+ @objc func longPressAction(_ gesture: UILongPressGestureRecognizer) {
+ if gesture.state == .began {
+ bgView.backgroundColor = .lightGray.withAlphaComponent(0.5)
+ longPressCallback?(self)
+ } else if gesture.state == .ended {
+ print("长按结束")
+ }
+ }
+
+ override func setEditing(_ editing: Bool, animated: Bool) {
+ super.setEditing(editing, animated: animated)
+ if editing {
+ if let deleteButton = findDeleteButton(in: self) {
+ deleteButton.backgroundColor = UIColor.red
+ deleteButton.setTitleColor(UIColor.white, for:.normal)
+ }
+ }
+ }
+
+ private func findDeleteButton(in view: UIView) -> UIButton? {
+ for subview in view.subviews {
+ if let button = subview as? UIButton, button.titleLabel?.text == "自定义删除" {
+ return button
+ } else if let foundButton = findDeleteButton(in: subview) {
+ return foundButton
+ }
+ }
+ return nil
+ }
}
--- /dev/null
+//
+// RecordHistoryBottomView.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/4.
+//
+
var updateTime = ""
required public init() { }
}
+
+class RecordHistorySelectedModel:HandyJSON{
+ var isSelcted = false
+ var model = RecordDetailModel()
+
+ required public init() { }
+}
--- /dev/null
+//
+// CloudRecordVC.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/25.
+//
+
+
+import UIKit
+import MJRefresh
+class CloudRecordVC: BaseVC{
+ let tableView = UITableView(frame: .zero, style: .plain)
+ let vm = HistoryRecordVM()
+ var list = [RecordHistoryModel]()
+
+ 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.title = "云存储空间"
+ let items = [NavigationRightItem(image: UIImage(named: "filter"),target: self, action: #selector(filterAction)),NavigationRightItem(image: UIImage(named: "search"), target: self,action: #selector(searchAction))]
+ v.setupRightViews(items)
+ }
+
+ tableView.do { v in
+ v.backgroundColor = .rgb(0xF7F7F7)
+ v.delegate = self
+ v.dataSource = self
+ v.estimatedRowHeight = 84
+ v.separatorStyle = .none
+ v.register(HistoryRecordCell.self, forCellReuseIdentifier: HistoryRecordCell.reuseID)
+ v.mj_header = MJRefreshNormalHeader(refreshingTarget: self, refreshingAction: #selector(refreshAction))
+ v.mj_footer = MJRefreshBackNormalFooter(refreshingTarget: self, refreshingAction: #selector(loadMoreAction))
+ }
+ view.addSubviews([tableView])
+ }
+ override func setupLayout() {
+ tableView.snp.makeConstraints { make in
+ make.left.right.equalToSuperview()
+ make.top.equalTo(kNavBtm)
+ make.bottom.equalToSuperview()
+ }
+ }
+ override func setupData() {
+ refreshAction()
+ }
+ @objc func searchAction(){
+
+ }
+ @objc func filterAction(){
+ let list = FiltterRecordType.alls.map({$0.title})
+ let v = CustomPicker(title: "筛选录音", list:list )
+ v.selectedIndex = list.firstIndex(where: {vm.type.title == $0})!
+ v.show()
+ v.didSelected = {[weak self] (index,value) in
+ guard let self = self else { return }
+ vm.type = FiltterRecordType.alls.first(where: {$0.title == value})!
+ tableView.mj_header?.beginRefreshing()
+ }
+ }
+ @objc func refreshAction(){
+ vm.refresh {[weak self] result in
+ guard let self = self else {return}
+ tableView.mj_header?.endRefreshing()
+ if result.success{
+ tableView.reloadData()
+ }
+
+ if result.success,result.data.hasNext == false{
+ tableView.mj_footer?.endRefreshingWithNoMoreData()
+ }
+ else{
+ tableView.mj_footer?.endRefreshing()
+ }
+ }
+ }
+ @objc func loadMoreAction(){
+ vm.loadMore {[weak self] result in
+ guard let self = self else {return}
+ if result.success{
+ tableView.reloadData()
+ }
+ }
+ }
+}
+
+extension CloudRecordVC:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return vm.list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = HistoryRecordCell.cell(withTableView: tableView, indexPath: indexPath)
+ cell.model = vm.list[indexPath.row]
+ return cell
+ }
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let data = vm.list[indexPath.row]
+ let vc = RecordDetailVC(remoteData: data)
+ vc.delegateCallback = {[weak self] in
+ guard let self = self else{return}
+ vm.list.removeAll(where: {data === $0})
+ tableView.reloadData()
+ }
+ App.shared.goToPage(vc)
+// let api = CommomApi.getVoiceRecord(recordId: data.id)
+// HttpClient.request(api) {[weak self] (result:RecordHistoryDetailRoot,res) in
+// guard let self = self else {return}
+// if result.isSuccess{
+// let model = RecordDetailModel()
+// model.type = .translate
+// model.origin = result.data.summary
+// model.translate = ""
+// model.path = result.data.fileId
+// model.name = result.data.name
+// App.shared.goToPage(RecordDetailVC(record: model))
+// }
+// }
+
+
+ }
+ // 实现滑动删除功能
+ 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)
+ }
+ }
+
+ // 允许编辑
+ func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
+ return true
+ }
+}
--- /dev/null
+//
+// RecordFontVC.swift
+// ShenYin
+//
+// Created by liangshi on 2025/8/13.
+//
+
+import UIKit
+class RecordFontVC: BaseVC{
+ let tableView = UITableView(frame: .zero, style: .plain)
+ var list:[FontType] = [.min,.stand,.big]
+ var currentType = FontCache.getFont()
+ let btn = CustomButton()
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ // Do any additional setup after loading the view.
+ }
+ override func setupViews() {
+ self.navBar.title = "调整字号"
+ tableView.do { v in
+ v.backgroundColor = .rgb(0xF7F7F7)
+ v.delegate = self
+ v.dataSource = self
+ v.rowHeight = 52
+ v.separatorStyle = .none
+ v.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0)
+ v.register(SelectCell.self, forCellReuseIdentifier: SelectCell.reuseID)
+ }
+ view.addSubviews([tableView,btn])
+
+ btn.set(title: "设置", target: self, action: #selector(btnAction))
+ }
+ override func setupLayout() {
+ tableView.snp.makeConstraints { make in
+ make.left.right.bottom.equalToSuperview()
+ make.top.equalTo(kNavBtm)
+ }
+ btn.snp.makeConstraints { make in
+ make.width.equalTo(272)
+ make.height.equalTo(46)
+ make.centerX.equalToSuperview()
+ make.bottom.equalToSuperview().inset(82)
+ }
+ }
+ @objc func btnAction(){
+ FontCache.saveFont(type: currentType)
+ self.navigationController?.popViewController(animated: true)
+ }
+}
+
+extension RecordFontVC:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = SelectCell.cell(withTableView: tableView, indexPath: indexPath)
+ cell.fontType = list[indexPath.row]
+ let rect = CGRect(x: 0, y: 0, width: kScreenWid - 36, height: 52)
+ if indexPath.row == 0 {
+ cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 8, height: 8))
+ }
+ else if indexPath.row == list.count - 1{
+ cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: 8, height: 8))
+ }
+ else{
+ cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
+ }
+ cell.selectedIcon.isHidden = cell.fontType != currentType
+ return cell
+ }
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let data = list[indexPath.row]
+ currentType = data
+ tableView.reloadData()
+ }
+}
+
+
--- /dev/null
+//
+// RecordShareVC.swift
+// ShenYin
+//
+// Created by liangshi on 2025/8/13.
+//
+
+import UIKit
+class RecordShareVC: BaseVC{
+ let tableView = UITableView(frame: .zero, style: .plain)
+ var list:[ShareType] = [.audio_document,.audio,.document]
+ var currentType = ShareType.audio_document
+ let btn = CustomButton()
+
+ var recordList = [RecordDetailModel]()
+ var cloudList = [RecordHistoryModel]()
+
+ init(localList: [RecordDetailModel]) {
+ self.recordList = localList
+ super.init()
+ }
+ init(cloudList : [RecordHistoryModel]) {
+ self.cloudList = cloudList
+ super.init()
+ }
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ // Do any additional setup after loading the view.
+ }
+ override func setupViews() {
+ self.navBar.title = "分享"
+ tableView.do { v in
+ v.backgroundColor = .rgb(0xF7F7F7)
+ v.delegate = self
+ v.dataSource = self
+ v.rowHeight = 52
+ v.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0)
+ v.separatorStyle = .none
+ v.register(SelectCell.self, forCellReuseIdentifier: SelectCell.reuseID)
+ v.tableHeaderView = ShareHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 70))
+ }
+ view.addSubviews([tableView,btn])
+
+ btn.set(title: "导出", target: self, action: #selector(btnAction))
+ }
+ override func setupLayout() {
+ tableView.snp.makeConstraints { make in
+ make.left.right.bottom.equalToSuperview()
+ make.top.equalTo(kNavBtm)
+ }
+ btn.snp.makeConstraints { make in
+ make.width.equalTo(272)
+ make.height.equalTo(46)
+ make.centerX.equalToSuperview()
+ make.bottom.equalToSuperview().inset(82)
+ }
+ }
+
+ override func setupData() {
+
+ }
+ func loadFile(filedId id:String){
+ let api = CommomApi.recordUrl(filedId: id)
+ HttpClient.request(api) {[weak self] (model:CommonDataModel,res) in
+ guard let self = self else {return}
+ if model.isSuccess{
+ startDownload(url: model.data)
+ }
+ }
+ }
+ func startDownload(url:String){
+ // let url = "https://dc-cloud-priv.tos-cn-guangzhou.volces.com/music-file/2025_10_09/1976135290430767105.mp3"
+// HttpClient.download(url: url,type: "wav"){[weak self] result in
+// guard let self = self else {return}
+// if let path = result{
+// recordModel.path = path
+// }
+// }
+ }
+
+ @objc func btnAction(){
+ if recordList.count == 1,let recordModel = recordList.first {
+ if currentType == .audio {
+ if recordModel.path.isNotEmpty {
+ saveFile(filePath: recordModel.path)
+ }
+ }
+ else if currentType == .document{
+ guard let path = FileSaver.saveStringAsTxt(recordModel.origin,fileName: recordModel.name + "") else {
+ return
+ }
+ saveFile(filePath: path)
+ }
+ else{
+
+ guard let orginPath = FileSaver.saveStringAsTxt(recordModel.origin ,fileName: recordModel.name + "") else {
+ return
+ }
+ var list = [orginPath]
+ if recordModel.path.isNotEmpty {
+ list.append(recordModel.path)
+ }
+
+ if recordModel.translate.count > 0,let path = FileSaver.saveStringAsTxt(recordModel.translate ,fileName: recordModel.name + "_translate") {
+ list.append(path)
+ }
+ if recordModel.summary.count > 0,let path = FileSaver.saveStringAsTxt(recordModel.summary ,fileName: recordModel.name + "_summary") {
+ list.append(path)
+ }
+ guard let path = FileSaver.zipFiles(files: list) else { return }
+
+ saveFile(filePath: path)
+ }
+ }
+ }
+}
+extension RecordShareVC:UIDocumentPickerDelegate{
+ //保存文件到手机文件指定目录
+ func saveFile(filePath:String) {
+ if !FileManager.default.fileExists(atPath: filePath){
+ Logger.debug("文件不存在",filePath)
+ return
+ }
+
+ let fUrl = NSURL(fileURLWithPath: filePath)
+ let vc = UIDocumentPickerViewController(url: fUrl as URL, in: .exportToService);
+ vc.delegate = self
+ vc.modalPresentationStyle = .overFullScreen
+ self.present(vc, animated: true)
+ }
+ public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
+ controller.dismiss(animated: true)
+ }
+}
+
+extension RecordShareVC:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = SelectCell.cell(withTableView: tableView, indexPath: indexPath)
+ cell.shareType = list[indexPath.row]
+ let rect = CGRect(x: 0, y: 0, width: kScreenWid - 36, height: 52)
+ if indexPath.row == 0 {
+ cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 8, height: 8))
+ }
+ else if indexPath.row == list.count - 1{
+ cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: 8, height: 8))
+ }
+ else{
+ cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
+ }
+ cell.selectedIcon.isHidden = cell.shareType != currentType
+ return cell
+ }
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let data = list[indexPath.row]
+ currentType = data
+ tableView.reloadData()
+ }
+}
+
+class ShareHeaderView: BaseView {
+ let titleLabel = UILabel()
+
+ override func setupViews() {
+ addSubviews([titleLabel])
+ titleLabel.do { (v) in
+ v.textColor = .hexString("#666666")
+ v.font = .regular(14)
+ v.numberOfLines = 0
+
+ let text = "多个文件将压缩成一个.zip的文件以便于分享。请选择您需要导出的文件类型:"
+ let textString = NSAttributedString(string: text)
+ let mutableAttributedString = NSMutableAttributedString()
+ mutableAttributedString.append(textString)
+ v.attributedText = mutableAttributedString
+ }
+ }
+
+ override func setupLayout() {
+ titleLabel.snp.makeConstraints { make in
+ make.left.right.equalToSuperview().inset(18)
+ make.top.equalToSuperview()
+ make.bottom.equalToSuperview()
+ }
+ }
+}
--- /dev/null
+//
+// HistorySearchBottomView.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/4.
+//
+
+
+class HistorySearchBottomView: BaseView {
+ let outItem = BarItem()
+ let deleteItem = BarItem()
+
+ override func setupViews() {
+ backgroundColor = .white
+ addSubviews([outItem,deleteItem])
+ outItem.do { v in
+ v.icon.image = UIImage(named: "output_icon")
+ v.titleLabel.text = "导出"
+ }
+ deleteItem.do { v in
+ v.icon.image = UIImage(named: "delete_4")
+ v.titleLabel.text = "删除"
+ }
+ }
+ override func setupLayout() {
+ outItem.snp.makeConstraints { make in
+ make.size.equalTo(80)
+ make.top.equalTo(15)
+ make.centerX.equalTo(kScreenWid/4)
+ }
+ deleteItem.snp.makeConstraints { make in
+ make.size.equalTo(80)
+ make.top.equalTo(15)
+ make.centerX.equalTo(kScreenWid/4*3)
+ }
+ }
+
+ class BarItem: BaseView {
+ let icon = UIImageView()
+ let titleLabel = UILabel()
+
+ override func setupViews() {
+// backgroundColor = .red
+ addSubviews([titleLabel,icon])
+ icon.do { v in
+ v.image = UIImage(named: "polygon")
+ }
+ titleLabel.do { v in
+ v.textColor = .rgb(0x121212)
+ v.font = .regular(10)
+ }
+ }
+
+ override func setupLayout() {
+ icon.snp.makeConstraints { make in
+ make.size.equalTo(30)
+ make.top.equalToSuperview()
+ make.centerX.equalToSuperview()
+ }
+ titleLabel.snp.makeConstraints { make in
+ make.centerX.equalToSuperview()
+ make.top.equalToSuperview().inset(35)
+ }
+ }
+ }
+}
--- /dev/null
+//
+// HistorySearchCell.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/4.
+//
+
+class HistorySearchCell: 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:HistorySearchCell)->Void)?
+
+// var model:RecordHistoryModel?{
+// didSet{
+// guard let model = 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")
+// }
+// }
+ 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 = localModel{
+ mode.isSelcted = !mode.isSelcted
+ self.localModel = mode
+ }
+ selectedCallback?(self)
+ }
+
+}
--- /dev/null
+//
+// Untitled.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/4.
+//
+
+import UIKit
+class HistorySelectedVC: BaseVC{
+ let tableView = UITableView(frame: .zero, style: .plain)
+ let bottomView = HistorySearchBottomView()
+ var list = [RecordHistorySelectedModel]()
+ var deleteCallback:((_ list:[RecordDetailModel])->Void)?
+
+ init(data:[RecordDetailModel]) {
+ var tempList = [RecordHistorySelectedModel]()
+ for item in data {
+ let model = RecordHistorySelectedModel()
+ 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(HistorySearchCell.self, forCellReuseIdentifier: HistorySearchCell.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 = [RecordDetailModel]()
+ for item in list {
+ if item.isSelcted {
+ tempList.append(item.model)
+ }
+ }
+ App.shared.goToPage(RecordShareVC(localList: tempList))
+ }
+ @objc func deleteAction(){
+ var tempList = [RecordDetailModel]()
+ for item in list {
+ if item.isSelcted {
+ tempList.append(item.model)
+ }
+ }
+ if tempList.count == 0 {
+ return
+ }
+
+ CustomAlert.showWith(title: "您要删除这些录音吗?", messgage: "删除后,这些记录将无法恢复。", cancelCallback: {}) {[weak self] in
+ guard let self = self else{return}
+ for item in tempList{
+ list.removeAll(where: {$0.model.createTime == item.createTime})
+ }
+ RecordCache.shared.remove(list:tempList)
+ deleteCallback?(tempList)
+ tableView.reloadData()
+
+ }
+ }
+}
+
+extension HistorySelectedVC:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = HistorySearchCell.cell(withTableView: tableView, indexPath: indexPath)
+ cell.localModel = list[indexPath.row]
+ cell.selectedCallback = {[weak self] cell in
+ self?.selectedAction()
+ }
+ 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
+// }
+}
guard let data = data else {
return
}
- App.shared.goToPage(HistoryRecordShareVC(record: data,fileId: remoteData?.fileId))
+ if let cloud = remoteData {
+ App.shared.goToPage(RecordShareVC(cloudList: [cloud]))
+ }
+ else{
+ App.shared.goToPage(RecordShareVC(localList: [data]))
+ }
}
v.fontCallback = {[weak self] in
guard let self = self else {
return
}
- App.shared.goToPage(HistoryFontVC())
+ App.shared.goToPage(RecordFontVC())
}
v.deleteCallback = {[weak self] in
guard let self = self else {
return
}
- CustomAlert.showWith(title: "æ\8f\90示", messgage: "ç¡®å®\9aè¦\81å\88 é\99¤é\80\89ä¸ç\9a\84项ç\9b®å\90\97ï¼\9f", cancelCallback: {}) {
+ CustomAlert.showWith(title: "æ\82¨è¦\81å\88 é\99¤è¿\99æ\9d¡å½\95é\9f³å\90\97?", messgage: "å\88 é\99¤å\90\8eï¼\8cæ¤è®°å½\95å°\86æ\97 æ³\95æ\81¢å¤\8d", cancelCallback: {}) {
if let data = self.remoteData{
let api = CommomApi.deleteVoiceRecord(recordId: data.id)
HttpClient.request(api) {(model:ResponseBaseModel,res) in
params["duration"] = YLToos.getDuration(data!.path)
params["fileId"] = fileId
params["summary"] = data!.origin
+ params["sourceLanguage"] = data!.from.value
+ params["targetLanguage"] = data!.to.value
+
Logger.debug(params)
HttpClient.request(.voiceRecord(param: params)) {[weak self](model:AppUpdateModelRoot,res) in
if model.isSuccess{
view.addSubviews([toolBar,textView,translateTextView])
navBar.title = "同传听译"
+ navBar.rightView.isHidden = false
navBar.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
toolBar.do { v in
JoyGemSIManager.shared().stop()
bar.startAnimating {[weak self] in
guard let self = self else{return}
- guard let path = recordFilePath else{return}
+ guard let path = recordFilePath,let wavPath = DCFolder.recordFileResave(srcPath: path) else{return}
let v = PopTextField()
v.show()
v.cancelTap = {
let model = RecordDetailModel()
model.type = .translate
model.from = bar.leftItem.language
- model.to = .english
+ model.to = bar.rightItem.language
model.name = text
- model.path = path
+ model.path = wavPath
model.duration = YLToos.getDuration(model.path)
model.origin = textView.text ?? ""
model.translate = translateTextView.text ?? ""
override func setupViews() {
self.navBar.title = ""
- navBar.rightView.setImage(UIImage(named: "tips_cion"), for: .normal)
+
+// navBar.rightView.setImage(UIImage(named: "tips_cion"), for: .normal)
view.addSubviews([titleLabel,addView,scanView])
titleLabel.do { v in
v.text = "从这里选择一项用来添加设备"
// Do any additional setup after loading the view.
}
override func setupViews() {
+ navBar.rightView.isHidden = false
navBar.rightView.setImage(UIImage(named: "refresh_icon"), for: .normal)
tableView.do { v in
v.backgroundColor = .rgb(0xF7F7F7)
}
else{
self.scanState = .none
+// self.headerView.rippleView.stopAnimating()
}
self.tableView.reloadData()
}
}
override func setupViews() {
// backgroundColor = .green
+ backgroundColor = UIColor.color(.bgColor)
addSubviews([titleLabel,desLabel])
titleLabel.do { (v) in
v.textColor = .rgb(0x121212)
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
}
}
contentView.addSubview(bgView)
bgView.addSubviews([originalLabel,translationLabel,line,copyIcon])
-
-
- // let brokenLineView = BrokenLineView(frame: CGRect(x: 0, y: 0, width: 300, height:100))
- // addSubview(brokenLineView)
}
override func setupLayout() {
}
func didLogin(){
+ // 加载目录
+ Logger.debug(DCFolder.user)
+ Logger.debug(DCFolder.record)
window?.rootViewController = BaseTC()
}
func goToLogin(){
App.shared.window = window
window?.rootViewController = BaseTC()
-// window?.rootViewController = UINavigationController(rootViewController: FeedbackCommitVC())
+// window?.rootViewController = UINavigationController(rootViewController: HistorySelectedVC())
AppLaunch.start()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
- CacheManager.shared.tokenIsValid(){[weak self] in
+ CacheManager.shared.user.tokenIsValid(){[weak self] in
self?.header.updateUI()
}
}
}
override func setupViews() {
self.navBar.title = "帮助与反馈"
+ navBar.rightView.isHidden = false
navBar.rightView.setImage(UIImage(named: "feedback_history"), for: .normal)
view.addSubview(bgView)
import UIKit
class InstructionsVC: BaseVC{
+ let bar = SearchBar()
let tableView = UITableView(frame: .zero, style: .plain)
- var list = [InstructionsModel]()
+ var orginList = [InstructionsModel]()
+ var searchList = [InstructionsModel]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func setupViews() {
self.navBar.title = "电子说明书"
+
+ view.addSubviews([tableView,bar])
+ bar.do { v in
+ v.delegate = self
+ }
tableView.do { v in
v.backgroundColor = .color(.bgColor)
v.delegate = self
v.sectionHeaderHeight = 52
v.separatorStyle = .none
v.register(CustomCell1.self, forCellReuseIdentifier: CustomCell1.reuseID)
- v.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: kScreenHei, height: 20))
+// v.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: kScreenHei, height: 20))
}
- view.addSubview(tableView)
+
}
override func setupLayout() {
+ bar.snp.makeConstraints { make in
+ make.top.equalToSuperview().inset(kNavBtm + 10)
+ make.left.right.equalToSuperview()
+ make.height.equalTo(44)
+ }
tableView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
- make.top.equalTo(kNavBtm)
+ make.top.equalTo(bar.snp.bottom).offset(10)
}
}
override func setupData() {
HttpClient.request(api) {[weak self] (model:InstructionsModelRoot,res) in
guard let self = self else {return}
if model.isSuccess{
- self.list = model.data
+ self.orginList = model.data
+ self.searchList = self.orginList
self.tableView.reloadData()
}
}
extension InstructionsVC:UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return list.count
+ return searchList.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = CustomCell1.cell(withTableView: tableView, indexPath: indexPath)
- cell.titleLabel.text = list[indexPath.row].name
+ cell.titleLabel.text = searchList[indexPath.row].name
let rect = CGRect(x: 0, y: 0, width: kScreenWid - 36, height: 52)
if indexPath.row == 0 {
cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 12, height: 12))
}
- else if indexPath.row == list.count - 1{
+ else if indexPath.row == searchList.count - 1{
cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: 12, height: 12))
}
else{
cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
}
- if list.count == 1 {
+ if searchList.count == 1 {
cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 12, height: 12))
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- let data = list[indexPath.row]
+ let data = searchList[indexPath.row]
App.shared.goToPage(InstructionsDetailVC(productId: data.id))
}
}
+
+extension InstructionsVC:SearchBarDelegate{
+ func searchBarTextDidChange(_ toolBar: SearchBar, _ text: String) {
+ if text.isEmpty {
+ searchList = orginList
+ }
+ else{
+ var list = [InstructionsModel]()
+ for item in orginList {
+ if item.name.contains(text) {
+ list.append(item)
+ }
+ }
+ searchList = list
+ }
+ tableView.reloadData()
+ }
+
+
+}
--- /dev/null
+//
+// Untitled.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/4.
+//
+
+
+@objc protocol SearchBarDelegate {
+ func searchBarTextDidChange(_ toolBar:SearchBar,_ text:String)
+}
+
+class SearchBar:UIView{
+ let bgView = UIView()
+ let textField = UITextField()
+ let icon = UIImageView(image: UIImage(named: "search_2"), )
+
+ weak var delegate:SearchBarDelegate?
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ backgroundColor = .clear
+
+ bgView.do { v in
+ v.yc.setCornerRadius(8)
+ v.backgroundColor = .white
+ }
+
+
+ textField.do { v in
+ v.clearButtonMode = .whileEditing
+ v.backgroundColor = .clear
+ v.placeholder = "输入型号查询"
+ v.returnKeyType = .done
+ v.delegate = self
+ v.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
+ }
+
+ addSubview(bgView)
+ bgView.addSubview(icon)
+ bgView.addSubview(textField)
+
+ bgView.snp.makeConstraints { make in
+ make.left.right.equalToSuperview().inset(18)
+ make.top.bottom.equalToSuperview()
+ }
+ icon.snp.makeConstraints { make in
+ make.size.equalTo(18)
+ make.centerY.equalToSuperview()
+ make.left.equalToSuperview().inset(12)
+ }
+ textField.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(34)
+ make.top.bottom.equalToSuperview()
+ make.right.equalToSuperview()
+ }
+ }
+
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ @objc func textFieldDidChange(_ textField:UITextField){
+ delegate?.searchBarTextDidChange(self, textField.text ?? "")
+ }
+
+}
+extension SearchBar:UITextFieldDelegate{
+ func textFieldShouldReturn(_ textField: UITextField) -> Bool {
+ textField.resignFirstResponder()
+ return false
+ }
+}
let api = CommomApi.login(param: param)
HttpClient.request(api) { (model:LoginModel,res) in
if model.isSuccess{
- CacheManager.shared.login(token: model.data)
+ CacheManager.shared.user.login(token: model.data)
}
completion(model)
}
let api = CommomApi.phoneCodeLogin(param: param)
HttpClient.request(api) { (model:LoginModel,res) in
if model.isSuccess{
- CacheManager.shared.login(token: model.data)
+ CacheManager.shared.user.login(token: model.data)
}
completion(model)
}
let api = CommomApi.emailCodeLogin(param: param)
HttpClient.request(api) { (model:LoginModel,res) in
if model.isSuccess{
- CacheManager.shared.login(token: model.data)
+ CacheManager.shared.user.login(token: model.data)
}
completion(model)
}
let api = CommomApi.appleLogin(param: param)
HttpClient.request(api) { (model:LoginModel,res) in
if model.isSuccess{
- CacheManager.shared.login(token: model.data)
+ CacheManager.shared.user.login(token: model.data)
}
completion(model)
}
let api = CommomApi.wechatLogin(param: param)
HttpClient.request(api) { (model:LoginModel,res) in
if model.isSuccess{
- CacheManager.shared.login(token: model.data)
+ CacheManager.shared.user.login(token: model.data)
}
completion(model)
}
}
@objc func swictAction(){
CustomAlert.showWith(title: "提示", messgage: "确定要切换账号吗?", cancelCallback: {}) {
- CacheManager.shared.logout()
+ CacheManager.shared.user.logout()
}
}
@objc func logoutAction(){
CustomAlert.showWith(title: "提示", messgage: "确定要退出登录吗?", cancelCallback: {}) {
- CacheManager.shared.logout()
+ CacheManager.shared.user.logout()
}
}
@objc func deactivateAction(){
HttpClient.request(.deactivate) { (result:ResponseBaseModel,res) in
if result.isSuccess{
YLprogressHUD.showSuccess {
- CacheManager.shared.logout()
+ CacheManager.shared.user.logout()
}
}
else{
else{
cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
}
+ if list.count == 1 {
+ cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 12, height: 12))
+ }
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
v.font = .regular(14)
v.textColor = .hexString("#666666")
v.numberOfLines = 0
- v.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此举还将撤回您对用户协议的同意,并退出DeepChor ds应用。\n\n请您知悉,撤回同意隐私政策不代表撤回同意前的相关行为和责任得到豁免或减轻。若您需要重新在该账号管理设备,需要您重新授权并绑定。请谨慎操作!"
+
+ let attributedString = NSMutableAttributedString(string: text)
+ let paragraphStyle = NSMutableParagraphStyle()
+ paragraphStyle.lineSpacing = 4
+ attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length))
+ v.attributedText = attributedString
}
btn.set(title: "确认撤回", style: .theme4,target: self, action: #selector(btnAction))
}
// Created by liangshi on 2025/10/21.
//
-import HandyJSON
-
-class BannerModelRoot:ResponseBaseModel {
- var data = [BannerModel]()
-}
-
-class BannerModel:HandyJSON {
- var id = ""
- var title = ""
- var cover = ""
- var url = ""
- var clickCount = 0
- required public init() { }
-}
v.setFillColor(UIColor.white.withAlphaComponent(0.4), for: .normal)
v.setFillColor(.white, for: .selected)
}
+ config(list: BannerCache.shared.get())
}
}
}
}
func updateUI(){
- CacheManager.shared.tokenIsValid(){[weak self] in
+ CacheManager.shared.user.tokenIsValid(){[weak self] in
guard let self = self else {return}
titleLabel.text = CacheManager.shared.user.info.userName
icon.kf.setImage(with:CacheManager.shared.user.info.avatar.yc.asUrl )
}
@objc func tapAction(){
- App.shared.goToPage(CloudHistoryRecordVC())
+ App.shared.goToPage(CloudRecordVC())
}
}
guard let self = self else {return}
if model.isSuccess{
headerView.banner.config(list: model.data)
+ BannerCache.shared.saveList(model.data)
}
}
headerView.userInfo.updateUI()
import UIKit
class UpdateVC:BaseVC{
+ let icon = UIImageView(image: UIImage(named: "update_icon"))
let versionLabel = UILabel()
let btn = UIButton(type: .custom)
override func viewDidLoad() {
}
override func setupViews() {
- view.addSubviews([versionLabel,btn])
+ view.addSubviews([icon,versionLabel,btn])
self.navBar.title = "固件升级"
versionLabel.do { v in
v.text = "当前版本\n"
}
btn.do { v in
v.setTitle("检查更新", for: .normal)
- v.titleLabel?.font = .regular(12)
+ v.titleLabel?.font = .bold(14)
v.setTitleColor(.color(.theme), for: .normal)
v.addTarget(self, action: #selector(tapAction), for: .touchUpInside)
v.backgroundColor = .hexString("#EDEDED")
}
}
override func setupLayout() {
+ icon.snp.makeConstraints { make in
+ make.width.equalTo(272)
+ make.height.equalTo(240)
+ make.centerX.equalToSuperview()
+ make.top.equalToSuperview().inset(kNavBtm + 90)
+ }
versionLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
- make.centerY.equalToSuperview()
+ make.top.equalTo(icon.snp.bottom).offset(65)
}
btn.snp.makeConstraints { make in
make.bottom.equalToSuperview().inset(82)
override func setupData() {
DeviceVM.getVersion {[weak self] version in
guard let self = self else{return}
- guard let version = version else{
- return
- }
- versionLabel.text = "当前版本\n" + "\(version)"
+ let version = version ?? "--"
+ let allText = "当前版本\n" + "V\(version)"
+ let attributedString = NSMutableAttributedString(string: allText)
+ let paragraphStyle = NSMutableParagraphStyle()
+ paragraphStyle.lineSpacing = 7
+ attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length))
+ attributedString.addAttribute(.font, value: UIFont.bold(16), range: NSRange(location: 0, length: attributedString.length))
+ attributedString.addAttribute(.font, value: UIFont.bold(14), range: NSRange(location: 4, length: version.count + 1))
+ versionLabel.attributedText = attributedString
+ versionLabel.textAlignment = .center
}
}
@objc func tapAction(){
}
}
func refreshUI(){
- CacheManager.shared.tokenIsValid(){[weak self] in
+ CacheManager.shared.user.tokenIsValid(){[weak self] in
self?.tableView.reloadData()
}
make.height.equalTo(h)
make.left.equalToSuperview().inset(x)
make.top.equalToSuperview().inset(y)
- if index == list.count - 1 {
- make.bottom.equalToSuperview().inset(14)
- }
+// if index == list.count - 1 {
+// make.bottom.equalToSuperview().inset(14)
+// }
}
}
NotificationManager.add(self, selector: #selector(deviceChange(_:)), forName: .deviceValidChange)
addSubviews([icon,titleLabel,selectedIcon])
icon.do { v in
v.yc.setCornerRadius(8)
- v.contentMode = .center
+// v.contentMode = .scaleAspectFill
}
titleLabel.do { (v) in
v.textColor = .white
//
class BrokenLineView: UIView {
-// override func draw(_ rect: CGRect) {
-// super.draw(rect)
-// let path = UIBezierPath()
-// let lineWidth: CGFloat = 0.5
-// let dashLength: CGFloat = 5.0
-// let spaceLength: CGFloat = 3.0
-// let startPoint = CGPoint(x: 0, y: bounds.midY)
-// let endPoint = CGPoint(x: bounds.width, y: bounds.midY)
-// path.move(to: startPoint)
-// path.addLine(to: endPoint)
-// let shapeLayer = CAShapeLayer()
-// shapeLayer.path = path.cgPath
-// shapeLayer.strokeColor = UIColor.hexString("#93C6EC").cgColor
-// shapeLayer.fillColor = UIColor.clear.cgColor
-// shapeLayer.lineWidth = lineWidth
-// shapeLayer.lineDashPattern = [NSNumber(value: dashLength), NSNumber(value: spaceLength)]
-// layer.addSublayer(shapeLayer)
-// }
+ override func draw(_ rect: CGRect) {
+ super.draw(rect)
+ let path = UIBezierPath()
+ let lineWidth: CGFloat = 0.5
+ let dashLength: CGFloat = 5.0
+ let spaceLength: CGFloat = 3.0
+ let startPoint = CGPoint(x: 0, y: bounds.midY)
+ let endPoint = CGPoint(x: bounds.width, y: bounds.midY)
+ path.move(to: startPoint)
+ path.addLine(to: endPoint)
+ let shapeLayer = CAShapeLayer()
+ shapeLayer.path = path.cgPath
+ shapeLayer.strokeColor = UIColor.hexString("#93C6EC").cgColor
+ shapeLayer.fillColor = UIColor.clear.cgColor
+ shapeLayer.lineWidth = lineWidth
+ shapeLayer.lineDashPattern = [NSNumber(value: dashLength), NSNumber(value: spaceLength)]
+ layer.addSublayer(shapeLayer)
+ }
}
+++ /dev/null
-//
-// DeviceCache.swift
-// ShenYin
-//
-// Created by liangshi on 2025/9/26.
-//
-
-class DeviceModel: NSObject, NSCoding {
- var name = ""
- var uuid = ""
-
- init(name: String, uuid: String) {
- self.name = name
- self.uuid = uuid
- }
-
- func encode(with aCoder: NSCoder) {
- aCoder.encode(name, forKey: "name")
- aCoder.encode(uuid, forKey: "uuid")
- }
-
- required init?(coder aDecoder: NSCoder) {
- name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
- uuid = aDecoder.decodeObject(forKey: "uuid") as? String ?? ""
- }
-}
-
-class DeviceCache {
- static let shared = DeviceCache()
- private let userDefaults = UserDefaults.standard
- private let deviceListKey = "deviceListKey"
-
- func saveDevice(_ device: DeviceModel) {
- var deviceList = getDeviceList()
- if let index = deviceList.firstIndex(where: { $0.uuid == device.uuid }) {
- deviceList[index] = device
- } else {
- deviceList.append(device)
- }
- let encoder = NSKeyedArchiver.archivedData(withRootObject: deviceList)
- userDefaults.set(encoder, forKey: deviceListKey)
- userDefaults.synchronize()
- }
-
- func getDeviceList() -> [DeviceModel] {
- if let data = userDefaults.data(forKey: deviceListKey),
- let deviceList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [DeviceModel] {
- return deviceList
- }
- return []
- }
-}
navBar.title = "log"
view.backgroundColor = .white
navBar.title = "log"
+ navBar.rightView.isHidden = false
navBar.rightView.setTitle("保存", for: .normal)
textView.isEditable = false
}
textFiled.do { v in
-// v.text = Date().format(.full3)
+ v.text = Date().format(.full3)
v.placeholder = "请输入录音名字"
v.font = .bold(16)
v.textColor = .hexString("#121212")
--- /dev/null
+//
+// RecordPopView.swift
+// ShenYin
+//
+// Created by liangshi on 2025/11/3.
+//
+
+import UIKit
+
+class RecordPopView: BasePresentView2 {
+ let contentView = UIView()
+ fileprivate let renameItem = MenuItem()
+ fileprivate let sharedItem = MenuItem()
+ fileprivate let deleteItem = MenuItem()
+ fileprivate let selectedItem = MenuItem()
+
+ var hidenCallback:(()->Void)?
+ var shareCallback:(()->Void)?
+ var renameCallback:(()->Void)?
+ var deleteCallback:(()->Void)?
+ var selectedCallback:(()->Void)?
+ var contentTop = 0.0{
+ didSet{
+ setupStyle()
+ }
+ }
+
+ init() {
+ super.init(backgroundEnabled: true)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func setupSubView() {
+ super.setupSubView()
+ addSubview(contentView)
+ contentView.addSubviews([renameItem,sharedItem,deleteItem,selectedItem])
+
+ renameItem.do { v in
+ v.label.text = "重命名"
+ v.yc.addTap(target: self, action: #selector(renameAction))
+ }
+ sharedItem.do { v in
+ v.label.text = "分享"
+ v.yc.addTap(target: self, action: #selector(sharedAction))
+ }
+ deleteItem.do { v in
+ v.label.text = "删除"
+ v.yc.addTap(target: self, action: #selector(deleteAction))
+ }
+ selectedItem.do { v in
+ v.label.text = "多选"
+ v.yc.addTap(target: self, action: #selector(selectedAction))
+ }
+ }
+ override func setupLayout() {
+ super.setupLayout()
+ contentView.do { (v) in
+ v.backgroundColor = .white
+ v.yc.setCornerRadius(12)
+ }
+ renameItem.snp.makeConstraints { make in
+ make.left.equalToSuperview()
+ make.top.equalToSuperview().inset(12)
+ make.width.equalToSuperview()
+ make.height.equalTo(34)
+ }
+ sharedItem.snp.makeConstraints { make in
+ make.left.equalToSuperview()
+ make.top.equalTo(renameItem.snp.bottom)
+ make.width.equalToSuperview()
+ make.height.equalTo(34)
+ }
+ deleteItem.snp.makeConstraints { make in
+ make.left.equalToSuperview()
+ make.top.equalTo(sharedItem.snp.bottom)
+ make.width.equalToSuperview()
+ make.height.equalTo(34)
+ }
+ selectedItem.snp.makeConstraints { make in
+ make.left.equalToSuperview()
+ make.top.equalTo(deleteItem.snp.bottom)
+ make.width.equalToSuperview()
+ make.height.equalTo(34)
+ }
+ }
+
+ override func setupStyle() {
+ super.setupStyle()
+ contentView.snp.remakeConstraints { make in
+ make.right.equalToSuperview().inset(18)
+ make.height.equalTo(166)
+ make.width.equalTo(160)
+
+ if contentTop > kScreenHei - 200{
+ make.top.equalToSuperview().offset(kScreenHei - 200)
+ }
+ else{
+ make.top.equalToSuperview().offset(contentTop)
+ }
+ }
+
+ }
+ @objc func renameAction(){
+ renameCallback?()
+ hide()
+ }
+ @objc func sharedAction(){
+ shareCallback?()
+ hide()
+ }
+ @objc func deleteAction(){
+ deleteCallback?()
+ hide()
+ }
+ @objc func selectedAction(){
+ selectedCallback?()
+ hide()
+ }
+ override func hide() {
+ hidenCallback?()
+ super.hide()
+ }
+}
+
+fileprivate class MenuItem: BaseView {
+ let label = UILabel()
+
+ override func setupViews() {
+ addSubviews([label])
+ label.do { v in
+ v.font = .regular(16)
+ v.textColor = .hexString("#121212")
+
+ }
+
+ }
+ override func setupLayout() {
+ label.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(18)
+ make.centerY.equalToSuperview()
+ }
+ }
+}