parent
d88176a8bc
commit
15e4c3df17
|
|
@ -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 = "";
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSContactsUsageDescription</key>
|
||||
<string>需要访问您的通讯录以导入联系人号码</string>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>douyu.otf</string>
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}()
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ class ScheduleViewedListCell: UITableViewCell {
|
|||
.top(18)
|
||||
.height(50)
|
||||
.widthToHeight(1)
|
||||
.bottom(18, relation: .greaterThanOrEqual)
|
||||
|
||||
nameLab.layoutChain
|
||||
.topToView(iconView)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct UserService {
|
|||
|
||||
static func imToken() -> Observable<ResponseModel> {
|
||||
let api = UserAPI.imToken.multiTarget
|
||||
return APIProvider.request(token: api)
|
||||
return APIProvider.request(token: api, handle: false)
|
||||
.map(ResponseModel.self)
|
||||
.asObservable()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue