deepchords替换成深音证书
authorliangzhenying <867174124@qq.com>
Wed, 4 Feb 2026 09:16:47 +0000 (17:16 +0800)
committerliangzhenying <867174124@qq.com>
Wed, 4 Feb 2026 09:16:47 +0000 (17:16 +0800)
55 files changed:
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example.xcodeproj/project.pbxproj
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/CallRecordManager.swift
DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/WxCallManager.swift [new file with mode: 0644]
ShenYin/ShenYin.xcodeproj/project.pbxproj
ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Slice 195@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Slice 195@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Slice 56@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Slice 56@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Slice 55@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Slice 55@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Group_2400@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Group_2400@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Slice 268@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Slice 268@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Contents.json [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Slice 59@2x.png [new file with mode: 0644]
ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Slice 59@3x.png [new file with mode: 0644]
ShenYin/ShenYin/Cache/TipsCache.swift
ShenYin/ShenYin/Launch/SceneDelegate.swift
ShenYin/ShenYin/Resource/colors/Colors+YL.swift
ShenYin/ShenYin/Sdk/DcSdk/tool/CCConfig.swift
ShenYin/ShenYin/Sdk/JoySdk/VC/JoyChatVC.swift
ShenYin/ShenYin/Sdk/JoySdk/tool/CCDevice.swift
ShenYin/ShenYin/Sdk/LogManager.swift
ShenYin/ShenYin/Tools/Extensions/UITextView+Scroll.swift
ShenYin/ShenYin/UI/Sport/Sport/Light/BrightnessView.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Light/LightSetVC.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Light/ModeView.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Light/StateView.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Ready/FooterView.swift
ShenYin/ShenYin/UI/Sport/Sport/Ready/Navbar.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyHeader.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyVC.swift
ShenYin/ShenYin/UI/Sport/Sport/Root/DataView.swift [moved from ShenYin/ShenYin/UI/Sport/Sport/root/DataView.swift with 100% similarity]
ShenYin/ShenYin/UI/Sport/Sport/Root/GroupView.swift [moved from ShenYin/ShenYin/UI/Sport/Sport/root/GroupView.swift with 100% similarity]
ShenYin/ShenYin/UI/Sport/Sport/Root/PlanView.swift [moved from ShenYin/ShenYin/UI/Sport/Sport/root/PlanView.swift with 100% similarity]
ShenYin/ShenYin/UI/Sport/Sport/Root/RouteView.swift [moved from ShenYin/ShenYin/UI/Sport/Sport/root/RouteView.swift with 100% similarity]
ShenYin/ShenYin/UI/Sport/Sport/Root/SportRootView.swift [moved from ShenYin/ShenYin/UI/Sport/Sport/root/SportRootView.swift with 100% similarity]
ShenYin/ShenYin/UI/Sport/Sport/Root/SportTypeView.swift [moved from ShenYin/ShenYin/UI/Sport/Sport/root/SportTypeView.swift with 100% similarity]
ShenYin/ShenYin/UI/Sport/Sport/Sporting/DetailBoard.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Sporting/SimpleBoard.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Sporting/SportingVC.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Target/CalorieView.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Target/DistanceView.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Target/DurationView.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/Sport/Target/SportTargetVC.swift [new file with mode: 0644]
ShenYin/ShenYin/UI/Sport/SportHomeVC.swift
ShenYin/ShenYin/UI/common/CustomButton.swift
ShenYin/ShenYin/UI/common/pop/CustomPicker3.swift
ShenYin/ShenYin/UI/common/pop/SportPopView.swift [new file with mode: 0644]

index 1d5ca53..f73584e 100644 (file)
                                CODE_SIGN_STYLE = Automatic;
                                CURRENT_PROJECT_VERSION = 1;
                                DEAD_CODE_STRIPPING = YES;
-                               DEVELOPMENT_TEAM = G23X75CJ67;
+                               DEVELOPMENT_TEAM = MAC46RQ4KH;
                                FRAMEWORK_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "$(PROJECT_DIR)/DeepChordsSdk",
                                CODE_SIGN_STYLE = Automatic;
                                CURRENT_PROJECT_VERSION = 1;
                                DEAD_CODE_STRIPPING = YES;
-                               DEVELOPMENT_TEAM = G23X75CJ67;
+                               DEVELOPMENT_TEAM = MAC46RQ4KH;
                                FRAMEWORK_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "$(PROJECT_DIR)/DeepChordsSdk",
index 44f6b82..a46bc51 100644 (file)
@@ -70,13 +70,16 @@ class CallRecordManager:NSObject{
         selfText = ""
         otherText = ""
         setupSdk()
-        if !DcCall.shared.isInCall {
+        if DcCall.shared.isInCall || WxCallManager.shared.isInWxCall() {
+            DCLogger.debug("开启通话录音")
+            DCCallRecord.shared.start()
+        }
+        else{
             DCLogger.debug("不在通话状态")
             callRecordNotOnCall?()
             return
         }
-        DCLogger.debug("开启通话录音")
-        DCCallRecord.shared.start()
+
     }
     func recordStop(){
         isRecording = false
diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/WxCallManager.swift b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/tools/WxCallManager.swift
new file mode 100644 (file)
index 0000000..65386d7
--- /dev/null
@@ -0,0 +1,228 @@
+//
+//  WxCallManager.swift
+//  Example
+//
+//  Created by liangshi on 2026/2/2.
+//
+
+import Foundation
+import AVFoundation
+
+class WxCallManager: NSObject {
+    static let shared = WxCallManager()
+    
+    private var audioSessionMonitor: AudioSessionMonitor?
+    private var lastCheckTime: TimeInterval = 0
+    private var isLikelyInAppCall = false
+    private var callStateChangeHandlers: [(Bool) -> Void] = []
+    
+    override init() {
+        super.init()
+        audioSessionMonitor = AudioSessionMonitor(delegate: self)
+    }
+    
+    // 添加通话状态变更回调处理
+    func addCallStateChangeHandler(_ handler: @escaping (Bool) -> Void) {
+        callStateChangeHandlers.append(handler)
+    }
+    
+    // 检测是否在应用内通话(如微信语音通话、QQ语音通话等)
+    func isInWxCall() -> Bool {
+        // 获取当前时间
+        let currentTime = Date.timeIntervalSinceReferenceDate
+        
+        // 限制检查频率,避免过度检查
+        if currentTime - lastCheckTime < 1.0 {
+            return isLikelyInAppCall
+        }
+        
+        lastCheckTime = currentTime
+        
+        let audioSession = AVAudioSession.sharedInstance()
+        
+        // 检查音频会话类别是否为录音或播放录音
+        let category = audioSession.category
+        if category == .playAndRecord || category == .record {
+            let currentRoute = audioSession.currentRoute
+            
+            // 检查是否有输入输出设备激活
+            let hasInput = !currentRoute.inputs.isEmpty
+            let hasOutput = !currentRoute.outputs.isEmpty
+            
+            // 检查特定的输出设备类型,这些通常出现在语音通话中
+            for outputPort in currentRoute.outputs {
+                if outputPort.portType == .builtInReceiver ||
+                    outputPort.portType == .builtInSpeaker ||
+                    outputPort.portType == .bluetoothHFP ||
+                    outputPort.portType == .bluetoothLE ||
+                    outputPort.portType == .bluetoothA2DP {
+                    // 同时检查是否有输入设备激活
+                    for inputPort in currentRoute.inputs {
+                        if inputPort.portType == .builtInMic ||
+                            inputPort.portType == .bluetoothHFP ||
+                            inputPort.portType == .bluetoothLE {
+                            if !isLikelyInAppCall {
+                                isLikelyInAppCall = true
+                                notifyCallStateChange(true)
+                            }
+                            return true
+                        }
+                    }
+                }
+            }
+            
+            // 检查是否同时存在输入和输出
+            if hasInput && hasOutput {
+                if !isLikelyInAppCall {
+                    isLikelyInAppCall = true
+                    notifyCallStateChange(true)
+                }
+                return true
+            }
+        }
+        
+        // 如果之前的通话状态是正在进行,但现在检测不到通话,则认为通话已结束
+        if isLikelyInAppCall {
+            let isStillInCall = checkAdvancedAudioSessionInfo()
+            if !isStillInCall {
+                isLikelyInAppCall = false
+                notifyCallStateChange(false)
+            }
+            return isStillInCall
+        }
+        
+        // 尝试获取当前音频会话的详细信息
+        let advancedCheckResult = checkAdvancedAudioSessionInfo()
+        if !isLikelyInAppCall && advancedCheckResult {
+            isLikelyInAppCall = true
+            notifyCallStateChange(true)
+        } else if isLikelyInAppCall && !advancedCheckResult {
+            isLikelyInAppCall = false
+            notifyCallStateChange(false)
+        }
+        
+        return advancedCheckResult
+    }
+    
+    // 通知通话状态变更
+    private func notifyCallStateChange(_ isCallActive: Bool) {
+        DispatchQueue.main.async {
+            self.callStateChangeHandlers.forEach { handler in
+                handler(isCallActive)
+            }
+        }
+    }
+    
+    // 更高级的音频会话信息检查
+    private func checkAdvancedAudioSessionInfo() -> Bool {
+        let audioSession = AVAudioSession.sharedInstance()
+        
+        let currentRoute = audioSession.currentRoute
+        
+        // 检查输出端口
+        for output in currentRoute.outputs {
+            if let channels = output.channels, channels.count > 0 {
+                // 检查输入端口
+                for input in currentRoute.inputs {
+                    if let inputChannels = input.channels, inputChannels.count > 0 {
+                        return true
+                    }
+                }
+            }
+        }
+        
+        return false
+    }
+}
+
+// 音频会话监控协议
+protocol AudioSessionMonitorDelegate: AnyObject {
+    func audioSessionRouteChanged(to isActive: Bool)
+}
+
+// 音频会话监控类
+class AudioSessionMonitor: NSObject {
+    private let audioSession = AVAudioSession.sharedInstance()
+    weak var delegate: AudioSessionMonitorDelegate?
+    
+    init(delegate: AudioSessionMonitorDelegate?) {
+        self.delegate = delegate
+        super.init()
+        setupNotifications()
+    }
+    
+    private func setupNotifications() {
+        // 监听音频会话中断通知
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(handleInterruption),
+            name: AVAudioSession.interruptionNotification,
+            object: audioSession
+        )
+        
+        // 监听路由变化通知
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(handleRouteChange),
+            name: AVAudioSession.routeChangeNotification,
+            object: audioSession
+        )
+    }
+    
+    deinit {
+        NotificationCenter.default.removeObserver(self)
+    }
+    
+    @objc private func handleInterruption(notification: Notification) {
+        guard let userInfo = notification.userInfo,
+              let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
+              let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
+            return
+        }
+        
+        switch type {
+        case .began:
+            // 通话被中断,可能是因为有新的来电
+            delegate?.audioSessionRouteChanged(to: false)
+        case .ended:
+            // 中断结束,重新检查通话状态
+            if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
+                let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
+                if options.contains(.shouldResume) {
+                    // 应该恢复音频,重新检查通话状态
+                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
+                        // 延迟一点时间再检查,确保系统状态稳定
+                        self.delegate?.audioSessionRouteChanged(to: WxCallManager.shared.isInWxCall())
+                    }
+                }
+            }
+        @unknown default:
+            break
+        }
+    }
+    
+    @objc private func handleRouteChange(notification: Notification) {
+        // 处理音频路由变化事件
+        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
+            // 延迟一点时间再检查,因为路由变化后可能需要一点时间才能稳定
+            let isCallActive = WxCallManager.shared.isInWxCall()
+            self.delegate?.audioSessionRouteChanged(to: isCallActive)
+        }
+    }
+}
+
+// 扩展WxCallManager以符合AudioSessionMonitorDelegate协议
+extension WxCallManager: AudioSessionMonitorDelegate {
+    func audioSessionRouteChanged(to isActive: Bool) {
+        if isActive != isLikelyInAppCall {
+            isLikelyInAppCall = isActive
+            notifyCallStateChange(isActive)
+        }
+        
+        if !isLikelyInAppCall {
+            if CallRecordManager.shared.isRecording{
+                CallRecordManager.shared.recordStop()
+            }
+        }
+    }
+}
index 80d4728..a9c06e7 100644 (file)
                                UI/common/pop/PopTextField.swift,
                                UI/common/pop/RecordPopView.swift,
                                UI/common/pop/RecordTipsView.swift,
