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:
+70
-14
@@ -6,27 +6,83 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
#if os(macOS)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
@main
|
||||
struct OutpostApp: App {
|
||||
var sharedModelContainer: ModelContainer = {
|
||||
let schema = Schema([
|
||||
Item.self,
|
||||
])
|
||||
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
|
||||
@State private var session = SessionStore()
|
||||
@AppStorage("outpost.appearance") private var appearance: AppAppearance = .system
|
||||
|
||||
do {
|
||||
return try ModelContainer(for: schema, configurations: [modelConfiguration])
|
||||
} catch {
|
||||
fatalError("Could not create ModelContainer: \(error)")
|
||||
}
|
||||
}()
|
||||
#if os(macOS)
|
||||
@Environment(\.openWindow) private var openWindow
|
||||
@State private var isShowingLogoutConfirmation = false
|
||||
#endif
|
||||
|
||||
var body: some Scene {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user