- Moya/Core (= 15.0.0)
- Moya/Core (15.0.0):
- Alamofire (~> 5.0)
- - MultiSlider (2.2.0):
- - SweeterSwift
- netfox (1.21.0)
- Realm (20.0.3):
- Realm/Headers (= 20.0.3)
- SVProgressHUD (2.3.1):
- SVProgressHUD/Core (= 2.3.1)
- SVProgressHUD/Core (2.3.1)
- - SweeterSwift (1.2.6)
- SwiftDate (7.0.0)
- swiftScan (1.2.1)
- TabPageViewController (0.2.8)
- Kingfisher (~> 6.0)
- MJRefresh
- Moya
- - MultiSlider
- netfox
- RealmSwift
- SnapKit
- Kingfisher
- MJRefresh
- Moya
- - MultiSlider
- netfox
- Realm
- RealmSwift
- SnapKit
- SocketRocket
- SVProgressHUD
- - SweeterSwift
- SwiftDate
- swiftScan
- TabPageViewController
Kingfisher: 016c8b653a35add51dd34a3aba36b580041acc74
MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
- MultiSlider: 9667217199a051fa729bf54986d68fb9b911554c
netfox: 9d5cc727fe7576c4c7688a2504618a156b7d44b7
Realm: 853e5089d6042dff807bda000277eadfe2da93d2
RealmSwift: f33c19577cefcbf681345d721fcbc7b42be4c949
SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22
- SweeterSwift: 1eca266517c703d7376e723a21926f5cb2ba4d0f
SwiftDate: bbc26e26fc8c0c33fbee8c140c5e8a68293a148a
swiftScan: 0849e7d7c1c641384767a573ee8cb90b88d1ddd9
TabPageViewController: 8bd4104909754416b35a98f3b72a5b674ab20dd5
YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
-PODFILE CHECKSUM: 826428f9bd4197f6e9759f68eaf9008f80c0563b
+PODFILE CHECKSUM: bc7d3a8004029604d5620b967136223e19d8a67d
COCOAPODS: 1.16.2
/* 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, ); }; };
+ 3FF8A4622E72CBBA00271F9E /* DSWaveformImage in Frameworks */ = {isa = PBXBuildFile; productRef = 3FF8A4612E72CBBA00271F9E /* DSWaveformImage */; };
+ 3FF8A4642E72CBBA00271F9E /* DSWaveformImageViews in Frameworks */ = {isa = PBXBuildFile; productRef = 3FF8A4632E72CBBA00271F9E /* DSWaveformImageViews */; };
F2E449CAD5874BE652A69B50 /* Pods_ShenYin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3862D5561144E20721225B96 /* Pods_ShenYin.framework */; };
/* End PBXBuildFile section */
buildActionMask = 2147483647;
files = (
F2E449CAD5874BE652A69B50 /* Pods_ShenYin.framework in Frameworks */,
+ 3FF8A4622E72CBBA00271F9E /* DSWaveformImage in Frameworks */,
3F79C6142E6055E500EC38B9 /* JoyGemAI.framework in Frameworks */,
+ 3FF8A4642E72CBBA00271F9E /* DSWaveformImageViews in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
);
mainGroup = 3F887B932E38D8DC00C98658;
minimizedProjectReferenceProxies = 1;
+ packageReferences = (
+ 3FF8A4602E72CBBA00271F9E /* XCRemoteSwiftPackageReference "DSWaveformImage" */,
+ );
preferredProjectObjectVersion = 77;
productRefGroup = 3F887B9D2E38D8DC00C98658 /* Products */;
projectDirPath = "";
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
+ inputPaths = (
+ );
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
+ outputPaths = (
+ );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks.sh\"\n";
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
+
+/* Begin XCRemoteSwiftPackageReference section */
+ 3FF8A4602E72CBBA00271F9E /* XCRemoteSwiftPackageReference "DSWaveformImage" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/dmrschmidt/DSWaveformImage";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 14.2.2;
+ };
+ };
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 3FF8A4612E72CBBA00271F9E /* DSWaveformImage */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 3FF8A4602E72CBBA00271F9E /* XCRemoteSwiftPackageReference "DSWaveformImage" */;
+ productName = DSWaveformImage;
+ };
+ 3FF8A4632E72CBBA00271F9E /* DSWaveformImageViews */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 3FF8A4602E72CBBA00271F9E /* XCRemoteSwiftPackageReference "DSWaveformImage" */;
+ productName = DSWaveformImageViews;
+ };
+/* End XCSwiftPackageProductDependency section */
};
rootObject = 3F887B942E38D8DC00C98658 /* Project object */;
}
--- /dev/null
+{
+ "originHash" : "eb3e6467aa3b79663b371a20cbe7f1b7c7a6a3c9f98e6945bc9704361b5ae42d",
+ "pins" : [
+ {
+ "identity" : "dswaveformimage",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/dmrschmidt/DSWaveformImage",
+ "state" : {
+ "revision" : "4c56578ee10128ee2b2c04c9c5aa73812de722db",
+ "version" : "14.2.2"
+ }
+ }
+ ],
+ "version" : 3
+}
@MainActor static func start(){
JoySdkManager.shared.setupSdk()
setupKeyboard()
+ loadCache()
}
@MainActor static func setupKeyboard(){
IQKeyboardManager.shared.isEnabled = true
IQKeyboardManager.shared.resignOnTouchOutside = true
}
+ static func loadCache(){
+ let list = DeviceCache.shared.getDeviceList()
+ Logger.debug("缓存设备",list)
+ if list.count > 0 {
+ CacheManager.shared.currentDevice = list.first
+ BleManager.shared.startScanDevice()
+ App.shared.enter()
+ }
+ }
}
{
"images" : [
{
- "idiom" : "universal",
- "platform" : "ios",
- "size" : "1024x1024"
- },
- {
- "appearances" : [
- {
- "appearance" : "luminosity",
- "value" : "dark"
- }
- ],
- "idiom" : "universal",
- "platform" : "ios",
- "size" : "1024x1024"
- },
- {
- "appearances" : [
- {
- "appearance" : "luminosity",
- "value" : "tinted"
- }
- ],
+ "filename" : "20250911-142330.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
import UIKit
import CoreBluetooth
import JoyGemAI
-import SVProgressHUD
import AVFAudio
class BleManager: NSObject {
var discoverDeviceCallback: (([CBPeripheral]) -> Void)?
}
devices.append(peripheral)
- print(peripheral)
+ Logger.debug(peripheral)
discoverDeviceCallback?(devices)
+ checkConnect()
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
stopScanDevice()
- print("蓝牙已连接 \(peripheral)")
+ Logger.debug("蓝牙已连接 \(peripheral)")
connectPeripheral = peripheral
peripheral.delegate = self
peripheral.discoverServices([CBUUID(string: kJoyGemAIServiceUUID)]);
didConnectDeviceCallback?(connectPeripheral!)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
- print("peripheral: %@ failed to connect", peripheral)
- SVProgressHUD.dismiss()
+ Logger.debug("peripheral: %@ failed to connect", peripheral)
+ YLprogressHUD.hidden()
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
- print("蓝牙已断开 \(peripheral)")
+ Logger.debug("蓝牙已断开 \(peripheral)")
disConnectDeviceCallback?(peripheral)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
- print("发现服务成功")
+ Logger.debug("发现服务成功")
for service in peripheral.services! {
- print("peripheral service: %@", service)
+ Logger.debug("peripheral service: %@", service)
peripheral.discoverCharacteristics(nil, for: service)
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: (any Error)?) {
if (characteristic.isNotifying == true && characteristic.service?.uuid.uuidString == kJoyGemAIServiceUUID && characteristic.uuid.uuidString == kJoyGemAICharacteristicNotifyUUID) {
//MARK: 使能成功时需要
- print("特征使能成功")
+ Logger.debug("特征使能成功")
JoyGemAIManager.shared().bleConnected()
}
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: (any Error)?) {
}
-
}
extension BleManager{
-
// MARK: - Public Methods
func startScanDevice() {
- print("扫描中...")
+ centralManager.stopScan()
+ Logger.debug("扫描中...")
devices = []
centralManager.scanForPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
+ discoverDeviceCallback?(devices)
+ }
+
+ func checkConnect(){
let list = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)])
for item in list {
devices.append(item)
break
}
- if list.count > 0 {
- print("缓存",list)
+
+ for item in devices{
+ if let current = CacheManager.shared.currentDevice,current.uuid == item.identifier.uuidString {
+ connectPeripheral(item)
+ return
+ }
+ }
+
+ if connectPeripheral == nil || connectPeripheral?.state == .disconnected {
+ DispatchQueue.main.asyncAfter(deadline:.now() + 3) {
+ self.checkConnect()
+ }
}
- discoverDeviceCallback?(devices)
}
func stopScanDevice() {
}
func connectPeripheral(_ peripheral: CBPeripheral) {
- print("连接中...")
-// YLprogressHUD.showLoading()
+ Logger.debug("连接中...")
centralManager.connect(peripheral, options: [CBConnectPeripheralOptionEnableTransportBridgingKey:true])
- SVProgressHUD.show(withStatus: "连接中")
- // DispatchQueue.main.asyncAfter(deadline: .now() + 15){[weak self] in
- // self?.cancel()
- // }
+ YLprogressHUD.showLoading()
}
func cancel() {
}
func joyGemAuthSuccessCallback() {
- YLprogressHUD.showAutoHiden(text: "鉴权成功"){
+ ConnectPopView().showAutoHide {
App.shared.enter()
}
-
+ CacheManager.shared.saveDevice(DeviceModel(name: connectPeripheral?.name ?? "", uuid: connectPeripheral?.identifier.uuidString ?? ""))
PcmSound.sharedInstance().setup(16000, withchannels: 1)
let options: AVAudioSession.CategoryOptions = [.allowBluetooth]
do {
try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
try AVAudioSession.sharedInstance().setActive(true)
} catch {
- print(error)
+ Logger.debug(error)
}
}
func joyGemAction(_ action: JoyGemActionMode) {
switch action {
case .cancel:
- SVProgressHUD.showInfo(withStatus: "请求关闭录音功能/通知关闭了对话")
+ YLprogressHUD.showAutoHiden("请求关闭录音功能/通知关闭了对话")
case .recordLive:
- SVProgressHUD.showInfo(withStatus: "请求开启现场录音")
+ YLprogressHUD.showAutoHiden("请求开启现场录音")
case .recordCall:
- SVProgressHUD.showInfo(withStatus: "请求开启通话录音")
+ YLprogressHUD.showAutoHiden("请求开启通话录音")
case .si:
- SVProgressHUD.showInfo(withStatus: "请求开启同传听译")
+ YLprogressHUD.showAutoHiden( "请求开启同传听译")
case .chat:
- SVProgressHUD.showInfo(withStatus: "通知开启了AI对话")
+ YLprogressHUD.showAutoHiden( "通知开启了AI对话")
@unknown default:
break
}
App.shared.window = window
window?.rootViewController = BaseTC()
- window?.rootViewController = UINavigationController(rootViewController: CustomEqVC())
+ window?.rootViewController = UINavigationController(rootViewController: BleScanVC())
AppLaunch.start()
}
self.tabBar.backgroundColor = .white
view.backgroundColor = .color(.bgColor)
- self.selectedIndex = 1
+ self.selectedIndex = 0
}
}
public class ChatCellModel {
public var type: Int = 0//1发,0收
public var content: String = ""
- public var id:UInt = 0
+ public var id:Int = 0
}
class ChatCell:BaseTableViewCell{
- let bgView = UIView()
+ let bgView = LoadingView()
let originalLabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
make.top.bottom.equalToSuperview().inset(14)
make.left.right.equalToSuperview().inset(12)
make.width.lessThanOrEqualTo(kScreenWid - 60)
+ make.width.greaterThanOrEqualTo(60)
+ make.height.greaterThanOrEqualTo(19)
}
}
var data:ChatCellModel!{
didSet{
if data.content.isEmpty{
- data.content = "..."
+ originalLabel.text = ""
+ bgView.startAnimating()
+ }
+ else{
+ bgView.stopAnimating()
+ originalLabel.text = data.content
}
if data.type == 1 {
bgView.backgroundColor = .color(.theme)
make.left.equalToSuperview().inset(20)
}
}
- originalLabel.text = data.content
}
}
}
extension ChatVC:ChatRecordBarDelegate{
func recordBarStart(_ toolBar: ChatRecordBar) {
-// JoyGemChatManager.shared().playAudioEnd()
+
+ let model = ChatCellModel()
+ model.type = 1
+ model.content = ""
+ model.id = -1
+ dataList.append(model)
+ tableView.reloadData()
+ scrollToBottom()
+
JoyGemChatManager.shared().stopChat()
JoyGemChatManager.shared().startSingleChat()
}
func chatManager(_ manager: JoyGemChatManager, requestText text: String?, index: UInt) {
Logger.debug(text,index)
- if let text = text {
- if let model = dataList.last,model.id == index,model.type == 1 {
- model.content = text
- }
- else{
- let model = ChatCellModel()
- model.type = 1
- model.content = text
- model.id = index
- dataList.append(model)
- }
- tableView.reloadData()
- scrollToBottom()
+ guard let text = text else{
+ return
+ }
+ if text.isEmpty {
+ return
+ }
+ if dataList.last?.id == -1 {
+ dataList.removeLast()
+ }
+ if let model = dataList.last,model.id == index,model.type == 1 {
+ model.content = text
+ }
+ else{
+ let model = ChatCellModel()
+ model.type = 1
+ model.content = text
+ model.id = Int(index)
+ dataList.append(model)
}
+ tableView.reloadData()
+ scrollToBottom()
}
func chatManager(_ manager: JoyGemChatManager, responseText text: String?, index: UInt, finish isFinish: Bool) {
let model = ChatCellModel()
model.type = 0
model.content = text
- model.id = index
+ model.id = Int(index)
dataList.append(model)
}
tableView.reloadData()
class FieldRecordBar: BaseView {
- let recordBtn = UIButton()
+ let recordBtn = LoadingButton()
let leftItem = RecordBarItem()
let rightItem = RecordBarButton()
var state:RecordSate = .stop
}
else if state == .stop{
JoyGemRecordManager.shared().stop()
-
- let v = PopTextField()
- v.show()
- v.cancelTap = {
-
- }
- v.okTap = {
-
+ bar.recordBtn.startAnimating {[weak self] in
+ guard let self = self else{return}
+// toolBar.recordBtn.stopCli()
+ let v = PopTextField()
+ v.show()
+ v.cancelTap = {
+
+ }
+ v.okTap = {
+
+ }
}
}
}
func recordManagerStopped(_ manager: JoyGemRecordManager, reason code: JoyGemRecordStopCode) {
-// if (code == .actively) {
+ if (code == .actively) {
// YLprogressHUD.showAutoHiden("用户主动结束")
-// } else {
-// YLprogressHUD.showAutoHiden("自动结束")
-// ///判断当前蓝牙是否连接从而确定是否因为蓝牙断开造成的录音断开
-// }
+// toolBar.recordBtn.stopLoading()
+// let v = PopTextField()
+// v.show()
+// v.cancelTap = {
+//
+// }
+// v.okTap = {
+//
+// }
+ } else {
+ YLprogressHUD.showAutoHiden("自动结束")
+ ///判断当前蓝牙是否连接从而确定是否因为蓝牙断开造成的录音断开
+ }
}
func recordManager(_ manager: JoyGemRecordManager, onError code: JoyGemErrorCode) {
import UIKit
+//import DSWaveformImage
-class RhythView: UIView {
-
+class RhythView: BaseView {
+// let wave = WaveformLiveView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 50))
+//
+// override func setupViews() {
+// backgroundColor = .red
+// wave.backgroundColor = .green
+// addSubview(wave)
+//
+// }
+// override func setupLayout() {
+//
+// }
+
}
import UIKit
import JoyGemAI
-import MultiSlider
class CustomEqVC:BaseVC{
private let bgView = UIView()
private let sliderBgView = UIView()
import UIKit
import CoreBluetooth
import DGActivityIndicatorView
+
+enum BleScanState{
+ case scan
+ case has
+ case none
+}
+
class BleScanVC: BaseVC{
+ let headerView = BleScanHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 280))
let tableView = UITableView(frame: .zero, style: .plain)
var list:[CBPeripheral] = []
v.estimatedRowHeight = 76
v.separatorStyle = .none
v.register(BleScanCell.self, forCellReuseIdentifier: BleScanCell.reuseID)
- v.tableHeaderView = BleScanHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 280))
+ v.tableHeaderView = headerView
}
view.addSubview(tableView)
}
BleManager.shared.discoverDeviceCallback = {[weak self] devices in
self?.list = devices
self?.tableView.reloadData()
+ if devices.count > 0 {
+ self?.headerView.stateView.state = .has
+ }
+ else{
+ self?.headerView.stateView.state = .none
+ }
}
startScan()
}
func startScan(){
list = []
tableView.reloadData()
- BleManager.shared.startScanDevice()
+ BleManager.shared.startScanDevice()
}
}
class BleScanHeaderView: BaseView {
let rippleView = DGActivityIndicatorView(type: .triplePulse,tintColor: UIColor.hexString("#0092E1"),size: 250)!
var radarImageView = UIImageView()
+ var stateView = ScanView()
override func setupViews() {
backgroundColor = .clear
// rippleView.backgroundColor = .red
- addSubviews([rippleView,radarImageView])
+ addSubviews([rippleView,radarImageView,stateView])
rippleView.startAnimating()
radarImageView.do { v in
make.size.equalTo(250)
make.center.equalToSuperview()
}
+ stateView.snp.makeConstraints { make in
+ make.centerX.equalToSuperview()
+ make.top.equalTo(rippleView.snp.bottom).offset(30)
+ }
+ }
+
+
+
+ class ScanView: BaseView {
+ let titleLabel = UILabel()
+ let desLabel = UILabel()
+ var state:BleScanState = .scan{
+ didSet{
+ self.isHidden = state == .has
+ if state == .none {
+// titleLabel.text = "正在扫描"
+// desLabel.text = "请确保智能设备已连接电源,且位于手机附近"
+ }
+ else{
+ titleLabel.text = "正在扫描"
+ desLabel.text = "请确保智能设备已连接电源,且位于手机附近"
+ }
+ }
+ }
+ override func setupViews() {
+ backgroundColor = .clear
+ addSubviews([titleLabel,desLabel])
+ titleLabel.do { (v) in
+ v.textColor = .rgb(0x121212)
+ v.font = .regular(14)
+ v.textAlignment = .center
+ v.numberOfLines = 0
+ }
+ desLabel.do { (v) in
+ v.textColor = .rgb(0x8D8D8D)
+ v.font = .regular(14)
+ v.textAlignment = .center
+ v.numberOfLines = 0
+ }
+ }
+ override func setupLayout() {
+ titleLabel.snp.makeConstraints { make in
+ make.top.equalToSuperview()
+ make.centerX.equalToSuperview()
+ }
+ desLabel.snp.makeConstraints { make in
+ make.top.equalTo(titleLabel.snp.bottom).offset(10)
+ make.centerX.equalToSuperview()
+ }
+ }
+
+
}
}
--- /dev/null
+//
+// LoadingButton.swift
+// ShenYin
+//
+// Created by liangshi on 2025/9/11.
+//
+import DGActivityIndicatorView
+import UIKit
+class LoadingButton:UIButton{
+ let loadingView = DGActivityIndicatorView(type: .ballClipRotate,tintColor: UIColor.hexString("#0092E1"))!
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ loadingView.backgroundColor = .white
+ addSubview(loadingView)
+ loadingView.snp.remakeConstraints { make in
+ make.edges.equalToSuperview()
+ }
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+ func startAnimating(finished:(()->Void)? = nil){
+ loadingView.startAnimating()
+ DispatchQueue.main.asyncAfter(deadline:.now() + 3) {
+ self.stopAnimating()
+ finished?()
+ }
+ }
+ func stopAnimating(){
+ loadingView.stopAnimating()
+ }
+}
+
+class LoadingView: UIView {
+ let activeView = DGActivityIndicatorView(type: .ballPulse,tintColor: .white)!
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ activeView.backgroundColor = .clear
+ addSubview(activeView)
+ activeView.snp.makeConstraints { make in
+ make.center.equalToSuperview()
+ make.width.equalTo(60)
+ make.height.equalTo(40)
+ }
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ func startAnimating(finished:(()->Void)? = nil){
+ activeView.startAnimating()
+ }
+ func stopAnimating(){
+ activeView.stopAnimating()
+ }
+}
--- /dev/null
+//
+// c.swift
+// ShenYin
+//
+// Created by liangshi on 2025/9/11.
+//
+import CoreBluetooth
+
+class CacheManager{
+ static let shared = CacheManager()
+ var currentDevice:DeviceModel?
+
+ func saveDevice(_ device: DeviceModel) {
+ self.currentDevice = device
+ DeviceCache.shared.saveDevice(device)
+ }
+}
+
+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)
+ }
+
+ func getDeviceList() -> [DeviceModel] {
+ if let data = userDefaults.data(forKey: deviceListKey),
+ let deviceList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [DeviceModel] {
+ return deviceList
+ }
+ return []
+ }
+}
--- /dev/null
+//
+// ConnectPopView.swift
+// ShenYin
+//
+// Created by liangshi on 2025/9/11.
+//
+
+import UIKit
+
+class ConnectPopView: BasePresentView2 {
+ let contentView = UIView()
+ private let titleLabel = UILabel()
+ private let imageView = UIImageView()
+ private let desLabel = UILabel()
+
+
+ init() {
+ super.init()
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func setupSubView() {
+ super.setupSubView()
+ addSubview(contentView)
+ contentView.addSubviews([titleLabel,imageView,desLabel])
+ }
+ override func setupLayout() {
+ super.setupLayout()
+
+ contentView.snp.makeConstraints { make in
+ make.left.right.equalToSuperview().inset(18)
+ make.height.equalTo(315)
+ make.center.equalToSuperview()
+ }
+ titleLabel.snp.makeConstraints { (m) in
+ m.top.equalToSuperview().inset(30)
+ m.left.right.equalToSuperview()
+ }
+ imageView.snp.makeConstraints { (m) in
+ m.centerX.equalToSuperview()
+ m.top.equalToSuperview().inset(76)
+ m.width.equalTo(190)
+ m.height.equalTo(156)
+ }
+ desLabel.snp.makeConstraints { (m) in
+ m.top.equalTo(imageView.snp.bottom).offset(20)
+ m.left.right.equalToSuperview()
+// m.bottom.equalToSuperview().inset(30)
+ }
+ }
+
+ override func setupStyle() {
+ super.setupStyle()
+ contentView.do { (v) in
+ v.backgroundColor = .white
+ v.yc.setCornerRadius(20)
+ }
+ imageView.do { v in
+ v.image = UIImage(named: "home_header")
+ }
+ titleLabel.do { (v) in
+ v.textColor = .rgb(0x121212)
+ v.font = .regular(20)
+ v.textAlignment = .center
+ v.text = "Deep Gen2 Max"
+ }
+ desLabel.do { (v) in
+ v.textColor = .rgb(0x121212)
+ v.font = .regular(24)
+ v.textAlignment = .center
+ v.text = "连接成功"
+ }
+ }
+
+ func showAutoHide(finished: (() -> Void)? = nil){
+ show()
+ DispatchQueue.main.asyncAfter(deadline:.now() + 0.5) {
+ self.hide()
+ finished?()
+ }
+ }
+}
+
pod 'SocketRocket'#socket,AI用到
pod 'DGActivityIndicatorView'#扫描雷达
- pod 'MultiSlider'
+# pod 'MultiSlider'
+# pod 'DSWaveformImage'
+
# pod 'NVActivityIndicatorView', '~> 5.1.1' # 最新稳定版
# pod 'EZAudio', '~> 1.1.0'
end