diff options
| author | Mitchell Hashimoto <m@mitchellh.com> | 2025-10-08 21:29:14 -0700 |
|---|---|---|
| committer | Mitchell Hashimoto <m@mitchellh.com> | 2025-10-08 21:41:18 -0700 |
| commit | bce49a08438b39bbc699348d8308e724f6334f75 (patch) | |
| tree | ec8f7c758ad168415069a1c5c0bdde426734a846 /macos/Sources/Features | |
| parent | b4ab1cc1edd273577449c9ced8f713c4293134b7 (diff) | |
macos: hook up our new update controller
Diffstat (limited to 'macos/Sources/Features')
| -rw-r--r-- | macos/Sources/Features/Update/UpdateController.swift | 55 | ||||
| -rw-r--r-- | macos/Sources/Features/Update/UpdateDriver.swift | 20 |
2 files changed, 69 insertions, 6 deletions
diff --git a/macos/Sources/Features/Update/UpdateController.swift b/macos/Sources/Features/Update/UpdateController.swift new file mode 100644 index 000000000..47e6c8def --- /dev/null +++ b/macos/Sources/Features/Update/UpdateController.swift @@ -0,0 +1,55 @@ +import Sparkle +import Cocoa + +/// Standard controller for managing Sparkle updates in Ghostty. +/// +/// This controller wraps SPUStandardUpdaterController to provide a simpler interface +/// for managing updates with Ghostty's custom driver and delegate. It handles +/// initialization, starting the updater, and provides the check for updates action. +class UpdateController { + private(set) var updater: SPUUpdater + private let userDriver: UpdateDriver + private let updaterDelegate = UpdaterDelegate() + + var viewModel: UpdateViewModel { + userDriver.viewModel + } + + /// Initialize a new update controller. + init() { + let hostBundle = Bundle.main + self.userDriver = UpdateDriver(viewModel: .init()) + self.updater = SPUUpdater( + hostBundle: hostBundle, + applicationBundle: hostBundle, + userDriver: userDriver, + delegate: updaterDelegate + ) + } + + /// Start the updater. + /// + /// This must be called before the updater can check for updates. If starting fails, + /// an error alert will be shown after a short delay. + func startUpdater() { + try? updater.start() + } + + /// Check for updates. + /// + /// This is typically connected to a menu item action. + @objc func checkForUpdates() { + updater.checkForUpdates() + } + + /// Validate the check for updates menu item. + /// + /// - Parameter item: The menu item to validate + /// - Returns: Whether the menu item should be enabled + func validateMenuItem(_ item: NSMenuItem) -> Bool { + if item.action == #selector(checkForUpdates) { + return updater.canCheckForUpdates + } + return true + } +} diff --git a/macos/Sources/Features/Update/UpdateDriver.swift b/macos/Sources/Features/Update/UpdateDriver.swift index 6627559e8..70f9341a6 100644 --- a/macos/Sources/Features/Update/UpdateDriver.swift +++ b/macos/Sources/Features/Update/UpdateDriver.swift @@ -1,13 +1,12 @@ +import Cocoa import Sparkle /// Implement the SPUUserDriver to modify our UpdateViewModel for custom presentation. class UpdateDriver: NSObject, SPUUserDriver { let viewModel: UpdateViewModel - let retryHandler: () -> Void - init(viewModel: UpdateViewModel, retryHandler: @escaping () -> Void) { + init(viewModel: UpdateViewModel) { self.viewModel = viewModel - self.retryHandler = retryHandler super.init() } @@ -38,9 +37,18 @@ class UpdateDriver: NSObject, SPUUserDriver { } func showUpdaterError(_ error: any Error, acknowledgement: @escaping () -> Void) { - viewModel.state = .error(.init(error: error, retry: retryHandler, dismiss: { [weak viewModel] in - viewModel?.state = .idle - })) + viewModel.state = .error(.init( + error: error, + retry: { + guard let delegate = NSApp.delegate as? AppDelegate else { + return + } + + // TODO fill this in + }, + dismiss: { [weak viewModel] in + viewModel?.state = .idle + })) } func showDownloadInitiated(cancellation: @escaping () -> Void) { |