+                               UI/common/pop/SportPopView.swift,
                                "UI/common/ScrollView+Bottom.swift",
                                UI/common/SendToolBar.swift,
                                UI/common/YLprogressHUD.swift,
                                UI/Sport/Sport/Ready/CountdownView.swift,
                                UI/Sport/Sport/Ready/CustomMapView.swift,
                                UI/Sport/Sport/Ready/FooterView.swift,
+                               UI/Sport/Sport/Ready/Navbar.swift,
+                               UI/Sport/Sport/Ready/ReadyHeader.swift,
                                UI/Sport/Sport/Ready/ReadyVC.swift,
-                               UI/Sport/Sport/root/DataView.swift,
-                               UI/Sport/Sport/root/GroupView.swift,
-                               UI/Sport/Sport/root/PlanView.swift,
-                               UI/Sport/Sport/root/RouteView.swift,
-                               UI/Sport/Sport/root/SportRootView.swift,
-                               UI/Sport/Sport/root/SportTypeView.swift,
+                               UI/Sport/Sport/Root/DataView.swift,
+                               UI/Sport/Sport/Root/GroupView.swift,
+                               UI/Sport/Sport/Root/PlanView.swift,
+                               UI/Sport/Sport/Root/RouteView.swift,
+                               UI/Sport/Sport/Root/SportRootView.swift,
+                               UI/Sport/Sport/Root/SportTypeView.swift,
                                UI/Sport/Sport/Set/SportSetCell.swift,
                                UI/Sport/Sport/Set/SportSetModel.swift,
                                UI/Sport/Sport/Set/SportSetVC.swift,
                                UI/Sport/Sport/Ready/CountdownView.swift,
                                UI/Sport/Sport/Ready/CustomMapView.swift,
                                UI/Sport/Sport/Ready/FooterView.swift,
+                               UI/Sport/Sport/Ready/Navbar.swift,
+                               UI/Sport/Sport/Ready/ReadyHeader.swift,
                                UI/Sport/Sport/Ready/ReadyVC.swift,
-                               UI/Sport/Sport/root/DataView.swift,
-                               UI/Sport/Sport/root/GroupView.swift,
-                               UI/Sport/Sport/root/PlanView.swift,
-                               UI/Sport/Sport/root/RouteView.swift,
-                               UI/Sport/Sport/root/SportRootView.swift,
-                               UI/Sport/Sport/root/SportTypeView.swift,
+                               UI/Sport/Sport/Root/DataView.swift,
+                               UI/Sport/Sport/Root/GroupView.swift,
+                               UI/Sport/Sport/Root/PlanView.swift,
+                               UI/Sport/Sport/Root/RouteView.swift,
+                               UI/Sport/Sport/Root/SportRootView.swift,
+                               UI/Sport/Sport/Root/SportTypeView.swift,
                                UI/Sport/Sport/Set/SportSetCell.swift,
                                UI/Sport/Sport/Set/SportSetModel.swift,
                                UI/Sport/Sport/Set/SportSetVC.swift,
                                CODE_SIGN_IDENTITY = "Apple Development";
                                CODE_SIGN_STYLE = Automatic;
                                CURRENT_PROJECT_VERSION = 100041;
-                               DEVELOPMENT_TEAM = G23X75CJ67;
+                               DEVELOPMENT_TEAM = MAC46RQ4KH;
                                FRAMEWORK_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "$(PROJECT_DIR)",
                                CODE_SIGN_IDENTITY = "Apple Development";
                                CODE_SIGN_STYLE = Automatic;
                                CURRENT_PROJECT_VERSION = 100041;
