From ffafe35ce72814c3fbbd5c0033ba597f87ee1e4c Mon Sep 17 00:00:00 2001 From: Davide Date: Mon, 17 Feb 2025 18:54:20 +0100 Subject: [PATCH 1/6] Override system appearance --- .../Sources/CommonLibrary/CommonLibrary.swift | 4 +- .../UILibrary/Domain/SystemAppearance.swift | 43 +++++++++++++++++++ .../UILibrary/Domain/UIPreference.swift | 2 + .../UILibrary/L10n/SwiftGen+Strings.swift | 12 ++++++ .../UILibrary/L10n/UILibrary+L10n.swift | 38 ++++++++++++++++ .../Resources/en.lproj/Localizable.strings | 7 +++ .../Views/Preferences/PreferencesGroup.swift | 18 ++++++++ 7 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 Packages/App/Sources/UILibrary/Domain/SystemAppearance.swift create mode 100644 Packages/App/Sources/UILibrary/L10n/UILibrary+L10n.swift diff --git a/Packages/App/Sources/CommonLibrary/CommonLibrary.swift b/Packages/App/Sources/CommonLibrary/CommonLibrary.swift index d9cfefd61..a7bcb69c4 100644 --- a/Packages/App/Sources/CommonLibrary/CommonLibrary.swift +++ b/Packages/App/Sources/CommonLibrary/CommonLibrary.swift @@ -74,8 +74,8 @@ private extension CommonLibrary { func configureShared() { UserDefaults.appGroup.register(defaults: [ - AppPreference.logsPrivateData.key: false, - AppPreference.dnsFallsBack.key: true + AppPreference.dnsFallsBack.key: true, + AppPreference.logsPrivateData.key: false ]) } } diff --git a/Packages/App/Sources/UILibrary/Domain/SystemAppearance.swift b/Packages/App/Sources/UILibrary/Domain/SystemAppearance.swift new file mode 100644 index 000000000..f139450d2 --- /dev/null +++ b/Packages/App/Sources/UILibrary/Domain/SystemAppearance.swift @@ -0,0 +1,43 @@ +// +// SystemAppearance.swift +// Passepartout +// +// Created by Davide De Rosa on 2/17/25. +// Copyright (c) 2025 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import Foundation +import SwiftUI + +public enum SystemAppearance: String, RawRepresentable { + case light + + case dark +} + +extension Optional where Wrapped == SystemAppearance { + public var colorScheme: ColorScheme? { + switch self { + case .none: return nil + case .light: return .light + case .dark: return .dark + } + } +} diff --git a/Packages/App/Sources/UILibrary/Domain/UIPreference.swift b/Packages/App/Sources/UILibrary/Domain/UIPreference.swift index 735248be4..7b0d6503e 100644 --- a/Packages/App/Sources/UILibrary/Domain/UIPreference.swift +++ b/Packages/App/Sources/UILibrary/Domain/UIPreference.swift @@ -39,6 +39,8 @@ public enum UIPreference: String, PreferenceProtocol { case profilesLayout + case systemAppearance + public var key: String { "UI.\(rawValue)" } diff --git a/Packages/App/Sources/UILibrary/L10n/SwiftGen+Strings.swift b/Packages/App/Sources/UILibrary/L10n/SwiftGen+Strings.swift index 255b4834e..97ad3521c 100644 --- a/Packages/App/Sources/UILibrary/L10n/SwiftGen+Strings.swift +++ b/Packages/App/Sources/UILibrary/L10n/SwiftGen+Strings.swift @@ -93,6 +93,16 @@ public enum Strings { /// Inactive public static let inactive = Strings.tr("Localizable", "entities.tunnel_status.inactive", fallback: "Inactive") } + public enum Ui { + public enum SystemAppearance { + /// Dark + public static let dark = Strings.tr("Localizable", "entities.ui.system_appearance.dark", fallback: "Dark") + /// Light + public static let light = Strings.tr("Localizable", "entities.ui.system_appearance.light", fallback: "Light") + /// System + public static let system = Strings.tr("Localizable", "entities.ui.system_appearance.system", fallback: "System") + } + } } public enum Errors { public enum App { @@ -844,6 +854,8 @@ public enum Strings { public static let locksInBackground = Strings.tr("Localizable", "views.preferences.locks_in_background", fallback: "Lock in background") /// Pin active profile public static let pinsActiveProfile = Strings.tr("Localizable", "views.preferences.pins_active_profile", fallback: "Pin active profile") + /// Appearance + public static let systemAppearance = Strings.tr("Localizable", "views.preferences.system_appearance", fallback: "Appearance") public enum DnsFallsBack { /// Fall back to CloudFlare servers when the VPN does not provide DNS settings. public static let footer = Strings.tr("Localizable", "views.preferences.dns_falls_back.footer", fallback: "Fall back to CloudFlare servers when the VPN does not provide DNS settings.") diff --git a/Packages/App/Sources/UILibrary/L10n/UILibrary+L10n.swift b/Packages/App/Sources/UILibrary/L10n/UILibrary+L10n.swift new file mode 100644 index 000000000..c5e56557e --- /dev/null +++ b/Packages/App/Sources/UILibrary/L10n/UILibrary+L10n.swift @@ -0,0 +1,38 @@ +// +// UILibrary+L10n.swift +// Passepartout +// +// Created by Davide De Rosa on 2/17/25. +// Copyright (c) 2025 Davide De Rosa. All rights reserved. +// +// https://github.com/passepartoutvpn +// +// This file is part of Passepartout. +// +// Passepartout is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Passepartout is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Passepartout. If not, see . +// + +import CommonUtils +import Foundation + +extension Optional: LocalizableEntity where Wrapped == SystemAppearance { + public var localizedDescription: String { + let V = Strings.Entities.Ui.SystemAppearance.self + switch self { + case .none: return V.system + case .light: return V.light + case .dark: return V.dark + } + } +} diff --git a/Packages/App/Sources/UILibrary/Resources/en.lproj/Localizable.strings b/Packages/App/Sources/UILibrary/Resources/en.lproj/Localizable.strings index 4340878c3..e399386cd 100644 --- a/Packages/App/Sources/UILibrary/Resources/en.lproj/Localizable.strings +++ b/Packages/App/Sources/UILibrary/Resources/en.lproj/Localizable.strings @@ -98,6 +98,7 @@ "views.paywall.alerts.restricted.message" = "Some features are unavailable in this build."; "views.paywall.alerts.pending.message" = "The purchase is pending external confirmation. The feature will be credited upon approval."; +"views.preferences.system_appearance" = "Appearance"; "views.preferences.launches_on_login" = "Launch on login"; "views.preferences.launches_on_login.footer" = "Open the app in background after login."; "views.preferences.keeps_in_menu" = "Keep in menu bar"; @@ -235,6 +236,12 @@ "entities.openvpn.otp_method.append" = "Append"; "entities.openvpn.otp_method.encode" = "Encode"; +// MARK: Entities (Library) + +"entities.ui.system_appearance.system" = "System"; +"entities.ui.system_appearance.light" = "Light"; +"entities.ui.system_appearance.dark" = "Dark"; + // MARK: - Features "features.appletv" = "%@"; diff --git a/Packages/App/Sources/UILibrary/Views/Preferences/PreferencesGroup.swift b/Packages/App/Sources/UILibrary/Views/Preferences/PreferencesGroup.swift index a1982f0e1..be18b5799 100644 --- a/Packages/App/Sources/UILibrary/Views/Preferences/PreferencesGroup.swift +++ b/Packages/App/Sources/UILibrary/Views/Preferences/PreferencesGroup.swift @@ -32,6 +32,9 @@ import SwiftUI public struct PreferencesGroup: View { + @AppStorage(UIPreference.systemAppearance.key) + private var systemAppearance: SystemAppearance? + #if os(iOS) @AppStorage(UIPreference.locksInBackground.key) private var locksInBackground = false @@ -56,6 +59,7 @@ public struct PreferencesGroup: View { } public var body: some View { + systemAppearancePicker #if os(iOS) lockInBackgroundToggle #elseif os(macOS) @@ -69,6 +73,20 @@ public struct PreferencesGroup: View { } private extension PreferencesGroup { + static let systemAppearances: [SystemAppearance?] = [ + nil, + .light, + .dark + ] + + var systemAppearancePicker: some View { + Picker(Strings.Views.Preferences.systemAppearance, selection: $systemAppearance) { + ForEach(Self.systemAppearances, id: \.self) { + Text($0.localizedDescription) + } + } + } + #if os(iOS) var lockInBackgroundToggle: some View { Toggle(Strings.Views.Preferences.locksInBackground, isOn: $locksInBackground) From af646dbe2824cad5e3c668d88afc8d3236c16643 Mon Sep 17 00:00:00 2001 From: Davide Date: Mon, 17 Feb 2025 19:19:46 +0100 Subject: [PATCH 2/6] Apply appearance to color scheme FIXME: nil colorScheme is flaky. --- .../App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift | 8 ++++++++ Passepartout/App/PassepartoutApp.swift | 3 +++ Passepartout/App/Platforms/App+iOS.swift | 1 + Passepartout/App/Platforms/App+macOS.swift | 2 ++ 4 files changed, 14 insertions(+) diff --git a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift index e7503d621..fbcfe1fbb 100644 --- a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift +++ b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift @@ -335,6 +335,9 @@ struct ThemeBooleanModalModifier: ViewModifier where Modal: View { @EnvironmentObject private var theme: Theme + @AppStorage(UIPreference.systemAppearance.key) + private var systemAppearance: SystemAppearance? + @Binding var isPresented: Bool @@ -358,6 +361,7 @@ struct ThemeBooleanModalModifier: ViewModifier where Modal: View { #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() + .preferredColorScheme(systemAppearance.colorScheme) } } } @@ -367,6 +371,9 @@ struct ThemeItemModalModifier: ViewModifier where Modal: View, T: Iden @EnvironmentObject private var theme: Theme + @AppStorage(UIPreference.systemAppearance.key) + private var systemAppearance: SystemAppearance? + @Binding var item: T? @@ -390,6 +397,7 @@ struct ThemeItemModalModifier: ViewModifier where Modal: View, T: Iden #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() + .preferredColorScheme(systemAppearance.colorScheme) } } } diff --git a/Passepartout/App/PassepartoutApp.swift b/Passepartout/App/PassepartoutApp.swift index 0d28ed53d..d90ae8d25 100644 --- a/Passepartout/App/PassepartoutApp.swift +++ b/Passepartout/App/PassepartoutApp.swift @@ -36,6 +36,9 @@ import SwiftUI @main struct PassepartoutApp: App { + @AppStorage(UIPreference.systemAppearance.key) + var systemAppearance: SystemAppearance? + #if os(iOS) || os(tvOS) @UIApplicationDelegateAdaptor diff --git a/Passepartout/App/Platforms/App+iOS.swift b/Passepartout/App/Platforms/App+iOS.swift index 30abbad3f..761b31c14 100644 --- a/Passepartout/App/Platforms/App+iOS.swift +++ b/Passepartout/App/Platforms/App+iOS.swift @@ -52,6 +52,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .tint(.accentColor) + .preferredColorScheme(systemAppearance.colorScheme) } } } diff --git a/Passepartout/App/Platforms/App+macOS.swift b/Passepartout/App/Platforms/App+macOS.swift index 4481a057a..697c8eb5c 100644 --- a/Passepartout/App/Platforms/App+macOS.swift +++ b/Passepartout/App/Platforms/App+macOS.swift @@ -64,6 +64,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .frame(minWidth: 600, minHeight: 400) + .preferredColorScheme(systemAppearance.colorScheme) } .defaultSize(width: 600, height: 400) @@ -72,6 +73,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environmentObject(settings) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) + .preferredColorScheme(systemAppearance.colorScheme) } .defaultSize(width: 500, height: 400) From 696fbe6015dcbbeb4885a89bbb285925c94359ed Mon Sep 17 00:00:00 2001 From: Davide Date: Mon, 17 Feb 2025 20:02:30 +0100 Subject: [PATCH 3/6] Wrap preferredColorScheme --- .../App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift | 8 ++++++-- Passepartout/App/Platforms/App+iOS.swift | 2 +- Passepartout/App/Platforms/App+macOS.swift | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift index fbcfe1fbb..480fadecd 100644 --- a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift +++ b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift @@ -65,6 +65,10 @@ public enum ThemeModalSize: Hashable { } extension View { + public func themeAppearance(_ appearance: SystemAppearance?) -> some View { + preferredColorScheme(appearance.colorScheme) + } + public func themeModal( isPresented: Binding, options: ThemeModalOptions? = nil, @@ -361,7 +365,7 @@ struct ThemeBooleanModalModifier: ViewModifier where Modal: View { #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() - .preferredColorScheme(systemAppearance.colorScheme) + .themeAppearance(systemAppearance) } } } @@ -397,7 +401,7 @@ struct ThemeItemModalModifier: ViewModifier where Modal: View, T: Iden #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() - .preferredColorScheme(systemAppearance.colorScheme) + .themeAppearance(systemAppearance) } } } diff --git a/Passepartout/App/Platforms/App+iOS.swift b/Passepartout/App/Platforms/App+iOS.swift index 761b31c14..3de0004f5 100644 --- a/Passepartout/App/Platforms/App+iOS.swift +++ b/Passepartout/App/Platforms/App+iOS.swift @@ -52,7 +52,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .tint(.accentColor) - .preferredColorScheme(systemAppearance.colorScheme) + .themeAppearance(systemAppearance) } } } diff --git a/Passepartout/App/Platforms/App+macOS.swift b/Passepartout/App/Platforms/App+macOS.swift index 697c8eb5c..aeb249d24 100644 --- a/Passepartout/App/Platforms/App+macOS.swift +++ b/Passepartout/App/Platforms/App+macOS.swift @@ -64,7 +64,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .frame(minWidth: 600, minHeight: 400) - .preferredColorScheme(systemAppearance.colorScheme) + .themeAppearance(systemAppearance) } .defaultSize(width: 600, height: 400) @@ -73,7 +73,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environmentObject(settings) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) - .preferredColorScheme(systemAppearance.colorScheme) + .themeAppearance(systemAppearance) } .defaultSize(width: 500, height: 400) From dc8be9f754f0a9ced1b15db77f937b9e1da972e0 Mon Sep 17 00:00:00 2001 From: Davide Date: Mon, 17 Feb 2025 20:07:00 +0100 Subject: [PATCH 4/6] Use current scheme explicitly rather than nil --- .../UILibrary/Theme/UI/Theme+Modifiers.swift | 14 ++++++++++---- Passepartout/App/PassepartoutApp.swift | 3 +++ Passepartout/App/Platforms/App+iOS.swift | 2 +- Passepartout/App/Platforms/App+macOS.swift | 4 ++-- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift index 480fadecd..2df9fbc9f 100644 --- a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift +++ b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift @@ -65,8 +65,8 @@ public enum ThemeModalSize: Hashable { } extension View { - public func themeAppearance(_ appearance: SystemAppearance?) -> some View { - preferredColorScheme(appearance.colorScheme) + public func themeAppearance(_ appearance: SystemAppearance?, defaultScheme: ColorScheme) -> some View { + preferredColorScheme(appearance.colorScheme ?? defaultScheme) } public func themeModal( @@ -339,6 +339,9 @@ struct ThemeBooleanModalModifier: ViewModifier where Modal: View { @EnvironmentObject private var theme: Theme + @Environment(\.colorScheme) + private var colorScheme + @AppStorage(UIPreference.systemAppearance.key) private var systemAppearance: SystemAppearance? @@ -365,7 +368,7 @@ struct ThemeBooleanModalModifier: ViewModifier where Modal: View { #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() - .themeAppearance(systemAppearance) + .themeAppearance(systemAppearance, defaultScheme: colorScheme) } } } @@ -375,6 +378,9 @@ struct ThemeItemModalModifier: ViewModifier where Modal: View, T: Iden @EnvironmentObject private var theme: Theme + @Environment(\.colorScheme) + private var colorScheme + @AppStorage(UIPreference.systemAppearance.key) private var systemAppearance: SystemAppearance? @@ -401,7 +407,7 @@ struct ThemeItemModalModifier: ViewModifier where Modal: View, T: Iden #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() - .themeAppearance(systemAppearance) + .themeAppearance(systemAppearance, defaultScheme: colorScheme) } } } diff --git a/Passepartout/App/PassepartoutApp.swift b/Passepartout/App/PassepartoutApp.swift index d90ae8d25..d90a0d0b0 100644 --- a/Passepartout/App/PassepartoutApp.swift +++ b/Passepartout/App/PassepartoutApp.swift @@ -36,6 +36,9 @@ import SwiftUI @main struct PassepartoutApp: App { + @Environment(\.colorScheme) + var colorScheme + @AppStorage(UIPreference.systemAppearance.key) var systemAppearance: SystemAppearance? diff --git a/Passepartout/App/Platforms/App+iOS.swift b/Passepartout/App/Platforms/App+iOS.swift index 3de0004f5..0fc132649 100644 --- a/Passepartout/App/Platforms/App+iOS.swift +++ b/Passepartout/App/Platforms/App+iOS.swift @@ -52,7 +52,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .tint(.accentColor) - .themeAppearance(systemAppearance) + .themeAppearance(systemAppearance, defaultScheme: colorScheme) } } } diff --git a/Passepartout/App/Platforms/App+macOS.swift b/Passepartout/App/Platforms/App+macOS.swift index aeb249d24..18bccac8e 100644 --- a/Passepartout/App/Platforms/App+macOS.swift +++ b/Passepartout/App/Platforms/App+macOS.swift @@ -64,7 +64,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .frame(minWidth: 600, minHeight: 400) - .themeAppearance(systemAppearance) + .themeAppearance(systemAppearance, defaultScheme: colorScheme) } .defaultSize(width: 600, height: 400) @@ -73,7 +73,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environmentObject(settings) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) - .themeAppearance(systemAppearance) + .themeAppearance(systemAppearance, defaultScheme: colorScheme) } .defaultSize(width: 500, height: 400) From b5460efa5d7d6d281b796e15f996988285f83dcd Mon Sep 17 00:00:00 2001 From: Davide Date: Mon, 17 Feb 2025 20:09:36 +0100 Subject: [PATCH 5/6] Wrap in view modifier --- .../UILibrary/Theme/UI/Theme+Modifiers.swift | 22 +++++++++++++++---- Passepartout/App/PassepartoutApp.swift | 6 ----- Passepartout/App/Platforms/App+iOS.swift | 2 +- Passepartout/App/Platforms/App+macOS.swift | 4 ++-- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift index 2df9fbc9f..2386ea8c3 100644 --- a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift +++ b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift @@ -65,8 +65,8 @@ public enum ThemeModalSize: Hashable { } extension View { - public func themeAppearance(_ appearance: SystemAppearance?, defaultScheme: ColorScheme) -> some View { - preferredColorScheme(appearance.colorScheme ?? defaultScheme) + public func themeAppearance() -> some View { + modifier(ThemeAppearanceModifier()) } public func themeModal( @@ -368,7 +368,7 @@ struct ThemeBooleanModalModifier: ViewModifier where Modal: View { #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() - .themeAppearance(systemAppearance, defaultScheme: colorScheme) + .themeAppearance() } } } @@ -407,7 +407,7 @@ struct ThemeItemModalModifier: ViewModifier where Modal: View, T: Iden #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() - .themeAppearance(systemAppearance, defaultScheme: colorScheme) + .themeAppearance() } } } @@ -472,6 +472,20 @@ struct ThemeNavigationStackModifier: ViewModifier { // MARK: - Content modifiers +struct ThemeAppearanceModifier: ViewModifier { + + @Environment(\.colorScheme) + var colorScheme + + @AppStorage(UIPreference.systemAppearance.key) + var systemAppearance: SystemAppearance? + + func body(content: Content) -> some View { + content + .preferredColorScheme(systemAppearance.colorScheme ?? colorScheme) + } +} + struct ThemeManualInputModifier: ViewModifier { } diff --git a/Passepartout/App/PassepartoutApp.swift b/Passepartout/App/PassepartoutApp.swift index d90a0d0b0..0d28ed53d 100644 --- a/Passepartout/App/PassepartoutApp.swift +++ b/Passepartout/App/PassepartoutApp.swift @@ -36,12 +36,6 @@ import SwiftUI @main struct PassepartoutApp: App { - @Environment(\.colorScheme) - var colorScheme - - @AppStorage(UIPreference.systemAppearance.key) - var systemAppearance: SystemAppearance? - #if os(iOS) || os(tvOS) @UIApplicationDelegateAdaptor diff --git a/Passepartout/App/Platforms/App+iOS.swift b/Passepartout/App/Platforms/App+iOS.swift index 0fc132649..19aa251cb 100644 --- a/Passepartout/App/Platforms/App+iOS.swift +++ b/Passepartout/App/Platforms/App+iOS.swift @@ -52,7 +52,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .tint(.accentColor) - .themeAppearance(systemAppearance, defaultScheme: colorScheme) + .themeAppearance() } } } diff --git a/Passepartout/App/Platforms/App+macOS.swift b/Passepartout/App/Platforms/App+macOS.swift index 18bccac8e..a51452408 100644 --- a/Passepartout/App/Platforms/App+macOS.swift +++ b/Passepartout/App/Platforms/App+macOS.swift @@ -64,7 +64,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .frame(minWidth: 600, minHeight: 400) - .themeAppearance(systemAppearance, defaultScheme: colorScheme) + .themeAppearance() } .defaultSize(width: 600, height: 400) @@ -73,7 +73,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environmentObject(settings) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) - .themeAppearance(systemAppearance, defaultScheme: colorScheme) + .themeAppearance() } .defaultSize(width: 500, height: 400) From d2bc37c2e0ec07f7a9c3b1ee4ad09163ccc8418b Mon Sep 17 00:00:00 2001 From: Davide Date: Mon, 17 Feb 2025 20:13:20 +0100 Subject: [PATCH 6/6] Pass colorScheme from main App Local env does not work. --- .../UILibrary/Theme/UI/Theme+Modifiers.swift | 17 ++++++++--------- Passepartout/App/PassepartoutApp.swift | 3 +++ Passepartout/App/Platforms/App+iOS.swift | 2 +- Passepartout/App/Platforms/App+macOS.swift | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift index 2386ea8c3..5d51d765c 100644 --- a/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift +++ b/Packages/App/Sources/UILibrary/Theme/UI/Theme+Modifiers.swift @@ -65,8 +65,8 @@ public enum ThemeModalSize: Hashable { } extension View { - public func themeAppearance() -> some View { - modifier(ThemeAppearanceModifier()) + public func themeAppearance(systemScheme: ColorScheme) -> some View { + modifier(ThemeAppearanceModifier(systemScheme: systemScheme)) } public func themeModal( @@ -368,7 +368,7 @@ struct ThemeBooleanModalModifier: ViewModifier where Modal: View { #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() - .themeAppearance() + .themeAppearance(systemScheme: colorScheme) } } } @@ -407,7 +407,7 @@ struct ThemeItemModalModifier: ViewModifier where Modal: View, T: Iden #endif .interactiveDismissDisabled(!options.isInteractive) .themeLockScreen() - .themeAppearance() + .themeAppearance(systemScheme: colorScheme) } } } @@ -474,15 +474,14 @@ struct ThemeNavigationStackModifier: ViewModifier { struct ThemeAppearanceModifier: ViewModifier { - @Environment(\.colorScheme) - var colorScheme - @AppStorage(UIPreference.systemAppearance.key) - var systemAppearance: SystemAppearance? + private var systemAppearance: SystemAppearance? + + let systemScheme: ColorScheme func body(content: Content) -> some View { content - .preferredColorScheme(systemAppearance.colorScheme ?? colorScheme) + .preferredColorScheme(systemAppearance.colorScheme ?? systemScheme) } } diff --git a/Passepartout/App/PassepartoutApp.swift b/Passepartout/App/PassepartoutApp.swift index 0d28ed53d..8da8d42fd 100644 --- a/Passepartout/App/PassepartoutApp.swift +++ b/Passepartout/App/PassepartoutApp.swift @@ -36,6 +36,9 @@ import SwiftUI @main struct PassepartoutApp: App { + @Environment(\.colorScheme) + var colorScheme + #if os(iOS) || os(tvOS) @UIApplicationDelegateAdaptor diff --git a/Passepartout/App/Platforms/App+iOS.swift b/Passepartout/App/Platforms/App+iOS.swift index 19aa251cb..f881b0799 100644 --- a/Passepartout/App/Platforms/App+iOS.swift +++ b/Passepartout/App/Platforms/App+iOS.swift @@ -52,7 +52,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .tint(.accentColor) - .themeAppearance() + .themeAppearance(systemScheme: colorScheme) } } } diff --git a/Passepartout/App/Platforms/App+macOS.swift b/Passepartout/App/Platforms/App+macOS.swift index a51452408..7ca82de42 100644 --- a/Passepartout/App/Platforms/App+macOS.swift +++ b/Passepartout/App/Platforms/App+macOS.swift @@ -64,7 +64,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) .frame(minWidth: 600, minHeight: 400) - .themeAppearance() + .themeAppearance(systemScheme: colorScheme) } .defaultSize(width: 600, height: 400) @@ -73,7 +73,7 @@ extension PassepartoutApp { .withEnvironment(from: context, theme: theme) .environmentObject(settings) .environment(\.isUITesting, AppCommandLine.contains(.uiTesting)) - .themeAppearance() + .themeAppearance(systemScheme: colorScheme) } .defaultSize(width: 500, height: 400)