add Sparkle appcast

This commit is contained in:
Micha
2025-11-25 16:21:07 +01:00
parent dc9560e31a
commit 01c89de738
18 changed files with 262 additions and 356 deletions

View File

@@ -0,0 +1,26 @@
import Sparkle
import Foundation
@MainActor
final class SparkleUpdater: NSObject, ObservableObject {
let controller: SPUStandardUpdaterController
override init() {
self.controller = SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil)
super.init()
}
var automaticallyChecksForUpdates: Bool {
get { controller.updater.automaticallyChecksForUpdates }
set { controller.updater.automaticallyChecksForUpdates = newValue }
}
var automaticallyDownloadsUpdates: Bool {
get { controller.updater.automaticallyDownloadsUpdates }
set { controller.updater.automaticallyDownloadsUpdates = newValue }
}
func checkForUpdates() {
controller.checkForUpdates(nil)
}
}

View File

@@ -1,95 +0,0 @@
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
])
}
}