From 15e4c3df174601778e0e101214c7e6b970e11600 Mon Sep 17 00:00:00 2001 From: linshujie Date: Fri, 10 Jul 2026 15:52:01 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E8=BD=A8=E8=BF=B9=E5=9B=9E=E6=94=BE?= =?UTF-8?q?=E4=BC=98=E5=8C=96=20-=20=E7=99=BB=E5=BD=95=E9=A1=B5=E7=AC=AC?= =?UTF-8?q?=E4=B8=89=E6=96=B9=E5=AD=97=E4=BD=93=E6=98=BE=E7=A4=BA=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E4=BF=AE=E5=A4=8D=20-=20=E7=89=88=E6=9C=AC=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QuickLocation.xcodeproj/project.pbxproj | 4 +- QuickLocation/AppDelegate.swift | 2 + .../Core/Extension/UIFont+Extension.swift | 2 +- QuickLocation/Info.plist | 2 + .../Manager/Account/UserConfigModel.swift | 32 +++++++ QuickLocation/Manager/App/ApiManager.swift | 5 +- .../Manager/App/AppCacheManager.swift | 10 +-- QuickLocation/Manager/App/Authorize.swift | 25 ++++++ .../GroupMemberList/ItineraryTraceVC.swift | 86 +++++++------------ QuickLocation/Section/Group/GroupView.swift | 1 + .../SearchLocationResultVC.swift | 8 ++ .../SearchLocation/SearchLocationVC.swift | 1 + .../SearchLocation/SearchLocationView.swift | 37 +++++++- .../Section/Launch/LaunchViewController.swift | 35 +++++++- QuickLocation/Section/Login/LoginView.swift | 2 +- .../Section/Login/OneTapLoginView.swift | 2 +- .../Section/Mine/Account/AccountVC.swift | 46 ++++++++++ .../Section/Mine/Account/AccountView.swift | 2 +- .../ScheduleViewed/ScheduleViewedView.swift | 1 + QuickLocation/Service/UserService.swift | 2 +- 20 files changed, 232 insertions(+), 73 deletions(-) diff --git a/QuickLocation.xcodeproj/project.pbxproj b/QuickLocation.xcodeproj/project.pbxproj index e0f7cc3..69ecfd8 100644 --- a/QuickLocation.xcodeproj/project.pbxproj +++ b/QuickLocation.xcodeproj/project.pbxproj @@ -2166,7 +2166,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = cn.zuomeng.jisuloca; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2218,7 +2218,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.0.0; PRODUCT_BUNDLE_IDENTIFIER = cn.zuomeng.jisuloca; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/QuickLocation/AppDelegate.swift b/QuickLocation/AppDelegate.swift index f54eb49..4dcf1a4 100644 --- a/QuickLocation/AppDelegate.swift +++ b/QuickLocation/AppDelegate.swift @@ -19,6 +19,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + UIFont.loadFontName("douyu.otf") + UIFont.loadFontName("zihunbiantaoti-r.ttf") setupLocation() ApiManager.shared.setup() AppRouter.shared.setup() diff --git a/QuickLocation/Core/Extension/UIFont+Extension.swift b/QuickLocation/Core/Extension/UIFont+Extension.swift index 536ff3a..f0c595c 100644 --- a/QuickLocation/Core/Extension/UIFont+Extension.swift +++ b/QuickLocation/Core/Extension/UIFont+Extension.swift @@ -34,7 +34,7 @@ public extension UIFont { /// 加载本地自定义字体 /// - Parameter name: 字体文件名称 - private static func loadFontName(_ fileName: String) -> String? { + public static func loadFontName(_ fileName: String) -> String? { // 字体文件资源路径 guard let fontURL = Bundle.main.url(forResource: fileName, withExtension: nil), let data = try? Data(contentsOf: fontURL), diff --git a/QuickLocation/Info.plist b/QuickLocation/Info.plist index ef187a1..ee972bb 100644 --- a/QuickLocation/Info.plist +++ b/QuickLocation/Info.plist @@ -40,6 +40,8 @@ NSAllowsArbitraryLoads + NSContactsUsageDescription + 需要访问您的通讯录以导入联系人号码 UIAppFonts douyu.otf diff --git a/QuickLocation/Manager/Account/UserConfigModel.swift b/QuickLocation/Manager/Account/UserConfigModel.swift index 7360d10..48270d9 100644 --- a/QuickLocation/Manager/Account/UserConfigModel.swift +++ b/QuickLocation/Manager/Account/UserConfigModel.swift @@ -70,6 +70,8 @@ struct SystemConfigModel: Mappable { var timeConfig: PopupWindowTimeModel? /// 微信分享配置 var shareConfig: WxShareConfigModel? + /// 版本更新 + var versionUpgradeModel: VersionUpgradeModel? /// 聊天界面的警告说明 var chatWarning: String = "" @@ -100,6 +102,7 @@ struct SystemConfigModel: Mappable { shareConfig <- map["client.weixin.share", nested: false] guideDisplay <- map["client.guide_display", nested: false] globalDisplay <- map["client.global_display", nested: false] + versionUpgradeModel <- map["client.version.upgrade", nested: false] } } @@ -173,3 +176,32 @@ struct WxShareConfigModel: Mappable { image <- map["image"] } } + +struct VersionUpgradeModel: Mappable { + /// 下载地址 + var url: String = "" + + /// 标题 + var title: String = "" + + /// 内容 + var description: String = "" + + /// 版本 + var version: String = "" + + /// 强制更新 + var force: Bool = false + + init?(map: Map) { + + } + + mutating func mapping(map: Map) { + url <- map["url"] + title <- map["title"] + description <- map["description"] + force <- map["force"] + version <- map["version"] + } +} diff --git a/QuickLocation/Manager/App/ApiManager.swift b/QuickLocation/Manager/App/ApiManager.swift index 743265b..6278af9 100644 --- a/QuickLocation/Manager/App/ApiManager.swift +++ b/QuickLocation/Manager/App/ApiManager.swift @@ -111,7 +111,7 @@ extension ApiManager { case GatewayStatusCode.userLoginExpair.rawValue: // token失效 handleTokenExpired(msg: message) case GatewayStatusCode.failure.rawValue, GatewayStatusCode.noAuthority.rawValue: // 退出当前界面 - handlePopView(message) + handlePopView(message, handle) default: // 接口没返回code的时候取success字段 if success != nil { @@ -171,8 +171,9 @@ extension ApiManager { } // MARK: - 业务中断(需退出当前页面) - private func handlePopView(_ msg: String?) { + private func handlePopView(_ msg: String?, _ handle: Bool) { MainAsync { + guard handle else { return } DLToast.showInfo(text: msg ?? "Error...") { guard let viewController = UIViewController.currentViewController() else { return } viewController.navigationController?.popViewController(animated: true) diff --git a/QuickLocation/Manager/App/AppCacheManager.swift b/QuickLocation/Manager/App/AppCacheManager.swift index 41165d7..e478586 100644 --- a/QuickLocation/Manager/App/AppCacheManager.swift +++ b/QuickLocation/Manager/App/AppCacheManager.swift @@ -23,14 +23,8 @@ final class AppCacheManager { let fullPath = path + "/" + subPath var isDir: ObjCBool = false if manager.fileExists(atPath: fullPath, isDirectory: &isDir) { - if isDir.boolValue { - totalSize += folderSize(at: fullPath) - } else { - // 读取文件属性,失败则跳过 - if let attrs = try? manager.attributesOfItem(atPath: fullPath) { - totalSize += attrs[.size] as? Int64 ?? 0 - } - } + if isDir.boolValue { continue } + totalSize += (try? manager.attributesOfItem(atPath: fullPath))?[.size] as? Int64 ?? 0 } } return totalSize diff --git a/QuickLocation/Manager/App/Authorize.swift b/QuickLocation/Manager/App/Authorize.swift index d41d41e..1446ceb 100644 --- a/QuickLocation/Manager/App/Authorize.swift +++ b/QuickLocation/Manager/App/Authorize.swift @@ -13,6 +13,7 @@ import UserNotifications import AdSupport import AppTrackingTransparency import URLNavigator +import Contacts // MARK: - AuthorizeType @@ -112,6 +113,8 @@ public protocol AuthorizeProtocol { return AuthorizeMicrophone() case .tracking: return AuthorizeTracking() + case .contacts: + return AuthorizeContacts() default: return nil } @@ -402,4 +405,26 @@ class AuthorizeTracking: NSObject, AuthorizeProtocol { } } +// MARK: - AuthorizeContacts +private class AuthorizeContacts: NSObject, AuthorizeProtocol { + func authorizeStatus() -> AuthorizeStatus { + switch CNContactStore.authorizationStatus(for: .contacts) { + case .restricted: + return .restricted + case .denied: + return .denied + case .authorized: + return .authorized + default: + return .notDetermined + } + } + + func authorize(_ completion: ((AuthorizeStatus) -> Void)?) { + CNContactStore().requestAccess(for: .contacts) { _, _ in + DispatchQueue.main.async { completion?(self.authorizeStatus()) } + } + } +} + diff --git a/QuickLocation/Section/Group/GroupMemberList/ItineraryTraceVC.swift b/QuickLocation/Section/Group/GroupMemberList/ItineraryTraceVC.swift index 98b7264..fb206d3 100644 --- a/QuickLocation/Section/Group/GroupMemberList/ItineraryTraceVC.swift +++ b/QuickLocation/Section/Group/GroupMemberList/ItineraryTraceVC.swift @@ -20,7 +20,6 @@ class ItineraryTraceVC: BaseViewController { private let memberModel: GroupMemberModel private var routeOverlays: [MAPolyline] = [] private let routeSearch = AMapSearchAPI() - private var drivingSegmentIndexes: [ObjectIdentifier: Int] = [:] private var playbackSegments: [[CLLocationCoordinate2D]?] = [] private var playbackPath: [(coordinate: CLLocationCoordinate2D, distance: Double)] = [] private var playbackTotalDistance: Double = 0 @@ -41,10 +40,6 @@ class ItineraryTraceVC: BaseViewController { private var playbackTargetCoordinate: CLLocationCoordinate2D? private let minPointDistance: CLLocationDistance = 10 - private let directSegmentDistance: CLLocationDistance = 80 - private let maxDrivingSegmentDistance: CLLocationDistance = 1500 - private let maxDrivingSegmentTimeGap: Int64 = 5 * 60 * 1000 - private let maxDrivingSegmentRequests = 40 private let eventCalloutTag = 91301 override func loadView() { @@ -146,32 +141,38 @@ class ItineraryTraceVC: BaseViewController { let points = cleanedTracePoints(model.trajectory_path) guard points.count >= 2 else { print("[trace] insufficient points: \(points.count)"); return } - playbackSegments = Array(repeating: nil, count: points.count - 1) + playbackSegments = [] - var drivingRequestCount = 0 - for i in 0..<(points.count - 1) { - let from = points[i] - let to = points[i + 1] - let fallback = [from.coordinate, to.coordinate] - let distance = from.coordinate.distance(to: to.coordinate) - let timeGap = abs(to.timestamp - from.timestamp) - - if distance < directSegmentDistance { - addPolyline(fallback) - playbackSegments[i] = fallback - } else if distance <= maxDrivingSegmentDistance, - timeGap <= maxDrivingSegmentTimeGap, - drivingRequestCount < maxDrivingSegmentRequests { - requestDrivingSegment(from: from.coordinate, to: to.coordinate, segmentIndex: i) - drivingRequestCount += 1 + var sampled: [(timestamp: Int64, coordinate: CLLocationCoordinate2D)] = [] + for pt in points { + if let last = sampled.last { + if pt.timestamp - last.timestamp >= 5_000 { + sampled.append(pt) + } } else { - // 断档或距离异常的轨迹段不绘制,避免把事件点/异常点直接连到终点。 - continue + sampled.append(pt) } } + + let coords = sampled.map { $0.coordinate } + addPolyline(coords) + playbackSegments = [coords] buildPlaybackPath() updatePlaybackAnnotation(progress: playbackProgress) - print("[trace] cleaned=\(points.count) drivingRequests=\(drivingRequestCount)") + +// let middle = sampled.dropFirst().dropLast().prefix(16) +// let waypoints = middle.map { $0.coordinate } +// +// let request = AMapDrivingRouteSearchRequest() +// request.origin = AMapGeoPoint.location(withLatitude: CGFloat(points.first!.coordinate.latitude), longitude: CGFloat(points.first!.coordinate.longitude)) +// request.destination = AMapGeoPoint.location(withLatitude: CGFloat(points.last!.coordinate.latitude), longitude: CGFloat(points.last!.coordinate.longitude)) +// request.strategy = 0 +// if !waypoints.isEmpty { +// request.waypoints = waypoints.map { AMapGeoPoint.location(withLatitude: CGFloat($0.latitude), longitude: CGFloat($0.longitude)) } +// } +// routeSearch?.aMapDrivingRouteSearch(request) + + print("[trace] cleaned=\(points.count) sampled=\(sampled.count)") } private func buildPlaybackPath() { @@ -198,7 +199,6 @@ class ItineraryTraceVC: BaseViewController { rootView.mapView.remove(overlay) } routeOverlays.removeAll() - drivingSegmentIndexes.removeAll() } private func cleanedTracePoints(_ points: [TrackPoint]) -> [(timestamp: Int64, coordinate: CLLocationCoordinate2D)] { @@ -222,15 +222,6 @@ class ItineraryTraceVC: BaseViewController { return result } - private func requestDrivingSegment(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D, segmentIndex: Int) { - let request = AMapDrivingRouteSearchRequest() - request.origin = AMapGeoPoint.location(withLatitude: CGFloat(from.latitude), longitude: CGFloat(from.longitude)) - request.destination = AMapGeoPoint.location(withLatitude: CGFloat(to.latitude), longitude: CGFloat(to.longitude)) - request.strategy = 0 - drivingSegmentIndexes[ObjectIdentifier(request)] = segmentIndex - routeSearch?.aMapDrivingRouteSearch(request) - } - private func setupPlaybackControls() { rootView.playBtn.addTarget(self, action: #selector(playButtonTapped), for: .touchUpInside) rootView.progressSlider.addTarget(self, action: #selector(progressSliderTouchDown), for: .touchDown) @@ -567,29 +558,18 @@ extension ItineraryTraceVC: MAMapViewDelegate { // MARK: - AMapSearchDelegate extension ItineraryTraceVC: AMapSearchDelegate { func onRouteSearchDone(_ request: AMapRouteSearchBaseRequest!, response: AMapRouteSearchResponse!) { - let requestId = ObjectIdentifier(request) - let segmentIndex = drivingSegmentIndexes.removeValue(forKey: requestId) - - guard let path = response.route?.paths?.first as? AMapPath else { - return - } + guard let path = response.route?.paths?.first as? AMapPath else { return } let coords = coordinates(from: path) - if coords.count > 1 { - addPolyline(coords) - if let segmentIndex, playbackSegments.indices.contains(segmentIndex) { - playbackSegments[segmentIndex] = coords - buildPlaybackPath() - updatePlaybackAnnotation(progress: playbackProgress) - } - } + guard coords.count > 1 else { return } + + addPolyline(coords) + playbackSegments = [coords] + buildPlaybackPath() + updatePlaybackAnnotation(progress: playbackProgress) } func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) { - if let request = request as? AMapRouteSearchBaseRequest { - let requestId = ObjectIdentifier(request) - drivingSegmentIndexes.removeValue(forKey: requestId) - } print("Trace route search error: \(error.localizedDescription)") } } diff --git a/QuickLocation/Section/Group/GroupView.swift b/QuickLocation/Section/Group/GroupView.swift index 3ef97ee..4ae0833 100644 --- a/QuickLocation/Section/Group/GroupView.swift +++ b/QuickLocation/Section/Group/GroupView.swift @@ -188,6 +188,7 @@ class GroupView: UIView { lazy var scanBtn: UIButton = { let btn = UIButton(type: .custom) btn.setImage(UIImage(named: "Group/scan"), for: .normal) + btn.isHidden = true return btn }() diff --git a/QuickLocation/Section/Home/SearchLocation/SearchLocationResultVC.swift b/QuickLocation/Section/Home/SearchLocation/SearchLocationResultVC.swift index 50a983d..f08f081 100644 --- a/QuickLocation/Section/Home/SearchLocation/SearchLocationResultVC.swift +++ b/QuickLocation/Section/Home/SearchLocation/SearchLocationResultVC.swift @@ -50,6 +50,14 @@ class SearchLocationResultVC: BaseViewController { GroupChooseView.show(groupModel: model) { _ in } } }).disposed(by: disposeBag) + + rootView.inviteBtn.rx.tap.subscribe(onNext: { _ in + guard let model = self.groupModel else { + self.requestGroupInfo(showPicker: true) + return + } + GroupChooseView.show(groupModel: model) { _ in } + }).disposed(by: disposeBag) } private func handleCode() { diff --git a/QuickLocation/Section/Home/SearchLocation/SearchLocationVC.swift b/QuickLocation/Section/Home/SearchLocation/SearchLocationVC.swift index 0204482..c88e7b7 100644 --- a/QuickLocation/Section/Home/SearchLocation/SearchLocationVC.swift +++ b/QuickLocation/Section/Home/SearchLocation/SearchLocationVC.swift @@ -28,6 +28,7 @@ class SearchLocationVC: BaseViewController { override func viewDidLoad() { super.viewDidLoad() + fd_interactivePopDisabled = true searchBtn.rx.tap.subscribe(onNext: { _ in guard let phone = self.rootView.phoneInputTF.text, phone.isPhoneNumber else { diff --git a/QuickLocation/Section/Home/SearchLocation/SearchLocationView.swift b/QuickLocation/Section/Home/SearchLocation/SearchLocationView.swift index 673617d..15c0aa6 100644 --- a/QuickLocation/Section/Home/SearchLocation/SearchLocationView.swift +++ b/QuickLocation/Section/Home/SearchLocation/SearchLocationView.swift @@ -10,6 +10,9 @@ import RxSwift import RxCocoa import AVFoundation import Lottie +import Contacts +import ContactsUI +import URLNavigator class SearchLocationView: UIView { @@ -365,8 +368,22 @@ class SearchLocationView: UIView { contactsBtn.titleLabel?.font = .systemFont(ofSize: 12, weight: .regular) contactsBtn.setImage(UIImage(named: "SearchLocation/contacts"), for: .normal) contactsBtn.extendEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 15) - contactsBtn.rx.tap.subscribe(onNext: { _ in - //TODO: - 通讯录 + contactsBtn.rx.tap.subscribe(onNext: { [weak self] in + guard let self = self else { return } + self.phoneInputTF.resignFirstResponder() + let status = CNContactStore.authorizationStatus(for: .contacts) + switch status { + case .notDetermined: + CNContactStore().requestAccess(for: .contacts) { granted, _ in + DispatchQueue.main.async { if granted { self.presentContactPicker() } } + } + case .authorized: + self.presentContactPicker() + case .denied, .restricted: + DLToast.show(text: "请在设置中开启通讯录权限") + default: + break + } }).disposed(by: disposeBag) inputView.addSubview(contactsBtn) contactsBtn.layoutChain @@ -540,4 +557,20 @@ class SearchLocationView: UIView { required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + private func presentContactPicker() { + let picker = CNContactPickerViewController() + picker.delegate = self + picker.displayedPropertyKeys = [CNContactPhoneNumbersKey] + UIViewController.topMost?.present(picker, animated: true) + } +} + +extension SearchLocationView: CNContactPickerDelegate { + func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) { + if let phone = contact.phoneNumbers.first?.value.stringValue { + phoneInputTF.text = phone.filter { $0.isNumber } + phoneInputTF.sendActions(for: .editingChanged) + } + } } diff --git a/QuickLocation/Section/Launch/LaunchViewController.swift b/QuickLocation/Section/Launch/LaunchViewController.swift index eb36c7c..925ddb5 100644 --- a/QuickLocation/Section/Launch/LaunchViewController.swift +++ b/QuickLocation/Section/Launch/LaunchViewController.swift @@ -59,8 +59,14 @@ class LaunchViewController: BaseViewController { guard let model = response.model else { return } MQTTService.shared.connect() Defaults[\.loginToken] = model.token + AppContextManager.shared.systemConfig = model.config - self.getUserIMToken() + + if let upgrade = model.config?.versionUpgradeModel { + self.showVersionUpgrade(upgrade, model: model) + return + } + self.continueAfterConfig(model: model) }, onError: { [weak self] (error) in DLAlert.show(title: error.localizedDescription, defaultTitle: "重试") { [weak self] in @@ -70,6 +76,31 @@ class LaunchViewController: BaseViewController { }).disposed(by: disposeBag) } + private func continueAfterConfig(model: UserConfigModel) { + model.temp ? self.navigateAfterDelay() : self.getUserIMToken() + } + + private func showVersionUpgrade(_ upgrade: VersionUpgradeModel, model: UserConfigModel) { + self.showConfirmPop( + showCloseBtn: !upgrade.force, + title: upgrade.title + upgrade.version, + message: upgrade.description, + confirmText: "立即更新", + confirmBlock: { + if let url = URL(string: upgrade.url) { + UIApplication.shared.open(url) + } + if !upgrade.force { + self.continueAfterConfig(model: model) + } + }, + cancelText: upgrade.force ? nil : "稍后再说", + cancelBlock: upgrade.force ? nil : { [weak self] in + self?.continueAfterConfig(model: model) + } + ) + } + /// 获取用户IM Token func getUserIMToken() { UserService.imToken().subscribe(onNext: { response in @@ -77,6 +108,8 @@ class LaunchViewController: BaseViewController { AppContextManager.shared.imToken = token GroupIMService.shared.login { _ in } self.navigateAfterDelay() + }, onError: { [weak self] (error) in + self?.navigateAfterDelay() }).disposed(by: disposeBag) } diff --git a/QuickLocation/Section/Login/LoginView.swift b/QuickLocation/Section/Login/LoginView.swift index 4c80781..320af4d 100644 --- a/QuickLocation/Section/Login/LoginView.swift +++ b/QuickLocation/Section/Login/LoginView.swift @@ -243,7 +243,7 @@ class LoginView: UIView { lazy var welcomeLabel: UILabel = { let label = UILabel() label.text = "欢迎登录" - label.font = UIFont(name: "DOUYU Font", size: 24) + label.font = UIFont(name: "DOUYU Font", size: 24) ?? .systemFont(ofSize: 24, weight: .medium) label.textColor = UIColor(hexStr: "#030303") label.textAlignment = .center return label diff --git a/QuickLocation/Section/Login/OneTapLoginView.swift b/QuickLocation/Section/Login/OneTapLoginView.swift index 20cfe52..4cf27e3 100644 --- a/QuickLocation/Section/Login/OneTapLoginView.swift +++ b/QuickLocation/Section/Login/OneTapLoginView.swift @@ -167,7 +167,7 @@ class OneTapLoginView: UIView { lazy var welcomeLabel: UILabel = { let label = UILabel() label.text = "欢迎登录" - label.font = UIFont(name: "DOUYU Font", size: 24) + label.font = UIFont(name: "DOUYU Font", size: 24) ?? .systemFont(ofSize: 24, weight: .medium) label.textColor = UIColor(hexStr: "#030303") label.textAlignment = .center return label diff --git a/QuickLocation/Section/Mine/Account/AccountVC.swift b/QuickLocation/Section/Mine/Account/AccountVC.swift index 5c0e3b2..2013311 100644 --- a/QuickLocation/Section/Mine/Account/AccountVC.swift +++ b/QuickLocation/Section/Mine/Account/AccountVC.swift @@ -9,8 +9,10 @@ import UIKit import RxSwift import RxCocoa import RxDataSources +import Kingfisher #if !targetEnvironment(simulator) import GeYanSdk +import RxGesture #endif class AccountVC: BaseViewController { @@ -55,6 +57,12 @@ class AccountVC: BaseViewController { self.deleteAccount() } }).disposed(by: disposeBag) + + let tap = UITapGestureRecognizer(target: self, action: #selector(handleClearCacheTap)) + rootView.clearView.addGestureRecognizer(tap) + + let versionTap = UITapGestureRecognizer(target: self, action: #selector(handleVersionViewTap)) + rootView.versionView.addGestureRecognizer(versionTap) } // MARK: - API @@ -76,4 +84,42 @@ class AccountVC: BaseViewController { DLToast.show(text: "申请成功") }, onError: { _ in }).disposed(by: disposeBag) } + + @objc private func handleClearCacheTap() { + clearCache() + } + + @objc private func handleVersionViewTap() { + guard let upgrade = AppContextManager.shared.systemConfig?.versionUpgradeModel else { + DLToast.show(text: "已是最新版本") + return + } + self.showConfirmPop( + showCloseBtn: !upgrade.force, + title: upgrade.title, + message: upgrade.description, + confirmText: "立即更新", + confirmBlock: { + if let url = URL(string: upgrade.url) { + UIApplication.shared.open(url) + } + }, + cancelText: upgrade.force ? nil : "稍后再说", + cancelBlock: nil + ) + } + + private func clearCache() { + DLToast.showLoading() + KingfisherManager.shared.cache.clearMemoryCache() + KingfisherManager.shared.cache.clearDiskCache { + AppCacheManager.clearCache { + DispatchQueue.main.async { + DLToast.dismiss() + DLToast.show(text: "缓存已清除") + self.rootView.cacheLab.text = "0 B" + } + } + } + } } diff --git a/QuickLocation/Section/Mine/Account/AccountView.swift b/QuickLocation/Section/Mine/Account/AccountView.swift index 8074661..f7cb443 100644 --- a/QuickLocation/Section/Mine/Account/AccountView.swift +++ b/QuickLocation/Section/Mine/Account/AccountView.swift @@ -238,7 +238,7 @@ class AccountView: UIView { let titleLab = UILabel() titleLab.text = "当前版本" titleLab.font = .systemFont(ofSize: 14, weight: .medium) - titleLab.textColor = UIColor(hexStr: "#1A1A1A") + titleLab.textColor = UIColor(hexStr: "#1A1A1A ") view.addSubview(titleLab) titleLab.layoutChain .left(15) diff --git a/QuickLocation/Section/Schedule/ScheduleViewed/ScheduleViewedView.swift b/QuickLocation/Section/Schedule/ScheduleViewed/ScheduleViewedView.swift index 69900c6..fcad42e 100644 --- a/QuickLocation/Section/Schedule/ScheduleViewed/ScheduleViewedView.swift +++ b/QuickLocation/Section/Schedule/ScheduleViewed/ScheduleViewedView.swift @@ -156,6 +156,7 @@ class ScheduleViewedListCell: UITableViewCell { .top(18) .height(50) .widthToHeight(1) + .bottom(18, relation: .greaterThanOrEqual) nameLab.layoutChain .topToView(iconView) diff --git a/QuickLocation/Service/UserService.swift b/QuickLocation/Service/UserService.swift index cbf535d..62c7bd2 100644 --- a/QuickLocation/Service/UserService.swift +++ b/QuickLocation/Service/UserService.swift @@ -36,7 +36,7 @@ struct UserService { static func imToken() -> Observable { let api = UserAPI.imToken.multiTarget - return APIProvider.request(token: api) + return APIProvider.request(token: api, handle: false) .map(ResponseModel.self) .asObservable() }