@@ -14,14 +14,17 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
1414 private var lastSuccessfulAgentData : [ AgentKind : AgentRawData ] = [ : ]
1515 private var lastUsageDataFingerprints : [ AgentKind : UsageDataFingerprint ] = [ : ]
1616 private let loginItemManager = LoginItemManager ( )
17- private let updaterController = SPUStandardUpdaterController (
17+ private lazy var updaterController = SPUStandardUpdaterController (
1818 startingUpdater: true ,
19- updaterDelegate: nil ,
20- userDriverDelegate: nil
19+ updaterDelegate: self ,
20+ userDriverDelegate: self
2121 )
2222 private var startAtLoginViewState = StartAtLoginViewState . make ( status: . notRegistered)
23+ private var softwareUpdateViewState = SoftwareUpdateViewState . idle
2324
2425 func applicationDidFinishLaunching( _ notification: Notification ) {
26+ _ = updaterController
27+
2528 let statusItem = NSStatusBar . system. statusItem ( withLength: NSStatusItem . variableLength)
2629 self . statusItem = statusItem
2730
@@ -237,6 +240,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
237240 let rows = MenuRowsBuilder . rows (
238241 for: state,
239242 startAtLogin: startAtLoginViewState,
243+ softwareUpdate: softwareUpdateViewState,
240244 appVersion: appVersion ( )
241245 )
242246 MenuRenderer . render ( menu: menu, rows: rows, target: self , selectorProvider: selector)
@@ -270,4 +274,38 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
270274 return #selector( quitMenuItemSelected)
271275 }
272276 }
277+
278+ private func noteAvailableUpdate( version: String ) {
279+ softwareUpdateViewState = SoftwareUpdateViewState ( availableVersion: version)
280+ refreshMenuIfNeeded ( )
281+ }
282+ }
283+
284+ extension AppDelegate : SPUUpdaterDelegate {
285+ func updater( _ updater: SPUUpdater , didFindValidUpdate item: SUAppcastItem ) {
286+ noteAvailableUpdate ( version: item. displayVersionString)
287+ }
288+
289+ func updaterDidNotFindUpdate( _ updater: SPUUpdater , error: Error ) {
290+ softwareUpdateViewState = . idle
291+ refreshMenuIfNeeded ( )
292+ }
293+
294+ func updater( _ updater: SPUUpdater , didAbortWithError error: Error ) {
295+ softwareUpdateViewState = . idle
296+ refreshMenuIfNeeded ( )
297+ }
298+ }
299+
300+ extension AppDelegate : SPUStandardUserDriverDelegate {
301+ nonisolated func standardUserDriverShouldHandleShowingScheduledUpdate(
302+ _ update: SUAppcastItem ,
303+ andInImmediateFocus immediateFocus: Bool
304+ ) -> Bool {
305+ let version = update. displayVersionString
306+ Task { @MainActor [ weak self] in
307+ self ? . noteAvailableUpdate ( version: version)
308+ }
309+ return false
310+ }
273311}
0 commit comments