feat(app): wire up appearance setting and app menu commands

AppAppearance (System/Light/Dark) applies via NSApp.appearance directly
rather than .preferredColorScheme(nil) — the latter doesn't reliably
reset a macOS window back to "follow system" after an explicit
override. App menu gets About/Log Out commands and the About/Keyboard
Shortcuts/Preferences windows registered as scenes.
This commit is contained in:
2026-08-14 00:24:38 +01:00
parent ef085f0018
commit 502888dfde
2 changed files with 93 additions and 14 deletions
+70 -14
View File
@@ -6,27 +6,83 @@
// //
import SwiftUI import SwiftUI
import SwiftData
#if os(macOS)
import AppKit
#endif
@main @main
struct OutpostApp: App { struct OutpostApp: App {
var sharedModelContainer: ModelContainer = { @State private var session = SessionStore()
let schema = Schema([ @AppStorage("outpost.appearance") private var appearance: AppAppearance = .system
Item.self,
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do { #if os(macOS)
return try ModelContainer(for: schema, configurations: [modelConfiguration]) @Environment(\.openWindow) private var openWindow
} catch { @State private var isShowingLogoutConfirmation = false
fatalError("Could not create ModelContainer: \(error)") #endif
}
}()
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
ContentView() RootView()
.environment(session)
#if os(iOS)
.preferredColorScheme(appearance.colorScheme)
#endif
#if os(macOS)
.onAppear { applyMacAppearance() }
.onChange(of: appearance) { _, _ in applyMacAppearance() }
.logoutConfirmationDialog(isPresented: $isShowingLogoutConfirmation, session: session)
#endif
} }
.modelContainer(sharedModelContainer) #if os(macOS)
.commands {
CommandGroup(replacing: .appInfo) {
Button("About Outpost") {
openWindow(id: "about")
} }
}
CommandGroup(after: .appSettings) {
Divider()
Button("Log Out…") {
isShowingLogoutConfirmation = true
}
.disabled(!session.isSignedIn)
}
}
#endif
#if os(macOS)
Window("About Outpost", id: "about") {
AboutView()
}
.windowResizability(.contentSize)
Window("Keyboard Shortcuts", id: "keyboard-shortcuts") {
KeyboardShortcutsView()
}
.windowResizability(.contentSize)
Settings {
PreferencesView()
.environment(session)
}
#endif
}
#if os(macOS)
/// `.preferredColorScheme(nil)` doesn't reliably reset the window's real
/// `NSAppearance` back to "follow system" after an explicit override this
/// sets the actual AppKit-level appearance directly instead, which every
/// window (present and future) inherits.
private func applyMacAppearance() {
switch appearance {
case .system:
NSApp.appearance = nil
case .light:
NSApp.appearance = NSAppearance(named: .aqua)
case .dark:
NSApp.appearance = NSAppearance(named: .darkAqua)
}
}
#endif
} }
+23
View File
@@ -0,0 +1,23 @@
import SwiftUI
enum AppAppearance: String, CaseIterable, Identifiable {
case system, light, dark
var id: String { rawValue }
var label: String {
switch self {
case .system: return "System"
case .light: return "Light"
case .dark: return "Dark"
}
}
var colorScheme: ColorScheme? {
switch self {
case .system: return nil
case .light: return .light
case .dark: return .dark
}
}
}