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",
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
--- /dev/null
+//
+// 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()
+ }
+ }
+ }
+}
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)",
--- /dev/null
+{
+ "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
+ }
+}
--- /dev/null
+{
+ "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
+ }
+}
--- /dev/null
+{
+ "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
+ }
+}
--- /dev/null
+{
+ "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
+ }
+}
--- /dev/null
+{
+ "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
+ }
+}
--- /dev/null
+{
+ "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
+ }
+}
}
}
+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")
App.shared.window = window
AppLaunch.start()
// MapManager.shared.setupSdk()
-// window?.rootViewController = UINavigationController(rootViewController: SportSetVC())
+// window?.rootViewController = UINavigationController(rootViewController: SportingVC())
+
}
func sceneDidDisconnect(_ scene: UIScene) {
case separateLine
case cellBg
+
+ case sport
}
extension YLColor: ColorRGBProviderProtocol {
return 0xF2F2F2
case .cellBg:
return 0xffffff
+ case .sport:
+ return 0x24C789
}
}
else{
return 0x666666
case .cellBg:
return 0x242424
+ case .sport:
+ return 0x24C789
}
}
}
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"
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(){
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()
/// 日记管理
class Logger {
- static var isDebug: Bool = true
+ static var isDebug: Bool = false
fileprivate static let shared = Logger()
private var fileHandle:FileHandle?
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)
+// }
+//}
--- /dev/null
+//
+// 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){
+
+ }
+ }
+}
--- /dev/null
+//
+// 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
+ }
+}
--- /dev/null
+//
+// 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()
+ }
+ }
+ }
+ }
+
+}
--- /dev/null
+//
+// 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)
+ }
+ }
+ }
+}
}
@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(){
--- /dev/null
+//
+// 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())
+ }
+ }
+
+
+}
+
+
--- /dev/null
+//
+// 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)
+ }
+ }
+ }
+
+ }
+
+}
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
}
}
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
--- /dev/null
+//
+// 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()
+ }
+ }
+ }
+
+}
--- /dev/null
+//
+// 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()
+ }
+ }
+ }
+ }
+}
--- /dev/null
+//
+// 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()
+ }
+}
--- /dev/null
+//
+// 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
+ }
+ }
+ }
+}
--- /dev/null
+//
+// 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
+ }
+ }
+ }
+}
--- /dev/null
+//
+// 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)
+ }
+ }
+ }
+}
--- /dev/null
+//
+// 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()
+ }
+
+ }
+}
// AudioPlayView.shared.show()
self.view.addSubview(AudioPlayView.shared)
-// MapManager.shared.setupSdk()
+ MapManager.shared.setupSdk()
}
override func setupLayout(){
case theme3
case theme4
case custom
+ case sport
}
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
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
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
--- /dev/null
+//
+// 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()
+ }
+ }
+ }
+
+}