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?()
|
||
}
|
||
}
|