fabulous-dev / Fabulous.XamarinForms

Declarative UIs for Xamarin.Forms with F# and MVU, using Fabulous
https://docs.fabulous.dev/xamarinforms
Apache License 2.0
13 stars 1 forks source link

Dynamically setting light/dark themes at runtime #19

Open gaelian opened 2 years ago

gaelian commented 2 years ago

I'm currently trying to figure out how to get light/dark themes working with my full Elmish style Fabulous app (multi-page, somewhat following the composition model of the FabulousContacts example app). I've managed to get the themes sorted out, mainly by the F#-coded styling approach, plus some native styling that I needed to do in the Android project (via values and values-night, etc). The F# style code is simple, an excerpt example:

module Style =
    let isDarkTheme = Application.Current.RequestedTheme = OSAppTheme.Dark

    let TabBackgroundColor = if isDarkTheme then Color.FromHex("#2d2d30") else Color.FromHex("#f6f6f6")
    let TabUnselectedColor = if isDarkTheme then Color.FromHex("#d0d0d0") else Color.FromHex("#949594")

These values are used within the various view functions to set colours on elements.

The themes are working, except that I can't apply them at runtime, e.g. if the theme changes automatically due to time of day or if the user manually changes the theme while the app is still running. The theme is only set when the app starts. I was hoping to use the Application.Current.RequestedThemeChanged event to dispatch a message (in conjunction with the approach discussed under Triggering Commands from External Events) as I assumed that I would need to somehow trigger an update of the pages in the app for the F#-coded styling approach to work and reapply the different colours to the view elements. But as @TimLariviere mentions here, the Application.Current.RequestedThemeChanged event does not seem to fire.

If anyone could give any info or examples on how they have managed dynamically applying light/dark themes at runtime for Fabulous, that would be much appreciated.

gaelian commented 2 years ago

For anyone coming across this in the future, I managed to get most of what I was hoping for by overriding OnResume(). For example:

type App () as app = 
    inherit Application ()

    let runner = 
        App.program
        |> XamarinFormsProgram.run app

    override this.OnResume () =
        runner.Dispatch App.Msg.RefreshTheme
edgarfgp commented 2 years ago

@gaelian . I'm implementing a similar use case and what I end up doing was to :