diff options
Diffstat (limited to 'macos/Sources/Features/Update/UpdateController.swift')
| -rw-r--r-- | macos/Sources/Features/Update/UpdateController.swift | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/macos/Sources/Features/Update/UpdateController.swift b/macos/Sources/Features/Update/UpdateController.swift index 446b82ebc..aa875567c 100644 --- a/macos/Sources/Features/Update/UpdateController.swift +++ b/macos/Sources/Features/Update/UpdateController.swift @@ -1,5 +1,6 @@ import Sparkle import Cocoa +import Combine /// Standard controller for managing Sparkle updates in Ghostty. /// @@ -10,6 +11,7 @@ class UpdateController { private(set) var updater: SPUUpdater private let userDriver: UpdateDriver private let updaterDelegate = UpdaterDelegate() + private var installCancellable: AnyCancellable? var viewModel: UpdateViewModel { userDriver.viewModel @@ -29,6 +31,10 @@ class UpdateController { ) } + deinit { + installCancellable?.cancel() + } + /// Start the updater. /// /// This must be called before the updater can check for updates. If starting fails, @@ -50,6 +56,34 @@ class UpdateController { } } + /// Force install the current update. As long as we're in some "update available" state this will + /// trigger all the steps necessary to complete the update. + func installUpdate() { + // Must be in an installable state + guard viewModel.state.isInstallable else { return } + + // If we're already force installing then do nothing. + guard installCancellable == nil else { return } + + // Setup a combine listener to listen for state changes and to always + // confirm them. If we go to a non-installable state, cancel the listener. + // The sink runs immediately with the current state, so we don't need to + // manually confirm the first state. + installCancellable = viewModel.$state.sink { [weak self] state in + guard let self else { return } + + // If we move to a non-installable state (error, idle, etc.) then we + // stop force installing. + guard state.isInstallable else { + self.installCancellable = nil + return + } + + // Continue the `yes` chain! + state.confirm() + } + } + /// Check for updates. /// /// This is typically connected to a menu item action. |