-                               DEVELOPMENT_TEAM = G23X75CJ67;
+                               DEVELOPMENT_TEAM = MAC46RQ4KH;
                                FRAMEWORK_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "$(PROJECT_DIR)",
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Contents.json
new file mode 100644 (file)
index 0000000..5215673
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Slice 195@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Slice 195@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Slice 195@2x.png b/ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Slice 195@2x.png
new file mode 100644 (file)
index 0000000..648cd34
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Slice 195@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Slice 195@3x.png b/ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Slice 195@3x.png
new file mode 100644 (file)
index 0000000..549d622
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/close_white.imageset/Slice 195@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Contents.json
new file mode 100644 (file)
index 0000000..d3ca90c
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Slice 56@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Slice 56@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Slice 56@2x.png b/ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Slice 56@2x.png
new file mode 100644 (file)
index 0000000..95351b8
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Slice 56@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Slice 56@3x.png b/ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Slice 56@3x.png
new file mode 100644 (file)
index 0000000..3ec27f0
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/ready_group.imageset/Slice 56@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Contents.json
new file mode 100644 (file)
index 0000000..bced9e9
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Slice 55@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Slice 55@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Slice 55@2x.png b/ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Slice 55@2x.png
new file mode 100644 (file)
index 0000000..9123d2e
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Slice 55@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Slice 55@3x.png b/ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Slice 55@3x.png
new file mode 100644 (file)
index 0000000..b4453e4
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/ready_set.imageset/Slice 55@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Contents.json
new file mode 100644 (file)
index 0000000..9dc064c
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Group_2400@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Group_2400@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Group_2400@2x.png b/ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Group_2400@2x.png
new file mode 100644 (file)
index 0000000..37aee86
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Group_2400@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Group_2400@3x.png b/ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Group_2400@3x.png
new file mode 100644 (file)
index 0000000..96e9a20
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/sport_ai.imageset/Group_2400@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Contents.json
new file mode 100644 (file)
index 0000000..8603a01
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Slice 268@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Slice 268@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Slice 268@2x.png b/ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Slice 268@2x.png
new file mode 100644 (file)
index 0000000..7a4afbe
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Slice 268@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Slice 268@3x.png b/ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Slice 268@3x.png
new file mode 100644 (file)
index 0000000..76d08b1
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/sport_light.imageset/Slice 268@3x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Contents.json b/ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Contents.json
new file mode 100644 (file)
index 0000000..ba40d8a
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "Slice 59@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "Slice 59@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Slice 59@2x.png b/ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Slice 59@2x.png
new file mode 100644 (file)
index 0000000..6802975
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Slice 59@2x.png differ
diff --git a/ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Slice 59@3x.png b/ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Slice 59@3x.png
new file mode 100644 (file)
index 0000000..3e96cb2
Binary files /dev/null and b/ShenYin/ShenYin/Assets.xcassets/sport/tips_2.imageset/Slice 59@3x.png differ
index 950b38c..10e15a0 100644 (file)
@@ -18,6 +18,29 @@ class TipsCache{
     }
 }
 
