From: liangzhenying <867174124@qq.com> Date: Wed, 11 Feb 2026 08:36:30 +0000 (+0800) Subject: 添加地图和运动 X-Git-Tag: 1.0.4~3 X-Git-Url: http://git.snicker.com.cn/sitemap.xml?a=commitdiff_plain;h=129a888835d3502d3011b96d1fd06ca03bfcafc0;p=mirrors%2FShenYin.git 添加地图和运动 --- diff --git a/ShenYin/Podfile.lock b/ShenYin/Podfile.lock index b49030b..38cdb30 100644 --- a/ShenYin/Podfile.lock +++ b/ShenYin/Podfile.lock @@ -1,4 +1,11 @@ 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) @@ -70,6 +77,9 @@ PODS: - 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 @@ -80,6 +90,7 @@ DEPENDENCIES: - IQKeyboardManagerSwift - JXPagingView/Paging - JXSegmentedView + - Kingfisher - Kingfisher (~> 6.0) - MBProgressHUD - MJRefresh @@ -97,6 +108,10 @@ DEPENDENCIES: SPEC REPOS: https://gitee.com/mirrors/CocoaPods-Specs.git: + - AMap3DMap-NO-IDFA + - AMapFoundation-NO-IDFA + - AMapLocation-NO-IDFA + - AMapSearch-NO-IDFA - CryptoSwift - DeviceKit - DGActivityIndicatorView @@ -130,6 +145,10 @@ SPEC REPOS: - 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 @@ -162,6 +181,6 @@ SPEC CHECKSUMS: YYText: 5c461d709e24d55a182d1441c41dc639a18a4849 ZipArchive: e25a4373192673e3229ac8d6e9f64a3e5713c966 -PODFILE CHECKSUM: 8be0cb581e3b6cc73fee508087fb68b46cbcd963 +PODFILE CHECKSUM: 90bab882d785e16d9a04264a779a1b161ec591b7 COCOAPODS: 1.16.2 diff --git a/ShenYin/ShenYin.xcodeproj/project.pbxproj b/ShenYin/ShenYin.xcodeproj/project.pbxproj index 4db690f..a881ca5 100644 --- a/ShenYin/ShenYin.xcodeproj/project.pbxproj +++ b/ShenYin/ShenYin.xcodeproj/project.pbxproj @@ -17,8 +17,8 @@ 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 */ @@ -480,6 +480,59 @@ 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 */; @@ -552,6 +605,59 @@ 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 */; }; @@ -565,31 +671,22 @@ /* 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, @@ -601,7 +698,7 @@ 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; @@ -611,9 +708,9 @@ 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; @@ -642,7 +739,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - F2E449CAD5874BE652A69B50 /* (null) in Frameworks */, + F2E449CAD5874BE652A69B50 /* BuildFile in Frameworks */, 7A6613B4B617D6E71D34944C /* Pods_ShenYin.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -652,7 +749,7 @@ 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 */, ); @@ -782,6 +879,7 @@ 3F887B9A2E38D8DC00C98658 /* Resources */, 5A934A35F54A5620CFD3C08A /* [CP] Embed Pods Frameworks */, 3FEFE9092F1B252000D82F17 /* Embed Frameworks */, + 66ADC9E36EC3B28429D51406 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -924,14 +1022,10 @@ 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"; @@ -967,19 +1061,32 @@ 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; diff --git a/ShenYin/ShenYin/UI/Sport/MusicRootView.swift b/ShenYin/ShenYin/UI/Sport/MusicRootView.swift new file mode 100644 index 0000000..fe93653 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/MusicRootView.swift @@ -0,0 +1,21 @@ +// +// 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 + } +} diff --git a/ShenYin/ShenYin/UI/Sport/RecordRootView.swift b/ShenYin/ShenYin/UI/Sport/RecordRootView.swift new file mode 100644 index 0000000..911138e --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/RecordRootView.swift @@ -0,0 +1,22 @@ +// +// 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 + } +} + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/AddGroupHeader.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/AddGroupHeader.swift new file mode 100644 index 0000000..f9912ab --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/AddGroupHeader.swift @@ -0,0 +1,40 @@ +// +// 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) + } + + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/CreateGroupVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/CreateGroupVC.swift new file mode 100644 index 0000000..512beca --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/CreateGroupVC.swift @@ -0,0 +1,140 @@ +// +// 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) + } + } + } +} + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/SportInputItem.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/SportInputItem.swift new file mode 100644 index 0000000..4c10566 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/SportInputItem.swift @@ -0,0 +1,136 @@ +// +// 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 + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/SportSelectItem.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/SportSelectItem.swift new file mode 100644 index 0000000..51d8041 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/SportSelectItem.swift @@ -0,0 +1,48 @@ +// +// 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) + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/SportSwitchItem.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/SportSwitchItem.swift new file mode 100644 index 0000000..4f5423a --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/Create/SportSwitchItem.swift @@ -0,0 +1,51 @@ +// +// 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(){ + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupCell.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupCell.swift new file mode 100644 index 0000000..3174168 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupCell.swift @@ -0,0 +1,90 @@ +// +// 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) + } + + } + + +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupModel.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupModel.swift new file mode 100644 index 0000000..703df34 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupModel.swift @@ -0,0 +1,31 @@ +// +// 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() { } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupVC.swift new file mode 100644 index 0000000..4b34e04 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupVC.swift @@ -0,0 +1,118 @@ +// +// 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) + + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupView.swift new file mode 100644 index 0000000..9cbc484 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/MyGroup/MyGroupView.swift @@ -0,0 +1,82 @@ +// +// 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 + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/Other/GroupRoleVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/Other/GroupRoleVC.swift new file mode 100644 index 0000000..7661102 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/Other/GroupRoleVC.swift @@ -0,0 +1,231 @@ +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) + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/Other/GroupTypeVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/Other/GroupTypeVC.swift new file mode 100644 index 0000000..bb7a0e6 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/Other/GroupTypeVC.swift @@ -0,0 +1,80 @@ +// +// 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() + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Group/add/AddGroupVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Group/add/AddGroupVC.swift new file mode 100644 index 0000000..89046c7 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Group/add/AddGroupVC.swift @@ -0,0 +1,98 @@ +// +// 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) + } + } + } +} + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Light/BrightnessView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Light/BrightnessView.swift new file mode 100644 index 0000000..48f4d23 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Light/BrightnessView.swift @@ -0,0 +1,78 @@ +// +// LightView.swift +// ShenYin +// +// Created by liangshi on 2026/2/2. +// + +extension LightSetVC{ + class BrightnessView: BaseView { + let bgView = UIView() + let titleLabel = UILabel() + let btn = UIButton() + let line = UIView() + let slider = UISlider() + + override func setupViews() { + addSubviews([titleLabel,slider,btn,line]) + + titleLabel.do { (v) in + v.textColor = .white + v.font = .bold(14) + v.textAlignment = .left + v.text = "亮度".l10n + } + + btn.do { v in + v.setImage(UIImage(named: "tips_2"), for: .normal) + v.addTarget(self, action: #selector(tipsAction), for: .touchUpInside) + } + + line.do { v in + v.backgroundColor = .color(.separateLine) + } + slider.do { v in + // v.backgroundColor = .red + v.minimumValue = 0 + v.maximumValue = 100 + v.value = 50 + v.minimumTrackTintColor = .white + v.maximumTrackTintColor = .white.withAlphaComponent(0.2) + v.setThumbImage(UIColor.white.imageCircle(with: CGSize(width: 20, height: 20)), for: .normal) + v.addTarget(self, action: #selector(sliderChanged(_:)), for: .valueChanged) // continuous changes + + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { (m) in + m.top.equalToSuperview().inset(16) + m.left.equalToSuperview().offset(32) + } + slider.snp.makeConstraints { make in + make.height.equalTo(40) + make.centerX.equalToSuperview() + make.left.right.equalToSuperview().inset(32) + make.top.equalToSuperview().inset(40) + } + btn.snp.makeConstraints { (m) in + m.size.equalTo(30) + m.right.equalToSuperview().inset(32) + m.centerY.equalTo(titleLabel.snp.centerY) + } + + line.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(28) + make.bottom.equalToSuperview() + make.height.equalTo(0.4) + } + } + + @objc func tipsAction(){ + SportPopView().show() + } + @objc func sliderChanged(_ slider:UISlider){ + + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Light/LightSetVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Light/LightSetVC.swift new file mode 100644 index 0000000..aa4eaee --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Light/LightSetVC.swift @@ -0,0 +1,100 @@ +// +// 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 + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Light/ModeView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Light/ModeView.swift new file mode 100644 index 0000000..81e393d --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Light/ModeView.swift @@ -0,0 +1,152 @@ +// +// ModeView.swift +// ShenYin +// +// Created by liangshi on 2026/2/2. +// +enum LightMode { + case normal + case breath + case flash + + var name:String{ + switch self { + case .normal: + return "正常".l10n + case .breath: + return "呼吸".l10n + case .flash: + return "闪烁".l10n + } + } +} +extension LightSetVC{ + + + class ModeView: BaseView { + let titleLabel = UILabel() + let normalItem = SelectedTypeItem() + let breathItem = SelectedTypeItem() + let flashItem = SelectedTypeItem() + let line = UIView() + + var isOk:Bool{ + return normalItem.isSelected || breathItem.isSelected || flashItem.isSelected + } + + + override func setupViews() { + // backgroundColor = .red + addSubviews([titleLabel,normalItem,breathItem,flashItem,line]) + + titleLabel.do { v in + v.textAlignment = .center + v.font = .bold(14) + v.textColor = .white + v.text = "模式".l10n + } + normalItem.do { v in + v.mode = .normal + v.yc.setCornerRadius(8) + v.yc.addTap(target: self, action: #selector(normalAction)) + } + breathItem.do { v in + v.mode = .breath + v.yc.setCornerRadius(8) + v.yc.addTap(target: self, action: #selector(breathAction)) + } + flashItem.do { v in + v.mode = .flash + v.yc.setCornerRadius(8) + v.yc.addTap(target: self, action: #selector(flashAction)) + } + line.do { v in + v.backgroundColor = .color(.separateLine) + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview().inset(20) + make.left.equalToSuperview().inset(32) + } + normalItem.snp.makeConstraints { make in + make.left.equalToSuperview().inset(32) + make.top.equalTo(titleLabel.snp.bottom).offset(10) + make.width.equalTo(80.fitR) + make.height.equalTo(32) + } + breathItem.snp.makeConstraints { make in + make.centerX.equalToSuperview() + make.top.width.height.equalTo(normalItem) + } + flashItem.snp.makeConstraints { make in + make.right.equalToSuperview().inset(32) + make.top.width.height.equalTo(normalItem) + } + line.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(28) + make.bottom.equalToSuperview() + make.height.equalTo(0.4) + } + } + + @objc func normalAction(){ + normalItem.isSelected = true + breathItem.isSelected = false + flashItem.isSelected = false + } + @objc func breathAction(){ + normalItem.isSelected = false + breathItem.isSelected = true + flashItem.isSelected = false + } + @objc func flashAction(){ + normalItem.isSelected = false + breathItem.isSelected = false + flashItem.isSelected = true + } + + + class SelectedTypeItem: BaseView { + let titleLabel = UILabel() + var mode:LightMode = .normal{ + didSet{ + titleLabel.text = mode.name + } + } + + var isSelected:Bool = false{ + didSet{ + if isSelected { + titleLabel.textColor = .color(.first) + backgroundColor = .color(.bgColor) + } + else{ + backgroundColor = .clear + titleLabel.textColor = .color(.secondary) + yc.setBorder(width: 1, color: .color(.secondary)) + } + } + } + + override func setupViews() { + backgroundColor = .color(.bgColor) + addSubviews([titleLabel]) + titleLabel.do { v in + v.textAlignment = .center + v.adjustsFontSizeToFitWidth = true + v.font = .regular(14) + } + self.isSelected = false + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + } + } + } + +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Light/StateView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Light/StateView.swift new file mode 100644 index 0000000..fead556 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Light/StateView.swift @@ -0,0 +1,52 @@ +// +// StateView.swift +// ShenYin +// +// Created by liangshi on 2026/2/2. +// + +extension LightSetVC{ + class StateView: BaseView { + let titleLabel = UILabel() + let iSwitch = UISwitch() + let line = UIView() + weak var delegate:SportSetCellDelegate? + + override func setupViews() { + addSubviews([titleLabel,iSwitch,line]) + + titleLabel.do { (v) in + v.textColor = .white + v.font = .bold(14) + v.textAlignment = .left + v.text = "灯带".l10n + } + + iSwitch.do { v in + // v.backgroundColor = .red + } + + line.do { v in + v.backgroundColor = .color(.separateLine) + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { (m) in + m.centerY.equalToSuperview() + m.left.equalToSuperview().offset(32) + } + + iSwitch.snp.makeConstraints { (m) in + m.right.equalToSuperview().inset(32) + m.centerY.equalToSuperview() + } + + line.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(28) + make.bottom.equalToSuperview() + make.height.equalTo(0.4) + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Ready/CountdownView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Ready/CountdownView.swift new file mode 100644 index 0000000..5afe77e --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Ready/CountdownView.swift @@ -0,0 +1,76 @@ +// +// 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() + } + } + +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Ready/CustomMapView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Ready/CustomMapView.swift new file mode 100644 index 0000000..fbc7567 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Ready/CustomMapView.swift @@ -0,0 +1,12 @@ +// +// Untitled.swift +// ShenYin +// +// Created by liangshi on 2026/1/21. +// + +class CustomMapView: BaseView { + + + +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Ready/FooterView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Ready/FooterView.swift new file mode 100644 index 0000000..78b2034 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Ready/FooterView.swift @@ -0,0 +1,106 @@ +// +// 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) + } + } + } + + } + +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Ready/Navbar.swift b/ShenYin/ShenYin/UI/Sport/Sport/Ready/Navbar.swift new file mode 100644 index 0000000..5b0aa0c --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Ready/Navbar.swift @@ -0,0 +1,110 @@ +// +// 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) + } + } + } + } + + +} + + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyHeader.swift b/ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyHeader.swift new file mode 100644 index 0000000..4b8fbbd --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyHeader.swift @@ -0,0 +1,107 @@ +// +// 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) + } + } + } + + } + +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyVC.swift new file mode 100644 index 0000000..6c0434f --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Ready/ReadyVC.swift @@ -0,0 +1,71 @@ +// +// 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() + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Root/DataView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Root/DataView.swift new file mode 100644 index 0000000..3c32ad5 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Root/DataView.swift @@ -0,0 +1,122 @@ +// +// 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) + } + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Root/GroupView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Root/GroupView.swift new file mode 100644 index 0000000..620dc8a --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Root/GroupView.swift @@ -0,0 +1,102 @@ +// +// 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) + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Root/PlanView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Root/PlanView.swift new file mode 100644 index 0000000..d29ffed --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Root/PlanView.swift @@ -0,0 +1,26 @@ +// +// 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() + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Root/RouteView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Root/RouteView.swift new file mode 100644 index 0000000..dadc7a4 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Root/RouteView.swift @@ -0,0 +1,98 @@ +// +// 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) + } + } + } + + + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Root/SportRootView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Root/SportRootView.swift new file mode 100644 index 0000000..29ea350 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Root/SportRootView.swift @@ -0,0 +1,66 @@ +// +// 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 + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Root/SportTypeView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Root/SportTypeView.swift new file mode 100644 index 0000000..deef027 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Root/SportTypeView.swift @@ -0,0 +1,134 @@ +// +// 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) + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Set/SportSetCell.swift b/ShenYin/ShenYin/UI/Sport/Sport/Set/SportSetCell.swift new file mode 100644 index 0000000..ce6aeb3 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Set/SportSetCell.swift @@ -0,0 +1,321 @@ +// +// 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) + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Set/SportSetModel.swift b/ShenYin/ShenYin/UI/Sport/Sport/Set/SportSetModel.swift new file mode 100644 index 0000000..0310fa4 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Set/SportSetModel.swift @@ -0,0 +1,22 @@ +// +// 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 +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Set/SportSetVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Set/SportSetVC.swift new file mode 100644 index 0000000..4347064 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Set/SportSetVC.swift @@ -0,0 +1,149 @@ +// +// 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 + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/CadenceView.swift b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/CadenceView.swift new file mode 100644 index 0000000..8e41a47 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/CadenceView.swift @@ -0,0 +1,7 @@ +// +// CadenceView.swift +// ShenYin +// +// Created by liangshi on 2026/2/10. +// + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/ElevationView.swift b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/ElevationView.swift new file mode 100644 index 0000000..d323eea --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/ElevationView.swift @@ -0,0 +1,7 @@ +// +// elevationView.swift +// ShenYin +// +// Created by liangshi on 2026/2/10. +// + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/FeelView.swift b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/FeelView.swift new file mode 100644 index 0000000..0d7a8ed --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/FeelView.swift @@ -0,0 +1,57 @@ +// +// 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) + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/PacePerView.swift b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/PacePerView.swift new file mode 100644 index 0000000..7945489 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/PacePerView.swift @@ -0,0 +1,7 @@ +// +// PacePerView.swift +// ShenYin +// +// Created by liangshi on 2026/2/10. +// + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/PaceView.swift b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/PaceView.swift new file mode 100644 index 0000000..9c69b83 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/PaceView.swift @@ -0,0 +1,7 @@ +// +// SpeepView.swift +// ShenYin +// +// Created by liangshi on 2026/2/10. +// + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/SportDetailBoard.swift b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/SportDetailBoard.swift new file mode 100644 index 0000000..fc5eaa7 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/SportDetailBoard.swift @@ -0,0 +1,172 @@ +//// +//// 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() + } + } + } + } + + + +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/SportDetailVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/SportDetailVC.swift new file mode 100644 index 0000000..19787df --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/SportDetailVC.swift @@ -0,0 +1,97 @@ +// +// 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() + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/StepRateView.swift b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/StepRateView.swift new file mode 100644 index 0000000..7913a83 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/StepRateView.swift @@ -0,0 +1,7 @@ +// +// stepRateView.swift +// ShenYin +// +// Created by liangshi on 2026/2/10. +// + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/StrideLengthView.swift b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/StrideLengthView.swift new file mode 100644 index 0000000..3266d83 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/SportDetail/StrideLengthView.swift @@ -0,0 +1,7 @@ +// +// strideLengthView.swift +// ShenYin +// +// Created by liangshi on 2026/2/10. +// + diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Sporting/DetailBoard.swift b/ShenYin/ShenYin/UI/Sport/Sport/Sporting/DetailBoard.swift new file mode 100644 index 0000000..769b2e1 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Sporting/DetailBoard.swift @@ -0,0 +1,283 @@ +// +// 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() + } + } + } + } + + + +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SimpleBoard.swift b/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SimpleBoard.swift new file mode 100644 index 0000000..ce06371 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SimpleBoard.swift @@ -0,0 +1,85 @@ +// +// Untitled.swift +// ShenYin +// +// Created by liangshi on 2026/2/3. +// + +import UIKit + +extension SportingVC{ + class SimpleBoard: BaseView { + let topIcon = UIImageView() + let distanceItem = LabelItem() + let durationItem = LabelItem() + + override func setupViews() { + backgroundColor = .white + addSubviews([topIcon,distanceItem,durationItem]) + topIcon.do { v in + v.backgroundColor = .color(.secondary) + v.yc.setCornerRadius(2) + } + distanceItem.do { v in + v.titleLabel.text = "0" + v.detailLabel.text = "总距离".l10n + } + durationItem.do { v in + v.titleLabel.text = "00:00:00" + v.detailLabel.text = "总时长".l10n + } + } + + override func setupLayout() { + topIcon.snp.makeConstraints { make in + make.width.equalTo(50) + make.height.equalTo(4) + make.top.equalToSuperview().inset(6) + make.centerX.equalToSuperview() + } + distanceItem.snp.makeConstraints { make in + make.left.equalToSuperview().inset(18) + make.top.equalToSuperview().inset(27) + make.height.equalTo(50) + } + durationItem.snp.makeConstraints { make in + make.left.equalToSuperview().inset(kScreenWid/2 + 18) + make.top.equalToSuperview().inset(27) + make.height.equalTo(distanceItem) + } + } + + @objc func groupAction(){ + App.shared.goToPage(SportSetVC()) + } + class LabelItem: BaseView { + let detailLabel = UILabel() + let titleLabel = UILabel() + + override func setupViews() { + addSubviews([titleLabel,detailLabel]) + titleLabel.do { v in + v.textColor = .color(.secondary) + v.font = .bold(24) + v.textAlignment = .left + } + detailLabel.do { v in + v.textColor = .color(.secondary) + v.font = .regular(12) + v.textAlignment = .left + } + } + + override func setupLayout() { + titleLabel.snp.makeConstraints { make in + make.top.equalToSuperview().inset(0) + make.left.right.equalToSuperview() + } + detailLabel.snp.makeConstraints { make in + make.bottom.equalToSuperview().inset(0) + make.left.right.equalToSuperview() + } + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SportingVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SportingVC.swift new file mode 100644 index 0000000..fe9a9f6 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Sporting/SportingVC.swift @@ -0,0 +1,87 @@ +// +// 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() + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Target/CalorieView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Target/CalorieView.swift new file mode 100644 index 0000000..e3f5607 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Target/CalorieView.swift @@ -0,0 +1,45 @@ +// +// CaloriView.swift +// ShenYin +// +// Created by liangshi on 2026/2/3. +// + +import JXSegmentedView + +extension SportTargetVC{ + class CaloriView: BaseView ,JXSegmentedListContainerViewListDelegate{ + let label = UILabel() + + override func setupViews() { + addSubviews([label]) + label.do { v in + v.font = .bold(28) + v.textAlignment = .center + v.textColor = .color(.first) + v.text = "300 千卡" + v.yc.addTap(target: self, action: #selector(tapAction)) + } + } + override func setupLayout() { + label.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().inset(50) + } + } + + func listView() -> UIView { + return self + } + @objc func tapAction(){ + let list = Array(stride(from: 1, to: 1000, by: 1)).map { String($0) + " 千卡" } + let v = CustomPicker2(title: "卡路里".l10n, list:list ) + v.selectedIndex = 0 + v.show() + v.didSelected = {[weak self] (index,value) in + guard let self = self else { return } + label.text = value + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Target/DistanceView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Target/DistanceView.swift new file mode 100644 index 0000000..4aeadce --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Target/DistanceView.swift @@ -0,0 +1,45 @@ +// +// DistanceView.swift +// ShenYin +// +// Created by liangshi on 2026/2/3. +// + +import JXSegmentedView + +extension SportTargetVC{ + class DistanceView: BaseView ,JXSegmentedListContainerViewListDelegate{ + let label = UILabel() + + override func setupViews() { + addSubviews([label]) + label.do { v in + v.font = .bold(28) + v.textAlignment = .center + v.textColor = .color(.first) + v.text = "3 km" + v.yc.addTap(target: self, action: #selector(tapAction)) + } + } + override func setupLayout() { + label.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().inset(50) + } + } + + func listView() -> UIView { + return self + } + @objc func tapAction(){ + let list = Array(stride(from: 1, to: 100, by: 1)).map { String($0) + " km" } + let v = CustomPicker2(title: "距离".l10n, list:list ) + v.selectedIndex = 0 + v.show() + v.didSelected = {[weak self] (index,value) in + guard let self = self else { return } + label.text = value + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Target/DurationView.swift b/ShenYin/ShenYin/UI/Sport/Sport/Target/DurationView.swift new file mode 100644 index 0000000..aa5b92d --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Target/DurationView.swift @@ -0,0 +1,44 @@ +// +// DurationView.swift +// ShenYin +// +// Created by liangshi on 2026/2/3. +// + +import JXSegmentedView + +extension SportTargetVC{ + class DurationView: BaseView ,JXSegmentedListContainerViewListDelegate{ + let label = UILabel() + + override func setupViews() { + addSubviews([label]) + label.do { v in + v.font = .bold(28) + v.textAlignment = .center + v.textColor = .color(.first) + v.text = "00:30" + v.yc.addTap(target: self, action: #selector(tapAction)) + } + } + override func setupLayout() { + label.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().inset(50) + } + } + + func listView() -> UIView { + return self + } + @objc func tapAction(){ + let v = CustomPicker3(title: "日期".l10n) + v.datePicker.datePickerMode = .time + v.show() + v.didSelected = {[weak self] (date) in + guard let self = self else { return } + label.text = date.format(.shortTime) + } + } + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Target/SportTargetVC.swift b/ShenYin/ShenYin/UI/Sport/Sport/Target/SportTargetVC.swift new file mode 100644 index 0000000..79dcfa0 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Target/SportTargetVC.swift @@ -0,0 +1,127 @@ +// +// SportTargetVC.swift +// ShenYin +// +// Created by liangshi on 2026/2/3. +// + +import JXSegmentedView + + +enum SportTargetType{ + case distance + case duration + case calorie + + var name:String{ + switch self { + case .distance: + return "距离".l10n + case .duration: + return "时长".l10n + case .calorie: + return "卡路里".l10n + } + } + static var all:[SportTargetType] = [.distance,.duration,.calorie] +} + +class SportTargetVC: BaseVC { + let okBtn = CustomButton() + private let segmentedDataSource = JXSegmentedTitleDataSource() + private let segmentedView = JXSegmentedView() + private lazy var listContainerView: JXSegmentedListContainerView! = { + let view = JXSegmentedListContainerView(dataSource: self, type: .scrollView) + return view + }() + + var list:[SportTargetType] = SportTargetType.all + override func viewDidLoad() { + super.viewDidLoad() + + + } + + override func setupLayout(){ + + segmentedView.snp.makeConstraints { (m) in + m.left.right.equalToSuperview() + m.height.equalTo(44.fitR) + m.top.equalToSuperview().inset(kNavBtm) + } + listContainerView.snp.makeConstraints { (m) in + m.width.left.equalToSuperview() + m.top.equalTo(segmentedView.snp.bottom) + m.bottom.equalToSuperview() + } + okBtn.snp.makeConstraints { make in + make.bottom.equalToSuperview().inset(80) + make.left.right.equalToSuperview().inset(51) + make.height.equalTo(46) + } + } + override func setupViews(){ + navBar.title = "设置目标".l10n + view.addSubview(segmentedView) + view.addSubview(listContainerView) + view.addSubview(okBtn) + + view.backgroundColor = .color(.bgColor) + segmentedView.do { (v) in + segmentedDataSource.titleNormalColor = .color(.secondary) + segmentedDataSource.titleSelectedColor = .color(.first) + segmentedDataSource.titleNormalFont = .regular(14) + segmentedDataSource.titleSelectedFont = .bold(16) + segmentedDataSource.isTitleZoomEnabled = true + // segmentedDataSource.titleSelectedZoomScale = 1 + segmentedDataSource.isTitleStrokeWidthEnabled = true + segmentedDataSource.isItemSpacingAverageEnabled = true + segmentedDataSource.isTitleColorGradientEnabled = true + segmentedDataSource.titles = list.map{"\($0.name)"} + segmentedView.backgroundColor = .clear + + //配置指示器 + let indicator = JXSegmentedIndicatorLineView() + indicator.indicatorWidth = 20 + indicator.indicatorHeight = 4 + indicator.verticalOffset = 6 + indicator.indicatorColor = .color(.sport) + segmentedView.indicators = [indicator] + + v.dataSource = segmentedDataSource + v.listContainer = listContainerView + } + okBtn.set(title: "确定".l10n,style: .sport, target: self, action: #selector(okAction)) + } + @objc func okAction(){ + self.navigationController?.popViewController(animated: true) + } +} + +extension SportTargetVC: JXSegmentedListContainerViewListDelegate { + func listView() -> UIView { + return view + } +} + +extension SportTargetVC: JXSegmentedListContainerViewDataSource { + func numberOfLists(in listContainerView: JXSegmentedListContainerView) -> Int { + if let titleDataSource = segmentedView.dataSource as? JXSegmentedBaseDataSource { + return titleDataSource.dataSource.count + } + return 0 + } + + func listContainerView(_ listContainerView: JXSegmentedListContainerView, initListAt index: Int) -> JXSegmentedListContainerViewListDelegate { + let type = list[index] + switch type { + case .distance: + return DistanceView() + case .duration: + return DurationView() + case .calorie: + return CaloriView() + } + + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Tools/MapManager.swift b/ShenYin/ShenYin/UI/Sport/Sport/Tools/MapManager.swift new file mode 100644 index 0000000..7344928 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Tools/MapManager.swift @@ -0,0 +1,58 @@ +// +// 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) + } +} diff --git a/ShenYin/ShenYin/UI/Sport/Sport/Tools/SportManager.swift b/ShenYin/ShenYin/UI/Sport/Sport/Tools/SportManager.swift new file mode 100644 index 0000000..ae6d427 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/Sport/Tools/SportManager.swift @@ -0,0 +1,13 @@ +// +// SportManager.swift +// ShenYin +// +// Created by liangshi on 2026/2/10. +// + +class SportManager { + static let shared = SportManager() + var sortType = SportType.ride + + +} diff --git a/ShenYin/ShenYin/UI/Sport/SportHomeVC.swift b/ShenYin/ShenYin/UI/Sport/SportHomeVC.swift new file mode 100644 index 0000000..be4ce07 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/SportHomeVC.swift @@ -0,0 +1,122 @@ +// +// 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() + } + + } +} diff --git a/ShenYin/ShenYin/UI/Sport/TranslateRootView.swift b/ShenYin/ShenYin/UI/Sport/TranslateRootView.swift new file mode 100644 index 0000000..a406472 --- /dev/null +++ b/ShenYin/ShenYin/UI/Sport/TranslateRootView.swift @@ -0,0 +1,21 @@ +// +// 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 + } +} diff --git a/ShenYin/podfile b/ShenYin/podfile index 4e4b133..b32c0c4 100644 --- a/ShenYin/podfile +++ b/ShenYin/podfile @@ -51,9 +51,9 @@ target 'ShenYin' do 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 @@ -71,7 +71,7 @@ target 'playboy' do pod 'SwiftDate'#时间转换 pod 'SVProgressHUD'#蒙版 pod 'MBProgressHUD'#蒙版 - pod 'Kingfisher', '~> 6.0'#图片下载K + pod 'Kingfisher' #图片下载K pod 'FSPagerView' pod "TabPageViewController" #tabpage pod 'JXSegmentedView'