swiftuiios-darkmode

SwiftUI Dark Mode not applying to sheets


I'm using a toggle and @AppStorage to change the preferredColorScheme in my app. Dark mode and light mode works fine on Views other than sheets and full screen modals.

struct MyApp: App {

    @AppStorage("darkMode") var darkMode = false

    init() {
        FirebaseApp.configure()
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
                .preferredColorScheme(darkMode ? .dark : .light)
        }
    }
}

App Settings View:

struct AppSettingsView: View {

    @ObservedObject var appSettingsVM: AppSettingsViewModel

    var body: some View {
        ScrollView {
            Toggle("Dark Mode", isOn: $appSettingsVM.darkMode.animation())
                .toggleStyle(SwitchToggleStyle(tint: .orange))
                .padding()
        }
    }
}

App Settings View Model:

class AppSettingsViewModel: ObservableObject {

    @AppStorage("darkMode") var darkMode: Bool = false

}

There are multiple sheets and full screen modals under the Content View hierarchy and none of them respond to the changes in Color Scheme.


Solution

  • I modified the solution from a YouTube video and this works.

    import Foundation
    import UIKit
    
    class ThemeManager {
        static let shared = ThemeManager()
    
        private init () {}
    
        func handleTheme(darkMode: Bool, system: Bool) {
        
            guard !system else {
                UIApplication.shared.windows.first?.overrideUserInterfaceStyle = .unspecified
                return
            }
            UIApplication.shared.windows.first?.overrideUserInterfaceStyle = darkMode ? .dark : .light
        }
    
    }
    

    import SwiftUI
    import Firebase
    
    @main
    struct MyApp: App {
    
        @AppStorage("darkMode") var darkMode: Bool = false
        @AppStorage("system") var system: Bool = true
    
        init() {
            FirebaseApp.configure()
        }
    
        var body: some Scene {
            WindowGroup {
                MainView(mainVM: MainViewModel())
                    .onAppear {
                        ThemeManager.shared.handleTheme(darkMode: self.darkMode, system: self.system)
                    }
            }
        }
    

    struct AppSettingsView: View {
    
        @ObservedObject var appSettingsVM: AppSettingsViewModel
    
        var body: some View {
        
            VStack {
            
                HStack {
                
                    Text("App Settings")
                        .font(.title2)
                        .padding()
                    Spacer()
                
                }
                .padding(.horizontal)
            
                Divider()
            
                ScrollView {
                
                    HStack {
                    
                        Text("Theme")
                    
                        Spacer()
                
                        Menu {
                            Button("System") {
                                appSettingsVM.handleTheme(darkMode: false, system: true)
                            }
                            Button("Light") {
                                appSettingsVM.handleTheme(darkMode: false, system: false)
                            }
                            Button("Dark") {
                                appSettingsVM.handleTheme(darkMode: true, system: false)
                            }
                        } label: {
                            Text(appSettingsVM.darkModeLabel)
                                .frame(width: 80)
                                .padding(5)
                                .background(Color.orange)
                                .foregroundColor(.white)
                                .clipShape(RoundedRectangle(cornerRadius: 12))
                        }
                    
                    }
                    .padding()
                }
            }
    

    import SwiftUI
    
    class AppSettingsViewModel: ObservableObject {
    
        @AppStorage("darkMode") var darkMode: Bool = false
        @AppStorage("system") var system: Bool = true
        @Published var darkModeLabel = "System"
    
        func handleTheme(darkMode: Bool, system: Bool) {
            self.darkMode = darkMode
            self.system = system
            if darkMode == false && system == true {
                withAnimation {
                    self.darkModeLabel = "System"
                }
            } else if darkMode == false && system == false {
                withAnimation {
                    self.darkModeLabel = "Light"
                }
            } else {
                withAnimation {
                    self.darkModeLabel = "Dark"
                }
            }
            ThemeManager.shared.handleTheme(darkMode: self.darkMode, system: self.system)
        }
        
    }
    

    Video link: https://www.youtube.com/watch?v=j7a4jvHz4MM