+class CommonTipsCache{
+    enum CommonTipsType:Int{
+        case light
+        var title:String{
+            switch self {
+            case .light:
+                return "亮度"
+                
+            }
+        }
+    }
+    static func needShow(type:CommonTipsType,show:Bool){
+        UserDefaults.standard.set(show, forKey: type.title)
+        UserDefaults.standard.synchronize()
+    }
+    static func needShow(type:CommonTipsType)->Bool{
+        if let value = UserDefaults.standard.value(forKey: type.title){
+            return value as? Bool ?? false
+        }
+        return true
+    }
+}
+
 class FontCache{
     static func saveFont(type:FontType){
         UserDefaults.standard.set(type.rawValue, forKey: "FontCache")
index 1f9d25a..e4b59b1 100644 (file)
@@ -19,7 +19,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
         App.shared.window = window
         AppLaunch.start()
 //        MapManager.shared.setupSdk()
-//        window?.rootViewController = UINavigationController(rootViewController: SportSetVC())
+//        window?.rootViewController = UINavigationController(rootViewController: SportingVC())
+        
     }
 
     func sceneDidDisconnect(_ scene: UIScene) {
index 7e0d091..85cbbd5 100644 (file)
@@ -26,6 +26,8 @@ public enum YLColor {
     case separateLine
     
     case cellBg
+    
+    case sport
 }
 
 extension YLColor: ColorRGBProviderProtocol {
@@ -50,6 +52,8 @@ extension YLColor: ColorRGBProviderProtocol {
                 return 0xF2F2F2
             case .cellBg:
                 return 0xffffff
+            case .sport:
+                return 0x24C789
             }
         }
         else{
@@ -72,6 +76,8 @@ extension YLColor: ColorRGBProviderProtocol {
                 return 0x666666
             case .cellBg:
                 return 0x242424
+            case .sport:
+                return 0x24C789
             }
         }
     }
index 5c354f1..52dcfb3 100644 (file)
@@ -15,7 +15,7 @@ class CCConfig{
     static let appStoreVersionURL = "https://itunes.apple.com/cn/lookup?id=6752551504"
     
     /// 服务器地址
-    //    static let baseURL = "http://118.145.178.188:32000"
+    //static let baseURL = "http://118.145.178.188:32000"
     static let baseURL = "https://app-api.deepchords.com"
     //海外版
     //    static let baseURL = "https://app-api.deepchords-ai.com"
index ee53a3f..c61bbfc 100644 (file)
@@ -153,7 +153,7 @@ class JoyChatVC:BaseVC{
     func refreshData(){
         tableView.reloadData()
         if JoySdkManager.shared.chat.dataList.count > 0 {
-            tableView.scrollToRow(at: IndexPath(row: JoySdkManager.shared.chat.dataList.count - 1, section: 0), at: .none, animated: true)
+            tableView.scrollToRow(at: IndexPath(row: JoySdkManager.shared.chat.dataList.count - 1, section: 0), at: .none, animated: false)
         }
     }
     func loadRoleList(){
index 00ae57b..b126b36 100644 (file)
@@ -7,7 +7,7 @@
 import JoyGemAI
 class CCDevice{
     static var isJoy = true
-    static var showRaisound = true
+    static var showRaisound = false
     static func initSdk(){
         if CCDevice.isJoy {
             JoySdkManager.shared.setupSdk()
index 8735333..f61e054 100644 (file)
@@ -9,7 +9,7 @@ import Foundation
 
 /// 日记管理
 class Logger {
-    static var isDebug: Bool = true
+    static var isDebug: Bool = false
     
     fileprivate static let shared = Logger()
     private var fileHandle:FileHandle?
index 002321d..b39058c 100644 (file)
@@ -11,3 +11,20 @@ public extension UITextView{
         self.scrollRangeToVisible(range)
     }
 }
+//public extension UITextView{
+//    func scrollToBottom(){
+//        // 优化:避免空文本情况
+//        guard !self.text.isEmpty else { return }
+//        
+//        // 优化:直接设置 contentOffset 而不是使用 scrollRangeToVisible
+//        let bottom = max(0, self.contentSize.height - self.bounds.height + self.contentInset.bottom)
+//        self.setContentOffset(CGPoint(x: 0, y: bottom), animated: false)
+//    }
+//    
+//    // 添加带动画控制的版本
+//    func scrollToBottomAnimated(_ animated: Bool = false) {
+////        guard !self.text.isEmpty else { return }
+//        let bottom = max(0, self.contentSize.height - self.bounds.height + self.contentInset.bottom)
+//        self.setContentOffset(CGPoint(x: 0, y: bottom), animated: animated)
+//    }
+//}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Light/BrightnessView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Light/BrightnessView.swift
new file mode 100644 (file)
index 0000000..48f4d23
--- /dev/null
@@ -0,0 +1,78 @@
+//
+//  LightView.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/2.
+//
+
+extension LightSetVC{
+    class BrightnessView: BaseView {
+        let bgView = UIView()
+        let titleLabel = UILabel()
+        let btn = UIButton()
+        let line = UIView()
+        let slider = UISlider()
+        
+        override func setupViews() {
+            addSubviews([titleLabel,slider,btn,line])
+
+            titleLabel.do { (v) in
+                v.textColor = .white
+                v.font = .bold(14)
+                v.textAlignment = .left
+                v.text = "亮度".l10n
+            }
+            
+            btn.do { v in
+                v.setImage(UIImage(named: "tips_2"), for: .normal)
+                v.addTarget(self, action: #selector(tipsAction), for: .touchUpInside)
+            }
+            
+            line.do { v in
+                v.backgroundColor = .color(.separateLine)
+            }
+            slider.do { v in
+                //            v.backgroundColor = .red
+                v.minimumValue = 0
+                v.maximumValue = 100
+                v.value = 50
+                v.minimumTrackTintColor = .white
+                v.maximumTrackTintColor = .white.withAlphaComponent(0.2)
+                v.setThumbImage(UIColor.white.imageCircle(with:  CGSize(width: 20, height: 20)), for: .normal)
+                v.addTarget(self, action: #selector(sliderChanged(_:)), for: .valueChanged) // continuous changes
+                
+            }
+        }
+        
+        override func setupLayout() {
+            titleLabel.snp.makeConstraints { (m) in
+                m.top.equalToSuperview().inset(16)
+                m.left.equalToSuperview().offset(32)
+            }
+            slider.snp.makeConstraints { make in
+                make.height.equalTo(40)
+                make.centerX.equalToSuperview()
+                make.left.right.equalToSuperview().inset(32)
+                make.top.equalToSuperview().inset(40)
+            }
+            btn.snp.makeConstraints { (m) in
+                m.size.equalTo(30)
+                m.right.equalToSuperview().inset(32)
+                m.centerY.equalTo(titleLabel.snp.centerY)
+            }
+            
+            line.snp.makeConstraints { make in
+                make.left.right.equalToSuperview().inset(28)
+                make.bottom.equalToSuperview()
+                make.height.equalTo(0.4)
+            }
+        }
+        
+        @objc func tipsAction(){
+            SportPopView().show()
+        }
+        @objc func sliderChanged(_ slider:UISlider){
+            
+        }
+    }
+}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Light/LightSetVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Light/LightSetVC.swift
new file mode 100644 (file)
index 0000000..dd68c5d
--- /dev/null
@@ -0,0 +1,97 @@
+//
+//  LightSetVC.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/2.
+//
+
+import UIKit
+class LightSetVC: BaseVC{
+    let bgView = UIScrollView()
+    let icon = UIImageView()
+    let stateView = StateView()
+    let modelView = ModeView()
+    let brightnessView = BrightnessView()
+    let sysView = StateView()
+    
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        // Do any additional setup after loading the view.
+
+    }
+    override func setupViews() {
+        navBar.do { v in
+            v.title = "灯带设置".l10n
+            v.titleLabel.textColor = .white
+            v.backgroundColor = .clear
+            v.leftView.setImage(UIImage(named: "arrow_left_1"), for: .normal)
+        }
+        view.backgroundColor = .rgb(0x1F1F1F)
+        view.addSubviews([bgView])
+        bgView.addSubviews([icon,stateView,modelView,brightnessView,sysView])
+
+        bgView.do { v in
+            v.backgroundColor = .clear
+        }
+        icon.do { v in
+            v.backgroundColor = .lightGray
+        }
+        stateView.do { v in
+            v.iSwitch.addTarget(self, action: #selector(stateAction), for: .valueChanged)
+
+        }
+        modelView.do { v in
+        }
+        brightnessView.do { v in
+//            v.backgroundColor = .yellow
+        }
+        sysView.do { v in
+            v.line.isHidden = true
+        }
+    }
+    override func setupLayout() {
+
+        bgView.snp.makeConstraints { make in
+            make.left.equalToSuperview()
+            make.width.equalTo(kScreenWid)
+            make.top.equalToSuperview().inset(kNavBtm)
+            make.height.equalTo(kScreenHei - kNavBtm)
+        }
+        icon.snp.makeConstraints { make in
+            make.height.equalTo(263.fitR)
+            make.width.equalTo(kScreenWid)
+            make.left.top.equalToSuperview()
+        }
+        stateView.snp.makeConstraints { make in
+            make.width.equalTo(kScreenWid)
+            make.height.equalTo(60)
+            make.top.equalTo(icon.snp.bottom).offset(0)
+            make.left.equalToSuperview()
+        }
+        modelView.snp.makeConstraints { make in
+            make.width.equalTo(kScreenWid)
+            make.height.equalTo(103)
+            make.top.equalTo(stateView.snp.bottom).offset(0)
+            make.left.equalToSuperview()
+        }
+        brightnessView.snp.makeConstraints { make in
+            make.width.equalTo(kScreenWid)
+            make.height.equalTo(90)
+            make.top.equalTo(modelView.snp.bottom).offset(0)
+            make.left.equalToSuperview()
+        }
+        sysView.snp.makeConstraints { make in
+            make.width.equalTo(kScreenWid)
+            make.height.equalTo(60)
+            make.top.equalTo(brightnessView.snp.bottom).offset(0)
+            make.left.equalToSuperview()
+            make.bottom.equalToSuperview()
+        }
+    }
+
+    @objc func stateAction(){
+        modelView.isHidden = !stateView.iSwitch.isOn
+        brightnessView.isHidden = !stateView.iSwitch.isOn
+        sysView.isHidden = !stateView.iSwitch.isOn
+    }
+}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Light/ModeView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Light/ModeView.swift
new file mode 100644 (file)
index 0000000..81e393d
--- /dev/null
@@ -0,0 +1,152 @@
+//
+//  ModeView.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/2.
+//
+enum LightMode {
+    case normal
+    case breath
+    case flash
+    
+    var name:String{
+        switch self {
+        case .normal:
+            return "正常".l10n
+        case .breath:
+            return "呼吸".l10n
+        case .flash:
+            return "闪烁".l10n
+        }
+    }
+}
+extension LightSetVC{
+
+    
+    class ModeView: BaseView {
+        let titleLabel = UILabel()
+        let normalItem = SelectedTypeItem()
+        let breathItem = SelectedTypeItem()
+        let flashItem = SelectedTypeItem()
+        let line = UIView()
+        
+        var isOk:Bool{
+            return normalItem.isSelected || breathItem.isSelected || flashItem.isSelected
+        }
+
+        
+        override func setupViews() {
+            //        backgroundColor = .red
+            addSubviews([titleLabel,normalItem,breathItem,flashItem,line])
+            
+            titleLabel.do { v in
+                v.textAlignment = .center
+                v.font = .bold(14)
+                v.textColor = .white
+                v.text = "模式".l10n
+            }
+            normalItem.do { v in
+                v.mode = .normal
+                v.yc.setCornerRadius(8)
+                v.yc.addTap(target: self, action: #selector(normalAction))
+            }
+            breathItem.do { v in
+                v.mode = .breath
+                v.yc.setCornerRadius(8)
+                v.yc.addTap(target: self, action: #selector(breathAction))
+            }
+            flashItem.do { v in
+                v.mode = .flash
+                v.yc.setCornerRadius(8)
+                v.yc.addTap(target: self, action: #selector(flashAction))
+            }
+            line.do { v in
+                v.backgroundColor = .color(.separateLine)
+            }
+        }
+        
+        override func setupLayout() {
+            titleLabel.snp.makeConstraints { make in
+                make.top.equalToSuperview().inset(20)
+                make.left.equalToSuperview().inset(32)
+            }
+            normalItem.snp.makeConstraints { make in
+                make.left.equalToSuperview().inset(32)
+                make.top.equalTo(titleLabel.snp.bottom).offset(10)
+                make.width.equalTo(80.fitR)
+                make.height.equalTo(32)
+            }
+            breathItem.snp.makeConstraints { make in
+                make.centerX.equalToSuperview()
+                make.top.width.height.equalTo(normalItem)
+            }
+            flashItem.snp.makeConstraints { make in
+                make.right.equalToSuperview().inset(32)
+                make.top.width.height.equalTo(normalItem)
+            }
+            line.snp.makeConstraints { make in
+                make.left.right.equalToSuperview().inset(28)
+                make.bottom.equalToSuperview()
+                make.height.equalTo(0.4)
+            }
+        }
+        
+        @objc func normalAction(){
+            normalItem.isSelected = true
+            breathItem.isSelected = false
+            flashItem.isSelected = false
+        }
+        @objc func breathAction(){
+            normalItem.isSelected = false
+            breathItem.isSelected = true
+            flashItem.isSelected = false
+        }
+        @objc func flashAction(){
+            normalItem.isSelected = false
+            breathItem.isSelected = false
+            flashItem.isSelected = true
+        }
+        
+        
+        class SelectedTypeItem: BaseView {
+            let titleLabel = UILabel()
+            var mode:LightMode = .normal{
+                didSet{
+                    titleLabel.text = mode.name
+                }
+            }
+            
+            var isSelected:Bool = false{
+                didSet{
+                    if isSelected {
+                        titleLabel.textColor = .color(.first)
+                        backgroundColor = .color(.bgColor)
+                    }
+                    else{
+                        backgroundColor = .clear
+                        titleLabel.textColor = .color(.secondary)
+                        yc.setBorder(width: 1, color: .color(.secondary))
+                    }
+                }
+            }
+            
+            override func setupViews() {
+                backgroundColor = .color(.bgColor)
+                addSubviews([titleLabel])
+                titleLabel.do { v in
+                    v.textAlignment = .center
+                    v.adjustsFontSizeToFitWidth = true
+                    v.font = .regular(14)
+                }
+                self.isSelected = false
+            }
+            
+            override func setupLayout() {
+                titleLabel.snp.makeConstraints { make in
+                    make.edges.equalToSuperview()
+                }
+            }
+        }
+    }
+
+}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Light/StateView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Light/StateView.swift
new file mode 100644 (file)
index 0000000..fead556
--- /dev/null
@@ -0,0 +1,52 @@
+//
+//  StateView.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/2.
+//
+
+extension LightSetVC{
+    class StateView: BaseView {
+        let titleLabel = UILabel()
+        let iSwitch = UISwitch()
+        let line = UIView()
+        weak var delegate:SportSetCellDelegate?
+
+        override func setupViews() {
+            addSubviews([titleLabel,iSwitch,line])
+
+            titleLabel.do { (v) in
+                v.textColor = .white
+                v.font = .bold(14)
+                v.textAlignment = .left
+                v.text = "灯带".l10n
+            }
+           
+            iSwitch.do { v in
+                //            v.backgroundColor = .red
+            }
+           
+            line.do { v in
+                v.backgroundColor = .color(.separateLine)
+            }
+        }
+        
+        override func setupLayout() {
+            titleLabel.snp.makeConstraints { (m) in
+                m.centerY.equalToSuperview()
+                m.left.equalToSuperview().offset(32)
+            }
+            
+            iSwitch.snp.makeConstraints { (m) in
+                m.right.equalToSuperview().inset(32)
+                m.centerY.equalToSuperview()
+            }
+            
+            line.snp.makeConstraints { make in
+                make.left.right.equalToSuperview().inset(28)
+                make.bottom.equalToSuperview()
+                make.height.equalTo(0.4)
+            }
+        }
+    }
+}
index e6847f0..31318c4 100644 (file)
@@ -54,10 +54,20 @@ extension ReadyVC{
         }
         
         @objc func targetAction(){
-            
+            App.shared.goToPage(SportTargetVC())
         }
         @objc func goAction(){
-            CountdownView.show(in: App.shared.window!)
+            if true {
+                CustomAlert.showWith(title: "完善数据".l10n, messgage: "完善你的身体档案,让运动数据更准确。".l10n,ok: "前往".l10n) {
+                    
+                } okCallback: {
+                    App.shared.goToPage(UserInfoVC())
+                }
+            }
+            else{
+                CountdownView.show(in: App.shared.window!)
+            }
+            
         }
         @objc func routeAction(){
             
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Ready/Navbar.swift b/ShenYin/ShenYin/UI/Sport/Sport/Ready/Navbar.swift
new file mode 100644 (file)
index 0000000..0cd46c1
--- /dev/null
@@ -0,0 +1,67 @@
+//
+//  Navbar.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/3.
+//
+
+import UIKit
+
+extension ReadyVC{
+    class Navbar: BaseView {
+        
+        let icon = UIImageView()
+        let groupBtn = UIButton()
+        let setBtn = UIButton()
+        
+        override func setupViews() {
+            //        backgroundColor = .red
+            addSubviews([icon,groupBtn,setBtn])
+            icon.do { v in
+                v.image = UIImage(named: "sport_ai")
+            }
+            groupBtn.do { v in
+                v.setBackgroundImage(UIImage(named: "ready_group"), for: .normal)
+                v.setTitle("组队".l10n, for: .normal)
+                v.setTitleColor(.color(.first), for: .normal)
+                v.titleLabel?.font = .medium(14)
+                v.addTarget(self, action: #selector(groupAction), for: .touchUpInside)
+            }
+            setBtn.do { v in
+                v.setImage(UIImage(named: "ready_set"), for: .normal)
+                v.addTarget(self, action: #selector(groupAction), for: .touchUpInside)
+            }
+        }
+        
+        override func setupLayout() {
+            icon.snp.makeConstraints { make in
+                make.size.equalTo(32)
+                make.bottom.equalToSuperview().inset(10)
+                make.centerX.equalToSuperview()
+            }
+            setBtn.snp.makeConstraints { make in
+                make.width.equalTo(32)
+                make.height.equalTo(32)
+                make.centerY.equalTo(icon)
+                make.right.equalToSuperview().inset(10)
+            }
+            groupBtn.snp.makeConstraints { make in
+                make.width.equalTo(60)
+                make.height.equalTo(24)
+                make.centerY.equalTo(icon)
+                make.right.equalTo(setBtn.snp.left).offset(-10)
+            }
+        }
+        
+        @objc func groupAction(){
+            App.shared.goToPage(SportSetVC())
+        }
+        @objc func setAction(){
+            App.shared.goToPage(SportSetVC())
+        }
+    }
+
+    
+}
+
+
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyHeader.swift b/ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyHeader.swift
new file mode 100644 (file)
index 0000000..3ca1809
--- /dev/null
@@ -0,0 +1,105 @@
+//
+//  ReadyHeader.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/3.
+//
+
+extension ReadyVC{
+    class ReadyHeader: BaseView {
+        let typeLabel = UILabel()
+        let totalLabel = UILabel()
+        let unitLabel = UILabel()
+        let aiBtn = ButtonItem()
+
+        
+        override func setupViews() {
+            addSubviews([typeLabel,totalLabel,unitLabel,aiBtn])
+            typeLabel.do { v in
+                v.textColor = .color(.secondary)
+                v.font = .regular(12)
+                v.text = "积累跑步距离"
+                v.textAlignment = .left
+            }
+            totalLabel.do { v in
+                v.textColor = .color(.first)
+                v.font = .bold(20)
+                v.text = "120"
+                v.textAlignment = .left
+            }
+            unitLabel.do { v in
+                v.textColor = .color(.first)
+                v.font = .medium(14)
+                v.text = "公里"
+                v.textAlignment = .left
+            }
+            aiBtn.do { v in
+                v.yc.setBorder(width: 1, color: .color(.secondary), radius: 18)
+                v.yc.addTap(target: self, action: #selector(aiAction))
+            }
+        }
+        
+        override func setupLayout() {
+            typeLabel.snp.makeConstraints { make in
+                make.left.equalToSuperview().inset(32)
+                make.top.equalToSuperview().inset(25)
+                
+            }
+            totalLabel.snp.makeConstraints { make in
+                make.left.equalTo(typeLabel)
+                make.bottom.equalToSuperview().inset(27)
+                
+            }
+            unitLabel.snp.makeConstraints { make in
+                make.left.equalTo(totalLabel.snp.right).offset(2)
+                make.bottom.equalToSuperview().inset(30)
+                
+            }
+            
+            aiBtn.snp.makeConstraints { make in
+                make.size.equalTo(105)
+                make.height.equalTo(36)
+                make.centerY.equalToSuperview()
+                make.right.equalToSuperview().inset(18)
+            }
+        }
+        
+        @objc func aiAction(){
+            App.shared.goToPage(SportTargetVC())
+        }
+
+        
+        class ButtonItem: BaseView {
+            let aiLabel = UILabel()
+            let titleLabel = UILabel()
+            
+            override func setupViews() {
+                addSubviews([titleLabel,aiLabel])
+                aiLabel.do { v in
+                    v.textColor = .color(.secondary)
+                    v.font = .bold(14)
+                    v.text = "AI"
+                }
+                titleLabel.do { v in
+                    v.textColor = .color(.secondary)
+                    v.font = .regular(14)
+                    v.text = "语音陪练".l10n
+                }
+                backgroundColor = .white
+            }
+            
+            override func setupLayout() {
+                aiLabel.snp.makeConstraints { make in
+                    make.left.equalToSuperview().inset(12)
+                    make.centerY.equalToSuperview()
+                }
+                titleLabel.snp.makeConstraints { make in
+                    make.centerY.equalToSuperview()
+                    make.right.equalToSuperview().inset(12)
+                }
+            }
+        }
+        
+    }
+    
+}
index 1eab05b..6c0434f 100644 (file)
@@ -7,17 +7,24 @@
 import MAMapKit
 
 class ReadyVC: BaseVC {
-    let headerView = UIView()
+    let bar = Navbar()
+    let headerView = ReadyHeader()
     var mapView:MAMapView!
     let footerView = FooterView()
     
     override func setupViews() {
+        
+        
+        
         mapView = MAMapView(frame: .zero)
         mapView.delegate = self
         mapView.showsUserLocation = true
         mapView.zoomLevel = 16
         mapView.userTrackingMode = .followWithHeading
         
+        navBar.do { v in
+            v.addSubview(bar)
+        }
         view.addSubviews([headerView,mapView,footerView])
         headerView.do { v in
             v.backgroundColor = .white
@@ -31,9 +38,12 @@ class ReadyVC: BaseVC {
         }
     }
     override func setupLayout() {
+        bar.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
         headerView.snp.makeConstraints { make in
             make.left.right.equalToSuperview()
-            make.top.equalToSuperview().inset(kNavBtm + 20)
+            make.top.equalToSuperview().inset(kNavBtm)
             make.height.equalTo(100)
         }
         footerView.snp.makeConstraints { make in
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Sporting/DetailBoard.swift b/ShenYin/ShenYin/UI/Sport/Sport/Sporting/DetailBoard.swift
new file mode 100644 (file)
index 0000000..87ce152
--- /dev/null
@@ -0,0 +1,118 @@
+//
+//  Untitled.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/3.
+//
+
+import UIKit
+
+extension SportingVC{
+    class DetailBoard: BaseView {
+        let topIcon = UIImageView()
+        let distanceItem = LabelItem()
+        let durationItem = LabelItem()
+        let speedItem = LabelItem()
+        let calorieItem = LabelItem()
+        let stepItem = LabelItem()
+        
+        override func setupViews() {
+            backgroundColor = .white
+            addSubviews([topIcon,distanceItem,durationItem,speedItem,calorieItem,stepItem])
+            topIcon.do { v in
+                v.backgroundColor = .color(.secondary)
+                v.yc.setCornerRadius(2)
+            }
+            distanceItem.do { v in
+                v.titleLabel.text = "0"
+                v.detailLabel.text = "总距离".l10n
+            }
+            durationItem.do { v in
+                v.titleLabel.text = "00:00:00"
+                v.detailLabel.text = "总时长".l10n
+            }
+            speedItem.do { v in
+                v.titleLabel.text = "00:00:00"
+                v.detailLabel.text = "总时长".l10n
+            }
+            calorieItem.do { v in
+                v.titleLabel.text = "00:00:00"
+                v.detailLabel.text = "总时长".l10n
+            }
+            stepItem.do { v in
+                v.titleLabel.text = "00:00:00"
+                v.detailLabel.text = "总时长".l10n
+            }
+        }
+        
+        override func setupLayout() {
+            topIcon.snp.makeConstraints { make in
+                make.width.equalTo(50)
+                make.height.equalTo(4)
+                make.top.equalToSuperview().inset(6)
+                make.centerX.equalToSuperview()
+            }
+            distanceItem.snp.makeConstraints { make in
+                make.left.equalToSuperview().inset(18)
+                make.top.equalToSuperview().inset(27)
+                make.height.equalTo(50)
+            }
+            durationItem.snp.makeConstraints { make in
+                make.left.equalToSuperview().inset(18)
+                make.top.equalToSuperview().inset(180)
+                make.height.equalTo(50)
+            }
+            speedItem.snp.makeConstraints { make in
+                make.left.equalToSuperview().inset(kScreenWid/2 + 18)
+                make.top.equalTo(durationItem.snp.top)
+                make.height.equalTo(50)
+            }
+            distanceItem.snp.makeConstraints { make in
+                make.left.equalToSuperview().inset(18)
+                make.top.equalToSuperview().inset(250)
+                make.height.equalTo(50)
+            }
+            stepItem.snp.makeConstraints { make in
+                make.left.equalToSuperview().inset(kScreenWid/2 + 18)
+                make.top.equalTo(distanceItem.snp.top)
+                make.height.equalTo(50)
+            }
+        }
+        
+        @objc func groupAction(){
+            App.shared.goToPage(SportSetVC())
+        }
+
+    }
+    
+    class LabelItem: BaseView {
+        let detailLabel = UILabel()
+        let titleLabel = UILabel()
+        
+        override func setupViews() {
+            addSubviews([titleLabel,detailLabel])
+            titleLabel.do { v in
+                v.textColor = .color(.first)
+                v.font = .bold(24)
+                v.textAlignment = .left
+            }
+            detailLabel.do { v in
+                v.textColor = .color(.secondary)
+                v.font = .regular(12)
+                v.textAlignment = .left
+            }
+        }
+        
+        override func setupLayout() {
+            titleLabel.snp.makeConstraints { make in
+                make.top.equalToSuperview().inset(0)
+                make.left.right.equalToSuperview()
+            }
+            detailLabel.snp.makeConstraints { make in
+                make.bottom.equalToSuperview().inset(0)
+                make.left.right.equalToSuperview()
+            }
+        }
+    }
+
+}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SimpleBoard.swift b/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SimpleBoard.swift
new file mode 100644 (file)
index 0000000..ce06371
--- /dev/null
@@ -0,0 +1,85 @@
+//
+//  Untitled.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/3.
+//
+
+import UIKit
+
+extension SportingVC{
+    class SimpleBoard: BaseView {
+        let topIcon = UIImageView()
+        let distanceItem = LabelItem()
+        let durationItem = LabelItem()
+        
+        override func setupViews() {
+            backgroundColor = .white
+            addSubviews([topIcon,distanceItem,durationItem])
+            topIcon.do { v in
+                v.backgroundColor = .color(.secondary)
+                v.yc.setCornerRadius(2)
+            }
+            distanceItem.do { v in
+                v.titleLabel.text = "0"
+                v.detailLabel.text = "总距离".l10n
+            }
+            durationItem.do { v in
+                v.titleLabel.text = "00:00:00"
+                v.detailLabel.text = "总时长".l10n
+            }
+        }
+        
+        override func setupLayout() {
+            topIcon.snp.makeConstraints { make in
+                make.width.equalTo(50)
+                make.height.equalTo(4)
+                make.top.equalToSuperview().inset(6)
+                make.centerX.equalToSuperview()
+            }
+            distanceItem.snp.makeConstraints { make in
+                make.left.equalToSuperview().inset(18)
+                make.top.equalToSuperview().inset(27)
+                make.height.equalTo(50)
+            }
+            durationItem.snp.makeConstraints { make in
+                make.left.equalToSuperview().inset(kScreenWid/2 + 18)
+                make.top.equalToSuperview().inset(27)
+                make.height.equalTo(distanceItem)
+            }
+        }
+        
+        @objc func groupAction(){
+            App.shared.goToPage(SportSetVC())
+        }
+        class LabelItem: BaseView {
+            let detailLabel = UILabel()
+            let titleLabel = UILabel()
+            
+            override func setupViews() {
+                addSubviews([titleLabel,detailLabel])
+                titleLabel.do { v in
+                    v.textColor = .color(.secondary)
+                    v.font = .bold(24)
+                    v.textAlignment = .left
+                }
+                detailLabel.do { v in
+                    v.textColor = .color(.secondary)
+                    v.font = .regular(12)
+                    v.textAlignment = .left
+                }
+            }
+            
+            override func setupLayout() {
+                titleLabel.snp.makeConstraints { make in
+                    make.top.equalToSuperview().inset(0)
+                    make.left.right.equalToSuperview()
+                }
+                detailLabel.snp.makeConstraints { make in
+                    make.bottom.equalToSuperview().inset(0)
+                    make.left.right.equalToSuperview()
+                }
+            }
+        }
+    }
+}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SportingVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SportingVC.swift
new file mode 100644 (file)
index 0000000..ed528b3
--- /dev/null
@@ -0,0 +1,86 @@
+//
+//  Untitled.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/3.
+//
+
+import MAMapKit
+
+class SportingVC: BaseVC {
+    var mapView:MAMapView!
+    let simpleView = SimpleBoard()
+    let detailView = DetailBoard()
+    
+    override func setupViews() {
+        
+        
+        
+        mapView = MAMapView(frame: .zero)
+        mapView.delegate = self
+        mapView.showsUserLocation = true
+        mapView.zoomLevel = 16
+        mapView.userTrackingMode = .followWithHeading
+
+        view.addSubviews([mapView,simpleView,detailView])
+        mapView.do { v in
+            
+        }
+        simpleView.do { v in
+            //            v.backgroundColor = .blue
+            v.yc.addTap(target: self, action: #selector(simpleTapAction))
+        }
+        detailView.do { v in
+            v.isHidden = true
+            v.yc.addTap(target: self, action: #selector(detailTapAction))
+        }
+    }
+    override func setupLayout() {
+        simpleView.snp.makeConstraints { make in
+            make.left.right.equalToSuperview()
+            make.bottom.equalToSuperview()
+            make.height.equalTo(100)
+        }
+        detailView.snp.makeConstraints { make in
+            make.left.right.equalToSuperview()
+            make.bottom.equalToSuperview()
+            make.height.equalTo(460)
+        }
+        mapView.snp.makeConstraints { make in
+            make.left.right.top.equalToSuperview()
+            make.bottom.equalTo(simpleView.snp.top)
+        }
+    }
+    override func setupData() {
+        
+    }
+    
+    @objc func simpleTapAction(){
+        simpleView.isHidden = true
+        detailView.isHidden = false
+        showDetail()
+    }
+    @objc func detailTapAction(){
+        simpleView.isHidden = false
+        detailView.isHidden = true
+        showSimple()
+    }
+    func showSimple(){
+        mapView.snp.remakeConstraints { make in
+            make.left.right.top.equalToSuperview()
+            make.bottom.equalTo(simpleView.snp.top)
+        }
+    }
+    func showDetail(){
+        mapView.snp.remakeConstraints { make in
+            make.left.right.top.equalToSuperview()
+            make.bottom.equalTo(detailView.snp.top)
+        }
+    }
+}
+
+extension SportingVC:MAMapViewDelegate{
+    func mapViewRequireLocationAuth(_ locationManager: CLLocationManager!) {
+        //        locationManager.requestAlwaysAuthorization()
+    }
+}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Target/CalorieView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Target/CalorieView.swift
new file mode 100644 (file)
index 0000000..e3f5607
--- /dev/null
@@ -0,0 +1,45 @@
+//
+//  CaloriView.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/3.
+//
+
+import JXSegmentedView
+
+extension SportTargetVC{
+    class CaloriView: BaseView ,JXSegmentedListContainerViewListDelegate{
+        let label = UILabel()
+        
+        override func setupViews() {
+            addSubviews([label])
+            label.do { v in
+                v.font = .bold(28)
+                v.textAlignment = .center
+                v.textColor = .color(.first)
+                v.text = "300 千卡"
+                v.yc.addTap(target: self, action: #selector(tapAction))
+            }
+        }
+        override func setupLayout() {
+            label.snp.makeConstraints { make in
+                make.left.right.equalToSuperview()
+                make.top.equalToSuperview().inset(50)
+            }
+        }
+        
+        func listView() -> UIView {
+            return self
+        }
+        @objc func tapAction(){
+            let list = Array(stride(from: 1, to: 1000, by: 1)).map { String($0) + " 千卡" }
+            let v = CustomPicker2(title: "卡路里".l10n, list:list )
+            v.selectedIndex = 0
+            v.show()
+            v.didSelected = {[weak self] (index,value) in
+                guard let self = self else { return  }
+                label.text = value
+            }
+        }
+    }
+}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Target/DistanceView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Target/DistanceView.swift
new file mode 100644 (file)
index 0000000..4aeadce
--- /dev/null
@@ -0,0 +1,45 @@
+//
+//  DistanceView.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/3.
+//
+
+import JXSegmentedView
+
+extension SportTargetVC{
+    class DistanceView: BaseView ,JXSegmentedListContainerViewListDelegate{
+        let label = UILabel()
+        
+        override func setupViews() {
+            addSubviews([label])
+            label.do { v in
+                v.font = .bold(28)
+                v.textAlignment = .center
+                v.textColor = .color(.first)
+                v.text = "3 km"
+                v.yc.addTap(target: self, action: #selector(tapAction))
+            }
+        }
+        override func setupLayout() {
+            label.snp.makeConstraints { make in
+                make.left.right.equalToSuperview()
+                make.top.equalToSuperview().inset(50)
+            }
+        }
+        
+        func listView() -> UIView {
+            return self
+        }
+        @objc func tapAction(){
+            let list = Array(stride(from: 1, to: 100, by: 1)).map { String($0) + " km" }
+            let v = CustomPicker2(title: "距离".l10n, list:list )
+            v.selectedIndex = 0
+            v.show()
+            v.didSelected = {[weak self] (index,value) in
+                guard let self = self else { return  }
+                label.text = value
+            }
+        }
+    }
+}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Target/DurationView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Target/DurationView.swift
new file mode 100644 (file)
index 0000000..aa5b92d
--- /dev/null
@@ -0,0 +1,44 @@
+//
+//  DurationView.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/3.
+//
+
+import JXSegmentedView
+
+extension SportTargetVC{
+    class DurationView: BaseView ,JXSegmentedListContainerViewListDelegate{
+        let label = UILabel()
+        
+        override func setupViews() {
+            addSubviews([label])
+            label.do { v in
+                v.font = .bold(28)
+                v.textAlignment = .center
+                v.textColor = .color(.first)
+                v.text = "00:30"
+                v.yc.addTap(target: self, action: #selector(tapAction))
+            }
+        }
+        override func setupLayout() {
+            label.snp.makeConstraints { make in
+                make.left.right.equalToSuperview()
+                make.top.equalToSuperview().inset(50)
+            }
+        }
+        
+        func listView() -> UIView {
+            return self
+        }
+        @objc func tapAction(){
+            let v = CustomPicker3(title: "日期".l10n)
+            v.datePicker.datePickerMode = .time
+            v.show()
+            v.didSelected = {[weak self] (date) in
+                guard let self = self else { return  }
+                label.text = date.format(.shortTime)
+            }
+        }
+    }
+}
diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Target/SportTargetVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Target/SportTargetVC.swift
new file mode 100644 (file)
index 0000000..f0cd5cc
--- /dev/null
@@ -0,0 +1,127 @@
+//
+//  SportTargetVC.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/3.
+//
+
+import JXSegmentedView
+
+
+enum SportTargetType{
+    case distance
+    case duration
+    case calorie
+    
+    var name:String{
+        switch self {
+        case .distance:
+            return "距离".l10n
+        case .duration:
+            return "时长".l10n
+        case .calorie:
+            return "卡路里".l10n
+        }
+    }
+    static var all:[SportTargetType] = [.distance,.duration,.calorie]
+}
+
+class SportTargetVC: BaseVC {
+    let okBtn = CustomButton()
+    private let segmentedDataSource = JXSegmentedTitleDataSource()
+    private let segmentedView = JXSegmentedView()
+    private lazy var listContainerView: JXSegmentedListContainerView! = {
+        let view = JXSegmentedListContainerView(dataSource: self, type: .scrollView)
+        return view
+    }()
+    
+    var list:[SportTargetType] = SportTargetType.all
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        
+
+    }
+    
+    override func setupLayout(){
+        
+        segmentedView.snp.makeConstraints { (m) in
+            m.left.right.equalToSuperview()
+            m.height.equalTo(44.fitR)
+            m.top.equalToSuperview().inset(kNavBtm)
+        }
+        listContainerView.snp.makeConstraints { (m) in
+            m.width.left.equalToSuperview()
+            m.top.equalTo(segmentedView.snp.bottom)
+            m.bottom.equalToSuperview()
+        }
+        okBtn.snp.makeConstraints { make in
+            make.bottom.equalToSuperview().inset(80)
+            make.left.right.equalToSuperview().inset(51)
+            make.height.equalTo(46)
+        }
+    }
+    override func setupViews(){
+        navBar.title = "设置目标".l10n
+        view.addSubview(segmentedView)
+        view.addSubview(listContainerView)
+        view.addSubview(okBtn)
+        
+        view.backgroundColor = .color(.bgColor)
+        segmentedView.do { (v) in
+            segmentedDataSource.titleNormalColor = .color(.secondary)
+            segmentedDataSource.titleSelectedColor = .color(.first)
+            segmentedDataSource.titleNormalFont = .regular(14)
+            segmentedDataSource.titleSelectedFont = .bold(16)
+            segmentedDataSource.isTitleZoomEnabled = true
+            // segmentedDataSource.titleSelectedZoomScale = 1
+            segmentedDataSource.isTitleStrokeWidthEnabled = true
+            segmentedDataSource.isItemSpacingAverageEnabled = true
+            segmentedDataSource.isTitleColorGradientEnabled = true
+            segmentedDataSource.titles = list.map{"\($0.name)"}
+            segmentedView.backgroundColor = .clear
+            
+            //配置指示器
+            let indicator = JXSegmentedIndicatorLineView()
+            indicator.indicatorWidth = 20
+            indicator.indicatorHeight = 4
+            indicator.verticalOffset = 6
+            indicator.indicatorColor = .color(.sport)
+            segmentedView.indicators = [indicator]
+            
+            v.dataSource = segmentedDataSource
+            v.listContainer = listContainerView
+        }
+        okBtn.set(title: "确认".l10n,style: .sport, target: self, action: #selector(okAction))
+    }
+    @objc func okAction(){
+        self.navigationController?.popViewController(animated: true)
+    }
+}
+
+extension SportTargetVC: JXSegmentedListContainerViewListDelegate {
+    func listView() -> UIView {
+        return view
+    }
+}
+
+extension SportTargetVC: JXSegmentedListContainerViewDataSource {
+    func numberOfLists(in listContainerView: JXSegmentedListContainerView) -> Int {
+        if let titleDataSource = segmentedView.dataSource as? JXSegmentedBaseDataSource {
+            return titleDataSource.dataSource.count
+        }
+        return 0
+    }
+    
+    func listContainerView(_ listContainerView: JXSegmentedListContainerView, initListAt index: Int) -> JXSegmentedListContainerViewListDelegate {
+        let type = list[index]
+        switch type {
+        case .distance:
+            return DistanceView()
+        case .duration:
+            return DurationView()
+        case .calorie:
+            return CaloriView()
+        }
+        
+    }
+}
index 4a4f320..be4ce07 100644 (file)
@@ -43,7 +43,7 @@ class SportHomeVC: BaseVC {
         
         //        AudioPlayView.shared.show()
         self.view.addSubview(AudioPlayView.shared)
-//        MapManager.shared.setupSdk()
+        MapManager.shared.setupSdk()
     }
     
     override func setupLayout(){
index a56ca70..c81ffad 100644 (file)
@@ -13,6 +13,7 @@ enum CustomButtonStyle:Int{
     case theme3
     case theme4
     case custom
+    case sport
 }
 
 class CustomButton: UIButton {
@@ -40,6 +41,10 @@ class CustomButton: UIButton {
                 backgroundColor =  .color(.cellBg)
                 titleLabel?.font = .regular(14)
             }
+            else if style == .sport {
+                setTitleColor(.white, for: .normal)
+                backgroundColor =  .color(.sport)
+            }
             else{
                 setTitleColor(.color(.theme), for: .normal)
                 backgroundColor = .clear
@@ -70,6 +75,10 @@ class CustomButton: UIButton {
                 backgroundColor =  .color(.cellBg)
                 titleLabel?.font = .regular(14)
             }
+            else if style == .sport {
+                setTitleColor(.white, for: .normal)
+                backgroundColor =  .color(.sport)
+            }
             else{
                 setTitleColor(.white, for: .normal)
                 backgroundColor = .clear
index 54c40bf..81933bb 100644 (file)
@@ -4,7 +4,7 @@ class CustomPicker3: BasePresentView {
     private let titleLabel = UILabel()
     private let btn = UIButton(type: .custom)
     private let okBtn = CustomButton()
-    private let datePicker = UIDatePicker()
+    let datePicker = UIDatePicker()
     var selectedDate = Date() {
         didSet {
             datePicker.date = selectedDate
diff --git a/ShenYin/ShenYin/UI/common/pop/SportPopView.swift b/ShenYin/ShenYin/UI/common/pop/SportPopView.swift
new file mode 100644 (file)
index 0000000..564334b
--- /dev/null
@@ -0,0 +1,178 @@
+//
+//  SportPopView.swift
+//  ShenYin
+//
+//  Created by liangshi on 2026/2/2.
+//
+
+import UIKit
+
+
+class SportPopView: BasePresentView {
+    let titleLabel = UILabel()
+    let scorllView = UIScrollView()
+    let btn = UIButton(type: .custom)
+    let tipsIcon = UIImageView()
+    let desLabel1 = UILabel()
+    let desLabel2 = UILabel()
+    let actionbtn = UIButton(type: .custom)
+    let agreeView = AgreeView()
+    var didSelected: ((Int,String)->Void)?
+    
+    init() {
+        let h =  350.0
+        super.init(contentHeight:h)
+    }
+    
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    override func setupSubView() {
+        super.setupSubView()
+        
+        contentView.addSubviews([titleLabel,btn,scorllView,actionbtn,agreeView])
+        scorllView.addSubviews([tipsIcon,desLabel1,desLabel2])
+        
+    }
+    override func setupLayout() {
+        super.setupLayout()
+        titleLabel.snp.makeConstraints { (m) in
+            m.top.equalToSuperview()
+            m.left.right.equalToSuperview().inset(36)
+            m.height.equalTo(60)
+        }
+        btn.snp.makeConstraints { (m) in
+            m.centerY.equalTo(titleLabel)
+            m.right.equalToSuperview()
+            m.size.equalTo(60)
+        }
+        actionbtn.snp.makeConstraints { (m) in
+            m.bottom.equalToSuperview().inset(60)
+            m.left.right.equalToSuperview().inset(52)
+            m.height.equalTo(46)
+        }
+        agreeView.snp.makeConstraints { (m) in
+            m.bottom.equalToSuperview().inset(20)
+            m.centerX.equalToSuperview()
+            m.height.equalTo(30)
+        }
+        
+        scorllView.snp.makeConstraints { make in
+            make.width.equalTo(kScreenWid)
+            make.height.equalTo(450)
+            make.left.equalToSuperview().inset(0)
+            make.top.equalToSuperview().inset(64)
+        }
+        tipsIcon.snp.makeConstraints { make in
+            make.centerX.equalToSuperview()
+            make.top.equalToSuperview()
+            make.size.equalTo(62)
+        }
+        desLabel1.snp.makeConstraints { (m) in
+            m.top.equalTo(tipsIcon.snp.bottom).offset(20)
+            m.left.equalToSuperview().inset(40)
+            m.width.equalTo(kScreenWid - 60)
+        }
+        desLabel2.snp.makeConstraints { (m) in
+            m.top.equalTo(desLabel1.snp.bottom).offset(20)
+            m.left.equalToSuperview().inset(30)
+            m.width.equalTo(kScreenWid - 60)
+            m.bottom.equalToSuperview().inset(10)
+        }
+        
+    }
+    
+    override func setupStyle() {
+        super.setupStyle()
+        contentView.backgroundColor = .rgb(0x242424)
+        scorllView.do { v in
+            v.backgroundColor = .clear
+        }
+        titleLabel.do { (v) in
+            v.textColor = .white
+            v.font = .semiBold(16)
+            v.textAlignment = .center
+            v.text = "亮度提醒".l10n
+        }
+        btn.do { v in
+            v.setImage(UIImage(named: "close_white"), for: .normal)
+            v.addTarget(self, action: #selector(closeAction), for: .touchUpInside)
+        }
+        tipsIcon.do { v in
+            v.image = UIImage(named: "sport_light")
+        }
+        desLabel1.do { v in
+            let text = "高亮度提升可见度,低亮度更省电量, 建议根据使用场景合理调节".l10n
+            let attributedString = NSMutableAttributedString(string: text)
+            let paragraphStyle = NSMutableParagraphStyle()
+            paragraphStyle.lineSpacing = 10
+            attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: text.count))
+            v.attributedText = attributedString
+            
+            v.textColor = .white
+            v.font = .semiBold(16)
+            v.textAlignment = .center
+            v.numberOfLines = 0
+        }
+        
+        actionbtn.do { v in
+            v.backgroundColor = .color(.theme)
+            v.setTitle("开始体验".l10n, for: .normal)
+            v.titleLabel?.font = .regular(14)
+            v.yc.setCornerRadius(12)
+            v.setTitleColor(.white, for: .normal)
+            v.addTarget(self, action: #selector(btnAction), for: .touchUpInside)
+        }
+        agreeView.do { v in
+            v.agreeBtn.isSelected = false
+            v.agreeBtn.addTarget(self, action: #selector(agreeBtnAction), for: .touchUpInside)
+        }
+    }
+    @objc func closeAction(){
+        CommonTipsCache.needShow(type: .light, show: !agreeView.agreeBtn.isSelected)
+        hide()
+    }
+    @objc func btnAction(){
+        CommonTipsCache.needShow(type: .light, show: !agreeView.agreeBtn.isSelected)
+        hide()
+    }
+    @objc func agreeBtnAction(){
+        agreeView.agreeBtn.isSelected = !agreeView.agreeBtn.isSelected
+        CommonTipsCache.needShow(type: .light, show: !agreeView.agreeBtn.isSelected)
+    }
+    class AgreeView: BaseView {
+        let agreeBtn = UIButton()
+        let agreeTitle = UILabel()
+        override func setupViews() {
+            agreeBtn.do { (v) in
+                v.isSelected = true
+                v.contentMode = .center
+                v.setImage(UIImage(named: "tip_normal"), for: .normal)
+                v.setImage(UIImage(named: "tip_selected"), for: .selected)
+            }
+            agreeTitle.do { (v) in
+                v.textColor = .color(.secondary)
+                v.font = .regular(12)
+                v.textAlignment = .left
+                v.text = "下次不再提示".l10n
+            }
+            //            backgroundColor = .red
+            addSubviews([agreeBtn,agreeTitle])
+        }
+        override func setupLayout() {
+            agreeBtn.snp.makeConstraints { (m) in
+                m.left.top.equalToSuperview()
+                m.height.equalTo(30)
+                m.width.equalTo(30)
+            }
+            agreeTitle.snp.makeConstraints { (m) in
+                m.left.equalTo(agreeBtn.snp.right)
+                m.height.equalToSuperview()
+                m.centerY.equalTo(agreeBtn)
+                m.right.equalToSuperview()
+            }
+        }
+    }
+    
+}