PODS:
+ - AMap3DMap-NO-IDFA (10.0.700):
+ - AMapFoundation-NO-IDFA (>= 1.8.0)
+ - AMapFoundation-NO-IDFA (1.8.2)
+ - AMapLocation-NO-IDFA (2.10.0):
+ - AMapFoundation-NO-IDFA (>= 1.8.0)
+ - AMapSearch-NO-IDFA (9.7.0):
+ - AMapFoundation-NO-IDFA (>= 1.8.0)
- CryptoSwift (1.8.4)
- DeviceKit (5.4.0)
- DGActivityIndicatorView (2.1.1)
- ZipArchive (1.4.0)
DEPENDENCIES:
+ - AMap3DMap-NO-IDFA (= 10.0.700)
+ - AMapLocation-NO-IDFA
+ - AMapSearch-NO-IDFA (= 9.7.0)
- CryptoSwift
- DeviceKit (~> 5.4.0)
- DGActivityIndicatorView
- IQKeyboardManagerSwift
- JXPagingView/Paging
- JXSegmentedView
+ - Kingfisher
- Kingfisher (~> 6.0)
- MBProgressHUD
- MJRefresh
SPEC REPOS:
https://gitee.com/mirrors/CocoaPods-Specs.git:
+ - AMap3DMap-NO-IDFA
+ - AMapFoundation-NO-IDFA
+ - AMapLocation-NO-IDFA
+ - AMapSearch-NO-IDFA
- CryptoSwift
- DeviceKit
- DGActivityIndicatorView
- ZipArchive
SPEC CHECKSUMS:
+ AMap3DMap-NO-IDFA: e029d65ea35d3e4c0a948e1dab9e77109bf0e86a
+ AMapFoundation-NO-IDFA: 6ce0ef596d4eb8d934ff498e56747b6de1247b05
+ AMapLocation-NO-IDFA: 735791aeb1ba52dff666e4158b86caf4b68b5be7
+ AMapSearch-NO-IDFA: 749f73d5a773758f01a24eb8872f8798c8b47cb4
CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
DeviceKit: bd34bb1766d926c3cc5a5f6e3e9a6dd10148b805
DGActivityIndicatorView: ff2c76073d79692f724863c8dd38685866a03cb6
YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
ZipArchive: e25a4373192673e3229ac8d6e9f64a3e5713c966
-PODFILE CHECKSUM: 8be0cb581e3b6cc73fee508087fb68b46cbcd963
+PODFILE CHECKSUM: 90bab882d785e16d9a04264a779a1b161ec591b7
COCOAPODS: 1.16.2
644D1BB5EDD3EA1D77C57786 /* Pods_DeepChordsSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 248D8B53B5A178ACA5867275 /* Pods_DeepChordsSdk.framework */; };
7666589AAA94A323B6090425 /* Pods_playboy.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4F1BB919D567C3B6B0EBAA7 /* Pods_playboy.framework */; };
7A6613B4B617D6E71D34944C /* Pods_ShenYin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90FF0C8B0D4D6AE0933FA672 /* Pods_ShenYin.framework */; };
- 817510A595D00CAD05E3772C /* (null) in Frameworks */ = {isa = PBXBuildFile; };
- F2E449CAD5874BE652A69B50 /* (null) in Frameworks */ = {isa = PBXBuildFile; };
+ 817510A595D00CAD05E3772C /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
+ F2E449CAD5874BE652A69B50 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
UI/Sleep/SleepListView.swift,
UI/Sleep/SleepVC.swift,
UI/Sleep/SleepVM.swift,
+ UI/Sport/MusicRootView.swift,
+ UI/Sport/RecordRootView.swift,
+ UI/Sport/Sport/Group/add/AddGroupVC.swift,
+ UI/Sport/Sport/Group/Create/AddGroupHeader.swift,
+ UI/Sport/Sport/Group/Create/CreateGroupVC.swift,
+ UI/Sport/Sport/Group/Create/SportInputItem.swift,
+ UI/Sport/Sport/Group/Create/SportSelectItem.swift,
+ UI/Sport/Sport/Group/Create/SportSwitchItem.swift,
+ UI/Sport/Sport/Group/MyGroup/MyGroupCell.swift,
+ UI/Sport/Sport/Group/MyGroup/MyGroupModel.swift,
+ UI/Sport/Sport/Group/MyGroup/MyGroupVC.swift,
+ UI/Sport/Sport/Group/MyGroup/MyGroupView.swift,
+ UI/Sport/Sport/Group/Other/GroupRoleVC.swift,
+ UI/Sport/Sport/Group/Other/GroupTypeVC.swift,
+ UI/Sport/Sport/Light/BrightnessView.swift,
+ UI/Sport/Sport/Light/LightSetVC.swift,
+ UI/Sport/Sport/Light/ModeView.swift,
+ UI/Sport/Sport/Light/StateView.swift,
+ UI/Sport/Sport/Ready/CountdownView.swift,
+ UI/Sport/Sport/Ready/CustomMapView.swift,
+ UI/Sport/Sport/Ready/FooterView.swift,
+ UI/Sport/Sport/Ready/Navbar.swift,
+ UI/Sport/Sport/Ready/ReadyHeader.swift,
+ UI/Sport/Sport/Ready/ReadyVC.swift,
+ UI/Sport/Sport/Root/DataView.swift,
+ UI/Sport/Sport/Root/GroupView.swift,
+ UI/Sport/Sport/Root/PlanView.swift,
+ UI/Sport/Sport/Root/RouteView.swift,
+ UI/Sport/Sport/Root/SportRootView.swift,
+ UI/Sport/Sport/Root/SportTypeView.swift,
+ UI/Sport/Sport/Set/SportSetCell.swift,
+ UI/Sport/Sport/Set/SportSetModel.swift,
+ UI/Sport/Sport/Set/SportSetVC.swift,
+ UI/Sport/Sport/SportDetail/CadenceView.swift,
+ UI/Sport/Sport/SportDetail/ElevationView.swift,
+ UI/Sport/Sport/SportDetail/FeelView.swift,
+ UI/Sport/Sport/SportDetail/PacePerView.swift,
+ UI/Sport/Sport/SportDetail/PaceView.swift,
+ UI/Sport/Sport/SportDetail/SportDetailBoard.swift,
+ UI/Sport/Sport/SportDetail/SportDetailVC.swift,
+ UI/Sport/Sport/SportDetail/StepRateView.swift,
+ UI/Sport/Sport/SportDetail/StrideLengthView.swift,
+ UI/Sport/Sport/Sporting/DetailBoard.swift,
+ UI/Sport/Sport/Sporting/SimpleBoard.swift,
+ UI/Sport/Sport/Sporting/SportingVC.swift,
+ UI/Sport/Sport/Target/CalorieView.swift,
+ UI/Sport/Sport/Target/DistanceView.swift,
+ UI/Sport/Sport/Target/DurationView.swift,
+ UI/Sport/Sport/Target/SportTargetVC.swift,
+ UI/Sport/Sport/Tools/MapManager.swift,
+ UI/Sport/Sport/Tools/SportManager.swift,
+ UI/Sport/SportHomeVC.swift,
+ UI/Sport/TranslateRootView.swift,
ViewController.swift,
);
target = 3F03695A2F2B604800F3CB95 /* playboy copy */;
Sdk/JoySdk/VC/JoyTctyVC.swift,
Sdk/JoySdk/VC/JoyXclyVC.swift,
Sdk/JoySdk/VC/ModeVC.swift,
+ UI/Sport/MusicRootView.swift,
+ UI/Sport/RecordRootView.swift,
+ UI/Sport/Sport/Group/add/AddGroupVC.swift,
+ UI/Sport/Sport/Group/Create/AddGroupHeader.swift,
+ UI/Sport/Sport/Group/Create/CreateGroupVC.swift,
+ UI/Sport/Sport/Group/Create/SportInputItem.swift,
+ UI/Sport/Sport/Group/Create/SportSelectItem.swift,
+ UI/Sport/Sport/Group/Create/SportSwitchItem.swift,
+ UI/Sport/Sport/Group/MyGroup/MyGroupCell.swift,
+ UI/Sport/Sport/Group/MyGroup/MyGroupModel.swift,
+ UI/Sport/Sport/Group/MyGroup/MyGroupVC.swift,
+ UI/Sport/Sport/Group/MyGroup/MyGroupView.swift,
+ UI/Sport/Sport/Group/Other/GroupRoleVC.swift,
+ UI/Sport/Sport/Group/Other/GroupTypeVC.swift,
+ UI/Sport/Sport/Light/BrightnessView.swift,
+ UI/Sport/Sport/Light/LightSetVC.swift,
+ UI/Sport/Sport/Light/ModeView.swift,
+ UI/Sport/Sport/Light/StateView.swift,
+ UI/Sport/Sport/Ready/CountdownView.swift,
+ UI/Sport/Sport/Ready/CustomMapView.swift,
+ UI/Sport/Sport/Ready/FooterView.swift,
+ UI/Sport/Sport/Ready/Navbar.swift,
+ UI/Sport/Sport/Ready/ReadyHeader.swift,
+ UI/Sport/Sport/Ready/ReadyVC.swift,
+ UI/Sport/Sport/Root/DataView.swift,
+ UI/Sport/Sport/Root/GroupView.swift,
+ UI/Sport/Sport/Root/PlanView.swift,
+ UI/Sport/Sport/Root/RouteView.swift,
+ UI/Sport/Sport/Root/SportRootView.swift,
+ UI/Sport/Sport/Root/SportTypeView.swift,
+ UI/Sport/Sport/Set/SportSetCell.swift,
+ UI/Sport/Sport/Set/SportSetModel.swift,
+ UI/Sport/Sport/Set/SportSetVC.swift,
+ UI/Sport/Sport/SportDetail/CadenceView.swift,
+ UI/Sport/Sport/SportDetail/ElevationView.swift,
+ UI/Sport/Sport/SportDetail/FeelView.swift,
+ UI/Sport/Sport/SportDetail/PacePerView.swift,
+ UI/Sport/Sport/SportDetail/PaceView.swift,
+ UI/Sport/Sport/SportDetail/SportDetailBoard.swift,
+ UI/Sport/Sport/SportDetail/SportDetailVC.swift,
+ UI/Sport/Sport/SportDetail/StepRateView.swift,
+ UI/Sport/Sport/SportDetail/StrideLengthView.swift,
+ UI/Sport/Sport/Sporting/DetailBoard.swift,
+ UI/Sport/Sport/Sporting/SimpleBoard.swift,
+ UI/Sport/Sport/Sporting/SportingVC.swift,
+ UI/Sport/Sport/Target/CalorieView.swift,
+ UI/Sport/Sport/Target/DistanceView.swift,
+ UI/Sport/Sport/Target/DurationView.swift,
+ UI/Sport/Sport/Target/SportTargetVC.swift,
+ UI/Sport/Sport/Tools/MapManager.swift,
+ UI/Sport/Sport/Tools/SportManager.swift,
+ UI/Sport/SportHomeVC.swift,
+ UI/Sport/TranslateRootView.swift,
);
target = 3FD1DFE32F0E00BF00A62733 /* playboy */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet section */
- 3FCC8B152F1E0280004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" phase from "ShenYin" target */ = {
+ 3FCC8B152F1E0280004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" build phase */ = {
isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
- attributesByRelativePath = {
- Sdk/JoySdk/tool/JoyGemAI.framework = (CodeSignOnCopy, RemoveHeadersOnCopy, );
- };
buildPhase = 3FEFE9092F1B252000D82F17 /* Embed Frameworks */;
membershipExceptions = (
Sdk/JoySdk/tool/JoyGemAI.framework,
);
};
- 3FCC8B1A2F1E030E004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" phase from "playboy" target */ = {
+ 3FCC8B1A2F1E030E004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" build phase */ = {
isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
- attributesByRelativePath = {
- Sdk/DcSdk/tool/JLAudioUnitKit.xcframework = (CodeSignOnCopy, RemoveHeadersOnCopy, );
- };
buildPhase = 3FD1DFEF2F0E00BF00A62733 /* Embed Frameworks */;
membershipExceptions = (
Sdk/DcSdk/tool/JLAudioUnitKit.xcframework,
);
};
- 3FFB77C62F17A11100EF9A60 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" phase from "DeepChordsSdk" target */ = {
+ 3FFB77C62F17A11100EF9A60 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" build phase */ = {
isa = PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
- attributesByRelativePath = {
- StarburstSdk.framework = (CodeSignOnCopy, RemoveHeadersOnCopy, );
- };
buildPhase = 3FFB77C52F17A11100EF9A60 /* Embed Frameworks */;
membershipExceptions = (
StarburstSdk.framework,
0D54E0F02F0A61E600A80EE7 /* DeepChordsSdk */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
- 3FFB77C62F17A11100EF9A60 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" phase from "DeepChordsSdk" target */,
+ 3FFB77C62F17A11100EF9A60 /* Exceptions for "DeepChordsSdk" folder in "Embed Frameworks" build phase */,
3FFB77C82F17A14C00EF9A60 /* Exceptions for "DeepChordsSdk" folder in "playboy" target */,
);
path = DeepChordsSdk;
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
3F887BAE2E38D8DD00C98658 /* Exceptions for "ShenYin" folder in "ShenYin" target */,
- 3FCC8B152F1E0280004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" phase from "ShenYin" target */,
+ 3FCC8B152F1E0280004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" build phase */,
3FD1DFF52F0E00BF00A62733 /* Exceptions for "ShenYin" folder in "playboy" target */,
- 3FCC8B1A2F1E030E004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" phase from "playboy" target */,
+ 3FCC8B1A2F1E030E004C2A13 /* Exceptions for "ShenYin" folder in "Embed Frameworks" build phase */,
3F03696C2F2B604900F3CB95 /* Exceptions for "ShenYin" folder in "playboy copy" target */,
);
path = ShenYin;
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- F2E449CAD5874BE652A69B50 /* (null) in Frameworks */,
+ F2E449CAD5874BE652A69B50 /* BuildFile in Frameworks */,
7A6613B4B617D6E71D34944C /* Pods_ShenYin.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
buildActionMask = 2147483647;
files = (
3FFB77C12F179F3100EF9A60 /* DeepChordsSdk.framework in Frameworks */,
- 817510A595D00CAD05E3772C /* (null) in Frameworks */,
+ 817510A595D00CAD05E3772C /* BuildFile in Frameworks */,
30B13DEF1AA0E4C54D873276 /* Pods_playboy.framework in Frameworks */,
7666589AAA94A323B6090425 /* Pods_playboy.framework in Frameworks */,
);
3F887B9A2E38D8DC00C98658 /* Resources */,
5A934A35F54A5620CFD3C08A /* [CP] Embed Pods Frameworks */,
3FEFE9092F1B252000D82F17 /* Embed Frameworks */,
+ 66ADC9E36EC3B28429D51406 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-playboy/Pods-playboy-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
- inputPaths = (
- );
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-playboy/Pods-playboy-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
- outputPaths = (
- );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-playboy/Pods-playboy-frameworks.sh\"\n";
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
- inputPaths = (
- );
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
- outputPaths = (
- );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
+ 66ADC9E36EC3B28429D51406 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-resources-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-resources-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
FEE3A20D8A2FA81E622C488B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
--- /dev/null
+//
+// MusicVC.swift
+// ShenYin
+//
+// Created by liangshi on 2026/1/20.
+//
+
+import UIKit
+import JXSegmentedView
+
+class MusicRootView: BaseView{
+ override func setupViews() {
+ backgroundColor = UIColor.random()
+ }
+}
+
+extension MusicRootView: JXSegmentedListContainerViewListDelegate {
+ func listView() -> UIView {
+ return self
+ }
+}
--- /dev/null
+//
+// RecordView.swift
+// ShenYin
+//
+// Created by liangshi on 2026/1/20.
+//
+
+import UIKit
+import JXSegmentedView
+
+class RecordRootView: BaseView{
+ override func setupViews() {
+ backgroundColor = UIColor.random()
+ }
+}
+
+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:ResponseBaseModel, res) in
+
+ if model.isSuccess{
+ YLprogressHUD.hidden()
+ }
+ 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
+//
+// 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) {
+ }
+
+}
+
+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)
+ }
+ 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
+ }
+ view.addSubviews([nameView,typeView,desView,okBtn])
+ nameView.do { v in
+ v.yc.setCornerRadius(12)
+ v.titleLabel.text = "团队号".l10n
+ v.textField.text = "2019706199229804545"
+ 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)])
+ }
+ 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)
+ }
+ 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)
+ }
+ okBtn.snp.makeConstraints { make in
+ make.bottom.equalToSuperview().inset(80)
+ make.left.right.equalToSuperview().inset(51)
+ make.height.equalTo(46)
+ }
+ }
+ @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("请求失败".l10n)
+ }
+ }
+ }
+}
+
--- /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_left_1"), for: .normal)
+ }
+ view.backgroundColor = .rgb(0x1F1F1F)
+ view.addSubviews([bgView])
+ bgView.addSubviews([icon,stateView,modelView,brightnessView,sysView])
+
+ bgView.do { v in
+ v.backgroundColor = .clear
+ }
+ icon.do { v in
+ v.backgroundColor = .lightGray
+ }
+ stateView.do { v in
+ v.iSwitch.addTarget(self, action: #selector(stateAction), for: .valueChanged)
+
+ }
+ modelView.do { v in
+ }
+ brightnessView.do { v in
+// v.backgroundColor = .yellow
+ }
+ sysView.do { v in
+ v.line.isHidden = true
+ }
+ }
+ override func setupLayout() {
+
+ bgView.snp.makeConstraints { make in
+ make.left.equalToSuperview()
+ make.width.equalTo(kScreenWid)
+ make.top.equalToSuperview().inset(kNavBtm)
+ make.height.equalTo(kScreenHei - kNavBtm)
+ }
+ icon.snp.makeConstraints { make in
+ make.height.equalTo(263.fitR)
+ make.width.equalTo(kScreenWid)
+ make.left.top.equalToSuperview()
+ }
+ stateView.snp.makeConstraints { make in
+ make.width.equalTo(kScreenWid)
+ make.height.equalTo(60)
+ make.top.equalTo(icon.snp.bottom).offset(0)
+ make.left.equalToSuperview()
+ }
+ modelView.snp.makeConstraints { make in
+ make.width.equalTo(kScreenWid)
+ make.height.equalTo(103)
+ make.top.equalTo(stateView.snp.bottom).offset(0)
+ make.left.equalToSuperview()
+ }
+ brightnessView.snp.makeConstraints { make in
+ make.width.equalTo(kScreenWid)
+ make.height.equalTo(90)
+ make.top.equalTo(modelView.snp.bottom).offset(0)
+ make.left.equalToSuperview()
+ }
+ sysView.snp.makeConstraints { make in
+ make.width.equalTo(kScreenWid)
+ make.height.equalTo(60)
+ make.top.equalTo(brightnessView.snp.bottom).offset(0)
+ make.left.equalToSuperview()
+ make.bottom.equalToSuperview()
+ }
+ }
+
+ @objc func stateAction(){
+ modelView.isHidden = !stateView.iSwitch.isOn
+ brightnessView.isHidden = !stateView.iSwitch.isOn
+ sysView.isHidden = !stateView.iSwitch.isOn
+ }
+}
--- /dev/null
+//
+// ModeView.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/2.
+//
+enum LightMode {
+ case normal
+ case breath
+ case flash
+
+ var name:String{
+ switch self {
+ case .normal:
+ return "正常".l10n
+ case .breath:
+ return "呼吸".l10n
+ case .flash:
+ return "闪烁".l10n
+ }
+ }
+}
+extension LightSetVC{
+
+
+ class ModeView: BaseView {
+ let titleLabel = UILabel()
+ let normalItem = SelectedTypeItem()
+ let breathItem = SelectedTypeItem()
+ let flashItem = SelectedTypeItem()
+ let line = UIView()
+
+ var isOk:Bool{
+ return normalItem.isSelected || breathItem.isSelected || flashItem.isSelected
+ }
+
+
+ override func setupViews() {
+ // backgroundColor = .red
+ addSubviews([titleLabel,normalItem,breathItem,flashItem,line])
+
+ titleLabel.do { v in
+ v.textAlignment = .center
+ v.font = .bold(14)
+ v.textColor = .white
+ v.text = "模式".l10n
+ }
+ normalItem.do { v in
+ v.mode = .normal
+ v.yc.setCornerRadius(8)
+ v.yc.addTap(target: self, action: #selector(normalAction))
+ }
+ breathItem.do { v in
+ v.mode = .breath
+ v.yc.setCornerRadius(8)
+ v.yc.addTap(target: self, action: #selector(breathAction))
+ }
+ flashItem.do { v in
+ v.mode = .flash
+ v.yc.setCornerRadius(8)
+ v.yc.addTap(target: self, action: #selector(flashAction))
+ }
+ line.do { v in
+ v.backgroundColor = .color(.separateLine)
+ }
+ }
+
+ override func setupLayout() {
+ titleLabel.snp.makeConstraints { make in
+ make.top.equalToSuperview().inset(20)
+ make.left.equalToSuperview().inset(32)
+ }
+ normalItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(32)
+ make.top.equalTo(titleLabel.snp.bottom).offset(10)
+ make.width.equalTo(80.fitR)
+ make.height.equalTo(32)
+ }
+ breathItem.snp.makeConstraints { make in
+ make.centerX.equalToSuperview()
+ make.top.width.height.equalTo(normalItem)
+ }
+ flashItem.snp.makeConstraints { make in
+ make.right.equalToSuperview().inset(32)
+ make.top.width.height.equalTo(normalItem)
+ }
+ line.snp.makeConstraints { make in
+ make.left.right.equalToSuperview().inset(28)
+ make.bottom.equalToSuperview()
+ make.height.equalTo(0.4)
+ }
+ }
+
+ @objc func normalAction(){
+ normalItem.isSelected = true
+ breathItem.isSelected = false
+ flashItem.isSelected = false
+ }
+ @objc func breathAction(){
+ normalItem.isSelected = false
+ breathItem.isSelected = true
+ flashItem.isSelected = false
+ }
+ @objc func flashAction(){
+ normalItem.isSelected = false
+ breathItem.isSelected = false
+ flashItem.isSelected = true
+ }
+
+
+ class SelectedTypeItem: BaseView {
+ let titleLabel = UILabel()
+ var mode:LightMode = .normal{
+ didSet{
+ titleLabel.text = mode.name
+ }
+ }
+
+ var isSelected:Bool = false{
+ didSet{
+ if isSelected {
+ titleLabel.textColor = .color(.first)
+ backgroundColor = .color(.bgColor)
+ }
+ else{
+ backgroundColor = .clear
+ titleLabel.textColor = .color(.secondary)
+ yc.setBorder(width: 1, color: .color(.secondary))
+ }
+ }
+ }
+
+ override func setupViews() {
+ backgroundColor = .color(.bgColor)
+ addSubviews([titleLabel])
+ titleLabel.do { v in
+ v.textAlignment = .center
+ v.adjustsFontSizeToFitWidth = true
+ v.font = .regular(14)
+ }
+ self.isSelected = false
+ }
+
+ override func setupLayout() {
+ titleLabel.snp.makeConstraints { make in
+ make.edges.equalToSuperview()
+ }
+ }
+ }
+ }
+
+}
--- /dev/null
+//
+// StateView.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/2.
+//
+
+extension LightSetVC{
+ class StateView: BaseView {
+ let titleLabel = UILabel()
+ let iSwitch = UISwitch()
+ let line = UIView()
+ weak var delegate:SportSetCellDelegate?
+
+ override func setupViews() {
+ addSubviews([titleLabel,iSwitch,line])
+
+ titleLabel.do { (v) in
+ v.textColor = .white
+ v.font = .bold(14)
+ v.textAlignment = .left
+ v.text = "灯带".l10n
+ }
+
+ iSwitch.do { v in
+ // v.backgroundColor = .red
+ }
+
+ line.do { v in
+ v.backgroundColor = .color(.separateLine)
+ }
+ }
+
+ override func setupLayout() {
+ titleLabel.snp.makeConstraints { (m) in
+ m.centerY.equalToSuperview()
+ m.left.equalToSuperview().offset(32)
+ }
+
+ iSwitch.snp.makeConstraints { (m) in
+ m.right.equalToSuperview().inset(32)
+ m.centerY.equalToSuperview()
+ }
+
+ line.snp.makeConstraints { make in
+ make.left.right.equalToSuperview().inset(28)
+ make.bottom.equalToSuperview()
+ make.height.equalTo(0.4)
+ }
+ }
+ }
+}
--- /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
+//
+// 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.sortType.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.sortType.readyText
+ v.textAlignment = .left
+ }
+ totalLabel.do { v in
+ v.textColor = .color(.first)
+ v.font = .bold(20)
+ v.text = "120"
+ v.textAlignment = .left
+ }
+ unitLabel.do { v in
+ v.textColor = .color(.first)
+ v.font = .medium(14)
+ v.text = "公里"
+ v.textAlignment = .left
+ }
+ aiBtn.do { v in
+ v.yc.setBorder(width: 1, color: .color(.secondary), radius: 18)
+ v.yc.addTap(target: self, action: #selector(aiAction))
+ }
+ }
+
+ override func setupLayout() {
+ typeLabel.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(32)
+ make.top.equalToSuperview().inset(25)
+
+ }
+ totalLabel.snp.makeConstraints { make in
+ make.left.equalTo(typeLabel)
+ make.bottom.equalToSuperview().inset(27)
+
+ }
+ unitLabel.snp.makeConstraints { make in
+ make.left.equalTo(totalLabel.snp.right).offset(2)
+ make.bottom.equalToSuperview().inset(30)
+
+ }
+
+ aiBtn.snp.makeConstraints { make in
+ make.size.equalTo(105)
+ make.height.equalTo(36)
+ make.centerY.equalToSuperview()
+ make.right.equalToSuperview().inset(18)
+ }
+ }
+
+ @objc func aiAction(){
+ App.shared.goToPage(SportTargetVC())
+ }
+
+
+ class ButtonItem: BaseView {
+ let aiLabel = UILabel()
+ let titleLabel = UILabel()
+
+ override func setupViews() {
+ addSubviews([titleLabel,aiLabel])
+ aiLabel.do { v in
+ v.textColor = .color(.secondary)
+ v.font = .bold(14)
+ v.text = "AI"
+ }
+ titleLabel.do { v in
+ v.textColor = .color(.secondary)
+ v.font = .regular(14)
+ v.text = "语音陪练".l10n
+ }
+ backgroundColor = .white
+ }
+
+ override func setupLayout() {
+ aiLabel.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(12)
+ make.centerY.equalToSuperview()
+ }
+ titleLabel.snp.makeConstraints { make in
+ make.centerY.equalToSuperview()
+ make.right.equalToSuperview().inset(12)
+ }
+ }
+ }
+
+ }
+
+}
--- /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()
+
+ override func setupViews() {
+
+
+
+ mapView = MAMapView(frame: .zero)
+ mapView.delegate = self
+ mapView.showsUserLocation = true
+ mapView.zoomLevel = 16
+ mapView.userTrackingMode = .followWithHeading
+
+ navBar.do { v in
+ v.addSubview(bar)
+ }
+ view.addSubviews([headerView,mapView,footerView])
+ headerView.do { v in
+ v.backgroundColor = .white
+ }
+ mapView.do { v in
+ v.backgroundColor = .green
+
+ }
+ footerView.do { v in
+// v.backgroundColor = .blue
+ }
+ }
+ 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()
+ make.top.equalTo(headerView.snp.bottom)
+ make.bottom.equalTo(footerView.snp.top)
+ }
+
+ }
+ 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)
+ }
+
+ 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)
+ }
+ }
+ 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.sortType = .run
+ App.shared.goToPage(ReadyVC())
+ }
+ @objc func rideAction(){
+ SportManager.shared.sortType = .ride
+ App.shared.goToPage(ReadyVC())
+ }
+ @objc func walkAction(){
+ SportManager.shared.sortType = .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 = headerItem()
+ let distanceItem = LabelItem()
+ let durationItem = LabelItem()
+ let speedItem = LabelItem()
+ let calorieItem = LabelItem()
+ let stepItem = LabelItem()
+
+ override func setupViews() {
+ backgroundColor = .white
+ addSubviews([topIcon,header,distanceItem,durationItem,speedItem,calorieItem,stepItem])
+ topIcon.do { v in
+ v.backgroundColor = .color(.secondary)
+ v.yc.setCornerRadius(2)
+ }
+ distanceItem.do { v in
+ v.titleLabel.text = "0"
+ v.detailLabel.text = "总距离".l10n
+ }
+ durationItem.do { v in
+ v.titleLabel.text = "00:00:00"
+ v.detailLabel.text = "总时长".l10n
+ }
+ speedItem.do { v in
+ v.titleLabel.text = "8'26\""
+ v.detailLabel.text = "配速".l10n
+ }
+ calorieItem.do { v in
+ v.titleLabel.text = "300"
+ v.detailLabel.text = "卡路里".l10n
+ }
+ stepItem.do { v in
+ v.titleLabel.text = "1200"
+ 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()
+ }
+ 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)
+ }
+ durationItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(18)
+ make.top.equalToSuperview().inset(180)
+ make.height.equalTo(50)
+ }
+ speedItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(kScreenWid/2 + 18)
+ make.top.equalTo(durationItem.snp.top)
+ make.height.equalTo(50)
+ }
+ calorieItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(18)
+ make.top.equalToSuperview().inset(250)
+ make.height.equalTo(50)
+ }
+ stepItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(kScreenWid/2 + 18)
+ make.top.equalTo(calorieItem.snp.top)
+ make.height.equalTo(50)
+ }
+ }
+
+ @objc func okAction(){
+ App.shared.goToPage(SportDetailVC())
+ }
+
+
+ class headerItem: BaseView {
+ let deviceLabel = UILabel()
+ let deviceView = UIView()
+ let titleLabel = UILabel()
+
+ override func setupViews() {
+ addSubviews([titleLabel,deviceView])
+ deviceView.addSubviews([deviceLabel])
+ titleLabel.do { v in
+ v.textColor = .color(.first)
+ v.font = .bold(16)
+ v.textAlignment = .left
+ v.text = "户外跑步"
+ }
+ deviceView.do { v in
+ v.backgroundColor = .rgb(0xF7F7F7 )
+ v.yc.setCornerRadius(13)
+ }
+ deviceLabel.do { v in
+ v.textColor = .color(.secondary)
+ v.font = .regular(10)
+ v.textAlignment = .center
+ v.text = "Deep Lite2 Ultra"
+ }
+ }
+
+ override func setupLayout() {
+ titleLabel.snp.makeConstraints { make in
+ make.centerY.equalToSuperview().inset(0)
+ make.left.equalToSuperview().inset(18)
+ }
+ deviceView.snp.makeConstraints { make in
+ make.width.equalTo(120)
+ make.height.equalTo(26)
+ make.left.equalToSuperview().inset(94)
+ make.centerY.equalToSuperview()
+ }
+ deviceLabel.snp.makeConstraints { make in
+ make.centerY.right.equalToSuperview()
+ make.left.equalToSuperview().inset(18)
+ }
+ }
+ }
+
+
+ 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
+//
+// 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()
+
+
+
+ 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(300)
+ }
+ 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 = LabelItem()
+ let durationItem = LabelItem()
+ let speedItem = LabelItem()
+ let calorieItem = LabelItem()
+ let stepItem = LabelItem()
+ let btnView = ButtonView()
+
+ override func setupViews() {
+ backgroundColor = .white
+ addSubviews([topIcon,header,distanceItem,durationItem,speedItem,calorieItem,stepItem,btnView])
+ topIcon.do { v in
+ v.backgroundColor = .color(.secondary)
+ v.yc.setCornerRadius(2)
+ }
+ distanceItem.do { v in
+ v.titleLabel.text = "0"
+ v.detailLabel.text = "总距离".l10n
+ }
+ durationItem.do { v in
+ v.titleLabel.text = "00:00:00"
+ v.detailLabel.text = "总时长".l10n
+ }
+ speedItem.do { v in
+ v.titleLabel.text = "8'26\""
+ v.detailLabel.text = "配速".l10n
+ }
+ calorieItem.do { v in
+ v.titleLabel.text = "300"
+ v.detailLabel.text = "卡路里".l10n
+ }
+ stepItem.do { v in
+ v.titleLabel.text = "1200"
+ 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()
+ }
+ 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)
+ }
+ durationItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(18)
+ make.top.equalToSuperview().inset(180)
+ make.height.equalTo(50)
+ }
+ speedItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(kScreenWid/2 + 18)
+ make.top.equalTo(durationItem.snp.top)
+ make.height.equalTo(50)
+ }
+ calorieItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(18)
+ make.top.equalToSuperview().inset(250)
+ make.height.equalTo(50)
+ }
+ stepItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(kScreenWid/2 + 18)
+ make.top.equalTo(calorieItem.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(){
+ 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(){
+ App.shared.goToPage(SportDetailVC())
+ }
+ @objc func continueAction(){
+ okBtn.isHidden = false
+ setBtn.isHidden = false
+ lockBtn.isHidden = false
+
+ continueBtn.isHidden = true
+ stopBtn.isHidden = true
+ }
+ }
+ class headerItem: BaseView {
+ let deviceLabel = UILabel()
+ let deviceView = UIView()
+ let titleLabel = UILabel()
+
+ override func setupViews() {
+ addSubviews([titleLabel,deviceView])
+ deviceView.addSubviews([deviceLabel])
+ titleLabel.do { v in
+ v.textColor = .color(.first)
+ v.font = .bold(16)
+ v.textAlignment = .left
+ v.text = "户外跑步"
+ }
+ deviceView.do { v in
+ v.backgroundColor = .rgb(0xF7F7F7 )
+ v.yc.setCornerRadius(13)
+ }
+ deviceLabel.do { v in
+ v.textColor = .color(.secondary)
+ v.font = .regular(10)
+ v.textAlignment = .center
+ v.text = "Deep Lite2 Ultra"
+ }
+ }
+
+ override func setupLayout() {
+ titleLabel.snp.makeConstraints { make in
+ make.centerY.equalToSuperview().inset(0)
+ make.left.equalToSuperview().inset(18)
+ }
+ deviceView.snp.makeConstraints { make in
+ make.width.equalTo(120)
+ make.height.equalTo(26)
+ make.left.equalToSuperview().inset(94)
+ make.centerY.equalToSuperview()
+ }
+ deviceLabel.snp.makeConstraints { make in
+ make.centerY.right.equalToSuperview()
+ make.left.equalToSuperview().inset(18)
+ }
+ }
+ }
+
+
+ class LabelItem: BaseView {
+ let detailLabel = UILabel()
+ let titleLabel = UILabel()
+
+ override func setupViews() {
+ addSubviews([titleLabel,detailLabel])
+ titleLabel.do { v in
+ v.textColor = .color(.first)
+ v.font = .bold(24)
+ v.textAlignment = .left
+ }
+ detailLabel.do { v in
+ v.textColor = .color(.secondary)
+ v.font = .regular(12)
+ v.textAlignment = .left
+ }
+ }
+
+ override func setupLayout() {
+ titleLabel.snp.makeConstraints { make in
+ make.top.equalToSuperview().inset(0)
+ make.left.right.equalToSuperview()
+ }
+ detailLabel.snp.makeConstraints { make in
+ make.bottom.equalToSuperview().inset(0)
+ make.left.right.equalToSuperview()
+ }
+ }
+ }
+ }
+
+
+
+}
--- /dev/null
+//
+// Untitled.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/3.
+//
+
+import UIKit
+
+extension SportingVC{
+ class SimpleBoard: BaseView {
+ let topIcon = UIImageView()
+ let distanceItem = LabelItem()
+ let durationItem = LabelItem()
+
+ override func setupViews() {
+ backgroundColor = .white
+ addSubviews([topIcon,distanceItem,durationItem])
+ topIcon.do { v in
+ v.backgroundColor = .color(.secondary)
+ v.yc.setCornerRadius(2)
+ }
+ distanceItem.do { v in
+ v.titleLabel.text = "0"
+ v.detailLabel.text = "总距离".l10n
+ }
+ durationItem.do { v in
+ v.titleLabel.text = "00:00:00"
+ v.detailLabel.text = "总时长".l10n
+ }
+ }
+
+ override func setupLayout() {
+ topIcon.snp.makeConstraints { make in
+ make.width.equalTo(50)
+ make.height.equalTo(4)
+ make.top.equalToSuperview().inset(6)
+ make.centerX.equalToSuperview()
+ }
+ distanceItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(18)
+ make.top.equalToSuperview().inset(27)
+ make.height.equalTo(50)
+ }
+ durationItem.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(kScreenWid/2 + 18)
+ make.top.equalToSuperview().inset(27)
+ make.height.equalTo(distanceItem)
+ }
+ }
+
+ @objc func groupAction(){
+ App.shared.goToPage(SportSetVC())
+ }
+ class LabelItem: BaseView {
+ let detailLabel = UILabel()
+ let titleLabel = UILabel()
+
+ override func setupViews() {
+ addSubviews([titleLabel,detailLabel])
+ titleLabel.do { v in
+ v.textColor = .color(.secondary)
+ v.font = .bold(24)
+ v.textAlignment = .left
+ }
+ detailLabel.do { v in
+ v.textColor = .color(.secondary)
+ v.font = .regular(12)
+ v.textAlignment = .left
+ }
+ }
+
+ override func setupLayout() {
+ titleLabel.snp.makeConstraints { make in
+ make.top.equalToSuperview().inset(0)
+ make.left.right.equalToSuperview()
+ }
+ detailLabel.snp.makeConstraints { make in
+ make.bottom.equalToSuperview().inset(0)
+ make.left.right.equalToSuperview()
+ }
+ }
+ }
+ }
+}
--- /dev/null
+//
+// Untitled.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/3.
+//
+
+import MAMapKit
+
+class SportingVC: BaseVC {
+ var mapView:MAMapView!
+ let simpleView = SimpleBoard()
+ let detailView = DetailBoard()
+
+ override func setupViews() {
+
+
+
+ mapView = MAMapView(frame: .zero)
+ mapView.delegate = self
+ mapView.showsUserLocation = true
+ mapView.zoomLevel = 16
+ mapView.userTrackingMode = .followWithHeading
+
+ view.addSubviews([mapView,simpleView,detailView])
+ mapView.do { v in
+
+ }
+ simpleView.do { v in
+ v.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() {
+
+ }
+
+ @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)
+ }
+ }
+}
+
+extension SportingVC:MAMapViewDelegate{
+ func mapViewRequireLocationAuth(_ locationManager: CLLocationManager!) {
+ // locationManager.requestAlwaysAuthorization()
+ }
+}
--- /dev/null
+//
+// CaloriView.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/3.
+//
+
+import JXSegmentedView
+
+extension SportTargetVC{
+ class CaloriView: BaseView ,JXSegmentedListContainerViewListDelegate{
+ let label = UILabel()
+
+ override func setupViews() {
+ addSubviews([label])
+ label.do { v in
+ v.font = .bold(28)
+ v.textAlignment = .center
+ v.textColor = .color(.first)
+ v.text = "300 千卡"
+ v.yc.addTap(target: self, action: #selector(tapAction))
+ }
+ }
+ override func setupLayout() {
+ label.snp.makeConstraints { make in
+ make.left.right.equalToSuperview()
+ make.top.equalToSuperview().inset(50)
+ }
+ }
+
+ func listView() -> UIView {
+ return self
+ }
+ @objc func tapAction(){
+ let list = Array(stride(from: 1, to: 1000, by: 1)).map { String($0) + " 千卡" }
+ let v = CustomPicker2(title: "卡路里".l10n, list:list )
+ v.selectedIndex = 0
+ v.show()
+ v.didSelected = {[weak self] (index,value) in
+ guard let self = self else { return }
+ label.text = value
+ }
+ }
+ }
+}
--- /dev/null
+//
+// DistanceView.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/3.
+//
+
+import JXSegmentedView
+
+extension SportTargetVC{
+ class DistanceView: BaseView ,JXSegmentedListContainerViewListDelegate{
+ let label = UILabel()
+
+ override func setupViews() {
+ addSubviews([label])
+ label.do { v in
+ v.font = .bold(28)
+ v.textAlignment = .center
+ v.textColor = .color(.first)
+ v.text = "3 km"
+ v.yc.addTap(target: self, action: #selector(tapAction))
+ }
+ }
+ override func setupLayout() {
+ label.snp.makeConstraints { make in
+ make.left.right.equalToSuperview()
+ make.top.equalToSuperview().inset(50)
+ }
+ }
+
+ func listView() -> UIView {
+ return self
+ }
+ @objc func tapAction(){
+ let list = Array(stride(from: 1, to: 100, by: 1)).map { String($0) + " km" }
+ let v = CustomPicker2(title: "距离".l10n, list:list )
+ v.selectedIndex = 0
+ v.show()
+ v.didSelected = {[weak self] (index,value) in
+ guard let self = self else { return }
+ label.text = value
+ }
+ }
+ }
+}
--- /dev/null
+//
+// DurationView.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/3.
+//
+
+import JXSegmentedView
+
+extension SportTargetVC{
+ class DurationView: BaseView ,JXSegmentedListContainerViewListDelegate{
+ let label = UILabel()
+
+ override func setupViews() {
+ addSubviews([label])
+ label.do { v in
+ v.font = .bold(28)
+ v.textAlignment = .center
+ v.textColor = .color(.first)
+ v.text = "00:30"
+ v.yc.addTap(target: self, action: #selector(tapAction))
+ }
+ }
+ override func setupLayout() {
+ label.snp.makeConstraints { make in
+ make.left.right.equalToSuperview()
+ make.top.equalToSuperview().inset(50)
+ }
+ }
+
+ func listView() -> UIView {
+ return self
+ }
+ @objc func tapAction(){
+ let v = CustomPicker3(title: "日期".l10n)
+ v.datePicker.datePickerMode = .time
+ v.show()
+ v.didSelected = {[weak self] (date) in
+ guard let self = self else { return }
+ label.text = date.format(.shortTime)
+ }
+ }
+ }
+}
--- /dev/null
+//
+// SportTargetVC.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/3.
+//
+
+import JXSegmentedView
+
+
+enum SportTargetType{
+ case distance
+ case duration
+ case calorie
+
+ var name:String{
+ switch self {
+ case .distance:
+ return "距离".l10n
+ case .duration:
+ return "时长".l10n
+ case .calorie:
+ return "卡路里".l10n
+ }
+ }
+ static var all:[SportTargetType] = [.distance,.duration,.calorie]
+}
+
+class SportTargetVC: BaseVC {
+ let okBtn = CustomButton()
+ private let segmentedDataSource = JXSegmentedTitleDataSource()
+ private let segmentedView = JXSegmentedView()
+ private lazy var listContainerView: JXSegmentedListContainerView! = {
+ let view = JXSegmentedListContainerView(dataSource: self, type: .scrollView)
+ return view
+ }()
+
+ var list:[SportTargetType] = SportTargetType.all
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+
+ }
+
+ override func setupLayout(){
+
+ segmentedView.snp.makeConstraints { (m) in
+ m.left.right.equalToSuperview()
+ m.height.equalTo(44.fitR)
+ m.top.equalToSuperview().inset(kNavBtm)
+ }
+ listContainerView.snp.makeConstraints { (m) in
+ m.width.left.equalToSuperview()
+ m.top.equalTo(segmentedView.snp.bottom)
+ m.bottom.equalToSuperview()
+ }
+ okBtn.snp.makeConstraints { make in
+ make.bottom.equalToSuperview().inset(80)
+ make.left.right.equalToSuperview().inset(51)
+ make.height.equalTo(46)
+ }
+ }
+ override func setupViews(){
+ navBar.title = "设置目标".l10n
+ view.addSubview(segmentedView)
+ view.addSubview(listContainerView)
+ view.addSubview(okBtn)
+
+ view.backgroundColor = .color(.bgColor)
+ segmentedView.do { (v) in
+ segmentedDataSource.titleNormalColor = .color(.secondary)
+ segmentedDataSource.titleSelectedColor = .color(.first)
+ segmentedDataSource.titleNormalFont = .regular(14)
+ segmentedDataSource.titleSelectedFont = .bold(16)
+ segmentedDataSource.isTitleZoomEnabled = true
+ // segmentedDataSource.titleSelectedZoomScale = 1
+ segmentedDataSource.isTitleStrokeWidthEnabled = true
+ segmentedDataSource.isItemSpacingAverageEnabled = true
+ segmentedDataSource.isTitleColorGradientEnabled = true
+ segmentedDataSource.titles = list.map{"\($0.name)"}
+ segmentedView.backgroundColor = .clear
+
+ //配置指示器
+ let indicator = JXSegmentedIndicatorLineView()
+ indicator.indicatorWidth = 20
+ indicator.indicatorHeight = 4
+ indicator.verticalOffset = 6
+ indicator.indicatorColor = .color(.sport)
+ segmentedView.indicators = [indicator]
+
+ v.dataSource = segmentedDataSource
+ v.listContainer = listContainerView
+ }
+ okBtn.set(title: "确定".l10n,style: .sport, target: self, action: #selector(okAction))
+ }
+ @objc func okAction(){
+ self.navigationController?.popViewController(animated: true)
+ }
+}
+
+extension SportTargetVC: JXSegmentedListContainerViewListDelegate {
+ func listView() -> UIView {
+ return view
+ }
+}
+
+extension SportTargetVC: JXSegmentedListContainerViewDataSource {
+ func numberOfLists(in listContainerView: JXSegmentedListContainerView) -> Int {
+ if let titleDataSource = segmentedView.dataSource as? JXSegmentedBaseDataSource {
+ return titleDataSource.dataSource.count
+ }
+ return 0
+ }
+
+ func listContainerView(_ listContainerView: JXSegmentedListContainerView, initListAt index: Int) -> JXSegmentedListContainerViewListDelegate {
+ let type = list[index]
+ switch type {
+ case .distance:
+ return DistanceView()
+ case .duration:
+ return DurationView()
+ case .calorie:
+ return CaloriView()
+ }
+
+ }
+}
--- /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
+//
+// SportManager.swift
+// ShenYin
+//
+// Created by liangshi on 2026/2/10.
+//
+
+class SportManager {
+ static let shared = SportManager()
+ var sortType = SportType.ride
+
+
+}
--- /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 {
+ 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(){
+
+ 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(){
+ 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{
+ override func setupViews() {
+ backgroundColor = UIColor.random()
+ }
+}
+
+extension TranslateRootView: JXSegmentedListContainerViewListDelegate {
+ func listView() -> UIView {
+ return self
+ }
+}
pod 'HorizonCalendar'#日历
#高德地图
-# pod 'AMap3DMap-NO-IDFA', '10.0.700'
-# pod 'AMapLocation-NO-IDFA'
-# pod 'AMapSearch-NO-IDFA', '9.7.0'
+ pod 'AMap3DMap-NO-IDFA', '10.0.700'
+ pod 'AMapLocation-NO-IDFA'
+ pod 'AMapSearch-NO-IDFA', '9.7.0'
end
pod 'SwiftDate'#时间转换
pod 'SVProgressHUD'#蒙版
pod 'MBProgressHUD'#蒙版
- pod 'Kingfisher', '~> 6.0'#图片下载K
+ pod 'Kingfisher' #图片下载K
pod 'FSPagerView'
pod "TabPageViewController" #tabpage
pod 'JXSegmentedView'