mirror of
https://github.com/yattee/yattee.git
synced 2026-07-19 22:02:10 +00:00
Enforce theme at the window level instead of preferredColorScheme
SwiftUI's .preferredColorScheme on the root view could not revert from dark back to light/system while a sheet was presented, and on macOS it never applied to secondary window scenes such as Settings. The override is now applied directly to UIKit/AppKit instead. - SettingsManager.applyTheme sets overrideUserInterfaceStyle on every window of every connected scene (iOS) or NSApp.appearance (macOS); the theme setter calls it, so any future code path that changes the theme outside the setter must do the same - AppTheme gains userInterfaceStyle / appearance mappings, with .system resolving to .unspecified / nil so the OS setting takes over again - Applied on app appear for the initial launch state, and after both iCloud sync paths, since theme can arrive as a synced change and is no longer driven by SwiftUI state Claude-Session: https://claude.ai/code/session_0154KH8RAVAvm6iVanhmoW8o
This commit is contained in:
@@ -389,6 +389,10 @@ extension SettingsManager {
|
||||
|
||||
clearCache()
|
||||
updateLastSyncTime()
|
||||
|
||||
#if !os(tvOS)
|
||||
Self.applyTheme(theme)
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Refreshes settings from iCloud by copying iCloud values to local storage.
|
||||
@@ -445,5 +449,11 @@ extension SettingsManager {
|
||||
|
||||
// Clear caches to force re-read from local storage
|
||||
clearCache()
|
||||
|
||||
// Re-apply the theme in case it was among the synced changes —
|
||||
// it is enforced at the window level, not via SwiftUI state.
|
||||
#if !os(tvOS)
|
||||
Self.applyTheme(theme)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,28 @@ extension SettingsManager {
|
||||
set {
|
||||
_theme = newValue
|
||||
set(newValue.rawValue, for: .theme)
|
||||
Self.applyTheme(newValue)
|
||||
}
|
||||
}
|
||||
|
||||
/// Forces the theme onto the platform windows directly. SwiftUI's
|
||||
/// `.preferredColorScheme` fails to revert from dark back to light/system
|
||||
/// while a sheet is presented, and on macOS it never covered secondary
|
||||
/// window scenes (Settings), so the override is applied at the
|
||||
/// UIKit/AppKit level instead.
|
||||
static func applyTheme(_ theme: AppTheme) {
|
||||
#if os(iOS)
|
||||
for scene in UIApplication.shared.connectedScenes {
|
||||
guard let windowScene = scene as? UIWindowScene else { continue }
|
||||
for window in windowScene.windows {
|
||||
window.overrideUserInterfaceStyle = theme.userInterfaceStyle
|
||||
}
|
||||
}
|
||||
#elseif os(macOS)
|
||||
NSApp.appearance = theme.appearance
|
||||
#endif
|
||||
}
|
||||
|
||||
var accentColor: AccentColor {
|
||||
get {
|
||||
if let cached = _accentColor { return cached }
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
#if canImport(UIKit)
|
||||
import UIKit
|
||||
#elseif canImport(AppKit)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
// MARK: - Theme & Appearance
|
||||
|
||||
@@ -22,6 +27,24 @@ enum AppTheme: String, CaseIterable, Codable {
|
||||
case .dark: return .dark
|
||||
}
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
var userInterfaceStyle: UIUserInterfaceStyle {
|
||||
switch self {
|
||||
case .system: return .unspecified
|
||||
case .light: return .light
|
||||
case .dark: return .dark
|
||||
}
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
var appearance: NSAppearance? {
|
||||
switch self {
|
||||
case .system: return nil
|
||||
case .light: return NSAppearance(named: .aqua)
|
||||
case .dark: return NSAppearance(named: .darkAqua)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
enum AccentColor: String, CaseIterable, Codable {
|
||||
|
||||
@@ -70,7 +70,6 @@ struct YatteeApp: App {
|
||||
ContentView()
|
||||
.appEnvironment(appEnvironment)
|
||||
#if !os(tvOS)
|
||||
.preferredColorScheme(appEnvironment.settingsManager.theme.colorScheme)
|
||||
.tint(appEnvironment.settingsManager.resolvedAccentColor)
|
||||
#endif
|
||||
#if os(macOS)
|
||||
@@ -85,6 +84,9 @@ struct YatteeApp: App {
|
||||
handleContinuedActivity(activity)
|
||||
}
|
||||
.onAppear {
|
||||
#if !os(tvOS)
|
||||
SettingsManager.applyTheme(appEnvironment.settingsManager.theme)
|
||||
#endif
|
||||
registerBackgroundTasksIfNeeded()
|
||||
#if os(tvOS)
|
||||
TopShelfSnapshotWriter.startObserving(dataManager: appEnvironment.dataManager)
|
||||
|
||||
Reference in New Issue
Block a user