macos: add a "restart later" option to the installing state
parent
bed219c132
commit
791d8f8200
|
|
@ -22,7 +22,13 @@ extension UpdateDriver: SPUUpdaterDelegate {
|
|||
/// When `auto-update = check`, Sparkle will call the corresponding
|
||||
/// delegate method on the responsible driver instead.
|
||||
func updater(_ updater: SPUUpdater, willInstallUpdateOnQuit item: SUAppcastItem, immediateInstallationBlock immediateInstallHandler: @escaping () -> Void) -> Bool {
|
||||
viewModel.state = .installing(.init(isAutoUpdate: true, retryTerminatingApplication: immediateInstallHandler))
|
||||
viewModel.state = .installing(.init(
|
||||
isAutoUpdate: true,
|
||||
retryTerminatingApplication: immediateInstallHandler,
|
||||
dismiss: { [weak viewModel] in
|
||||
viewModel?.state = .idle
|
||||
}
|
||||
))
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,12 @@ class UpdateDriver: NSObject, SPUUserDriver {
|
|||
}
|
||||
|
||||
func showInstallingUpdate(withApplicationTerminated applicationTerminated: Bool, retryTerminatingApplication: @escaping () -> Void) {
|
||||
viewModel.state = .installing(.init(retryTerminatingApplication: retryTerminatingApplication))
|
||||
viewModel.state = .installing(.init(
|
||||
retryTerminatingApplication: retryTerminatingApplication,
|
||||
dismiss: { [weak viewModel] in
|
||||
viewModel?.state = .idle
|
||||
}
|
||||
))
|
||||
|
||||
if !hasUnobtrusiveTarget {
|
||||
standard.showInstallingUpdate(withApplicationTerminated: applicationTerminated, retryTerminatingApplication: retryTerminatingApplication)
|
||||
|
|
|
|||
|
|
@ -291,7 +291,15 @@ fileprivate struct InstallingView: View {
|
|||
}
|
||||
|
||||
HStack {
|
||||
Button("Restart Later") {
|
||||
installing.dismiss()
|
||||
dismiss()
|
||||
}
|
||||
.keyboardShortcut(.cancelAction)
|
||||
.controlSize(.small)
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Restart Now") {
|
||||
installing.retryTerminatingApplication()
|
||||
dismiss()
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ enum UpdateSimulator {
|
|||
/// Shows the installing state with restart button: installing (stays until dismissed)
|
||||
case installing
|
||||
|
||||
/// Simulates auto-update flow: goes directly to installing state without showing intermediate UI
|
||||
case autoUpdate
|
||||
|
||||
func simulate(with viewModel: UpdateViewModel) {
|
||||
switch self {
|
||||
case .happyPath:
|
||||
|
|
@ -49,6 +52,8 @@ enum UpdateSimulator {
|
|||
simulateCancelDuringChecking(viewModel)
|
||||
case .installing:
|
||||
simulateInstalling(viewModel)
|
||||
case .autoUpdate:
|
||||
simulateAutoUpdate(viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -270,9 +275,27 @@ enum UpdateSimulator {
|
|||
}
|
||||
|
||||
private func simulateInstalling(_ viewModel: UpdateViewModel) {
|
||||
viewModel.state = .installing(.init(retryTerminatingApplication: {
|
||||
print("Restart button clicked in simulator - resetting to idle")
|
||||
viewModel.state = .idle
|
||||
}))
|
||||
viewModel.state = .installing(.init(
|
||||
retryTerminatingApplication: {
|
||||
print("Restart button clicked in simulator - resetting to idle")
|
||||
viewModel.state = .idle
|
||||
},
|
||||
dismiss: {
|
||||
viewModel.state = .idle
|
||||
}
|
||||
))
|
||||
}
|
||||
|
||||
private func simulateAutoUpdate(_ viewModel: UpdateViewModel) {
|
||||
viewModel.state = .installing(.init(
|
||||
isAutoUpdate: true,
|
||||
retryTerminatingApplication: {
|
||||
print("Restart button clicked in simulator - resetting to idle")
|
||||
viewModel.state = .idle
|
||||
},
|
||||
dismiss: {
|
||||
viewModel.state = .idle
|
||||
}
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -367,5 +367,6 @@ enum UpdateState: Equatable {
|
|||
/// True if this state is triggered by ``Ghostty/UpdateDriver/updater(_:willInstallUpdateOnQuit:immediateInstallationBlock:)``
|
||||
var isAutoUpdate = false
|
||||
let retryTerminatingApplication: () -> Void
|
||||
let dismiss: () -> Void
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,10 +25,10 @@ struct UpdateStateTests {
|
|||
}
|
||||
|
||||
@Test func testInstallingEquality() {
|
||||
let state1: UpdateState = .installing(.init(isAutoUpdate: false, retryTerminatingApplication: {}))
|
||||
let state2: UpdateState = .installing(.init(isAutoUpdate: false, retryTerminatingApplication: {}))
|
||||
let state1: UpdateState = .installing(.init(isAutoUpdate: false, retryTerminatingApplication: {}, dismiss: {}))
|
||||
let state2: UpdateState = .installing(.init(isAutoUpdate: false, retryTerminatingApplication: {}, dismiss: {}))
|
||||
#expect(state1 == state2)
|
||||
let state3: UpdateState = .installing(.init(isAutoUpdate: true, retryTerminatingApplication: {}))
|
||||
let state3: UpdateState = .installing(.init(isAutoUpdate: true, retryTerminatingApplication: {}, dismiss: {}))
|
||||
#expect(state3 != state2)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ struct UpdateViewModelTests {
|
|||
|
||||
@Test func testInstallingText() {
|
||||
let viewModel = UpdateViewModel()
|
||||
viewModel.state = .installing(.init(isAutoUpdate: false, retryTerminatingApplication: {}))
|
||||
viewModel.state = .installing(.init(isAutoUpdate: false, retryTerminatingApplication: {}, dismiss: {}))
|
||||
#expect(viewModel.text == "Installing…")
|
||||
viewModel.state = .installing(.init(isAutoUpdate: true, retryTerminatingApplication: {}))
|
||||
viewModel.state = .installing(.init(isAutoUpdate: true, retryTerminatingApplication: {}, dismiss: {}))
|
||||
#expect(viewModel.text == "Restart to Complete Update")
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue