feat: surface check/revert/version in the menu and badge the icon
AppModel exposes appVersion, previousVersion, isCheckingForUpdates and updateStatusMessage (an alias for the existing statusLine plumbing — one status channel, not a new one), plus checkForUpdates() and revertToPreviousVersion() wired to the hardened UpdateChecker. Menu gains, in order: "Update to X" (unchanged, staged-only), "Check for updates" (labelled "Checking…" and disabled mid-check), "Revert to <version>" (only when a rollback copy exists), then the existing rows unchanged, then a non-interactive footer "Redline <version>" with the status line under it — same caption/secondary styles already used elsewhere in the file, no new tokens. Menu-bar icon gets a small badge while an update is staged: uses the SF Symbol's own ".badge" variant when one exists for the current icon, otherwise overlays a small dot on the plain symbol. Reads live model state, so the badge disappears on its own once the offer clears. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -21,8 +21,9 @@ struct ShotdeckApp: App {
|
||||
.environment(appDelegate.model)
|
||||
} label: {
|
||||
let state = appDelegate.model.iconState
|
||||
let hasUpdate = appDelegate.model.updateAvailable != nil
|
||||
HStack(spacing: 4) {
|
||||
Image(systemName: state.symbolName)
|
||||
menuBarIcon(for: state, hasUpdate: hasUpdate)
|
||||
if let count = state.countText {
|
||||
Text(count).font(.system(size: 11, weight: .semibold))
|
||||
}
|
||||
@@ -33,6 +34,29 @@ struct ShotdeckApp: App {
|
||||
}
|
||||
}
|
||||
|
||||
/// The menu-bar symbol for `state`, badged while an update is staged. Uses the
|
||||
/// SF Symbol's own `.badge` variant when one exists; falls back to a small
|
||||
/// overlaid dot on the plain symbol otherwise. The badge disappears on its own
|
||||
/// once `updateAvailable` clears, since this reads live model state.
|
||||
@ViewBuilder
|
||||
private func menuBarIcon(for state: MenuIconState, hasUpdate: Bool) -> some View {
|
||||
if hasUpdate {
|
||||
let badgeName = "\(state.symbolName).badge"
|
||||
if NSImage(systemSymbolName: badgeName, accessibilityDescription: nil) != nil {
|
||||
Image(systemName: badgeName)
|
||||
} else {
|
||||
ZStack(alignment: .topTrailing) {
|
||||
Image(systemName: state.symbolName)
|
||||
Circle()
|
||||
.frame(width: 6, height: 6)
|
||||
.offset(x: 3, y: -3)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Image(systemName: state.symbolName)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
let model: AppModel
|
||||
|
||||
Reference in New Issue
Block a user