88 lines
2.8 KiB
Swift
88 lines
2.8 KiB
Swift
//
|
|
// SettingViewModel.swift
|
|
// suixinkan
|
|
//
|
|
|
|
import Foundation
|
|
|
|
/// 设置中心 ViewModel,管理版本展示、协议入口和更新标记。
|
|
final class SettingViewModel {
|
|
private let infoDictionary: [String: Any]?
|
|
private let environment: APIEnvironment
|
|
|
|
private(set) var latestVersion: VersionResponse?
|
|
private(set) var hasNewVersion = false
|
|
|
|
var onStateChange: (() -> Void)?
|
|
|
|
init(
|
|
infoDictionary: [String: Any]? = Bundle.main.infoDictionary,
|
|
environment: APIEnvironment = .current
|
|
) {
|
|
self.infoDictionary = infoDictionary
|
|
self.environment = environment
|
|
}
|
|
|
|
var appVersion: String {
|
|
AppClientInfo.appVersion(infoDictionary: infoDictionary)
|
|
}
|
|
|
|
var appDownloadURL: URL {
|
|
environment.baseURL.appending(path: "h5/app/download")
|
|
}
|
|
|
|
/// 静默检查最新版本,失败时保持当前页面状态。
|
|
func checkLatestVersion(api: SettingAPI) async {
|
|
do {
|
|
let response = try await api.checkLatestVersion()
|
|
latestVersion = response
|
|
hasNewVersion = Self.isNewerVersionCode(response.versionCode, than: currentVersionCode(infoDictionary: infoDictionary))
|
|
notifyStateChange()
|
|
} catch is CancellationError {
|
|
return
|
|
} catch {
|
|
latestVersion = nil
|
|
hasNewVersion = false
|
|
notifyStateChange()
|
|
}
|
|
}
|
|
|
|
/// 返回指定协议入口的标题和 URL。
|
|
func agreementDestination(for kind: SettingAgreementKind) -> SettingAgreementDestination {
|
|
switch kind {
|
|
case .aboutUs:
|
|
SettingAgreementDestination(
|
|
title: "关于我们",
|
|
url: environment.baseURL.appending(path: "h5/app/about-us")
|
|
)
|
|
case .userAgreement:
|
|
SettingAgreementDestination(
|
|
title: "用户协议",
|
|
url: environment.baseURL.appending(path: "h5/app/user-agreement")
|
|
)
|
|
case .privacyPolicy:
|
|
SettingAgreementDestination(
|
|
title: "隐私政策",
|
|
url: environment.baseURL.appending(path: "h5/app/privacy-policy")
|
|
)
|
|
}
|
|
}
|
|
|
|
/// 判断后端版本号是否高于当前构建号。
|
|
nonisolated static func isNewerVersionCode(_ latestVersionCode: Int, than currentVersionCode: Int?) -> Bool {
|
|
guard let currentVersionCode else { return false }
|
|
return latestVersionCode > currentVersionCode
|
|
}
|
|
|
|
private func currentVersionCode(infoDictionary: [String: Any]?) -> Int? {
|
|
let build = (infoDictionary?["CFBundleVersion"] as? String)?
|
|
.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
guard let build, !build.isEmpty else { return nil }
|
|
return Int(build)
|
|
}
|
|
|
|
private func notifyStateChange() {
|
|
onStateChange?()
|
|
}
|
|
}
|