Files
iKeyMon/Sources/ViewModels/UpdateViewModel.swift
2025-11-22 18:56:55 +01:00

96 lines
2.9 KiB
Swift

import Foundation
#if os(macOS)
import AppKit
#endif
@MainActor
final class UpdateViewModel: ObservableObject {
struct StatusAlert: Identifiable {
let id = UUID()
let title: String
let message: String
}
@Published var availableRelease: ReleaseInfo?
@Published var latestFetchedRelease: ReleaseInfo?
@Published var statusAlert: StatusAlert?
@Published var isChecking = false
private let service: UpdateService
private let userDefaults: UserDefaults
private let autoCheckKey = "autoCheckUpdates"
private let includePrereleaseKey = "includePrereleaseUpdates"
init(service: UpdateService = UpdateService(), userDefaults: UserDefaults = .standard) {
self.service = service
self.userDefaults = userDefaults
registerDefaultsIfNeeded()
}
func startAutomaticCheckIfNeeded() {
if userDefaults.bool(forKey: autoCheckKey) {
checkForUpdates(userInitiated: false)
}
}
func checkForUpdates(userInitiated: Bool) {
guard !isChecking else { return }
isChecking = true
Task {
do {
let release = try await service.fetchLatestRelease(includePrerelease: userDefaults.bool(forKey: includePrereleaseKey))
handle(release: release, userInitiated: userInitiated)
} catch {
if userInitiated {
statusAlert = StatusAlert(
title: "Update Check Failed",
message: error.localizedDescription
)
}
}
self.isChecking = false
}
}
func openReleaseNotes() {
guard let releaseURL = availableRelease?.releaseURL ?? latestFetchedRelease?.releaseURL else { return }
#if os(macOS)
NSWorkspace.shared.open(releaseURL)
#endif
}
func downloadLatest() {
let release = availableRelease ?? latestFetchedRelease
availableRelease = nil
guard let downloadURL = release?.downloadURL else { return }
#if os(macOS)
NSWorkspace.shared.open(downloadURL)
#endif
}
private func handle(release: ReleaseInfo, userInitiated: Bool) {
let currentVersion = VersionNumber(
Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "0.0.0"
)
latestFetchedRelease = release
if release.version > currentVersion {
availableRelease = release
} else if userInitiated {
statusAlert = StatusAlert(
title: "You're Up To Date",
message: "iKeyMon \(currentVersion.rawValue) is the latest version."
)
}
}
private func registerDefaultsIfNeeded() {
userDefaults.register(defaults: [
autoCheckKey: true,
includePrereleaseKey: true
])
}
}