flutterthemes

Switch between light/dark/system theme on Flutter


I'm trying to make an option on my app to allow the user to choose between a light theme, a dark theme or just leave the theme to match the one on their phone's preferences, that is, if they have a dark appearance and the user selects the option it will match the phone's appearance.

What I have right now is:

  1. My Provider which looks like this:
class ThemeChanger with ChangeNotifier {

  ThemeData _themeData;

  ThemeChanger(this._themeData);

  getTheme() => _themeData;

  setTheme( ThemeData theme) {
    this._themeData = theme;
    notifyListeners();
  }

}
  1. My home.dart, where I have the basics to work with the view and looks like this
class HomePage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Scaffold( 
      appBar: AppBar( 
        title: const Text('AppBar'),
      ),
      body: const ButtonsList(),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.ads_click),
        onPressed: (){}),
    );
  }
}


class ButtonsList extends StatelessWidget {
  const ButtonsList({super.key});

  @override
  Widget build(BuildContext context) {

    final theme = Provider.of<ThemeChanger>(context);

    return Center(
      child: Row( 
        mainAxisAlignment: MainAxisAlignment.center,
        children: [ 
          FloatingActionButton(
            child: Icon(Icons.sunny),
            onPressed: () => theme.setTheme(ThemeData.light())
          ),
          SizedBox(width: 20,),
          FloatingActionButton(
            child: Icon(Icons.dark_mode),
            onPressed: () => theme.setTheme(ThemeData.dark())
          ),
          SizedBox(width: 20,),
          FloatingActionButton(
            child: Icon(Icons.settings),
            onPressed: (){} //should pick the system theme
          ),
        ],
      ),
    );
  }
}
  1. And finally my main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:tema_provider/blocs/theme.dart';
import 'package:tema_provider/pages/home.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: ( _ ) => ThemeChanger( ThemeData.light() ),
      child: MaterialAppWithTheme(),
    );
  }
}

class MaterialAppWithTheme extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    final theme = Provider.of<ThemeChanger>(context);

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: theme.getTheme(),
      home: HomePage()
    );
  }
}

One of the problems I have is that I know the system's theme can be access with the themeMode.system but in my code I'm working with ThemeData, I've tried changing the code on my 1st block of code and work with ThemeMode instead because it also has dark and light modes but it didn't work.

I don't know if what I'm trying to do is possible, all I've found so far is switch between dark/light mode which the app does with the code as it is.

Any help/indication/link to a resource is highly appreciated :)


Solution

  • Thank you so much for your answers :) In the end, with the help on a colleague we found another solution for my problem.

    We changed the default value that was called from Main to light because we thought that it was preventing the theme from updating properly. We also updated the ChangeNotifierProvider to do the system theme setting right there.

    In theme.dart the default value is set to be light, but what it does there now is check the 'platformBrightness', which collects the status of the device theme to know if it is dark or light.

    With these changes we could finally make the app behave like we wanted.