//
// Created by liangshi on 2026/2/26.
//
-import StarburstSdk
-public class DCTts:NSObject{
- public static let shared = DCTts()
-
- ///
- var ttsCallBack:((_ stream:Data)->Void)?
-
- /// 文本合成语音
- /// - Parameters:
- /// - text: 文本
- /// - callback: 音频流回调
- public func tts(text:String,callback: @escaping ((Data))->Void){
- self.ttsCallBack = callback
- TextToSpeechManager.sharedInstance().textToSpeech(
- companyId: "2101982539",
- text: text,
- reqId: UUID().uuidString,
- speedRatio: 1.0,
- voiceType: "zh_female_qingchezizi_moon_bigtts",
- encoding: "pcm",
- callback: self
- )
- }
-}
-extension DCTts: TextToSpeechCallback {
- public func onResult(_ response: String) {
- guard let jsonObj = try? JSONSerialization.jsonObject(with: response.data(using: .utf8)!, options: []) as? [String:Any],
- let respObj = jsonObj["resp"] as? [String:Any],
- let base64Data = respObj["data"] as? String,
- let pcmBytes = Data(base64Encoded: base64Data) else {
- DCLogger.debug("解析PCM失败\n")
- return
- }
- ttsCallBack?(pcmBytes)
- }
-
- public func onError(_ code: Int, message: String) {
- DCLogger.debug("合成失败:\(message)\n")
- }
-}
+//import StarburstSdk
+//public class DCTts:NSObject{
+// public static let shared = DCTts()
+//
+// ///
+// var ttsCallBack:((_ stream:Data)->Void)?
+//
+// /// 文本合成语音
+// /// - Parameters:
+// /// - text: 文本
+// /// - callback: 音频流回调
+// public func tts(text:String,callback: @escaping ((Data))->Void){
+// self.ttsCallBack = callback
+// TextToSpeechManager.sharedInstance().textToSpeech(
+// companyId: "2101982539",
+// text: text,
+// reqId: UUID().uuidString,
+// speedRatio: 1.0,
+// voiceType: "zh_female_qingchezizi_moon_bigtts",
+// encoding: "pcm",
+// callback: self
+// )
+// }
+//}
+//extension DCTts: TextToSpeechCallback {
+// public func onResult(_ response: String) {
+// guard let jsonObj = try? JSONSerialization.jsonObject(with: response.data(using: .utf8)!, options: []) as? [String:Any],
+// let respObj = jsonObj["resp"] as? [String:Any],
+// let base64Data = respObj["data"] as? String,
+// let pcmBytes = Data(base64Encoded: base64Data) else {
+// DCLogger.debug("解析PCM失败\n")
+// return
+// }
+// ttsCallBack?(pcmBytes)
+// }
+//
+// public func onError(_ code: Int, message: String) {
+// DCLogger.debug("合成失败:\(message)\n")
+// }
+//}
UI/Login/Controller/Binding/BindingPhoneVC.swift,
UI/Login/Controller/Binding/VarifyBindingVC.swift,
UI/Login/Controller/ContryListVC.swift,
+ UI/Login/Controller/DcLoginVC.swift,
UI/Login/Controller/ForgetVC.swift,
UI/Login/Controller/LoginVC.swift,
UI/Login/Controller/RegisterVC.swift,
self.window?.rootViewController = BaseTC()
}
func goToLogin(){
- window?.rootViewController = BaseNC(rootViewController: LoginVC())
+ if CCDevice.isJoy{
+ window?.rootViewController = BaseNC(rootViewController: LoginVC())
+ }
+ else{
+ window?.rootViewController = BaseNC(rootViewController: DcLoginVC())
+ }
}
func goToPage(_ viewController: UIViewController,animated:Bool = true){
translateTextView.do { v in
v.textView.textColor = .color(.first)
v.placeHolde = "此处将显示译文".l10n
- v.bgView.yc.addgradientLayer(colors: [.color(.theme),.color(.bgColor)], direction: .top2down,rect: CGRect(x: 0, y: 0, width: kScreenWid, height: (kScreenHei - kNavBtm - 120 - 10)/2))
- v.bgView.alpha = 0.1
+ if CCDevice.isJoy{
+ v.bgView.yc.addgradientLayer(colors: [.color(.theme),.color(.bgColor)], direction: .top2down,rect: CGRect(x: 0, y: 0, width: kScreenWid, height: (kScreenHei - kNavBtm - 120 - 10)/2))
+ v.bgView.alpha = 0.1
+ }
+ else{
+ v.bgView.backgroundColor = .color(.cellBg)
+ }
v.yc.setCorners(withRoundedRect: CGRect(x: 0, y: 0, width: kScreenWid, height: (kScreenHei - kNavBtm - 120 - 10)/2), roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 20, height: 20))
}
}
super.init(coder: aDecoder)
fd_fullscreenPopGestureRecognizer?.isEnabled = true
}
+ override var preferredStatusBarStyle: UIStatusBarStyle {
+ return topViewController?.preferredStatusBarStyle ?? .lightContent
+ }
}
func setupUI(){
if CCDevice.isJoy{
-// let homeVC = HomeDeviceVC()
- let homeVC = SportHomeVC()
+ let homeVC = HomeDeviceVC()
+// let homeVC = SportHomeVC()
let modeVC = ModeVC()
let sleepVC = SleepVC()
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.navigationController?.navigationBar.isHidden = true
+ self.setNeedsStatusBarAppearanceUpdate()
}
deinit {
Logger.debug("deinit \(Self.self)")
}
-
override open func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
KingfisherManager.shared.cache.clearMemoryCache()
)
)
}
-
// 日期配置
.dayItemProvider { [weak self, calendar, dayDateFormatter] day in
guard let self else { return nil }
var invariantViewProperties = DayView.InvariantViewProperties.baseInteractive
-
-
-
let date = calendar.date(from: day.components)
let selectedDate = date?.format(.short)
if let text = defaultDate, selectedDate == text {
else{
invariantViewProperties.textColor = .color(.secondary)
}
+ if let date = date,date > Date(){
+ invariantViewProperties.textColor = CCDevice.isJoy ? .color(.placeholder):.rgb(0x333333)
+ }
+
+
return DayView.calendarItemModel(
invariantViewProperties: invariantViewProperties,
content: .init(
--- /dev/null
+//
+// DcLoginVC.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/26.
+//
+
+import UIKit
+import DeviceKit
+
+class DcLoginVC:BaseVC{
+ let logoImg = LoginHeaderView()
+ let bgView = LoginBgView()
+ let titleLabel = UILabel()
+ let phoneView = CustomInputView()
+ let pwdView = PasswordView()
+ let loginBtn = CustomButton()
+ let smsBtn = CustomButton()
+ let othersView = DCOthersLoginView()
+ let agreeView = AgreeView()
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ }
+ override func setupViews(){
+ // self.navBar.title = ""
+ navBar.isHidden = true
+ view.backgroundColor = .color(.bgColor)
+
+ titleLabel.do { v in
+ v.text = "用户登录".l10n
+ v.font = .medium(18)
+ v.textColor = .color(.first)
+ }
+ phoneView.do { v in
+ // v.textField.text = "13480939445"
+ v.textField.attributedPlaceholder = NSAttributedString(string: "请输入手机号码/邮箱".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
+ v.textField.keyboardType = .emailAddress
+ }
+ pwdView.do { v in
+ v.textField.attributedPlaceholder = NSAttributedString(string: "请输入密码".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
+
+ }
+
+ loginBtn.set(title: "登录".l10n,style: .theme1, target: self, action: #selector(loginAction))
+ smsBtn.set(title: "验证码登录".l10n, style: .theme2,target: self, action: #selector(smsAction))
+ view.addSubviews([logoImg,bgView])
+ bgView.addSubviews([titleLabel,phoneView,pwdView,loginBtn,smsBtn,agreeView,othersView])
+
+ }
+ override func setupLayout(){
+ logoImg.snp.makeConstraints { make in
+ if CCDevice.isJoy{
+ make.left.equalToSuperview().inset(28)
+ make.top.equalTo(kNavBtm + 20)
+ make.centerX.equalToSuperview()
+ }
+ else{
+ make.width.equalTo(62)
+ make.height.equalTo(80)
+ make.top.equalTo(kNavBtm + 20)
+ make.centerX.equalToSuperview()
+ }
+ }
+ bgView.snp.makeConstraints { make in
+ make.left.right.equalToSuperview()
+ make.top.equalToSuperview().inset(244)
+ make.bottom.equalToSuperview()
+ }
+
+ titleLabel.snp.makeConstraints { make in
+ make.top.equalToSuperview().offset(34)
+ make.left.right.equalToSuperview().inset(36)
+ }
+ phoneView.snp.makeConstraints { make in
+ make.top.equalToSuperview().offset(82)
+ make.left.right.equalToSuperview().inset(36)
+ }
+ pwdView.snp.makeConstraints { make in
+ make.top.equalTo(phoneView.snp.bottom).offset(20)
+ make.left.right.equalToSuperview().inset(36)
+ }
+ loginBtn.snp.makeConstraints { make in
+ make.top.equalTo(pwdView.snp.bottom).offset(54)
+ make.left.right.equalToSuperview().inset(51)
+ make.height.equalTo(46)
+ }
+ smsBtn.snp.makeConstraints { make in
+ make.top.equalTo(loginBtn.snp.bottom).offset(20)
+ make.left.right.equalToSuperview().inset(51)
+ make.height.equalTo(46)
+ }
+ agreeView.snp.makeConstraints { make in
+ make.top.equalTo(pwdView.snp.bottom).offset(10)
+ make.centerX.equalToSuperview()
+ make.height.equalTo(30)
+ }
+ othersView.snp.makeConstraints { make in
+ make.centerX.equalToSuperview()
+ make.height.equalTo(180)
+ make.left.right.equalToSuperview()
+ make.bottom.equalToSuperview().inset(40)
+ }
+ }
+
+}
+
+extension DcLoginVC{
+ @objc func smsAction(){
+ App.shared.goToPage(SmsLoginVC())
+ }
+ @objc func loginAction(){
+ self.view.endEditing(true)
+ if !agreeView.isAgree {
+ YLprogressHUD.showAutoHiden("请阅读用户协议以及隐私政策并点击同意".l10n)
+ return
+ }
+ guard let phone = phoneView.textField.value else{
+ YLprogressHUD.showAutoHiden("请输入正确的手机号码".l10n)
+ return
+ }
+ guard let pwd = pwdView.textField.value else{
+ YLprogressHUD.showAutoHiden("请输入密码".l10n)
+ return
+ }
+ YLprogressHUD.showLoading()
+
+
+ let plainText = pwd
+ let key = Date().format(.full4)
+ let iv = AESEncryption.generateRandomString()
+
+ Logger.debug("pwd: \(pwd)")
+ Logger.debug("iv: \(iv)")
+ Logger.debug("key: \(key)")
+
+ guard let encryptedText = AESEncryption.encrypt(plainText, key: key, iv: iv) else {
+ return
+ }
+ Logger.debug("Encrypted: \(encryptedText)")
+ // if let decryptedText = AESEncryption.decrypt(encryptedText, key: key, iv: iv) {
+ // Logger.debug("Decrypted: \(decryptedText)")
+ // }
+
+ var params:[String:Any] = [:]
+ params["account"] = phone
+ params["password"] = encryptedText
+ params["nonce"] = iv
+
+ params["deviceName"] = Device.current.name
+ params["deviceCode"] = CacheManager.uuid()
+
+ LoginVM.login(param: params) { result in
+ if result.isSuccess{
+ YLprogressHUD.showSuccess {
+ App.shared.willLogin()
+ }
+ }
+ else{
+ YLprogressHUD.showAutoHiden(result.msg)
+ }
+ }
+ }
+}
+
+
+extension DcLoginVC{
+ class DCOthersLoginView: BaseView {
+ let toolView = UIView()
+ let registerLabel = UILabel()
+ let pwdLabel = UILabel()
+ let line1 = UIView()
+ let thirdView = ThirdLoginView()
+
+ override func setupViews() {
+ // backgroundColor = .red
+ addSubviews([toolView,thirdView])
+ toolView.addSubviews([registerLabel,pwdLabel,line1])
+ line1.backgroundColor = .color(.secondary)
+
+ registerLabel.do { v in
+ v.text = "注册".l10n
+ v.textColor = .color(.secondary)
+ v.font = .regular(12)
+ v.textAlignment = .center
+ v.yc.addTap(target: self, action: #selector(registerAction))
+ }
+ pwdLabel.do { v in
+
+ v.text = "忘记密码".l10n
+ v.textColor = .color(.secondary)
+ v.font = .regular(12)
+ v.textAlignment = .center
+ v.yc.addTap(target: self, action: #selector(forgetAction))
+ }
+ }
+ override func setupLayout() {
+ toolView.snp.makeConstraints { make in
+ make.width.equalToSuperview()
+ make.top.left.equalToSuperview()
+ make.height.equalTo(50)
+ }
+ line1.snp.makeConstraints { make in
+ make.height.equalTo(12)
+ make.width.equalTo(1)
+ make.centerX.equalToSuperview()
+ make.centerY.equalToSuperview()
+ }
+ registerLabel.snp.makeConstraints { make in
+ make.height.equalToSuperview()
+ make.centerY.equalToSuperview()
+ make.right.equalTo(line1.snp.left).offset(-15)
+ }
+ pwdLabel.snp.makeConstraints { make in
+ make.height.equalToSuperview()
+ make.centerY.equalToSuperview()
+ make.left.equalTo(line1.snp.right).offset(15)
+ }
+
+ thirdView.snp.makeConstraints { make in
+ make.bottom.equalToSuperview().inset(0)
+ make.height.equalTo(80)
+ make.centerX.equalToSuperview()
+ }
+ }
+ @objc func forgetAction(){
+ App.shared.goToPage(ForgetVC(type: .forget))
+ }
+
+ @objc func registerAction(){
+ App.shared.goToPage(RegisterVC())
+ }
+ }
+}
phoneView.textField.keyboardType = .phonePad
}
else{
- phoneView.textField.attributedPlaceholder = NSAttributedString(string: "请输入邮箱".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
+ phoneView.textField.attributedPlaceholder = NSAttributedString(string: "请输入邮箱地址".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
phoneView.textField.keyboardType = .emailAddress
}
}
v.textColor = .color(.first)
}
phoneView.do { v in
- v.textField.attributedPlaceholder = NSAttributedString(string: "请输入邮箱".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
+ v.textField.attributedPlaceholder = NSAttributedString(string: "请输入邮箱地址".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
v.textField.keyboardType = .emailAddress
}
updateLayout()
phoneView.showLeftView = model.isChinese
}
- v.region = CountryModel.chinese()
}
phoneView.do { v in
// v.textField.text = "13480939445"
phoneView.textField.keyboardType = .phonePad
}
else{
- phoneView.textField.attributedPlaceholder = NSAttributedString(string: "请输入邮箱".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
+ phoneView.textField.attributedPlaceholder = NSAttributedString(string: "请输入邮箱地址".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
phoneView.textField.keyboardType = .emailAddress
}
App.shared.goToPage(vc)
}
func loadData(){
+ if let model = CountryCache.shared.get().first {
+ self.region = model
+ }
-
LoginVM.fetchCountryList {[weak self] result in
guard let self = self else{return}
if result.isSuccess{
}
desLabel.do { v in
- v.text = "耳机在附近,可通过响铃进行查找".l10n
+ v.text = "眼镜在附近,可通过响铃进行查找".l10n
v.font = .regular(14)
v.textColor = .color(.secondary)
}
btn.do { v in
v.setTitle("眼镜响铃".l10n, for: .normal)
+ v.setTitle("查找中".l10n, for: .selected)
v.addTarget(self, action: #selector(btnAction), for: .touchUpInside)
v.layer.cornerRadius = 23
v.layer.masksToBounds = true
mode = .all
}
CCDevice.findHeadphone(mode)
+
+ if mode == .cancel {
+ radar.stop()
+ }
+ else{
+ radar.start()
+ }
}
}
var radarImageView = UIImageView()
override func setupViews() {
addSubviews([radarImageView])
-
radarImageView.do { v in
v.image = UIImage(named: "radar_icon")
- //
+ }
+ radarImageView.snp.makeConstraints { make in
+ make.size.equalTo(200)
+ make.center.equalToSuperview()
+ }
+ }
+ func start(){
let animation = CABasicAnimation.init(keyPath: "transform.rotation.z")
animation.beginTime = 0.0
animation.fromValue = 0.0
animation.toValue = 2*Double.pi
animation.duration = 2
animation.repeatCount = MAXFLOAT
- v.layer.add(animation, forKey: "radar.transform.rotation.x")
- }
- radarImageView.snp.makeConstraints { make in
- make.size.equalTo(200)
- make.center.equalToSuperview()
- }
+ radarImageView.layer.add(animation, forKey: "radar.transform.rotation.x")
+ }
+ func stop(){
+ radarImageView.layer.removeAllAnimations()
}
}
+++ /dev/null
-//
-// MusicVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/20.
-//
-
-
-import UIKit
-import JXSegmentedView
-
-class MusicRootView: BaseView{
- let content = SprotRocrodView()
-
- override func setupViews() {
- addSubviews([content])
- content.do { v in
- v.header.titleLabel.text = "音乐".l10n
- v.header.detailLabel.isHidden = true
- v.header.icon.isHidden = true
- v.item1.titleLabel.text = "我的歌单".l10n
- v.item1.icon.image = UIImage(named: "sport_music_list")
- v.item2.titleLabel.text = "我的收藏".l10n
- v.item2.icon.image = UIImage(named: "sport_music_collection")
-// v.header.yc.addTap(target: self, action: #selector(historyAction))
- v.item1.yc.addTap(target: self, action: #selector(recordAction))
- v.item2.yc.addTap(target: self, action: #selector(callAction))
- }
- }
-
- override func setupLayout() {
- content.snp.makeConstraints { make in
- make.left.right.top.equalToSuperview().inset(18)
- make.height.equalTo(209)
- }
- }
-// @objc func historyAction(){
-// App.shared.goToPage(HistoryRecordVC())
-// }
- @objc func recordAction(){
- App.shared.goToPage(HistoryRecordVC())
- }
- @objc func callAction(){
- App.shared.goToPage(HistoryRecordVC())
- }
-}
-
-extension MusicRootView: JXSegmentedListContainerViewListDelegate {
- func listView() -> UIView {
- return self
- }
-}
-
+++ /dev/null
-//
-// Untitled.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/25.
-//
-class SprotRocrodView: BaseView {
- let header = RecordheadItem()
- let line = UIView()
- let item1 = SportRecordItem()
- let item2 = SportRecordItem()
-
- override func setupViews() {
- yc.setCornerRadius(12)
- backgroundColor = .color(.cellBg)
- addSubviews([header,line,item1,item2])
- line.backgroundColor = .color(.separateLine)
- }
-
- override func setupLayout() {
- header.snp.makeConstraints { make in
- make.left.right.top.equalToSuperview()
- make.height.equalTo(51)
- }
- item1.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(15)
- make.height.equalTo(60)
- make.top.equalToSuperview().offset(61)
- }
- item2.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(15)
- make.height.equalTo(60)
- make.top.equalTo(item1.snp.bottom).offset(14)
- }
- line.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(14)
- make.height.equalTo(1)
- make.top.equalToSuperview().inset(47)
- }
- }
-}
-class SportRecordItem: BaseView {
- let icon = UIImageView()
- let titleLabel = UILabel()
-
- override func setupViews() {
- yc.setCornerRadius(12)
- backgroundColor = .color(.bgColor)
- addSubviews([icon,titleLabel])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(14)
- v.text = "".l10n
- }
- icon.do { v in
- v.image = UIImage(named: "arrow_2")
- }
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(60)
- }
- icon.snp.makeConstraints { make in
- make.size.equalTo(32)
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(14)
- }
- }
-}
-
-class RecordheadItem: BaseView {
- let icon = UIImageView()
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- override func setupViews() {
- yc.setCornerRadius(12)
- addSubviews([icon,titleLabel,detailLabel])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(14)
- v.text = "".l10n
- }
- detailLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(12)
- v.text = "历史记录".l10n
- }
- icon.do { v in
- v.image = UIImage(named: "arrow_2")
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(14)
- }
- detailLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(27)
- }
- icon.snp.makeConstraints { make in
- make.width.equalTo(7)
- make.height.equalTo(13)
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(12)
- }
- }
-}
+++ /dev/null
-//
-// RecordView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/20.
-//
-
-import UIKit
-import JXSegmentedView
-
-class RecordRootView: BaseView{
- let content = SprotRocrodView()
-
- override func setupViews() {
- addSubviews([content])
- content.do { v in
- v.header.titleLabel.text = "录音".l10n
- v.item1.titleLabel.text = "现场录音".l10n
- v.item1.icon.image = UIImage(named: "sport_record")
- v.item2.titleLabel.text = "通话录音".l10n
- v.item2.icon.image = UIImage(named: "sport_call")
- v.header.yc.addTap(target: self, action: #selector(historyAction))
- v.item1.yc.addTap(target: self, action: #selector(recordAction))
- v.item2.yc.addTap(target: self, action: #selector(callAction))
- }
- }
-
- override func setupLayout() {
- content.snp.makeConstraints { make in
- make.left.right.top.equalToSuperview().inset(18)
- make.height.equalTo(209)
- }
- }
- @objc func historyAction(){
- App.shared.goToPage(HistoryRecordVC())
- }
- @objc func recordAction(){
- CCPage.gotoFieldRecord()
- }
- @objc func callAction(){
- CCPage.gotoCallRecord()
- }
-}
-
-extension RecordRootView: JXSegmentedListContainerViewListDelegate {
- func listView() -> UIView {
- return self
- }
-}
-
+++ /dev/null
-//
-// AddGroupHeader.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
-class AddGroupHeader: BaseView {
- let icon = UIImageView()
- let titleLabel = UILabel()
-
- override func setupViews() {
- addSubviews([icon,titleLabel])
-
- titleLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(10)
- v.text = "设置团队头像".l10n
- }
-
- icon.do { v in
- v.image = UIImage(named: "group_avatar")
- yc.setCornerRadius(12)
-
- }
- }
-
- override func setupLayout() {
- icon.snp.makeConstraints { make in
- make.size.equalTo(90)
- make.centerX.equalToSuperview()
- make.top.equalToSuperview()
- }
- titleLabel.snp.makeConstraints { make in
- make.centerX.equalToSuperview()
- make.top.equalTo(icon.snp.bottom).offset(6)
- }
-
- }
-}
+++ /dev/null
-//
-// CreateGroupVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/5.
-//
-
-import UIKit
-
-class CreateGroupVC: BaseVC{
- let headerView = AddGroupHeader()
- let nameView = SportInputItem()
- let typeView = SportSelectItem()
- let desView = SportInputItem()
- let lightView = SportSelectItem()
- let verifyView = SportSwitchItem()
- let okBtn = CustomButton()
- var sportType:SportType = .walk
-
- override func setupViews() {
- navBar.do { v in
- v.title = "创建团队".l10n
- v.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
- v.rightView.isHidden = false
- }
- view.addSubviews([headerView,nameView,typeView,desView,lightView,verifyView,okBtn])
- nameView.do { v in
- v.yc.setCornerRadius(12)
- v.titleLabel.text = "团队名称".l10n
- v.textField.text = "111"
- v.textField.attributedPlaceholder = NSAttributedString(string: "给团队起个名字".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
-
- }
- typeView.do { v in
- v.yc.setCornerRadius(12)
- v.titleLabel.text = "团队类型".l10n
- v.detailLabel.text = sportType.name
- v.yc.addTap(target: self, action: #selector(typeAction))
- }
- desView.do { v in
- v.yc.setCornerRadius(12)
- v.titleLabel.text = "简介".l10n
- v.textField.attributedPlaceholder = NSAttributedString(string: "描述一下您的团".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
- }
- lightView.do { v in
- v.yc.setCornerRadius(12)
- v.titleLabel.text = "灯带设置".l10n
- v.yc.addTap(target: self, action: #selector(lightAction))
-
- }
- verifyView.do { v in
- v.yc.setCornerRadius(12)
- v.titleLabel.text = "加入验证".l10n
- v.detailLabel.text = "开启后,成员需要申请才能加入".l10n
- }
- okBtn.set(title: "完成创建".l10n,style: .theme1, target: self, action: #selector(okAction))
- }
- override func setupLayout() {
- headerView.snp.makeConstraints { make in
- make.left.right.equalToSuperview()
- make.top.equalToSuperview().inset(kNavBtm + 20)
- make.height.equalTo(120)
- }
- nameView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(headerView.snp.bottom).offset(10)
- make.height.equalTo(51)
- }
- typeView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(nameView.snp.bottom).offset(10)
- make.height.equalTo(51)
- }
- desView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(typeView.snp.bottom).offset(10)
- make.height.equalTo(65)
- }
- lightView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(desView.snp.bottom).offset(10)
- make.height.equalTo(51)
- }
- verifyView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(lightView.snp.bottom).offset(10)
- make.height.equalTo(65)
- }
- okBtn.snp.makeConstraints { make in
- make.bottom.equalToSuperview().inset(80)
- make.left.right.equalToSuperview().inset(51)
- make.height.equalTo(46)
- }
- }
- override func navRightViewTapped() {
- let tip = GroupDesPopView()
- tip.show()
- }
- @objc func typeAction(){
- let vc = GroupTypeVC()
- vc.didSelected = {[weak self] value in
- self?.sportType = value
- self?.typeView.detailLabel.text = value.name
- }
- App.shared.goToPage(vc)
- }
- @objc func lightAction(){
- App.shared.goToPage(LightSetVC())
- }
- @objc func okAction(){
- if nameView.isEmpty {
- YLprogressHUD.showAutoHiden("团队名称不能为空".l10n)
- return
- }
-
- YLprogressHUD.showLoading()
- var params:[String:Any] = [:]
- // 团队名称,必须
- params["name"] = nameView.value
- // 头像
-// params["icon"] = ""
- // 运动类型:running | cycling | walking,必须
- params["type"] = sportType.rawValue
- // 团队简介,非必须
-// params["introduction"] = ""
- // 1加入审核,0不需要审核,非必须,默认0
- params["joinReview"] = verifyView.iSwitch.isOn ? "1":"0"
- let api = CommomApi.createSportGroup(param: params)
- HttpClient.request(api){ (model:CommonDataModel, res) in
-
- if model.isSuccess{
- YLprogressHUD.showSuccess {
- App.shared.popPage(animated: false)
- let vc = GroupDetailVC(groupId:model.data )
- App.shared.goToPage(vc)
- }
- }
- else{
- YLprogressHUD.showAutoHiden("请求失败".l10n)
- }
- }
- }
-}
-
+++ /dev/null
-//
-// SportInputItem.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
-class SportInputItem: BaseView,UITextFieldDelegate {
- let valueLabel = UILabel()
- let textField = UITextField()
- let titleLabel = UILabel()
- var maxLength = 10
-
- var isEmpty:Bool{
- if let text = textField.text,text.isNotEmpty {
- return false
- }
- return true
- }
- var value:String{
- return textField.text ?? ""
- }
-
- override func setupViews() {
- yc.setCornerRadius(12)
- addSubviews([valueLabel,titleLabel,textField])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(14)
- }
- textField.do { v in
- v.textColor = .color(.first)
- v.keyboardType = .default
- v.returnKeyType = .done
- v.textAlignment = .left
- v.addTarget(self, action: #selector(textFieldValueChange), for: .valueChanged)
-// v.backgroundColor = .red
- v.delegate = self
- }
- valueLabel.do { v in
- v.textColor = .color(.placeholder)
- v.font = .regular(10)
- v.textAlignment = .right
- v.text = "0/\(maxLength)"
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(14)
- }
- textField.snp.makeConstraints { make in
- make.left.equalTo(titleLabel.snp.right).offset(10).priority(.high)
- make.centerY.height.equalToSuperview()
- make.right.equalToSuperview().inset(50).priority(.low)
- }
- valueLabel.snp.makeConstraints { make in
- make.width.equalTo(38)
- make.height.equalToSuperview()
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(12)
- }
- }
- @objc func textFieldValueChange(){
- valueLabel.text = "\(textField.text?.count ?? 0)/\(maxLength)"
- }
- func textFieldShouldReturn(_ textField: UITextField) -> Bool {
- textField.resignFirstResponder()
- return false
- }
-}
-
-class SportTextViewItem: BaseView,UITextViewDelegate {
- let valueLabel = UILabel()
- let textView = UITextView()
- let titleLabel = UILabel()
- var maxLength = 10
-
- override func setupViews() {
- yc.setCornerRadius(12)
- addSubviews([valueLabel,titleLabel,textView])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(14)
- v.text = "简介".l10n
- }
- textView.do { v in
- v.textColor = .color(.first)
- v.keyboardType = .default
- v.returnKeyType = .done
- v.textAlignment = .left
- v.delegate = self
- }
- valueLabel.do { v in
- v.textColor = .color(.placeholder)
- v.font = .regular(10)
- v.textAlignment = .right
- v.text = "0/\(maxLength)"
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(14)
- }
- textView.snp.makeConstraints { make in
- make.left.equalTo(titleLabel.snp.right).offset(10).priority(.high)
- make.centerY.height.equalToSuperview()
- make.right.equalToSuperview().inset(50).priority(.low)
- }
- valueLabel.snp.makeConstraints { make in
- make.width.equalTo(38)
- make.height.equalToSuperview()
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(12)
- }
- }
-
- func textViewDidChange(_ textView: UITextView) {
- valueLabel.text = "\(textView.text?.count ?? 0)/\(maxLength)"
- }
-
- func textView(_ textView: UITextView, shouldChangeTextInRanges ranges: [NSValue], replacementText text: String) -> Bool {
- textView.resignFirstResponder()
-
- return false
- }
-}
+++ /dev/null
-//
-// SportItem.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
-class SportSelectItem: BaseView {
- let icon = UIImageView()
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- override func setupViews() {
- yc.setCornerRadius(12)
- addSubviews([icon,titleLabel,detailLabel])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(14)
- }
- detailLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(12)
- }
- icon.do { v in
- v.image = UIImage(named: "arrow_2")
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(14)
- }
- detailLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(27)
- }
- icon.snp.makeConstraints { make in
- make.width.equalTo(7)
- make.height.equalTo(13)
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(12)
- }
- }
-}
+++ /dev/null
-//
-// SportSwitchItem.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
-class SportSwitchItem: BaseTableViewCell {
- let titleLabel = UILabel()
- let detailLabel = UILabel()
- let iSwitch = UISwitch()
-
-
- override func setupViews() {
- addSubviews([titleLabel,detailLabel,iSwitch])
-
- backgroundColor = .color(.cellBg)
- titleLabel.do { (v) in
- v.textColor = .color(.first)
- v.font = .bold(14)
- v.textAlignment = .left
- }
- detailLabel.do { (v) in
- v.textColor = .color(.secondary)
- v.font = .regular(10)
- v.textAlignment = .left
- }
- iSwitch.do { v in
- v.addTarget(self, action: #selector(swicthAction), for: .valueChanged)
- }
- }
-
- override func setupLayout() {
- titleLabel.snp.makeConstraints { (m) in
- m.top.equalToSuperview().inset(16)
- m.left.equalToSuperview().offset(16)
- }
- detailLabel.snp.makeConstraints { (m) in
- m.bottom.equalToSuperview().inset(16)
- m.left.equalToSuperview().offset(16)
- }
- iSwitch.snp.makeConstraints { (m) in
- m.right.equalToSuperview().inset(15)
- m.centerY.equalToSuperview()
- }
- }
-
-
- @objc func swicthAction(){
- }
-}
+++ /dev/null
-//
-// GroupDetailVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/25.
-//
-
-import UIKit
-
-class GroupDetailVC: BaseVC{
- var groupId = ""
-
-
- init(groupId:String) {
- self.groupId = groupId
- super.init()
- }
-
- override func setupViews() {
- navBar.do { v in
- v.title = "团队详情".l10n
- }
-
- }
- override func setupLayout() {
-
- }
-
-}
+++ /dev/null
-//
-// GroupMemberCell.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/12.
-//
-
-class GroupMemberCell: BaseTableViewCell {
- let bgView = UIView()
- let icon = UIImageView()
- let nameLabel = UILabel()
- let roleType = UIImageView()
- let roleLabel = UILabel()
- let moreIcon = UIImageView()
- let line = UIView()
- var model:GroupMemberModel!{
- didSet{
- icon.kf.setImage(with: model.avatar.yc.asUrl)
- nameLabel.text = model.userName
- roleLabel.text = model.role.name
- roleType.backgroundColor = model.role.color
-// moreIcon.isHidden = model.userId != CacheManager.shared.user.info.userId
- }
- }
-
-
- override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
- super.init(style: style, reuseIdentifier: reuseIdentifier)
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- override func setupViews() {
- contentView.addSubview(bgView)
- bgView.addSubviews([icon,nameLabel,roleLabel,roleType,moreIcon,line])
-
- backgroundColor = .color(.bgColor)
- contentView.backgroundColor = .clear
- selectionStyle = .none
- bgView.do { v in
- v.backgroundColor = .color(.cellBg)
-// v.yc.setCornerRadius(18)
- }
- nameLabel.do { (v) in
- v.textColor = .color(.first)
- v.font = .medium(12)
- v.textAlignment = .left
- v.lineBreakMode = .byTruncatingTail
- }
- roleLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(10)
- v.textAlignment = .left
- v.lineBreakMode = .byTruncatingTail
- }
- roleType.do { v in
- v.yc.setCornerRadius(3)
- }
- icon.do { v in
- v.yc.setCornerRadius(18)
- }
- moreIcon.do { v in
- v.image = UIImage(named: "more")
- v.contentMode = .center
- v.yc.addTap(target: self, action: #selector(moreAction))
- }
- line.do { v in
- v.backgroundColor = .color(.separateLine)
- }
- }
-
- override func setupLayout() {
- bgView.snp.makeConstraints { (m) in
- m.left.right.equalToSuperview().inset(18)
- m.top.equalToSuperview()
- m.bottom.equalToSuperview()
- }
-
- icon.snp.makeConstraints { (m) in
- m.size.equalTo(36)
- m.left.equalToSuperview().inset(15)
- m.top.equalToSuperview().inset(15)
- }
- nameLabel.snp.makeConstraints { (m) in
- m.top.equalToSuperview().inset(16)
- m.left.equalToSuperview().offset(60)
- m.right.lessThanOrEqualToSuperview().inset(16)
- }
- roleType.snp.makeConstraints { make in
- make.left.equalTo(nameLabel)
- make.bottom.equalToSuperview().inset(16)
- make.width.equalTo(6)
- make.height.equalTo(10)
- }
- roleLabel.snp.makeConstraints { (m) in
- m.bottom.equalToSuperview().inset(16)
- m.left.equalToSuperview().offset(77)
- m.right.lessThanOrEqualToSuperview().inset(16)
- }
- moreIcon.snp.makeConstraints { make in
- make.right.equalToSuperview()
- make.centerY.equalToSuperview()
- make.width.equalTo(18+18+5)
- make.height.equalToSuperview()
- }
- line.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.bottom.equalToSuperview()
- make.height.equalTo(0.4)
- }
- }
-
- @objc func moreAction(){
- let vc = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
- let action0 = UIAlertAction(title: "团长转让".l10n, style: .default) {[weak self] action in
- self?.transferGroup()
- }
- let action1 = UIAlertAction(title: "移除团队".l10n, style: .default) {[weak self] action in
- self?.removeFromGroup()
- }
- let action2 = UIAlertAction(title: "取消".l10n, style: .cancel) { action in
-
- }
- vc.addAction(action0)
- vc.addAction(action1)
- vc.addAction(action2)
- App.shared.topVC().present(vc, animated: true)
- }
- @objc func removeFromGroup(){
- let vc = UIAlertController(title: "提示".l10n, message: "确认要把TA移出团队吗?".l10n, preferredStyle: .alert)
- let action0 = UIAlertAction(title: "确定".l10n, style: .destructive) {[weak self] action in
- self?.removeFromGroup2()
- }
- let action1 = UIAlertAction(title: "取消".l10n, style: .cancel) {[weak self] action in
- }
-
- vc.addAction(action0)
- vc.addAction(action1)
- App.shared.topVC().present(vc, animated: true)
- }
- @objc func removeFromGroup2(){
-
- }
-
- @objc func transferGroup(){
- let vc = UIAlertController(title: "提示".l10n, message: "确认要把团长转让给TA吗?".l10n, preferredStyle: .alert)
- let action0 = UIAlertAction(title: "确定".l10n, style: .destructive) {[weak self] action in
- self?.transferGroup2()
- }
- let action1 = UIAlertAction(title: "取消".l10n, style: .cancel) {[weak self] action in
- }
-
- vc.addAction(action0)
- vc.addAction(action1)
- App.shared.topVC().present(vc, animated: true)
- }
- @objc func transferGroup2(){
-
- }
-}
+++ /dev/null
-//
-// GroupMemberModel.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/12.
-//
-
-import HandyJSON
-
-class GroupMemberModelRoot:ResponseBaseModel {
- var data = [GroupMemberModel]()
-}
-
-class GroupMemberModel:HandyJSON {
- var userId = ""/// 用户ID
- var userName = "" /// 用户名
- var role:GroupRoleType = .bjy /// 角色名
- var avatar = "" /// 头像
-
- required public init() { }
-}
+++ /dev/null
-//
-// GroupMemberVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/12.
-//
-
-import UIKit
-
-class GroupMemberVC: BaseVC{
- let tableView = UITableView(frame: .zero, style: .plain)
- var list:[GroupMemberModel] = []
- var currentType = GroupRoleType.none
- let btn = CustomButton()
- var groupId = ""
-
-
- init(groupId:String) {
- self.groupId = groupId
- super.init()
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- // Do any additional setup after loading the view.
- }
- override func setupViews() {
- navBar.do { v in
- v.title = "成员管理".l10n
-// v.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
-// v.rightView.isHidden = false
- }
-
- tableView.do { v in
- v.backgroundColor = .clear
- v.delegate = self
- v.dataSource = self
- v.rowHeight = 68
- v.separatorStyle = .none
- v.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0)
- v.register(GroupMemberCell.self, forCellReuseIdentifier: GroupMemberCell.reuseID)
-
- let header = UIView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 40))
- let label = UILabel(frame: CGRect(x: 18, y: 0, width: kScreenWid - 36, height: 40))
- label.do { v in
- v.text = "成员列表".l10n
- v.font = .regular(14)
- v.textColor = .color(.secondary)
- }
- header.addSubview(label)
- v.tableHeaderView = header
- }
- view.addSubviews([tableView,btn])
-
- btn.set(title: "邀请".l10n, target: self, action: #selector(btnAction))
- }
- override func setupLayout() {
- tableView.snp.makeConstraints { make in
- make.left.right.bottom.equalToSuperview()
- make.top.equalTo(kNavBtm)
- }
- btn.snp.makeConstraints { make in
- make.width.equalTo(272)
- make.height.equalTo(46)
- make.centerX.equalToSuperview()
- make.bottom.equalToSuperview().inset(82)
- }
- }
- override func setupData() {
- let api = CommomApi.getGroupMembers(groupId: self.groupId)
- HttpClient.request(api) {[weak self] (model:GroupMemberModelRoot,res) in
- guard let self = self else {return}
- if model.isSuccess{
- list = model.data
- }
- tableView.reloadData()
- tableView.mj_header?.endRefreshing()
- }
- }
- @objc func btnAction(){
-
- }
- override func navRightViewTapped() {
-
- }
-}
-
-extension GroupMemberVC:UITableViewDelegate,UITableViewDataSource {
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return list.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = GroupMemberCell.cell(withTableView: tableView, indexPath: indexPath)
- cell.model = list[indexPath.row]
- let rect = CGRect(x: 0, y: 0, width: kScreenWid - 36, height: 68)
- if indexPath.row == 0 {
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 8, height: 8))
- }
- else if indexPath.row == list.count - 1{
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: 8, height: 8))
- }
- else{
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
- }
- if list.count == 1 {
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 8, height: 8))
- }
- return cell
- }
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-
- }
-}
+++ /dev/null
-//
-// MyGroupCell.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
- class MyGroupCell: BaseTableViewCell {
- let bgView = UIView()
- let icon = UIImageView()
- let nameLabel = UILabel()
- let contentLabel = UILabel()
-
- var model:MyGroupModel!{
- didSet{
- if model.icon.isEmpty{
- icon.image = UIImage(named: "group_avatar")
- }
- else{
- icon.kf.setImage(with: model.icon.yc.asUrl)
- }
- nameLabel.text = model.name
- contentLabel.text = model.type.name + ".\(model.userCount)" + "人已加入".l10n
- }
- }
-
-
- override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
- super.init(style: style, reuseIdentifier: reuseIdentifier)
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- override func setupViews() {
- contentView.addSubview(bgView)
- bgView.addSubviews([icon,nameLabel,contentLabel])
-
- backgroundColor = .color(.bgColor)
- contentView.backgroundColor = .clear
- selectionStyle = .none
- bgView.do { v in
- v.backgroundColor = .color(.cellBg)
- v.yc.setCornerRadius(8)
- }
- nameLabel.do { (v) in
- v.textColor = .color(.first)
- v.font = .medium(14)
- v.textAlignment = .left
- v.lineBreakMode = .byTruncatingTail
- }
- contentLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(11)
- v.textAlignment = .left
- v.lineBreakMode = .byTruncatingTail
- }
-
- icon.do { v in
- v.yc.setCornerRadius(8)
- }
- }
-
- override func setupLayout() {
- bgView.snp.makeConstraints { (m) in
- m.left.right.equalToSuperview().inset(18)
- m.top.equalToSuperview().inset(6)
- m.bottom.equalToSuperview()
- }
-
- icon.snp.makeConstraints { (m) in
- m.size.equalTo(36)
- m.left.equalToSuperview().inset(15)
- m.top.equalToSuperview().inset(15)
- }
- nameLabel.snp.makeConstraints { (m) in
- m.top.equalToSuperview().inset(16)
- m.left.equalToSuperview().offset(60)
- m.right.lessThanOrEqualToSuperview().inset(16)
- }
- contentLabel.snp.makeConstraints { (m) in
- m.bottom.equalToSuperview().inset(16)
- m.left.equalToSuperview().offset(60)
- m.right.lessThanOrEqualToSuperview().inset(16)
- }
-
- }
-
-
-}
+++ /dev/null
-//
-// Untitled.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
-import HandyJSON
-
-class MyGroupModelRoot:ResponseBaseModel {
- var data = [MyGroupModel]()
-}
-
-class MyGroupModel:HandyJSON {
- var id = "" // 团队ID
- var userId = ""// 用户ID,创建者的ID
- var creatorNickname = "" // 创建者昵称
- var creatorAvatar = "" // https://example.com/avatar.jpg", // 创建者头像
- var icon = "" // https://example.com/icon.jpg", // 图标
- var state = "" // 状态:1正常,0解散
- var name = "" // 团队名称
- var type:SportType = SportType.walk // 运动类型:running | cycling | walking
- var introduction = "" // 团队简介
- var joinReview = ""// 1加入审核,0不需要审核
- var userCount = 0 //加入人数
- var totalDistance = "" // 总距离,单位米
- var totalTime = "" // 总运动时长,单位秒
- var createTime = "" // 创建时间
- var updateTime = ""// 更新时间
- required public init() { }
-}
+++ /dev/null
-//
-// MyGroupVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
-import JXSegmentedView
-
-
-enum MyGroupType{
- case create
- case add
-
- var name:String{
- switch self {
- case .create:
- return "我管理的"
- case .add:
- return "我加入的"
- }
- }
- var value:String{
- switch self {
- case .create:
- return "1"
- case .add:
- return "0"
- }
- }
- static var all:[MyGroupType] = [.create,.add]
-}
-
-class MyGroupVC: BaseVC {
- private let segmentedDataSource = JXSegmentedTitleDataSource()
- private let segmentedView = JXSegmentedView()
- private lazy var listContainerView: JXSegmentedListContainerView! = {
- let view = JXSegmentedListContainerView(dataSource: self, type: .scrollView)
- return view
- }()
-
- var list:[MyGroupType] = MyGroupType.all
- override func viewDidLoad() {
- super.viewDidLoad()
-
- // AudioPlayView.shared.show()
- self.view.addSubview(AudioPlayView.shared)
- MapManager.shared.setupSdk()
- }
-
- 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()
- }
- }
- override func setupViews(){
- navBar.do { v in
- v.title = "我的团队"
- }
- view.addSubview(segmentedView)
- view.addSubview(listContainerView)
-
- 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(.theme)
- segmentedView.indicators = [indicator]
-
- v.dataSource = segmentedDataSource
- v.listContainer = listContainerView
- }
- }
-}
-
-extension MyGroupVC: JXSegmentedListContainerViewListDelegate {
- func listView() -> UIView {
- return view
- }
-}
-
-extension MyGroupVC: 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]
- return MyGroupView(selectType: type)
-
- }
-}
+++ /dev/null
-//
-// GroupListView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
-import UIKit
-import JXSegmentedView
-import MJRefresh
-
-
-class MyGroupView: BaseView,UITableViewDelegate,UITableViewDataSource {
- let tableView = UITableView(frame: .zero, style: .plain)
- var list = [MyGroupModel]()
- var type = MyGroupType.add
-
- init(selectType type:MyGroupType){
- super.init(frame: .zero)
- self.type = type
- tableView.mj_header?.beginRefreshing()
- }
-
- override func setupViews() {
- addSubview(tableView)
- tableView.do { v in
- v.backgroundColor = .color(.bgColor)
- v.delegate = self
- v.dataSource = self
- v.rowHeight = 74
- v.separatorStyle = .none
- v.register(MyGroupCell.self, forCellReuseIdentifier: MyGroupCell.reuseID)
- v.mj_header = MJRefreshNormalHeader(refreshingTarget: self, refreshingAction: #selector(refreshAction))
- }
- }
-
- override func setupLayout() {
- tableView.snp.makeConstraints { (m) in
- m.top.equalToSuperview().inset(10)
- m.left.right.bottom.equalToSuperview()
- }
- }
-
- @objc func refreshAction(){
- var params:[String:Any] = [:]
- params["type"] = type.value
-
- let api = CommomApi.getSportGroupList(param: params)
- HttpClient.request(api) {[weak self] (model:MyGroupModelRoot,res) in
- guard let self = self else {return}
- if model.isSuccess{
- list = model.data
- }
- tableView.reloadData()
- tableView.mj_header?.endRefreshing()
- }
-
- }
-
-
- @MainActor required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return list.count
- }
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = MyGroupCell.cell(withTableView: tableView, indexPath: indexPath)
- cell.model = list[indexPath.row]
- return cell
- }
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- let vc = GroupDetailVC(groupId: list[indexPath.row].id)
- App.shared.goToPage(vc)
- }
-
-}
-
-extension MyGroupView: JXSegmentedListContainerViewListDelegate {
- func listView() -> UIView {
- return self
- }
-}
+++ /dev/null
-import UIKit
-import HandyJSON
-
-enum GroupRoleType:String,HandyJSONEnum{
- case none = "none"
- case pfs = "pfs"
- case lpz = "lpz"
- case gpz = "gpz"
- case ccs = "ccs"
- case psy = "psy"
- case bjy = "bjy"
- case qns = "qns"
- case lqz = "lqz"
- case gqz = "gqz"
- case pps = "pps"
-
-
- var name:String{
- switch self {
- case .none:
- return "无"
- case .pfs:
- return "破风手"
- case .lpz:
- return "领跑者"
- case .gpz:
- return "跟跑者"
- case .ccs:
- return "冲刺手"
- case .psy:
- return "配速员"
- case .bjy:
- return "补给员"
- case .qns:
- return "全能手"
- case .lqz:
- return "领骑者"
- case .gqz:
- return "跟骑者"
- case .pps:
- return "爬坡手"
- }
- }
- var color:UIColor{
- switch self {
- case .none:
- return .rgb(0xD9D9D9)
- case .pfs:
- return .rgb(0xFF9232)
- case .lpz:
- return .rgb(0x7C2CED)
- case .gpz:
- return .rgb(0x21B7F8)
- case .ccs:
- return .rgb(0xFF583B)
- case .psy:
- return .rgb(0x4252FF)
- case .bjy:
- return .rgb(0x13D598)
- case .qns:
- return .rgb(0xF1BF18)
- case .lqz:
- return .rgb(0x7C2CED)
- case .gqz:
- return .rgb(0xF1BF18)
- case .pps:
- return .rgb(0xF1BF18)
- }
- }
-
- static var all:[GroupRoleType] = [.none,.pfs,.lpz,.gpz,.ccs,.psy,.bjy,.qns]
-}
-
-class GroupRoleVC: BaseVC{
- let tableView = UITableView(frame: .zero, style: .plain)
- var list:[GroupRoleType] = GroupRoleType.all
- var currentType = GroupRoleType.none
- let btn = CustomButton()
- var didSelected:((GroupRoleType)->Void)?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- // Do any additional setup after loading the view.
- }
- override func setupViews() {
- navBar.do { v in
- v.title = "我的团队角色".l10n
- v.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
- v.rightView.isHidden = false
- }
-
- tableView.do { v in
- v.backgroundColor = .color(.bgColor)
- v.delegate = self
- v.dataSource = self
- v.rowHeight = 52
- v.separatorStyle = .none
- v.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0)
- v.register(RoleCell.self, forCellReuseIdentifier: RoleCell.reuseID)
-
- let header = UIView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 40))
- let label = UILabel(frame: CGRect(x: 18, y: 0, width: kScreenWid - 36, height: 40))
- label.do { v in
- v.text = "我的团队-团队设置-骑行团队角色".l10n
- v.font = .regular(14)
- v.textColor = .color(.secondary)
- }
- header.addSubview(label)
- v.tableHeaderView = header
- }
- view.addSubviews([tableView,btn])
-
- btn.set(title: "确定".l10n, target: self, action: #selector(btnAction))
- }
- override func setupLayout() {
- tableView.snp.makeConstraints { make in
- make.left.right.bottom.equalToSuperview()
- make.top.equalTo(kNavBtm)
- }
- btn.snp.makeConstraints { make in
- make.width.equalTo(272)
- make.height.equalTo(46)
- make.centerX.equalToSuperview()
- make.bottom.equalToSuperview().inset(82)
- }
- }
- @objc func btnAction(){
- didSelected?(currentType)
- self.navigationController?.popViewController(animated: true)
- }
- override func navRightViewTapped() {
- let tip = GroupDesPopView()
- tip.titleLabel.text = "团队角色说明".l10n
- tip.titleLabel1.text = "团队角色是什么?".l10n
- tip.desLabel2.text = "团队运动中各角色是分工明确、协同发力的核心单元,通过精准配合最大化团队运动效果;".l10n
- tip.titleLabel2.text = "团队角色说明".l10n
- tip.desLabel2.text = "破风手:以 “挡风减阻” 为核心,为后方队友节省体能;\n领骑者:把控整体节奏,稳定配速避免失衡;\n跟骑者:借助风阻优势储备体力,为关键阶段蓄力;\n冲刺手:聚焦终点前爆发,锁定最终成绩;\n配速员:作为 “节奏标杆”,助力队友校准目标; \n补给员:保障物资供应,维持运动续航; \n全能手:灵活补位,适配破风、带速等多元需求。".l10n
- tip.tipsIcon.image = UIImage(named: "role_des")
- tip.show()
- }
-}
-
-extension GroupRoleVC:UITableViewDelegate,UITableViewDataSource {
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return list.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = RoleCell.cell(withTableView: tableView, indexPath: indexPath)
- cell.titleLabel.text = list[indexPath.row].name
- cell.type.backgroundColor = list[indexPath.row].color
- let rect = CGRect(x: 0, y: 0, width: kScreenWid - 36, height: 52)
- if indexPath.row == 0 {
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 8, height: 8))
- }
- else if indexPath.row == list.count - 1{
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: 8, height: 8))
- }
- else{
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
- }
- cell.selectedIcon.isHidden = list[indexPath.row] != currentType
- return cell
- }
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- let data = list[indexPath.row]
- currentType = data
- tableView.reloadData()
- }
-}
-class RoleCell: BaseTableViewCell {
- let bgView = UIView()
- let type = UIView()
- let titleLabel = UILabel()
- let selectedIcon = UIImageView()
- let line = UIView()
-
-
- override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
- super.init(style: style, reuseIdentifier: reuseIdentifier)
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- override func setupViews() {
- contentView.addSubview(bgView)
- bgView.addSubviews([type,titleLabel,selectedIcon,line])
-
- backgroundColor = .color(.bgColor)
- contentView.backgroundColor = .clear
- selectionStyle = .none
- bgView.do { v in
- v.backgroundColor = .color(.cellBg)
- }
- type.do { v in
- v.yc.setCornerRadius(3)
- v.backgroundColor = .red
- }
- titleLabel.do { (v) in
- v.textColor = .color(.first)
- v.font = .bold(14)
- v.textAlignment = .left
- }
-
- selectedIcon.image = UIImage(named: "cell_selected")
- line.do { v in
- v.backgroundColor = .color(.separateLine)
- }
- }
-
- override func setupLayout() {
- bgView.snp.makeConstraints { (m) in
- m.left.right.equalToSuperview().inset(18)
- m.top.equalToSuperview()
- m.bottom.equalToSuperview()
- }
- type.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(16)
- make.centerY.equalToSuperview()
- make.width.equalTo(6)
- make.height.equalTo(16)
- }
- selectedIcon.snp.makeConstraints { (m) in
- m.width.equalTo(21)
- m.height.equalTo(16)
- m.right.equalToSuperview().inset(22)
- m.centerY.equalToSuperview()
- }
- titleLabel.snp.makeConstraints { (m) in
- m.centerY.equalToSuperview()
- m.left.equalToSuperview().offset(32)
- m.height.equalToSuperview()
- }
- line.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.bottom.equalToSuperview()
- make.height.equalTo(0.4)
- }
- }
-}
+++ /dev/null
-//
-// GroupTypeVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
-import UIKit
-
-class GroupTypeVC: BaseVC{
- let tableView = UITableView(frame: .zero, style: .plain)
- var list:[SportType] = SportType.all
- var currentType = SportType.walk
- let btn = CustomButton()
- var didSelected:((SportType)->Void)?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- // Do any additional setup after loading the view.
- }
- override func setupViews() {
- self.navBar.title = "团队类型".l10n
- tableView.do { v in
- v.backgroundColor = .color(.bgColor)
- v.delegate = self
- v.dataSource = self
- v.rowHeight = 52
- v.separatorStyle = .none
- v.contentInset = UIEdgeInsets(top: 10, left: 0, bottom: 0, right: 0)
- v.register(SelectCell.self, forCellReuseIdentifier: SelectCell.reuseID)
- }
- view.addSubviews([tableView,btn])
-
- btn.set(title: "确定".l10n, target: self, action: #selector(btnAction))
- }
- override func setupLayout() {
- tableView.snp.makeConstraints { make in
- make.left.right.bottom.equalToSuperview()
- make.top.equalTo(kNavBtm)
- }
- btn.snp.makeConstraints { make in
- make.width.equalTo(272)
- make.height.equalTo(46)
- make.centerX.equalToSuperview()
- make.bottom.equalToSuperview().inset(82)
- }
- }
- @objc func btnAction(){
- didSelected?(currentType)
- self.navigationController?.popViewController(animated: true)
- }
-}
-
-extension GroupTypeVC:UITableViewDelegate,UITableViewDataSource {
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return list.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = SelectCell.cell(withTableView: tableView, indexPath: indexPath)
- cell.titleLabel.text = list[indexPath.row].name
- let rect = CGRect(x: 0, y: 0, width: kScreenWid - 36, height: 52)
- if indexPath.row == 0 {
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 8, height: 8))
- }
- else if indexPath.row == list.count - 1{
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: 8, height: 8))
- }
- else{
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
- }
- cell.selectedIcon.isHidden = list[indexPath.row] != currentType
- return cell
- }
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- let data = list[indexPath.row]
- currentType = data
- tableView.reloadData()
- }
-}
+++ /dev/null
-//
-// AddGrpupVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/6.
-//
-
-import UIKit
-
-class AddGroupVC: BaseVC{
- let nameView = SportInputItem()
- let typeView = SportSelectItem()
- let desView = SportInputItem()
- let okBtn = CustomButton()
- var sportType:GroupRoleType = .none
-
- override func setupViews() {
- navBar.do { v in
- v.title = "加入团队".l10n
- v.rightView.setImage(UIImage(named: "help_icon"), for: .normal)
- v.rightView.isHidden = false
- }
- view.addSubviews([nameView,typeView,desView,okBtn])
- nameView.do { v in
- v.yc.setCornerRadius(12)
- v.titleLabel.text = "团队号".l10n
- v.textField.text = ""
- v.textField.attributedPlaceholder = NSAttributedString(string: "请输入团队号".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
-
- }
- typeView.do { v in
- v.yc.setCornerRadius(12)
- v.titleLabel.text = "团队角色".l10n
- v.detailLabel.text = sportType.name
- v.yc.addTap(target: self, action: #selector(typeAction))
- }
- desView.do { v in
- v.yc.setCornerRadius(12)
- v.titleLabel.text = "打招呼内容".l10n
- v.textField.attributedPlaceholder = NSAttributedString(string: "描述一下您的团".l10n, attributes: [NSAttributedString.Key.foregroundColor: UIColor.color(.placeholder)])
- v.maxLength = 50
- }
- okBtn.set(title: "加入".l10n,style: .theme1, target: self, action: #selector(okAction))
- }
- override func setupLayout() {
- nameView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalToSuperview().inset(kNavBtm + 20)
- make.height.equalTo(51)
- }
-
- desView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(nameView.snp.bottom).offset(10)
- make.height.equalTo(65)
- }
- typeView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(desView.snp.bottom).offset(10)
- make.height.equalTo(51)
- }
- okBtn.snp.makeConstraints { make in
- make.bottom.equalToSuperview().inset(80)
- make.left.right.equalToSuperview().inset(51)
- make.height.equalTo(46)
- }
- }
- override func navRightViewTapped() {
- let tip = GroupDesPopView()
- tip.show()
- }
- @objc func typeAction(){
- let vc = GroupRoleVC()
- vc.didSelected = {[weak self] value in
- self?.sportType = value
- self?.typeView.detailLabel.text = value.name
- }
- App.shared.goToPage(vc)
- }
- @objc func lightAction(){
- App.shared.goToPage(LightSetVC())
- }
- @objc func okAction(){
- if nameView.isEmpty {
- YLprogressHUD.showAutoHiden("团队名称不能为空".l10n)
- return
- }
-
- YLprogressHUD.showLoading()
- var params:[String:Any] = [:]
- params["id"] = nameView.value
- params["requestText"] = desView.value
-
- let api = CommomApi.applyJoinGroup(param: params)
- HttpClient.request(api){ (model:ResponseBaseModel, res) in
-
- if model.isSuccess{
- YLprogressHUD.hidden()
- }
- else{
- YLprogressHUD.showAutoHiden(model.msg)
- }
- }
- }
-}
-
+++ /dev/null
-//
-// History.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/25.
-//
-
-import JXSegmentedView
-
-
-enum SportHistoryType{
- case week
- case month
- case year
- case all
-
- var name:String{
- switch self {
- case .week:
- return "周"
- case .month:
- return "月"
- case .year:
- return "年"
- case .all:
- return "总"
- }
- }
- static var allData:[SportHistoryType] = [.week,.month,.year,.all]
-}
-
-class SportHistoryVC: BaseVC {
- private let segmentedDataSource = JXSegmentedTitleDataSource()
- private let segmentedView = JXSegmentedView()
- private lazy var listContainerView: JXSegmentedListContainerView! = {
- let view = JXSegmentedListContainerView(dataSource: self, type: .scrollView)
- return view
- }()
-
- var list:[SportHistoryType] = SportHistoryType.allData
- override func viewDidLoad() {
- super.viewDidLoad()
-
- // AudioPlayView.shared.show()
- self.view.addSubview(AudioPlayView.shared)
- MapManager.shared.setupSdk()
- }
-
- 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()
- }
- }
- override func setupViews(){
- navBar.do { v in
- v.title = "运动记录"
- }
- view.addSubview(segmentedView)
- view.addSubview(listContainerView)
-
- 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(.theme)
- segmentedView.indicators = [indicator]
-
- v.dataSource = segmentedDataSource
- v.listContainer = listContainerView
- }
- }
-}
-
-extension SportHistoryVC: JXSegmentedListContainerViewListDelegate {
- func listView() -> UIView {
- return view
- }
-}
-
-extension SportHistoryVC: 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 .week:
- return SprotHistoryView()
- case .month:
- return SprotHistoryView()
- case .year:
- return SprotHistoryView()
- case .all:
- return SprotHistoryView()
- }
-
- }
-}
+++ /dev/null
-//
-// SprotHistoryView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/25.
-//
-
-import UIKit
-import JXSegmentedView
-
-class SprotHistoryView: BaseView{
-
- override func setupViews() {
-
- }
- override func setupLayout() {
-
- }
-}
-
-extension SprotHistoryView: JXSegmentedListContainerViewListDelegate {
- func listView() -> UIView {
- return self
- }
-}
+++ /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.
-
- }
- open override var preferredStatusBarStyle: UIStatusBarStyle {
- return .lightContent
- }
- override func setupViews() {
- navBar.do { v in
- v.title = "灯带设置".l10n
- v.titleLabel.textColor = .white
- v.backgroundColor = .clear
- v.leftView.setImage(UIImage(named: "arrow_back_white"), 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.image = UIImage(named: "guchuandao_icon")
- }
- stateView.do { v in
- v.iSwitch.addTarget(self, action: #selector(stateAction), for: .valueChanged)
- v.titleLabel.text = "灯带".l10n
- }
- modelView.do { v in
- }
- brightnessView.do { v in
-// v.backgroundColor = .yellow
- }
- sysView.do { v in
- v.line.isHidden = true
- v.titleLabel.text = "同步至队员".l10n
- }
- stateAction()
- }
- 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(130.fitR)
- make.width.equalTo(220.fitR)
- make.centerX.equalToSuperview()
- make.top.equalToSuperview().inset(40)
- }
- stateView.snp.makeConstraints { make in
- make.width.equalTo(kScreenWid)
- make.height.equalTo(60)
- make.top.equalTo(icon.snp.bottom).offset(35)
- 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
- }
- var mode:LightMode?{
- if normalItem.isSelected {
- return .normal
- }
- if breathItem.isSelected {
- return .breath
- }
- if flashItem.isSelected {
- return .flash
- }
- return nil
- }
-
-
- 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))
- v.isSelected = true
- }
- 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
- }
-
- iSwitch.do { v in
- // v.backgroundColor = .red
- v.isOn = true
- }
-
- 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)
- }
- }
- }
-}
+++ /dev/null
-//
-// Untitled.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/21.
-//
-
-extension ReadyVC{
- class CountdownView: BaseView {
- let label = UILabel()
- let skip = UILabel()
- var timer:Timer!
- var count = 3
-
- override func setupViews() {
- addSubviews([label,skip])
- label.do { v in
- v.textColor = .color(.first)
- v.font = .bold(210)
- v.textAlignment = .center
- v.text = "\(count)"
- }
- skip.do { v in
- v.textColor = .color(.first)
- v.font = .regular(14)
- v.textAlignment = .center
- v.text = "直接开始".l10n
- v.yc.addTap(target: self, action: #selector(skipAction))
-
- let line = UIView()
- line.backgroundColor = .color(.first)
- v.addSubview(line)
- line.snp.makeConstraints { make in
- make.height.equalTo(1)
- make.left.right.equalToSuperview()
- make.bottom.equalToSuperview().offset(4)
- }
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
- label.snp.makeConstraints { make in
- make.center.equalToSuperview()
- }
- skip.snp.makeConstraints { make in
- make.bottom.equalToSuperview().inset(100)
- make.centerX.equalToSuperview()
- }
- }
- override func setupData() {
- timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
- }
- @objc func timerAction(){
- count -= 1
- label.text = "\(count)"
- print(count)
- if count == 0 {
- skipAction()
- }
- }
- static func show(in view:UIView){
- let countView = CountdownView()
- view.addSubview(countView)
- countView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
- }
- @objc func skipAction(){
- timer.invalidate()
- App.shared.goToPage(SportingVC())
- removeFromSuperview()
- }
- }
-
-}
+++ /dev/null
-//
-// Untitled.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/21.
-//
-
-class CustomMapView: BaseView {
-
-
-
-}
+++ /dev/null
-//
-// Untitled.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/25.
-//
-
-class DeviceStateView: BaseView {
- let deviceLabel = UILabel()
- let deviceBg = UIView()
- let stateLabel = UIView()
-
-
- var value:String = ""{
- didSet{
- deviceLabel.text = value
- }
- }
-
- override func setupViews() {
- addSubviews([deviceBg])
- deviceBg.addSubviews([stateLabel,deviceLabel])
- deviceBg.do { v in
- v.backgroundColor = .rgb(0xF7F7F7 )
- v.yc.setCornerRadius(13)
- }
- stateLabel.do { v in
- v.backgroundColor = .rgb(0x2BD84E )
- v.yc.setCornerRadius(2)
- }
- deviceLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(10)
- v.textAlignment = .center
- v.text = "Deep Lite2 Ultra"
- }
- }
-
- override func setupLayout() {
- deviceBg.snp.makeConstraints { make in
- make.height.equalTo(26)
- make.top.equalToSuperview()
- make.left.right.equalToSuperview()
- }
- stateLabel.snp.makeConstraints { make in
- make.size.equalTo(4)
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(9)
- }
- deviceLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(18)
- make.right.equalToSuperview().inset(8)
- make.height.equalToSuperview()
- }
- }
- }
+++ /dev/null
-//
-// FooterView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/21.
-//
-
-extension ReadyVC{
- class FooterView: BaseView {
- let targetBtn = ButtonItem()
- let routeBtn = ButtonItem()
- let goBtn = UIImageView()
-
- override func setupViews() {
- addSubviews([targetBtn,goBtn,routeBtn])
- targetBtn.do { v in
- v.titleLabel.text = "目标".l10n
- v.icon.image = UIImage(named: "ready_target")
- v.yc.setCornerRadius(18)
- v.yc.addTap(target: self, action: #selector(targetAction))
- }
- goBtn.do { v in
- v.image = UIImage(named: "ready_go")
- v.yc.addTap(target: self, action: #selector(goAction))
- }
- routeBtn.do { v in
- v.yc.setCornerRadius(18)
- v.titleLabel.text = "路线".l10n
- v.icon.image = UIImage(named: "ready_route")
- v.yc.addTap(target: self, action: #selector(routeAction))
- }
- }
-
- override func setupLayout() {
- goBtn.snp.makeConstraints { make in
- make.size.equalTo(90)
- make.centerY.equalToSuperview()
- make.centerX.equalTo(kScreenWid/2)
- }
-
- targetBtn.snp.makeConstraints { make in
- make.width.equalTo(90)
- make.height.equalTo(36)
- make.centerY.equalToSuperview()
- make.right.equalTo(goBtn.snp.left).offset(-27)
- }
- routeBtn.snp.makeConstraints { make in
- make.width.equalTo(90)
- make.height.equalTo(36)
- make.centerY.equalToSuperview()
- make.left.equalTo(goBtn.snp.right).offset(27)
- }
-
- }
-
- @objc func targetAction(){
- App.shared.goToPage(SportTargetVC())
- }
- @objc func goAction(){
- if false {
- CustomAlert.showWith(title: "完善数据".l10n, messgage: "完善你的身体档案,让运动数据更准确。".l10n,ok: "前往".l10n) {
-
- } okCallback: {
- App.shared.goToPage(UserInfoVC())
- }
- }
- else{
- CountdownView.show(in: App.shared.window!)
- }
-
- }
- @objc func routeAction(){
-
- }
-
- class ButtonItem: BaseView {
- let icon = UIImageView()
- let titleLabel = UILabel()
-
- override func setupViews() {
- addSubviews([titleLabel,icon])
- icon.do { v in
- }
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .regular(14)
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
- icon.snp.makeConstraints { make in
- make.size.equalTo(24)
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(16)
- }
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalTo(43)
- }
- }
- }
-
- }
-
-}
+++ /dev/null
-//
-// Navbar.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/3.
-//
-
-import UIKit
-
-extension ReadyVC{
- class Navbar: BaseView {
- let backItem = BackItem()
- let icon = UIImageView()
- let groupBtn = UIButton()
- let setBtn = UIButton()
-
- //
-
- override func setupViews() {
- backgroundColor = .color(.bgColor)
- addSubviews([backItem,icon,groupBtn,setBtn])
- backItem.do { v in
- v.titleLabel.text = SportManager.shared.sportType.name
- v.yc.addTap(target: self, action: #selector(backAction))
- }
- 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)
- }
- backItem.snp.makeConstraints { make in
- make.left.equalToSuperview()
- make.centerY.equalTo(icon)
- make.height.equalTo(32)
- make.width.equalTo(100)
- }
- }
- @objc func backAction(){
- App.shared.popPage()
- }
- @objc func groupAction(){
- App.shared.goToPage(SportSetVC())
- }
- @objc func setAction(){
- App.shared.goToPage(SportSetVC())
- }
-
- class BackItem: BaseView {
- let icon = UIImageView()
- let titleLabel = UILabel()
-
- override func setupViews() {
- addSubviews([titleLabel,icon])
- icon.do { v in
- v.image = UIImage(named: "arrow_back")
- }
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .bold(16)
- }
- }
-
- override func setupLayout() {
- icon.snp.makeConstraints { make in
- make.width.equalTo(10)
- make.height.equalTo(19)
- make.left.equalToSuperview().inset(18)
- make.centerY.equalToSuperview()
- }
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(42)
- }
- }
- }
- }
-
-
-}
-
-
+++ /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 = SportManager.shared.sportType.readyText
- v.textAlignment = .left
- }
- totalLabel.do { v in
- v.textColor = .color(.first)
- v.font = .bold(20)
- v.text = "00"
- 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)
- }
- }
- }
-
- }
-
-}
+++ /dev/null
-//
-// Untitled.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/21.
-//
-import MAMapKit
-
-class ReadyVC: BaseVC {
- let bar = Navbar()
- let headerView = ReadyHeader()
- var mapView:MAMapView!
- let footerView = FooterView()
- let deviceView = DeviceStateView()
-
- override func setupViews() {
- navBar.do { v in
- v.addSubview(bar)
- }
-
- mapView = MAMapView(frame: .zero)
- mapView.do { v in
- v.delegate = self
- v.showsUserLocation = true
- v.zoomLevel = 16
- v.userTrackingMode = .followWithHeading
- }
-
-
- view.addSubviews([headerView,mapView,footerView])
- mapView.addSubview(deviceView)
-
- headerView.do { v in
- v.backgroundColor = .clear
- }
- mapView.do { v in
- v.yc.setCornerRadius(12)
- }
- footerView.do { v in
- }
- }
- 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)
- make.height.equalTo(100)
- }
- footerView.snp.makeConstraints { make in
- make.left.right.equalToSuperview()
- make.bottom.equalToSuperview()
- make.height.equalTo(200)
- }
- mapView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(headerView.snp.bottom)
- make.bottom.equalTo(footerView.snp.top)
- }
- deviceView.snp.makeConstraints { make in
- make.top.right.equalToSuperview().inset(12)
- make.height.equalTo(26)
- }
- }
- override func setupData() {
-
- }
-
-}
-
-extension ReadyVC:MAMapViewDelegate{
- func mapViewRequireLocationAuth(_ locationManager: CLLocationManager!) {
-// locationManager.requestAlwaysAuthorization()
- }
-}
+++ /dev/null
-//
-// DataView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/21.
-//
-
-extension SportRootView{
- class DataView: BaseView {
- let header = headItem()
- let line = UIView()
- let lastView = ItemView()
-
- override func setupViews() {
- backgroundColor = .color(.cellBg)
- addSubviews([header,lastView,line])
- line.backgroundColor = .color(.separateLine)
- header.do { v in
- v.yc.addTap(target: self, action: #selector(allAction))
- }
- lastView.do { v in
- v.yc.addTap(target: self, action: #selector(lastAction))
- }
- }
-
- override func setupLayout() {
- header.snp.makeConstraints { make in
- make.left.right.top.equalToSuperview()
- make.height.equalTo(51)
- }
- lastView.snp.makeConstraints { make in
- make.left.right.bottom.equalToSuperview()
- make.height.equalTo(72)
- }
- line.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(14)
- make.height.equalTo(1)
- make.bottom.equalTo(header)
- }
- }
- @objc func allAction(){
- App.shared.goToPage(SportHistoryVC())
- }
- @objc func lastAction(){
- App.shared.goToPage(SportDetailVC())
-
- }
-
- class headItem: BaseView {
- let icon = UIImageView()
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- override func setupViews() {
- yc.setCornerRadius(12)
- addSubviews([icon,titleLabel,detailLabel])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(14)
- v.text = "运动数据".l10n
- }
- detailLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(12)
- v.text = "全部".l10n
- }
- icon.do { v in
- v.image = UIImage(named: "arrow_2")
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(14)
- }
- detailLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(27)
- }
- icon.snp.makeConstraints { make in
- make.width.equalTo(7)
- make.height.equalTo(13)
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(12)
- }
- }
- }
-
- class ItemView: BaseView {
- let icon = UIImageView()
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- override func setupViews() {
- yc.setCornerRadius(12)
- addSubviews([icon,titleLabel,detailLabel])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(14)
- v.text = "户外跑步 6.21公里"
- }
- detailLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(10)
- v.text = "30分26秒"
- }
- icon.do { v in
- v.image = UIImage(named: "add_2")
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.top.equalToSuperview().inset(16)
- make.left.equalToSuperview().inset(64)
- }
- detailLabel.snp.makeConstraints { make in
- make.bottom.equalToSuperview().inset(16)
- make.left.equalTo(titleLabel)
- }
- icon.snp.makeConstraints { make in
- make.size.equalTo(40)
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(14)
- }
- }
- }
- }
-}
+++ /dev/null
-//
-// GroupView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/21.
-//
-
-extension SportRootView{
- class GroupView: BaseView {
- let creatGroup = ItemView()
- let addGroup = ItemView()
- let myGroup = ItemView()
-
- override func setupViews() {
- addSubviews([creatGroup,addGroup,myGroup])
- creatGroup.do { v in
- v.titleLabel.text = "创建团队".l10n
- v.detailLabel.text = "创建我的团队".l10n
- v.yc.addTap(target: self, action: #selector(creatAction))
- }
- addGroup.do { v in
- v.titleLabel.text = "加入团队".l10n
- v.detailLabel.text = "加入已创建的团队".l10n
- v.yc.addTap(target: self, action: #selector(joinAction))
-
- }
- myGroup.do { v in
- v.titleLabel.text = "我的团队".l10n
- v.detailLabel.text = "我创建和已加入的团队".l10n
- v.icon.isHidden = true
- v.yc.addTap(target: self, action: #selector(myAction))
- }
- }
-
- override func setupLayout() {
- creatGroup.snp.makeConstraints { make in
- make.left.top.right.equalToSuperview()
- make.height.equalTo(65)
- }
- addGroup.snp.makeConstraints { make in
- make.left.bottom.equalToSuperview()
- make.height.equalTo(65)
- make.width.equalTo((kScreenWid - 36 - 10)/2)
- }
- myGroup.snp.makeConstraints { make in
- make.right.bottom.equalToSuperview()
- make.height.equalTo(addGroup)
- make.left.equalTo(addGroup.snp.right).offset(10)
- }
- }
- @objc func creatAction(){
- App.shared.goToPage(CreateGroupVC())
- }
- @objc func joinAction(){
- App.shared.goToPage(AddGroupVC())
- }
- @objc func myAction(){
- App.shared.goToPage(MyGroupVC())
- }
- }
- class ItemView: BaseView {
- let icon = UIImageView()
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- override func setupViews() {
- backgroundColor = .color(.cellBg)
- yc.setCornerRadius(12)
- addSubviews([icon,titleLabel,detailLabel])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(14)
- }
- detailLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(10)
- }
- icon.do { v in
- v.image = UIImage(named: "add_2")
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.top.equalToSuperview().inset(16)
- make.left.equalToSuperview().inset(14)
- }
- detailLabel.snp.makeConstraints { make in
- make.bottom.equalToSuperview().inset(16)
- make.left.equalTo(titleLabel)
- }
- icon.snp.makeConstraints { make in
- make.size.equalTo(36)
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(12)
- }
- }
- }
-}
+++ /dev/null
-//
-// PlanView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/21.
-//
-
-extension SportRootView{
- class PlanView: BaseView {
- let icon = ItemView()
-
- override func setupViews() {
- addSubviews([icon])
- icon.do { v in
- v.titleLabel.text = "智能运动计划建议".l10n
- v.detailLabel.text = "AI规划个人定制运动计划".l10n
- }
- }
-
- override func setupLayout() {
- icon.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
- }
- }
-}
+++ /dev/null
-//
-// RouteView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/21.
-//
-
-extension SportRootView{
- class RouteView: BaseView {
- let header = headItem()
- let line = UIView()
- let routeView1 = UIView()
- let routeView2 = UIView()
-
-
- override func setupViews() {
- backgroundColor = .color(.cellBg)
- addSubviews([header,routeView1,routeView2,line])
- line.backgroundColor = .color(.separateLine)
-
- routeView1.do { v in
- v.backgroundColor = .lightGray
- v.yc.setCornerRadius(12)
- }
- routeView2.do { v in
- v.backgroundColor = .lightGray
- v.yc.setCornerRadius(12)
- }
- }
-
- override func setupLayout() {
- header.snp.makeConstraints { make in
- make.left.right.top.equalToSuperview()
- make.height.equalTo(51)
- }
- routeView1.snp.makeConstraints { make in
- make.left.bottom.equalToSuperview().inset(14)
- make.height.equalTo(96)
- make.width.equalTo(((kScreenWid - 64 - 10)/2))
- }
- routeView2.snp.makeConstraints { make in
- make.right.bottom.equalToSuperview().inset(14)
- make.height.equalTo(96)
- make.width.equalTo(((kScreenWid - 64 - 10)/2))
- }
- line.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(14)
- make.height.equalTo(1)
- make.bottom.equalTo(header)
- }
- }
- class headItem: BaseView {
- let icon = UIImageView()
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- override func setupViews() {
- yc.setCornerRadius(12)
- addSubviews([icon,titleLabel,detailLabel])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(14)
- v.text = "路线探索".l10n
- }
- detailLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(12)
- v.text = "全部".l10n
- }
- icon.do { v in
- v.image = UIImage(named: "arrow_2")
- }
- backgroundColor = .white
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(14)
- }
- detailLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(27)
- }
- icon.snp.makeConstraints { make in
- make.width.equalTo(7)
- make.height.equalTo(13)
- make.centerY.equalToSuperview()
- make.right.equalToSuperview().inset(12)
- }
- }
- }
-
-
- }
-}
+++ /dev/null
-//
-// SportVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/20.
-//
-
-import UIKit
-import JXSegmentedView
-
-class SportRootView: BaseView{
- let sportType = SportTypeView()
- let dataView = DataView()
- let groupView = GroupView()
- let planView = PlanView()
- let routeView = RouteView()
-
- override func setupViews() {
- addSubviews([sportType,dataView,groupView,planView,routeView])
- dataView.do { v in
- v.yc.setCornerRadius(12)
- }
- groupView.do { v in
- v.yc.setCornerRadius(12)
- }
- planView.do { v in
- v.yc.setCornerRadius(12)
- }
- routeView.do { v in
- v.yc.setCornerRadius(12)
- }
- }
- override func setupLayout() {
- sportType.snp.makeConstraints { make in
- make.left.right.equalToSuperview()
- make.top.equalToSuperview().inset(20)
- make.height.equalTo(80)
- }
- dataView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(sportType.snp.bottom).offset(10)
- make.height.equalTo(123)
- }
- groupView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(dataView.snp.bottom).offset(10)
- make.height.equalTo(140)
- }
- planView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(groupView.snp.bottom).offset(10)
- make.height.equalTo(65)
- }
- routeView.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.top.equalTo(planView.snp.bottom).offset(10)
- make.height.equalTo(180)
- }
- }
-}
-
-extension SportRootView: JXSegmentedListContainerViewListDelegate {
- func listView() -> UIView {
- return self
- }
-}
+++ /dev/null
-//
-// SportTypeView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/20.
-//
-import HandyJSON
-
-enum SportType:String,HandyJSONEnum{
- case run = "running"
- case ride = "cycling"
- case walk = "walking"
-
- var name:String{
- switch self {
- case .run:
- return "户外跑步"
- case .ride:
- return "户外骑行"
- case .walk:
- return "健走"
- }
- }
- var icon:String{
- switch self {
- case .run:
- return "sport_run"
- case .ride:
- return "sport_ride"
- case .walk:
- return "sport_walk"
- }
- }
- var readyText:String{
- switch self {
- case .run:
- return "累积跑步距离".l10n
- case .ride:
- return "累积骑行距离".l10n
- case .walk:
- return "累积健走距离".l10n
- }
- }
-
- static var all:[SportType] = [.run,.ride,.walk]
-}
-
-class SportTypeView: BaseView {
- let run = SportTypeItem()
- let ride = SportTypeItem()
- let walk = SportTypeItem()
-
- override func setupViews() {
- addSubviews([run,ride,walk])
- run.do { v in
- v.type = .run
- v.yc.addTap(target: self, action: #selector(runAction))
- }
- ride.do { v in
- v.type = .ride
- v.yc.addTap(target: self, action: #selector(rideAction))
- }
- walk.do { v in
- v.type = .walk
- v.yc.addTap(target: self, action: #selector(walkAction))
- }
- }
-
- override func setupLayout() {
- run.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(38)
- make.width.equalTo(50)
- make.height.equalTo(80)
- make.top.equalToSuperview()
- }
- ride.snp.makeConstraints { make in
- make.left.equalTo(run.snp.right).offset(32)
- make.width.equalTo(50)
- make.height.equalTo(80)
- make.top.equalToSuperview()
- }
- walk.snp.makeConstraints { make in
- make.left.equalTo(ride.snp.right).offset(32)
- make.width.equalTo(50)
- make.height.equalTo(80)
- make.top.equalToSuperview()
- }
- }
- @objc func runAction(){
- SportManager.shared.sportType = .run
- App.shared.goToPage(ReadyVC())
- }
- @objc func rideAction(){
- SportManager.shared.sportType = .ride
- App.shared.goToPage(ReadyVC())
- }
- @objc func walkAction(){
- SportManager.shared.sportType = .walk
- App.shared.goToPage(ReadyVC())
- }
-}
-
-class SportTypeItem: BaseView {
- private let icon = UIImageView()
- private let titleLabel = UILabel()
- var type:SportType = .run{
- didSet{
- titleLabel.text = type.name
- icon.image = UIImage(named: type.icon)
- }
- }
- override func setupViews() {
- addSubviews([titleLabel,icon])
- icon.do { v in
-
- }
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .regular(10)
- }
- }
-
- override func setupLayout() {
- icon.snp.makeConstraints { make in
- make.size.equalTo(50)
- make.top.equalToSuperview()
- make.centerX.equalToSuperview()
- }
- titleLabel.snp.makeConstraints { make in
- make.top.equalTo(icon.snp.bottom).offset(5)
- make.centerX.equalTo(icon)
- }
- }
-}
+++ /dev/null
-//
-// Untitled.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/23.
-//
-
-
-public enum SportSetCellType: Int {
- case light
- case voiceReport
- case lcReport
- case lcReportRate
- case xlfdReport
- case guideReport
- case guideReportSet
- case metronome
- case metronomeRate
- case metronomeAudio
- case background
- case permisson
- case realData
-
- var title:String{
- switch self {
- case .light:
- return "灯带设置".l10n
- case .voiceReport:
- return "语音播报".l10n
- case .lcReport:
- return "里程播报".l10n
- case .lcReportRate:
- return "里程播报频次".l10n
- case .xlfdReport:
- return "训练分段播报".l10n
- case .guideReport:
- return "指导播报".l10n
- case .guideReportSet:
- return "指导语音设置".l10n
- case .metronome:
- return "节拍器".l10n
- case .metronomeRate:
- return "节拍器频率".l10n
- case .metronomeAudio:
- return "节拍器声音".l10n
- case .background:
- return "后台保护".l10n
- case .permisson:
- return "运动权限".l10n
- case .realData:
- return "运动实况".l10n
- }
- }
- var detail:String{
- switch self {
- case .lcReport:
- return "当前已跑里程播报".l10n
- case .xlfdReport:
- return "训练分段开始和结束提示音".l10n
- case .guideReport:
- return "跑步过程中的指导语音".l10n
- case .realData:
- return "组内成员基本运动信息实时显示".l10n
- default:
- return ""
- }
- }
- var showSwitch:Bool{
- switch self {
- case .voiceReport,.lcReport,.xlfdReport,.guideReport,.metronome,.background,.realData:
- return true
- default:
- return false
- }
- }
-}
-
-protocol SportSetCellDelegate:NSObject{
- func sportSetCellSwitchAction(cell:SportSetCell)
-}
-class SportSetCell: BaseTableViewCell {
- let bgView = UIView()
- let titleLabel = UILabel()
- let detailLabel = UILabel()
- let valueLabel = UILabel()
- let iSwitch = UISwitch()
- let nextIcon = UIImageView(image: UIImage(named: "arrow_next"))
- let line = UIView()
- weak var delegate:SportSetCellDelegate?
- var model:SportSetModel!{
- didSet{
- switch type {
- case .light:
- break
- case .voiceReport:
- iSwitch.isOn = model.voiceReport
- case .lcReport:
- iSwitch.isOn = model.lcReport
-
- case .lcReportRate:
- valueLabel.text = model.lcReportRate
- case .xlfdReport:
- iSwitch.isOn = model.xlfdReport
- case .guideReport:
- iSwitch.isOn = model.guideReport
- case .guideReportSet:
- valueLabel.text = model.guideReportSet
- case .metronome:
- iSwitch.isOn = model.metronome
- case .metronomeRate:
- valueLabel.text = model.metronomeRate
- case .metronomeAudio:
- valueLabel.text = model.metronomeAudio
- case .background:
- iSwitch.isOn = model.background
- case .permisson:
- break
- case .realData:
- iSwitch.isOn = model.realData
- }
-
- if type == .lcReport {
- line.isHidden = model.lcReport
- }
- else if type == .guideReport {
- line.isHidden = model.guideReport
- }
- else if type == .metronome {
- line.isHidden = model.metronome
- }
- else if type == .permisson || type == .realData || type == .metronomeRate{
- line.isHidden = true
- }
- else{
- line.isHidden = false
- }
- }
- }
-
- var type:SportSetCellType = .light{
- didSet{
- titleLabel.text = type.title
- detailLabel.text = type.detail
- iSwitch.isHidden = !type.showSwitch
- nextIcon.isHidden = !iSwitch.isHidden
-
- if type.detail.isEmpty {
- titleLabel.snp.remakeConstraints { (m) in
- m.centerY.equalToSuperview()
- m.left.equalToSuperview().offset(16)
- }
- }
- else{
- titleLabel.snp.remakeConstraints { (m) in
- m.top.equalToSuperview().inset(16)
- m.left.equalToSuperview().offset(16)
- }
- }
-
- if type == .metronomeRate || type == .metronomeAudio {
- valueLabel.isHidden = false
- }
- else{
- valueLabel.isHidden = true
- }
- }
- }
-
-
- override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
- super.init(style: style, reuseIdentifier: reuseIdentifier)
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- override func setupViews() {
- contentView.addSubview(bgView)
- bgView.addSubviews([titleLabel,detailLabel,iSwitch,nextIcon,valueLabel,line])
-
- backgroundColor = .color(.bgColor)
- contentView.backgroundColor = .clear
- selectionStyle = .none
- bgView.do { v in
- v.backgroundColor = .color(.cellBg)
- v.yc.addTap(target: self, action: #selector(tapAction))
- }
- titleLabel.do { (v) in
- v.textColor = .color(.first)
- v.font = .bold(14)
- v.textAlignment = .left
- }
- detailLabel.do { (v) in
- v.textColor = .color(.secondary)
- v.font = .regular(10)
- v.textAlignment = .left
- }
- iSwitch.do { v in
-// v.backgroundColor = .red
- v.addTarget(self, action: #selector(swicthAction), for: .valueChanged)
- }
- valueLabel.do { v in
- v.textColor = .color(.secondary)
- v.font = .regular(14)
- v.textAlignment = .right
- }
- line.do { v in
- v.backgroundColor = .color(.separateLine)
- }
- }
-
- override func setupLayout() {
- bgView.snp.makeConstraints { (m) in
- m.left.right.equalToSuperview().inset(18)
- m.top.equalToSuperview()
- m.bottom.equalToSuperview()
- }
- titleLabel.snp.makeConstraints { (m) in
- m.top.equalToSuperview().inset(16)
- m.left.equalToSuperview().offset(16)
- }
- detailLabel.snp.makeConstraints { (m) in
- m.bottom.equalToSuperview().inset(16)
- m.left.equalToSuperview().offset(16)
- }
- iSwitch.snp.makeConstraints { (m) in
- m.right.equalToSuperview().inset(15)
- m.centerY.equalToSuperview()
- }
- nextIcon.snp.makeConstraints { (m) in
- m.width.equalTo(8)
- m.height.equalTo(12)
- m.right.equalToSuperview().inset(15)
- m.centerY.equalToSuperview()
- }
- valueLabel.snp.makeConstraints { (m) in
- m.centerY.equalToSuperview()
- m.right.equalToSuperview().inset(38)
- m.height.equalToSuperview()
- m.left.equalToSuperview().inset(90)
- }
- line.snp.makeConstraints { make in
- make.left.right.equalToSuperview().inset(18)
- make.bottom.equalToSuperview()
- make.height.equalTo(0.4)
- }
- }
- @objc func tapAction(){
- switch type {
- case .light:
- App.shared.goToPage(LightSetVC())
- case .lcReportRate:
- lcReportAction()
- break
- case .guideReportSet:
- guideReportSetAction()
- break
- case .metronomeRate:
- metronomeRateAction()
- break
- case .metronomeAudio:
- metronomeAudioAction()
- break
-
- case .background:
- backgroundAction()
- break
- default:
- break
- }
- }
- func lcReportAction(){
- let list = Array(stride(from: 500, to: 1500, by: 500)).map { String($0) + "m" }
- let v = CustomPicker2(title: "选择播报间距".l10n, list:list )
- v.selectedIndex = 50
- v.show()
- v.didSelected = {[weak self] (index,value) in
- guard let self = self else { return }
-
- }
- }
- func guideReportSetAction(){
- let list = [
- CustomPickerModel(title: "详细".l10n, detail: "1公里配速、总平均配速、1公里用时、总运动时长".l10n),
- CustomPickerModel(title: "简洁".l10n, detail: "1公里配速、1公里用时".l10n),
- CustomPickerModel(title: "极简".l10n, detail: "总距离、总时长".l10n)]
- let v = CustomPicker4(title: "指导语音密度".l10n, list:list )
- v.selectedIndex = 0
- v.show()
- v.didSelected = {[weak self] (index,value) in
- guard let self = self else { return }
-
- }
- }
- func metronomeRateAction(){
- let list = Array(stride(from: 100, to: 250, by: 1)).map { String($0) + "次/分钟".l10n }
- let v = CustomPicker2(title: "节拍器频率".l10n, list:list )
- v.selectedIndex = 50
- v.show()
- v.didSelected = {[weak self] (index,value) in
- guard let self = self else { return }
-
- }
- }
- func metronomeAudioAction(){
- let list = ["默认".l10n,"清脆".l10n,"重击".l10n]
- let v = CustomPicker2(title: "节拍器声音".l10n, list:list )
- v.selectedIndex = 50
- v.show()
- v.didSelected = {[weak self] (index,value) in
- guard let self = self else { return }
-
- }
- }
- func backgroundAction(){
-
- }
- @objc func swicthAction(){
- delegate?.sportSetCellSwitchAction(cell: self)
- }
-}
+++ /dev/null
-//
-// SportSetModel.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/30.
-//
-
-class SportSetModel{
- var light = ""
- var voiceReport = true
- var lcReport = false
- var lcReportRate = ""
- var xlfdReport = false
- var guideReport = false
- var guideReportSet = ""
- var metronome = false
- var metronomeRate = ""
- var metronomeAudio = ""
- var background = false
- var permisson = ""
- var realData = false
-}
+++ /dev/null
-//
-// SportSetVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/23.
-//,,
-
-
-import UIKit
-class SportSetVC: BaseVC{
- let tableView = UITableView(frame: .zero, style: .plain)
- var list:[[SportSetCellType]] = [[.light],[.voiceReport],[.lcReport],[.xlfdReport],[.guideReport],[.metronome],[.background],[.permisson],[.realData]]
- let model = SportSetModel()
-
- override func viewDidLoad() {
- super.viewDidLoad()
- // Do any additional setup after loading the view.
- }
- override func setupViews() {
- self.navBar.title = "设置".l10n
- tableView.do { v in
- v.backgroundColor = .color(.bgColor)
- v.delegate = self
- v.dataSource = self
- v.rowHeight = 65
- v.sectionHeaderHeight = 52
- v.separatorStyle = .none
- v.register(SportSetCell.self, forCellReuseIdentifier: SportSetCell.reuseID)
- v.register(CustomSectionHeader.self, forHeaderFooterViewReuseIdentifier: CustomSectionHeader.reuseID)
- if #available(iOS 15.0, *) {
- tableView.sectionHeaderTopPadding = 0
- }
- }
-
- view.addSubview(tableView)
- }
- override func setupLayout() {
- tableView.snp.makeConstraints { make in
- make.left.right.bottom.equalToSuperview()
- make.top.equalTo(kNavBtm)
- }
- }
- override func viewWillAppear(_ animated: Bool) {
- super.viewWillAppear(animated)
-// CacheManager.shared.user.tokenIsValid(){[weak self] sucess in
-// self?.header.updateUI()
-// }
- }
-}
-
-extension SportSetVC:UITableViewDelegate,UITableViewDataSource {
- func numberOfSections(in tableView: UITableView) -> Int {
- return list.count
- }
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return list[section].count
- }
- func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
- if section == list.count - 1 {
- let view = CustomSectionHeader.header(withTableView: tableView)
- view.titleLabel.text = "组队设置".l10n
- view.titleLabel.textColor = .color(.secondary)
- return view
- }
- else{
- return nil
- }
- }
- func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
- if section == list.count - 1 {
- return 52
- }
- else{
- return 0
- }
- }
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = SportSetCell.cell(withTableView: tableView, indexPath: indexPath)
- cell.type = list[indexPath.section][indexPath.row]
- cell.model = model
- cell.delegate = self
- let rect = CGRect(x: 0, y: 0, width: kScreenWid - 36, height: 65)
- if cell.type == .light {
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 12, height: 12))
- }
- else {
- if cell.type == .realData{
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 12, height: 12))
- }
- else if cell.type == .permisson {
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.bottomLeft,.bottomRight], cornerRadii: CGSize(width: 12, height: 12))
- }
- else{
- cell.bgView.yc.setCorners(withRoundedRect: rect, roundingCorners: [.allCorners], cornerRadii: CGSize(width: 0, height: 0))
- }
- }
-
- return cell
- }
-// func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-// let data = list[indexPath.section][indexPath.row]
-// switch data {
-// case .light:
-//
-// default:
-// break
-// }
-// }
-}
-extension SportSetVC:SportSetCellDelegate {
- func sportSetCellSwitchAction(cell:SportSetCell){
- let state = cell.iSwitch.isOn
- switch cell.type {
- case .voiceReport:
- model.voiceReport = state
- tableView.reloadData()
- break
- case .lcReport:
- model.lcReport = state
- list[2] = state ? [.lcReport,.lcReportRate]:[.lcReport]
- tableView.reloadData()
- break
- case .xlfdReport:
- model.xlfdReport = state
- tableView.reloadData()
- break
- case .guideReport:
- model.guideReport = state
- list[4] = state ? [.guideReport,.guideReportSet]:[.guideReport]
- tableView.reloadData()
- break
- case .metronome:
- model.metronome = state
- list[5] = state ? [.metronome,.metronomeRate,.metronomeAudio]:[.metronome]
- tableView.reloadData()
- break
- case .background:
- model.background = state
- tableView.reloadData()
- break
- case .realData:
- model.realData = state
- tableView.reloadData()
- break
- default:
- break
- }
- }
-}
+++ /dev/null
-//
-// CadenceView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/10.
-//
-
+++ /dev/null
-//
-// elevationView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/10.
-//
-
+++ /dev/null
-//
-// FeelView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/10.
-//
-
-class FeelView: BaseView {
- let header = SportDetailTitleView()
-
- override func setupViews() {
- backgroundColor = .white
- addSubviews([header])
- header.do { v in
- v.titleLabel.text = "运动感受".l10n
- v.icon.image = UIImage(named: "sport_feel")
- }
- }
-
- override func setupLayout() {
- header.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.height.equalTo(55)
- make.left.right.equalToSuperview()
- }
-
- }
-}
-class SportDetailTitleView: BaseView {
- let icon = UIImageView()
- let titleLabel = UILabel()
-
- override func setupViews() {
- addSubviews([icon,titleLabel])
-
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .medium(16)
- }
- icon.do { v in
- v.image = UIImage(named: "")
- }
- }
-
- override func setupLayout() {
-
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(48)
- }
- icon.snp.makeConstraints { make in
- make.size.equalTo(24)
- make.centerY.equalToSuperview()
- make.left.equalToSuperview().inset(18)
- }
- }
-}
+++ /dev/null
-//
-// PacePerView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/10.
-//
-
+++ /dev/null
-//
-// SpeepView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/10.
-//
-
+++ /dev/null
-////
-//// Untitled.swift
-//// ShenYin
-////
-//// Created by liangshi on 2026/2/5.
-////
-//
-import UIKit
-
-extension SportDetailVC{
- class SportDetailBoard: BaseView {
- let topIcon = UIImageView()
- let header = UILabel()
- let distanceItem = DistanceItem()
- let item1 = LabelItem()
- let item2 = LabelItem()
- let item3 = LabelItem()
- let item4 = LabelItem()
- let item5 = LabelItem()
- let item6 = LabelItem()
- let item7 = LabelItem()
- let item8 = LabelItem()
- let item9 = LabelItem()
- func updateUI(){
- if SportManager.shared.sportType == .walk{
- header.do { v in
- v.text = "健走".l10n
- }
- distanceItem.do { v in
- v.title = SportManager.shared.distanceStr
- }
- item1.do { v in
- v.title = SportManager.shared.durationStr
- v.detail = "时长".l10n
- }
- item2.do { v in
- v.title = SportManager.shared.peisuStr
- v.detail = "平均配速".l10n
- }
- item3.do { v in
- v.title = SportManager.shared.calorieStr
- v.detail = "运动消耗".l10n
- }
- item4.do { v in
- v.title = SportManager.shared.bushuStr
- v.detail = "步数".l10n
- }
- item5.do { v in
- v.title = SportManager.shared.avgBuFuStr
- v.detail = "平均步幅".l10n
- }
- item6.do { v in
- v.title = SportManager.shared.avgBuPinStr
- v.detail = "平均步频".l10n
- }
- item7.do { v in
- v.title = SportManager.shared.upStr
- v.detail = "积累爬升".l10n
- }
- item8.do { v in
- v.title = SportManager.shared.downStr
- v.detail = "积累下降".l10n
- }
-
- }
- else if SportManager.shared.sportType == .run{
- header.do { v in
- v.text = "户外跑步".l10n
- }
- distanceItem.do { v in
- v.title = SportManager.shared.distanceStr
- }
- item1.do { v in
- v.title = SportManager.shared.durationStr
- v.detail = "时长".l10n
- }
- item2.do { v in
- v.title = SportManager.shared.peisuStr
- v.detail = "平均配速".l10n
- }
- item3.do { v in
- v.title = SportManager.shared.calorieStr
- v.detail = "运动消耗".l10n
- }
- item4.do { v in
- v.title = SportManager.shared.bushuStr
- v.detail = "步数".l10n
- }
- item5.do { v in
- v.title = SportManager.shared.avgBuFuStr
- v.detail = "平均步幅".l10n
- }
- item6.do { v in
- v.title = SportManager.shared.avgBuPinStr
- v.detail = "平均步频".l10n
- }
- item7.do { v in
- v.title = SportManager.shared.upStr
- v.detail = "积累爬升".l10n
- }
- item8.do { v in
- v.title = SportManager.shared.downStr
- v.detail = "积累下降".l10n
- }
-
- }
- else if SportManager.shared.sportType == .ride{
- header.do { v in
- v.text = "户外骑行".l10n
- }
- distanceItem.do { v in
- v.title = SportManager.shared.distanceStr
- }
- item1.do { v in
- v.title = SportManager.shared.durationStr
- v.detail = "时长".l10n
- }
- item2.do { v in
- v.title = SportManager.shared.peisuStr
- v.detail = "平均配速".l10n
- }
- item3.do { v in
- v.title = SportManager.shared.calorieStr
- v.detail = "运动消耗".l10n
- }
- item4.do { v in
- v.title = SportManager.shared.bushuStr
- v.detail = "步数".l10n
- }
- item5.do { v in
- v.title = SportManager.shared.avgBuFuStr
- v.detail = "平均步幅".l10n
- }
- item6.do { v in
- v.title = SportManager.shared.avgBuPinStr
- v.detail = "平均步频".l10n
- }
- item7.do { v in
- v.title = SportManager.shared.upStr
- v.detail = "积累爬升".l10n
- }
- item8.do { v in
- v.title = SportManager.shared.downStr
- v.detail = "积累下降".l10n
- }
-
- }
- }
- override func setupViews() {
- backgroundColor = .white
- addSubviews([topIcon,header,distanceItem,item1,item2,item3,item4,item5,item6,item7,item8,item9])
- topIcon.do { v in
- v.backgroundColor = .color(.secondary)
- v.yc.setCornerRadius(12)
- }
- header.do { v in
- v.font = .medium(16)
- v.textColor = .color(.first)
- }
- item9.do { v in
- v.isHidden = true
- }
- updateUI()
- }
-
- override func setupLayout() {
- topIcon.snp.makeConstraints { make in
- make.width.equalTo(42)
- make.height.equalTo(42)
- make.top.equalToSuperview().inset(18)
- make.right.equalToSuperview().inset(18)
- }
- header.snp.makeConstraints { make in
- make.top.leading.equalToSuperview().inset(18)
- }
- distanceItem.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(18)
- make.top.equalToSuperview().inset(50)
-// make.height.equalTo(64)
- }
- item1.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(18)
- make.top.equalToSuperview().inset(130)
- make.height.equalTo(50)
- make.width.equalTo(kScreenWid/3)
- }
- item2.snp.makeConstraints { make in
- make.centerX.equalToSuperview().offset(20)
- make.width.top.height.equalTo(item1)
- }
- item3.snp.makeConstraints { make in
- make.right.equalToSuperview()
- make.width.top.height.equalTo(item1)
- }
- item4.snp.makeConstraints { make in
- make.top.equalToSuperview().inset(200)
- make.width.left.height.equalTo(item1)
- }
- item5.snp.makeConstraints { make in
- make.centerX.equalTo(item2)
- make.width.top.height.equalTo(item4)
- }
- item6.snp.makeConstraints { make in
- make.right.equalToSuperview()
- make.width.height.equalTo(item1)
- make.top.equalTo(item4)
- }
- item7.snp.makeConstraints { make in
- make.top.equalToSuperview().inset(270)
- make.width.left.height.equalTo(item1)
- }
- item8.snp.makeConstraints { make in
- make.centerX.equalTo(item2)
- make.width.top.height.equalTo(item7)
- }
- item9.snp.makeConstraints { make in
- make.right.equalToSuperview()
- make.width.height.equalTo(item1)
- make.top.equalTo(item7)
- }
- }
-
- class LabelItem: BaseView {
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- var title:String = ""{
- didSet{
- titleLabel.text = title
- }
- }
- var detail:String = ""{
- didSet{
- detailLabel.text = detail
- }
- }
-
- override func setupViews() {
- addSubviews([titleLabel,detailLabel])
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .semiBold(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()
- }
- }
- }
- class DistanceItem: BaseView {
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- var title:String = ""{
- didSet{
- titleLabel.text = title
- }
- }
- var detail:String = ""{
- didSet{
- detailLabel.text = detail
- }
- }
-
- override func setupViews() {
- addSubviews([titleLabel,detailLabel])
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .bold(48)
- v.textAlignment = .left
- }
- detailLabel.do { v in
- v.textColor = .color(.first)
- v.font = .bold(20)
- v.textAlignment = .left
- v.text = "公里".l10n
- }
- }
-
- override func setupLayout() {
- titleLabel.snp.makeConstraints { make in
- make.top.equalToSuperview().inset(0)
- make.left.equalToSuperview()
- }
- detailLabel.snp.makeConstraints { make in
- make.bottom.equalTo(titleLabel.snp.bottom).inset(8)
- make.left.equalTo(titleLabel.snp.right).offset(10)
- }
- }
- }
- }
-
-
-
-}
-
+++ /dev/null
-//
-// SportDetailVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/5.
-//
-
-import MAMapKit
-
-class SportDetailVC: BaseVC {
- let scrollView = UIScrollView()
- var mapView:MAMapView!
- let detailView = SportDetailBoard()
- let pace = FeelView()
- let pacePer = FeelView()
- let cadence = FeelView()
- let elevation = FeelView()
- let feel = FeelView()
-
-
- override func setupViews() {
- MapManager.shared.setupSdk()
- navBar.do { v in
- v.title = "运动数据".l10n
- }
-
-
- mapView = MAMapView(frame: .zero)
- mapView.do { v in
- v.delegate = self
- v.showsUserLocation = true
- v.zoomLevel = 16
- v.userTrackingMode = .followWithHeading
- }
- view.addSubview(scrollView)
- scrollView.addSubviews([mapView,detailView,pace,pacePer,cadence,elevation,feel])
-
- scrollView.do { v in
-
- }
- detailView.do { v in
- v.yc.setCorners(withRoundedRect: CGRect(x: 0, y: 0, width: kScreenWid, height: 460), roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 20, height: 20))
- }
- }
- override func setupLayout() {
- scrollView.snp.makeConstraints { make in
- make.top.equalToSuperview().inset(kNavBtm)
- make.left.equalToSuperview()
- make.width.equalTo(kScreenWid)
- make.height.equalTo(kScreenHei - kNavBtm)
- }
- mapView.snp.makeConstraints { make in
- make.width.equalTo(kScreenWid)
- make.left.top.equalToSuperview()
- make.height.equalTo(300)
- }
- detailView.snp.makeConstraints { make in
- make.left.equalToSuperview()
- make.width.equalTo(kScreenWid)
- make.top.equalTo(mapView.snp.bottom)
- make.height.equalTo(342)
- }
- pace.snp.makeConstraints { make in
- make.left.width.equalTo(detailView)
- make.top.equalTo(detailView.snp.bottom)
- make.height.equalTo(100)
- }
- pacePer.snp.makeConstraints { make in
- make.left.width.equalTo(detailView)
- make.top.equalTo(pace.snp.bottom)
- make.height.equalTo(100)
- }
- cadence.snp.makeConstraints { make in
- make.left.width.equalTo(detailView)
- make.top.equalTo(pacePer.snp.bottom)
- make.height.equalTo(100)
- }
- elevation.snp.makeConstraints { make in
- make.left.width.equalTo(detailView)
- make.top.equalTo(cadence.snp.bottom)
- make.height.equalTo(100)
- }
- feel.snp.makeConstraints { make in
- make.left.width.equalTo(detailView)
- make.top.equalTo(elevation.snp.bottom)
- make.height.equalTo(100)
- make.bottom.equalToSuperview()
- }
- }
- override func setupData() {
-
- }
-}
-
-extension SportDetailVC:MAMapViewDelegate{
- func mapViewRequireLocationAuth(_ locationManager: CLLocationManager!) {
- // locationManager.requestAlwaysAuthorization()
- }
-}
+++ /dev/null
-//
-// stepRateView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/10.
-//
-
+++ /dev/null
-//
-// strideLengthView.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/10.
-//
-
+++ /dev/null
-//
-// Untitled.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/3.
-//
-
-import UIKit
-
-extension SportingVC{
- class DetailBoard: BaseView {
- let topIcon = UIImageView()
- let header = headerItem()
- let distanceItem = DistanceItem()
- let item1 = LabelItem()
- let item2 = LabelItem()
- let item3 = LabelItem()
- let item4 = LabelItem()
- let btnView = ButtonView()
- func updateUI(){
- if SportManager.shared.sportType == .walk{
- header.do { v in
- v.title = "健走".l10n
- }
- distanceItem.do { v in
- v.title = SportManager.shared.distanceStr
- }
- item1.do { v in
- v.title = SportManager.shared.durationStr
- v.detail = "时长".l10n
- }
- item2.do { v in
- v.title = SportManager.shared.peisuStr
- v.detail = "配速".l10n
- }
- item3.do { v in
- v.title = SportManager.shared.calorieStr
- v.detail = "卡路里".l10n
- }
- item4.do { v in
- v.title = SportManager.shared.bushuStr
- v.detail = "步数".l10n
- }
- }
- else if SportManager.shared.sportType == .run{
- header.do { v in
- v.title = "户外跑步".l10n
- }
- distanceItem.do { v in
- v.title = SportManager.shared.distanceStr
- }
- item1.do { v in
- v.title = SportManager.shared.durationStr
- v.detail = "时长".l10n
- }
- item2.do { v in
- v.title = SportManager.shared.peisuStr
- v.detail = "配速".l10n
- }
- item3.do { v in
- v.title = SportManager.shared.calorieStr
- v.detail = "卡路里".l10n
- }
- item4.do { v in
- v.title = SportManager.shared.bushuStr
- v.detail = "步数".l10n
- }
- }
- else if SportManager.shared.sportType == .ride{
- header.do { v in
- v.title = "户外骑行".l10n
- }
- distanceItem.do { v in
- v.title = SportManager.shared.distanceStr
- }
- item1.do { v in
- v.title = SportManager.shared.durationStr
- v.detail = "时长".l10n
- }
- item2.do { v in
- v.title = SportManager.shared.speedStr
- v.detail = "时速".l10n
- }
- item3.do { v in
- v.title = SportManager.shared.calorieStr
- v.detail = "卡路里".l10n
- }
- item4.do { v in
-
- }
- }
- }
- override func setupViews() {
- backgroundColor = .white
- addSubviews([topIcon,header,distanceItem,item1,item2,item3,item4,btnView])
- topIcon.do { v in
- v.backgroundColor = .color(.secondary)
- v.yc.setCornerRadius(2)
- }
- updateUI()
- }
-
- override func setupLayout() {
- topIcon.snp.makeConstraints { make in
- make.width.equalTo(50)
- make.height.equalTo(4)
- make.top.equalToSuperview().inset(6)
- make.centerX.equalToSuperview()
- }
- header.snp.makeConstraints { make in
- make.top.equalToSuperview().inset(28)
- make.left.right.equalToSuperview()
- make.height.equalTo(25)
- }
- distanceItem.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(18)
- make.top.equalToSuperview().inset(100)
- make.height.equalTo(50)
- }
- item1.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(18)
- make.top.equalToSuperview().inset(180)
- make.height.equalTo(50)
- }
- item2.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(kScreenWid/2 + 18)
- make.top.equalTo(item1.snp.top)
- make.height.equalTo(50)
- }
- item3.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(18)
- make.top.equalToSuperview().inset(250)
- make.height.equalTo(50)
- }
- item4.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(kScreenWid/2 + 18)
- make.top.equalTo(item3.snp.top)
- make.height.equalTo(50)
- }
- btnView.snp.makeConstraints { make in
- make.left.right.bottom.equalToSuperview()
- make.height.equalTo(140)
- }
- }
-
-
- class ButtonView: BaseView {
- let okBtn = UIButton(type: .custom)
- let lockBtn = UIButton(type: .custom)
- let setBtn = UIButton(type: .custom)
-
- let lockedBtn = UIButton(type: .custom)
- let stopBtn = UIButton(type: .custom)
- let continueBtn = UIButton(type: .custom)
-
- override func setupViews() {
-// backgroundColor = .red
- addSubviews([okBtn,lockBtn,setBtn,lockedBtn,stopBtn,continueBtn])
- okBtn.do { v in
- v.setImage(UIImage(named: "btn_pause"), for: .normal)
- v.addTarget(self, action: #selector(okAction), for: .touchUpInside)
- }
- lockBtn.do { v in
- v.setImage(UIImage(named: "btn_lock"), for: .normal)
- v.addTarget(self, action: #selector(lockAction), for: .touchUpInside)
- }
- setBtn.do { v in
- v.setImage(UIImage(named: "btn_set"), for: .normal)
- v.addTarget(self, action: #selector(setAction), for: .touchUpInside)
- }
-
- lockedBtn.do { v in
- v.setImage(UIImage(named: "btn_locked"), for: .normal)
- v.addTarget(self, action: #selector(lockedAction), for: .touchUpInside)
- v.isHidden = true
- }
- stopBtn.do { v in
- v.setImage(UIImage(named: "btn_stop"), for: .normal)
- v.addTarget(self, action: #selector(stopAction), for: .touchUpInside)
- v.isHidden = true
- }
- continueBtn.do { v in
- v.setImage(UIImage(named: "btn_continue"), for: .normal)
- v.addTarget(self, action: #selector(continueAction), for: .touchUpInside)
- v.isHidden = true
- }
- }
-
- override func setupLayout() {
- okBtn.snp.makeConstraints { make in
- make.centerX.equalToSuperview()
- make.bottom.equalToSuperview().inset(24)
- make.size.equalTo(90)
- }
- lockBtn.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(46)
- make.centerY.equalTo(okBtn)
- make.size.equalTo(50)
- }
- setBtn.snp.makeConstraints { make in
- make.right.equalToSuperview().inset(46)
- make.centerY.equalTo(okBtn)
- make.size.equalTo(50)
- }
-
- lockedBtn.snp.makeConstraints { make in
- make.centerX.equalToSuperview()
- make.bottom.equalToSuperview().inset(24)
- make.size.equalTo(90)
- }
- continueBtn.snp.makeConstraints { make in
- make.left.equalToSuperview().inset(55)
- make.bottom.equalToSuperview().inset(24)
- make.size.equalTo(90)
- }
- stopBtn.snp.makeConstraints { make in
- make.right.equalToSuperview().inset(55)
- make.bottom.equalToSuperview().inset(24)
- make.size.equalTo(90)
- }
- }
- @objc func okAction(){
- SportManager.shared.pause()
- continueBtn.isHidden = false
- stopBtn.isHidden = false
-
- okBtn.isHidden = true
- setBtn.isHidden = true
- lockBtn.isHidden = true
- }
- @objc func lockAction(){
- okBtn.isHidden = true
- setBtn.isHidden = true
- lockBtn.isHidden = true
- lockedBtn.isHidden = false
- }
- @objc func setAction(){
-
- }
- @objc func lockedAction(){
- okBtn.isHidden = false
- setBtn.isHidden = false
- lockBtn.isHidden = false
- lockedBtn.isHidden = true
- }
- @objc func stopAction(){
- SportManager.shared.stop()
- App.shared.goToPage(SportDetailVC())
- }
- @objc func continueAction(){
- SportManager.shared.resume()
- okBtn.isHidden = false
- setBtn.isHidden = false
- lockBtn.isHidden = false
-
- continueBtn.isHidden = true
- stopBtn.isHidden = true
- }
- }
- class headerItem: BaseView {
- let deviceView = DeviceStateView()
- let titleLabel = UILabel()
-
- var title:String = ""{
- didSet{
- titleLabel.text = title
- }
- }
- override func setupViews() {
- addSubviews([titleLabel,deviceView])
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .bold(16)
- v.textAlignment = .left
- }
- }
-
- override func setupLayout() {
- titleLabel.snp.makeConstraints { make in
- make.centerY.equalToSuperview().inset(0)
- make.left.equalToSuperview().inset(18)
- }
- deviceView.snp.makeConstraints { make in
- make.height.equalTo(26)
- make.left.equalToSuperview().inset(94)
- make.centerY.equalToSuperview()
- }
- }
- }
-
-
- class LabelItem: BaseView {
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- var title:String = ""{
- didSet{
- titleLabel.text = title
- }
- }
- var detail:String = ""{
- didSet{
- detailLabel.text = detail
- }
- }
-
- 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()
- }
- }
- }
- class DistanceItem: BaseView {
- let detailLabel = UILabel()
- let titleLabel = UILabel()
-
- var title:String = ""{
- didSet{
- titleLabel.text = title
- }
- }
- var detail:String = ""{
- didSet{
- detailLabel.text = detail
- }
- }
-
- override func setupViews() {
- addSubviews([titleLabel,detailLabel])
- titleLabel.do { v in
- v.textColor = .color(.first)
- v.font = .bold(48)
- v.textAlignment = .left
- }
- detailLabel.do { v in
- v.textColor = .color(.first)
- v.font = .bold(20)
- v.textAlignment = .left
- v.text = "公里".l10n
- }
- }
-
- override func setupLayout() {
- titleLabel.snp.makeConstraints { make in
- make.top.equalToSuperview().inset(0)
- make.left.equalToSuperview()
- }
- detailLabel.snp.makeConstraints { make in
- make.bottom.equalToSuperview().inset(0)
- make.left.equalTo(titleLabel.snp.right).offset(10)
- }
- }
- }
- }
-
-
-
-}
+++ /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()
-
- func updateUI(){
- distanceItem.titleLabel.text = SportManager.shared.distanceStr
- durationItem.titleLabel.text = SportManager.shared.durationStr
- }
-
- 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(.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 MAMapKit
-
-class SportingVC: BaseVC {
- var line: MAPolyline!
- var mapView:MAMapView!
- let simpleView = SimpleBoard()
- let detailView = DetailBoard()
-
- var trackOverlay: MAPolyline?
-
- override func setupViews() {
- mapView = MAMapView(frame: .zero)
- mapView.delegate = self
- mapView.showsUserLocation = true
- mapView.zoomLevel = 16
- mapView.userTrackingMode = .followWithHeading
-// mapView.desiredAccuracy = kCLLocationAccuracyBest
- mapView.desiredAccuracy = kCLLocationAccuracyKilometer
- mapView.distanceFilter = 0.001
-
-
- view.addSubviews([mapView,simpleView,detailView])
- mapView.do { v in
-
- }
- simpleView.do { v in
- v.yc.setCorners(withRoundedRect: CGRect(x: 0, y: 0, width: kScreenWid, height: 100), roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 20, height: 20))
- v.yc.addTap(target: self, action: #selector(simpleTapAction))
- }
- detailView.do { v in
- v.yc.setCorners(withRoundedRect: CGRect(x: 0, y: 0, width: kScreenWid, height: 460), roundingCorners: [.topLeft,.topRight], cornerRadii: CGSize(width: 20, height: 20))
- 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).offset(20)
- }
- }
- override func setupData() {
- NotificationManager.add(self, selector: #selector(updateLocation(_:)), forName: .updateLocation)
- SportManager.shared.start()
- }
- @objc func updateLocation(_ noti:Notification){
- if let userLocation = mapView.userLocation {
- let latitude = userLocation.location.coordinate.latitude
- let longitude = userLocation.location.coordinate.longitude
- let altitude = userLocation.location.altitude
- let point = TrackPoint(latitude: latitude, longitude: longitude, altitude: altitude)
-
-
- SportManager.shared.pointList.append(point)
- updateUI()
- }
-
- simpleView.updateUI()
- detailView.updateUI()
- }
- @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).offset(20)
- }
- }
- func showDetail(){
- mapView.snp.remakeConstraints { make in
- make.left.right.top.equalToSuperview()
- make.bottom.equalTo(detailView.snp.top).offset(20)
- }
- }
- func updateUI(){
- // 移除旧轨迹
- if let oldTrackOverlay = trackOverlay {
- mapView.remove(oldTrackOverlay)
- }
-
- var trackCoordinates = [CLLocationCoordinate2D]()
- for point in SportManager.shared.pointList {
- let coordinate = CLLocationCoordinate2D(latitude: point.latitude, longitude: point.longitude)
- trackCoordinates.append(coordinate)
- }
-
-
-
- // 只有当有足够的点时才绘制轨迹线
- if trackCoordinates.count >= 2 {
- let coordinatesPointer = UnsafeMutablePointer<CLLocationCoordinate2D>.allocate(capacity: trackCoordinates.count)
- coordinatesPointer.initialize(from: trackCoordinates, count: trackCoordinates.count)
-
- // 创建新的轨迹线
- let newTrackOverlay = MAPolyline(coordinates: coordinatesPointer, count: UInt(trackCoordinates.count))
-
- // 添加到地图
- mapView.add(newTrackOverlay)
-
- // 保存引用
- trackOverlay = newTrackOverlay
-
-// // 调整地图视野以适应轨迹
-// mapView.showOverlays([newTrackOverlay], edgePadding: UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50), animated: true)
- }
- }
-}
-
-extension SportingVC:MAMapViewDelegate{
- func mapViewRequireLocationAuth(_ locationManager: CLLocationManager!) {
- // locationManager.requestAlwaysAuthorization()
- }
- func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! {
-
- if (overlay.isKind(of: MAPolyline.self))
- {
- let renderer = MAPolylineRenderer(polyline: overlay as! MAPolyline)
- renderer?.lineWidth = 8.0
-
-
- return renderer;
- }
-
- return nil;
- }
-
- func mapView(_ mapView: MAMapView!, didUpdate userLocation: MAUserLocation!, updatingLocation: Bool) {
- Logger.debug(userLocation.location)
-
-// let latitude = userLocation.location.coordinate.latitude
-// let longitude = userLocation.location.coordinate.longitude
-// let altitude = userLocation.location.altitude
-// let point = TrackPoint(latitude: latitude, longitude: longitude, altitude: altitude)
-//
-//
-// SportManager.shared.pointList.append(point)
-// updateUI()
- }
-}
+++ /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()
- }
-
- }
-}
+++ /dev/null
-//
-// Untitled.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/26.
-//
-
-
-import AVFoundation
-
-class IBSpeaker: NSObject, AVSpeechSynthesizerDelegate {
- static let shared = IBSpeaker()
- // MARK: - Properties
- private let synthesizer = AVSpeechSynthesizer()
- private var textBuffer: String = "" // 用于存储待播放的文字
- private var isPlaying: Bool = false // 是否正在播放
-
-
- // MARK: - Initializer
- override init() {
- super.init()
- synthesizer.delegate = self
- }
-
- // MARK: - Public Methods
-
- /// 添加文字并开始播放
- func appendText(_ text: String) {
- textBuffer += text
-
- // 如果没有正在播放,则开始播放
- if !isPlaying {
- playNextChunk()
- }
- }
-
- /// 停止播放并清空缓冲区
- func stop() {
- synthesizer.stopSpeaking(at: .immediate)
- textBuffer = ""
- isPlaying = false
- }
-
- // MARK: - Private Methods
-
- /// 播放缓冲区中的下一段文字
- private func playNextChunk() {
- guard !textBuffer.isEmpty else {
- isPlaying = false
- return
- }
-
- // 每次播放一段文字(可以根据需要调整)
- let chunkSize = textBuffer.count // 每次播放的字符数
- let endIndex = textBuffer.index(textBuffer.startIndex, offsetBy: min(chunkSize, textBuffer.count))
- let chunk = String(textBuffer[..<endIndex])
-
- // 移除已播放的文字
- textBuffer.removeSubrange(..<endIndex)
-
- // 创建语音并播放
- let utterance = AVSpeechUtterance(string: chunk)
- utterance.voice = AVSpeechSynthesisVoice(language: "zh-CN") // 设置语言为中文
- utterance.rate = AVSpeechUtteranceDefaultSpeechRate // 设置语速
- // utterance.pitchMultiplier = 1.0 // 设置音调
-
- synthesizer.speak(utterance)
- isPlaying = true
- }
-
- // MARK: - AVSpeechSynthesizerDelegate
-
- func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
- print("语音播放完成")
- // 当前段落播放完成后,继续播放下一段
- playNextChunk()
- }
-
- func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {
- print("语音播放取消")
- isPlaying = false
- }
-
- func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, willSpeakRangeOfSpeechString characterRange: NSRange, utterance: AVSpeechUtterance) {
- print("正在播放: \(characterRange)")
- }
-}
+++ /dev/null
-//
-// MapManager.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/21.
-//
-import MAMapKit
-import UIKit
-
-class MapManager {
- static let shared = MapManager()
-
- func setupSdk(){
- MAMapView.updatePrivacyAgree(AMapPrivacyAgreeStatus.didAgree)
- AMapServices.shared().apiKey = "57aebc5a63fa3ccb8cb81ae0cab649d1"
-// //判断是否是首次启动
-// if !UserDefaults.standard.bool(forKey: "agreeStatus") {
-// //添加隐私合规弹窗
-// self.addAlertController()
-// //更新App是否显示隐私弹窗的状态,隐私弹窗是否包含高德SDK隐私协议内容的状态. since 8.1.0
-// MAMapView.updatePrivacyShow(AMapPrivacyShowStatus.didShow, privacyInfo: AMapPrivacyInfoStatus.didContain)
-// }
- }
-
-
- func addAlertController(){
-
- let paragraphStyle : NSMutableParagraphStyle = NSMutableParagraphStyle.init()
- paragraphStyle.alignment = NSTextAlignment.left
-
- let message : NSMutableAttributedString = NSMutableAttributedString.init(string: "\n亲,感谢您对XXX一直以来的信任!我们依据最新的监管要求更新了XXX《隐私权政策》,特向您说明如下\n1.为向您提供交易相关基本功能,我们会收集、使用必要的信息;\n2.基于您的明示授权,我们可能会获取您的位置(为您提供附近的商品、店铺及优惠资讯等)等信息,您有权拒绝或取消授权;\n3.我们会采取业界先进的安全措施保护您的信息安全;\n4.未经您同意,我们不会从第三方处获取、共享或向提供您的信息;", attributes: [NSAttributedString.Key.paragraphStyle:paragraphStyle])
-
- message.setAttributes([NSAttributedString.Key.foregroundColor:UIColor.blue], range: message.mutableString.range(of: "《隐私权政策》"))
-
- let alert : UIAlertController = UIAlertController.init(title: "温馨提示(隐私合规示例)", message: "", preferredStyle: UIAlertController.Style.alert)
-
- alert.setValue(message, forKey: "attributedMessage")
-
- let conform : UIAlertAction = UIAlertAction.init(title: "同意", style: UIAlertAction.Style.default) { UIAlertAction in
- UserDefaults.standard.set(true, forKey: "agreeStatus")
- UserDefaults.standard.synchronize()
- //更新用户授权高德SDK隐私协议状态. since 8.1.0
- MAMapView.updatePrivacyAgree(AMapPrivacyAgreeStatus.didAgree)
- }
-
- let cancel : UIAlertAction = UIAlertAction.init(title: "不同意", style: UIAlertAction.Style.default) { UIAlertAction in
- UserDefaults.standard.set(false, forKey: "agreeStatus")
- UserDefaults.standard.synchronize()
- //更新用户授权高德SDK隐私协议状态. since 8.1.0
- MAMapView.updatePrivacyAgree(AMapPrivacyAgreeStatus.notAgree)
- }
-
- alert.addAction(conform)
- alert.addAction(cancel)
-
- App.shared.window?.rootViewController?.present(alert, animated: true, completion: nil)
- }
-}
+++ /dev/null
-import Foundation
-
-class SportCalculateUtil {
- // 地球半径(米)
- private static let EARTH_RADIUS: Double = 6378137.0
- // 保留2位小数
- private static let df: NumberFormatter = {
- let formatter = NumberFormatter()
- formatter.numberStyle = .decimal
- formatter.minimumFractionDigits = 2
- formatter.maximumFractionDigits = 2
- return formatter
- }()
- // 保留1位小数(步幅、海拔)
- private static let df1: NumberFormatter = {
- let formatter = NumberFormatter()
- formatter.numberStyle = .decimal
- formatter.minimumFractionDigits = 1
- formatter.maximumFractionDigits = 1
- return formatter
- }()
-
-
-
- // 2. 计算平均时速:总里程(km) ÷ 总时长(h)
- static func calculateAverageSpeed(totalKm: Double, totalTimeSec: Int) -> Double {
- guard totalKm > 0 && totalTimeSec > 0 else { return 0.0 }
- let totalHour = Double(totalTimeSec) / 3600.0 // 秒转小时
- let avgSpeed = totalKm / totalHour
- return Double((df1.string(from: NSNumber(value: avgSpeed)) ?? "0.0")) ?? 0.0
- }
-
- // ====================== 1. 总里程(同之前,改用TrackPoint) ======================
- static func calculateTotalDistanceMeter(pointList: [TrackPoint]?) -> Double {
- guard let pointList = pointList, pointList.count >= 2 else { return 0.0 }
- var total: Double = 0
- for i in 0..<pointList.count - 1 {
- let p1 = pointList[i]
- let p2 = pointList[i + 1]
- total += calculateDistanceBetweenTwoPoints(lat1: p1.latitude, lng1: p1.longitude, lat2: p2.latitude, lng2: p2.longitude)
- }
- return total // 单位:米
- }
-
- /**
- * 无传感器估算步数(核心方法)
- * @param totalDistanceMeter 总里程(米)
- * @param stride 平均步幅(米/步)
- * @return 估算步数(取整)
- */
- static func estimateStepCount(totalDistanceMeter: Double, stride: Float) -> Int {
- guard totalDistanceMeter > 0 && stride > 0 else { return 0 }
- // 总里程 ÷ 步幅 = 步数(四舍五入取整)
- return Int(round(totalDistanceMeter / Double(stride)))
- }
-
- static func calculateTotalDistanceKm(pointList: [TrackPoint]?) -> Double {
- let meter = calculateTotalDistanceMeter(pointList: pointList)
- return Double((df.string(from: NSNumber(value: meter / 1000)) ?? "0.00")) ?? 0.0
- }
-
- // 两点球面距离(米)
- private static func calculateDistanceBetweenTwoPoints(lat1: Double, lng1: Double, lat2: Double, lng2: Double) -> Double {
- let radLat1 = lat1 * Double.pi / 180.0
- let radLng1 = lng1 * Double.pi / 180.0
- let radLat2 = lat2 * Double.pi / 180.0
- let radLng2 = lng2 * Double.pi / 180.0
- let dLat = radLat2 - radLat1
- let dLng = radLng2 - radLng1
-
- let a = sin(dLat / 2) * sin(dLat / 2) +
- cos(radLat1) * cos(radLat2) *
- sin(dLng / 2) * sin(dLng / 2)
- let c = 2 * atan2(sqrt(a), sqrt(1 - a))
- return EARTH_RADIUS * c
- }
-
- // ====================== 2. 配速(分/公里) ======================
- static func calculatePace(totalTimeSec: Int, totalDistanceKm: Double) -> String {
- guard totalDistanceKm > 0 && totalTimeSec > 0 else { return "--'--''" }
- let secPerKm = Double(totalTimeSec) / totalDistanceKm
- let min = Int(secPerKm / 60)
- let sec = Int(secPerKm.truncatingRemainder(dividingBy: 60))
- return String(format: "%d'%02d''", min, sec)
- }
-
- static func calculatePaceNum(totalTimeSec: Int, totalDistanceKm: Double) -> Double {
- guard totalDistanceKm > 0 && totalTimeSec > 0 else { return 0 }
- return Double(totalTimeSec) / totalDistanceKm
- }
-
- // ====================== 3. 卡路里 ======================
- static func calculateCalorie(totalDistanceKm: Double, weightKg: Float, sportType: Int) -> Int {
- guard totalDistanceKm > 0 && weightKg > 0 else { return 0 }
- let coef: Double
- switch sportType {
- case 1: coef = 1.0; break // 跑
- case 2: coef = 0.8; break // 慢跑
- default: coef = 0.5; break // 走
- }
- return Int(round(Double(weightKg) * totalDistanceKm * coef))
- }
-
- // ====================== 4. 步频(步/分钟) ======================
- static func calculateCadence(stepCount: Int, totalTimeSec: Int) -> Double {
- guard stepCount > 0 && totalTimeSec > 0 else { return 0 }
- let min = Double(totalTimeSec) / 60.0
- let cadence = Double(stepCount) / min
- return Double((df1.string(from: NSNumber(value: cadence)) ?? "0.0")) ?? 0.0
- }
-
- // ====================== 5. 步幅(米/步) ======================
- static func calculateStrideLength(totalDistanceMeter: Double, stepCount: Int) -> Double {
- guard totalDistanceMeter > 0 && stepCount > 0 else { return 0 }
- let stride = totalDistanceMeter / Double(stepCount)
- return Double((df1.string(from: NSNumber(value: stride)) ?? "0.0")) ?? 0.0
- }
-
- // ====================== 6. 海拔变化(累计上升、累计下降、净变化) ======================
- static func calculateAltitudeChange(pointList: [TrackPoint]?) -> AltitudeResult {
- let res = AltitudeResult()
- guard let pointList = pointList,!pointList.isEmpty else { return res }
-
- let firstAlt = pointList[0].altitude
- let lastAlt = pointList[pointList.count - 1].altitude
- res.netChange = lastAlt - firstAlt
-
- var up: Double = 0, down: Double = 0
- for i in 1..<pointList.count {
- let prev = pointList[i - 1].altitude
- let curr = pointList[i].altitude
- let delta = curr - prev
- // 过滤微小抖动,减少误差(可调整阈值:0.5~1米)
- if delta > 0.5 {
- up += delta
- } else if delta < -0.5 {
- down -= delta
- }
- }
- res.totalUp = Double((df1.string(from: NSNumber(value: up)) ?? "0.0")) ?? 0.0
- res.totalDown = Double((df1.string(from: NSNumber(value: down)) ?? "0.0")) ?? 0.0
- res.netChange = Double((df1.string(from: NSNumber(value: res.netChange)) ?? "0.0")) ?? 0.0
- return res
- }
-
-
-}
-
-
-
-// 存储轨迹点,包含经纬度 + 海拔
-class TrackPoint {
- var latitude: Double
- var longitude: Double
- var altitude: Double // 海拔(米)
-
- init(latitude: Double, longitude: Double, altitude: Double) {
- self.latitude = latitude
- self.longitude = longitude
- self.altitude = altitude
- }
- }
-// 海拔结果实体
-class AltitudeResult {
- var totalUp: Double = 0.0 // 累计上升(米)
- var totalDown: Double = 0.0 // 累计下降(米)
- var netChange: Double = 0.0 // 净变化(米)
- }
+++ /dev/null
-//
-// SportManager.swift
-// ShenYin
-//
-// Created by liangshi on 2026/2/10.
-//
-
-class SportManager {
- static let shared = SportManager()
- var sportType = SportType.ride
-
- var pointList:[TrackPoint] = [TrackPoint]()
-
- var timer:Timer?
- /// 运动时间
- var duration = 0
- /// 运动距离
- var distance = 0.0
- /// 当前配速
- var peisu = 0.0
- /// 步数
- var bushu = 0
-
- private var hasPlayed100M = false
- private var hasPlayed500M = false
- private var hasPlayed1000M = false
-
- func start(){
- duration = 0
- if let t = timer,t.isValid {
- t.invalidate()
- }
- timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
- }
- func stop(){
- if let t = timer,t.isValid {
- t.invalidate()
- }
- SportManager.shared.play(text: "运动已结束")
- }
- func pause(){
- if let t = timer,t.isValid {
- t.invalidate()
- }
- SportManager.shared.play(text: "运动已暂停")
- }
- func resume(){
- if let t = timer,t.isValid {
- t.invalidate()
- }
- timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
- }
-
- @objc func timerAction(){
- self.distance = SportCalculateUtil.calculateTotalDistanceMeter(pointList: pointList)
- if self.distance == 0 {
- self.peisu = 0
- self.bushu = 0
- }
- else{
- self.peisu = (Double(duration)/60.0) / (Double(distance) / 1000.0)
- self.bushu = Int(distance/0.6)
- }
-
- duration += 1
- NotificationManager.post(type: .updateLocation, objtect: nil)
-
- if self.distance > 100.0 && hasPlayed100M == false{
- hasPlayed100M = true
- SportManager.shared.play(text: "您已经跑了100米,继续加油")
- }
- else if self.distance > 500.0 && hasPlayed500M == false{
- hasPlayed500M = true
- SportManager.shared.play(text: "您已经跑了500米,继续加油")
- }
- else if self.distance > 1000.0 && hasPlayed1000M == false {
- hasPlayed1000M = true
- SportManager.shared.play(text: "您已经跑了1000米,继续加油")
- }
- }
-
- var durationStr:String{
- return YLToos.formatSeconds(duration)
- }
- var distanceStr:String {
- return String(format: "%.2f", distance/1000.0)
- }
- var peisuStr:String {
- let minutes = Int(peisu)
- let seconds = Int(peisu.truncatingRemainder(dividingBy: 1)*60)
- return String(format: "%d'%02d''", minutes, seconds)
- }
- var calorieStr:String {
- let value = SportCalculateUtil.calculateCalorie(totalDistanceKm: distance, weightKg: 50, sportType: 1)
- return "\(value)"
- }
- var bushuStr:String {
- return "\(bushu)"
- }
- var speedStr:String {
- let value = distance/Double(duration)
- return String(format: "%.1f", value)
- }
- var avgBuFuStr:String {
- let value = distance/Double(bushu)
- return String(format: "%.1f", value)
- }
- var avgBuPinStr:String {
- let bupin = Double(bushu)/(Double(duration)/60.0)
- return "\(Int(bupin))"
- }
- var upStr:String {
- let value = SportCalculateUtil.calculateAltitudeChange(pointList: pointList)
- return String(format: "%.1f", value.totalUp)
- }
- var downStr:String {
- let value = SportCalculateUtil.calculateAltitudeChange(pointList: pointList)
- return String(format: "%.1f", value.totalDown)
- }
-}
-extension SportManager{
- func play(text:String ){
- IBSpeaker.shared.appendText(text)
- }
-}
-
+++ /dev/null
-//
-// SportHomeVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/20.
-//
-
-import JXSegmentedView
-
-
-enum SportHomeType{
- case sport
- case record
- case translate
- case music
-
- var name:String{
- switch self {
- case .sport:
- return "运动"
- case .record:
- return "录音"
- case .translate:
- return "翻译"
- case .music:
- return "音乐"
- }
- }
- static var all:[SportHomeType] = [.sport,.record,.translate,.music]
-}
-
-class SportHomeVC: BaseVC {
- let icon = UIImageView()
- private let segmentedDataSource = JXSegmentedTitleDataSource()
- private let segmentedView = JXSegmentedView()
- private lazy var listContainerView: JXSegmentedListContainerView! = {
- let view = JXSegmentedListContainerView(dataSource: self, type: .scrollView)
- return view
- }()
-
- var list:[SportHomeType] = SportHomeType.all
- override func viewDidLoad() {
- super.viewDidLoad()
-
- // AudioPlayView.shared.show()
- self.view.addSubview(AudioPlayView.shared)
- MapManager.shared.setupSdk()
- }
-
- override func setupLayout(){
- icon.snp.makeConstraints { make in
- make.size.equalTo(32)
- make.bottom.equalToSuperview().inset(10)
- make.centerX.equalToSuperview()
- }
- 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()
- }
- }
- override func setupViews(){
- icon.do { v in
- v.image = UIImage(named: "sport_ai")
- }
- navBar.addSubview(icon)
- view.addSubview(segmentedView)
- view.addSubview(listContainerView)
-
- 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(.theme)
- segmentedView.indicators = [indicator]
-
- v.dataSource = segmentedDataSource
- v.listContainer = listContainerView
- }
- }
-}
-
-extension SportHomeVC: JXSegmentedListContainerViewListDelegate {
- func listView() -> UIView {
- return view
- }
-}
-
-extension SportHomeVC: 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 .sport:
- return SportRootView()
- case .record:
- return RecordRootView()
- case .translate:
- return TranslateRootView()
- case .music:
- return MusicRootView()
- }
-
- }
-}
+++ /dev/null
-//
-// TranslateVC.swift
-// ShenYin
-//
-// Created by liangshi on 2026/1/20.
-//
-
-import UIKit
-import JXSegmentedView
-
-class TranslateRootView: BaseView{
- let content = SprotRocrodView()
-
- override func setupViews() {
- addSubviews([content])
- content.do { v in
- v.header.titleLabel.text = "翻译".l10n
- v.item1.titleLabel.text = "对话翻译".l10n
- v.item1.icon.image = UIImage(named: "sport_record")
- v.item2.titleLabel.text = "同传听译".l10n
- v.item2.icon.image = UIImage(named: "sport_call")
- v.header.yc.addTap(target: self, action: #selector(historyAction))
- v.item1.yc.addTap(target: self, action: #selector(dialogTranslateAction))
- v.item2.yc.addTap(target: self, action: #selector(tctyAction))
- }
- }
-
- override func setupLayout() {
- content.snp.makeConstraints { make in
- make.left.right.top.equalToSuperview().inset(18)
- make.height.equalTo(209)
- }
- }
- @objc func historyAction(){
- App.shared.goToPage(HistoryRecordVC())
- }
- @objc func dialogTranslateAction(){
- CCPage.gotoDialogTranslate()
- }
- @objc func tctyAction(){
- CCPage.gotoTcty()
- }
-}
-
-extension TranslateRootView: JXSegmentedListContainerViewListDelegate {
- func listView() -> UIView {
- return self
- }
-}
v.text = "保存录音".l10n
}
textFiledBg.do { v in
- v.yc.setBorder(width: 2, color: .color(.theme), radius: 10)
+ if CCDevice.isJoy{
+ v.yc.setBorder(width: 2, color: .color(.theme), radius: 10)
+ }
+ else{
+ v.backgroundColor = .rgb(0x3E3E3E)
+ v.yc.setCornerRadius(10)
+ }
}
textFiled.do { v in
okButton.do { (v) in
v.setTitle("确定".l10n, for: .normal)
v.titleLabel?.font = .bold(16)
- v.setTitleColor(.white, for: .normal)
- v.backgroundColor = UIColor.color(.theme)
+ if CCDevice.isJoy{
+ v.setTitleColor(.white, for: .normal)
+ v.backgroundColor = UIColor.color(.theme)
+ }
+ else{
+ v.setTitleColor(.rgb(0x121212), for: .normal)
+ v.backgroundColor = UIColor.white
+ }
v.addTarget(self, action: #selector(okButtonAction), for: .touchUpInside)
v.yc.setCornerRadius(12)
else{
switch self {
case .dialog:
- return "- 情景示例 -\n张张靠近手机讲中文,对方耳机播放英语".l10n
+ return "- 情景示例 -\n张张靠近手机讲中文,对方眼镜播放英语".l10n
case .chinese2english:
return "- 情景示例 -\n张张戴一只耳机讲中文,双方耳机播放英文翻译 Lucy戴一只耳机讲英文,双方耳机播报中文翻译".l10n
case .tongchuan:
v.numberOfLines = 0
}
actionbtn.do { v in
- v.backgroundColor = .color(.theme)
+ if CCDevice.isJoy{
+ v.backgroundColor = .color(.theme)
+ v.setTitleColor(.white, for: .normal)
+ }
+ else{
+ v.backgroundColor = .white
+ v.setTitleColor(.rgb(0x121212), for: .normal)
+ }
+
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
"设备":"",
"已连接" : "",
"未连接" : "",
+ "添加新设备":"",
"现场录音" : "",
"随时随地,一键开录" : "",
"手机靠近音源,两人各佩戴一只耳机,双方耳机中播放目标语言" : "",
"手机靠近音源收音,佩戴耳机收听译文" : "",
"- 情景示例 -\n张张靠近手机讲中文,对方耳机播放英语" : "",
+ "- 情景示例 -\n张张靠近手机讲中文,对方眼镜播放英语":"",
"- 情景示例 -\n张张戴一只耳机讲中文,双方耳机播放英文翻译 Lucy戴一只耳机讲英文,双方耳机播报中文翻译" : "",
"- 情景示例 -\nLisa对着手机讲英语,小徐耳机中播放中文" : "",
"开始体验" : "",
"左耳机响铃":"",
"右耳机响铃":"",
"耳机在附近,可通过响铃进行查找":"",
+ "眼镜在附近,可通过响铃进行查找":"",
+ "查找中":"",
"个智能设备":"",
"云储存空间" : "",
"安全手机" : "",
"安全邮箱" : "",
"基本资料" : "",
+ "个人资料":"",
"登录设备管理" : "",
"头像" : "",
"昵称" : "",
"请输入手机号码" : "",
"请输入新的安全邮箱地址" : "",
+ "修改安全邮箱" : "",
"请输入邮箱地址" : "",
"请使用安全手机":"",
"请使用安全邮箱":"",
"倒计时结束后关闭APP":"",
"播放完整首后停止":"",
"自定义时间":"",
-
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
- // "":"",
]
"scale" : "1x"
},
{
- "filename" : "Frame 1986@2x.png",
+ "filename" : "复制_1@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
- "filename" : "Frame 1986@3x.png",
+ "filename" : "复制_1@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
<string>bluetooth-central</string>
<string>audio</string>
</array>
- <key>UIStatusBarStyle</key>
- <string>UIStatusBarStyleLightContent</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
</dict>