rizwankce / SwiftUIColorSchemeTest

Test project for SwiftUI's preferredColorScheme modifier
MIT License
12 stars 1 forks source link

Using Introspect to grab UIViewController #3

Open tyirvine opened 3 years ago

tyirvine commented 3 years ago

Introduction

After reading your article I fiddled with this all day and I didn't even see @junjie's solution! I was little bummed to find out I had been working all day to know it was already solved lol.

However, I found a different solution, and for some reason junjie's solution didn't work too well for me. I believe it has something to do with system colour, I'm not exactly sure. But it wouldn't always flip the background colour. This would happen after I changed the app theme and then changed the device's theme.

Solution

Anyways, instead I used the package Introspect to do a .introspectViewController to grab the UIViewController and then set the theme based on that. The theme is controlled by a @State object that updates an @AppStorage object → so that appStorage is always the user set theme after app close down.

Code

// MARK: - Theme Management

/// All themes
enum Themes: String {
    case Dark
    case Light
    case System
}

// MARK: - Theme Switch

struct ThemeSwitch: ViewModifier {
    let appStorage: String

    func body(content: Content) -> some View {
        content
            .introspectViewController { UIViewController in
                switch appStorage {
                case Themes.System.rawValue: UIViewController.overrideUserInterfaceStyle = .unspecified
                case Themes.Dark.rawValue: UIViewController.overrideUserInterfaceStyle = .dark
                case Themes.Light.rawValue: UIViewController.overrideUserInterfaceStyle = .light
                default: UIViewController.overrideUserInterfaceStyle = .unspecified
                }
            }
    }
}

// MARK: - Extensions

extension View {
    func themeSwitch(appStorage: String) -> some View {
        modifier(ThemeSwitch(appStorage: appStorage))
    }
}

Pros / Cons

I like this solution because it seems reliable however it relies on a package which isn't ideal and it's just not native. Also it is a little bit more code then I'd like. However, I feel this is a good solution till Apple supports this natively.

You can close this as making a pr would require setting up cocoapods.

rizwankce commented 3 years ago

@tyirvine

👋 Thanks for checking out the try to solve the problem. We have lots of ways to fix this. I even tried to fix it by going UIKit way of getting the window from scene and set the user interface style. It works but not SwiftUI way.

I created this repo to submit Feedback to 🍎 and it seems kind of fixed from Xcode 12. Im gonna add this feature to NetNewsWire repo multi platform SwiftUI app which we are building.

rizwankce commented 3 years ago

Im gonna leave this issue open - so any future reader can get solution and thoughts behind the solution.

tyirvine commented 3 years ago

Sounds good!