mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 22:15:33 +00:00
Move Settings out of the menu-bar popover into a standalone resizable AppKit window so clicking it no longer steals focus and dismisses the bar (the .sheet inside MenuBarExtra(.window) was the root cause). Force the actual NSWindow appearance (aqua/darkAqua/system) on both the popover and the settings window so Light/Dark visibly flips materials and semantic colors, not just custom tokens. Replace the fragile popover quit dialog with an inline two-step arm/confirm. Widen the dropdown and increase spacing/type for readability. Fill the settings window responsively and make Done close it via the window controller (dismiss() is a no-op in a hosted NSWindow).
74 lines
3.1 KiB
Swift
74 lines
3.1 KiB
Swift
import SwiftUI
|
|
import CCSBarCore
|
|
|
|
/// CCS Bar entry point. A menu-bar-only app (no dock icon) whose title shows
|
|
/// the leading account's quota and today's total cost, with a dropdown for
|
|
/// per-account detail and control.
|
|
@main
|
|
struct CCSBarApp: App {
|
|
@StateObject private var viewModel = BarViewModel()
|
|
|
|
init() {
|
|
// Seed the registration domain BEFORE any pref read so absent Bool keys
|
|
// resolve to their real defaults (true) instead of reading back as false,
|
|
// which would silently disable every alert on a fresh install.
|
|
BarPreferences().registerDefaults()
|
|
}
|
|
|
|
var body: some Scene {
|
|
MenuBarExtra {
|
|
// ThemedRoot forces the chosen scheme and injects the resolved tokens, so
|
|
// the whole dropdown follows the user's appearance pick independently of
|
|
// the macOS system appearance. The label (status item) stays OS-tinted.
|
|
ThemedRoot(appearance: viewModel.appearance) {
|
|
BarMenuView(viewModel: viewModel)
|
|
}
|
|
} label: {
|
|
// The CCS mark + compact glance. The image re-renders when the style
|
|
// preference changes because `iconStyle` is observed.
|
|
Image(nsImage: MenuBarIcon.statusImage(viewModel.iconStyle))
|
|
Text(viewModel.statusTitle)
|
|
}
|
|
.menuBarExtraStyle(.window)
|
|
}
|
|
}
|
|
|
|
/// Forces the chosen color scheme on the dropdown content at the boundary, then
|
|
/// hands off to `ResolvedThemeHost` to read the now-forced scheme and inject
|
|
/// tokens. The split is deliberate: `.preferredColorScheme` rewrites the
|
|
/// environment for DESCENDANTS only, so a view cannot read its own forced scheme
|
|
/// in the same scope. `ResolvedThemeHost` is a descendant and therefore sees it.
|
|
struct ThemedRoot<Content: View>: View {
|
|
let appearance: BarAppearance
|
|
@ViewBuilder var content: Content
|
|
|
|
var body: some View {
|
|
// Order matters: .preferredColorScheme first updates the SwiftUI \.colorScheme
|
|
// environment for descendants (so the token resolver + Color.primary/.secondary
|
|
// pick up the chosen scheme), THEN the .background WindowAppearanceForcer sets
|
|
// the actual host NSWindow.appearance so system materials + semantic-color
|
|
// inversions flip at the AppKit layer too — not just the custom RGB tokens.
|
|
// The two are complementary: env tokens + real window appearance. KEEP both.
|
|
ResolvedThemeHost(content: content)
|
|
.preferredColorScheme(appearance.forced)
|
|
.background(WindowAppearanceForcer(appearance: appearance))
|
|
}
|
|
}
|
|
|
|
/// Reads the (already-forced) color scheme, resolves the matching `BarTheme`,
|
|
/// paints the themed window plate behind the content, and injects the tokens.
|
|
/// In dark the plate is `.clear` (native MenuBarExtra material shows through —
|
|
/// zero regression); in light it is the explicit #F5F5F7 plate so the dropdown
|
|
/// renders light even when macOS is in dark mode.
|
|
struct ResolvedThemeHost<Content: View>: View {
|
|
@Environment(\.colorScheme) private var colorScheme
|
|
let content: Content
|
|
|
|
var body: some View {
|
|
let theme = BarTheme.resolve(colorScheme)
|
|
content
|
|
.background(theme.windowSurface)
|
|
.environment(\.barTheme, theme)
|
|
}
|
|
}
|