Easiest way to add support for light and dark theme in your flutter app.

Overview

adaptive_theme

Adaptive Theme

Easiest way to add support for light and dark theme in your Flutter app. It allows to manually set light or dark theme and also lets you define themes based on the system. It also persists the theme modes changes across app restarts.

Build Tests Codecov Pub Version

Demo: Adaptive Theme

Index

Getting Started

add following dependency to your pubspec.yaml

dependencies:
  adaptive_theme: <latest_version>

Initialization

You need to wrap your MaterialApp with AdaptiveTheme in order to apply themes.

import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return AdaptiveTheme(
      light: ThemeData(
        brightness: Brightness.light,
        primarySwatch: Colors.red,
        accentColor: Colors.amber,
      ),
      dark: ThemeData(
        brightness: Brightness.dark,
        primarySwatch: Colors.red,
        accentColor: Colors.amber,
      ),
      initial: AdaptiveThemeMode.light,
      builder: (theme, darkTheme) => MaterialApp(
        title: 'Adaptive Theme Demo',
        theme: theme,
        darkTheme: darkTheme,
        home: MyHomePage(),
      ),
    );
  }
}

Changing Theme Mode

Now that you have initialized your app as mentioned above. It's very easy and straight forward to change your theme modes: light to dark, dark to light or to system default.

// sets theme mode to dark
AdaptiveTheme.of(context).setDark();

// sets theme mode to light
AdaptiveTheme.of(context).setLight();

// sets theme mode to system default
AdaptiveTheme.of(context).setSystem();

Toggle Theme Mode

AdaptiveTheme allows you to toggle between light, dark and system theme the easiest way possible.

AdaptiveTheme.of(context).toggleThemeMode();

Changing Themes

If you want to change the theme entirely like change all the colors to some other color swatch, then you can use setTheme method.

AdaptiveTheme.of(context).setTheme(
  light: ThemeData(
    brightness: Brightness.light,
    primarySwatch: Colors.purple,
    accentColor: Colors.amber,
  ),
  dark: ThemeData(
    brightness: Brightness.dark,
    primarySwatch: Colors.purple,
    accentColor: Colors.amber,
  ),
);

Reset Theme

AdaptiveTheme is smart enough to keep your default themes handy that you provided at the time of initialization. You can fallback to those default themes in a very easy way.

AdaptiveTheme.of(context).reset();

This will reset your theme as well as theme mode to the initial values provided at the time of initialization.

Set Default Theme

AdaptiveTheme persists theme mode changes across app restarts and uses the default themes to set theme modes(light/dark) on. You can change this behavior if you want to set a different theme as default theme other then the one provided at the time of initialization.

This comes handy when you're fetching themes remotely on app starts and setting theme as current theme.

Doing so is quit easy. You would set a new theme normally as you do by calling setTheme method but this time, with a flag isDefault set to true.

This is only useful when you might want to reset to default theme at some point.

AdaptiveTheme.of(context).setTheme(
  light: ThemeData(
    brightness: Brightness.light,
    primarySwatch: Colors.blue,
    accentColor: Colors.amber,
  ),
  dark: ThemeData(
    brightness: Brightness.dark,
    primarySwatch: Colors.blue,
    accentColor: Colors.amber,
  ),
  isDefault: true,
);

Get ThemeMode at App Start

When you change your theme, next app run won't be able to pick the most recent theme directly before rendering with default theme first time. This is because at time of initialization, we cannot run async code to get previous theme mode. However it can be avoided if you make your main() method async and load previous theme mode asynchronously. Below example shows how it can be done.

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final savedThemeMode = await AdaptiveTheme.getThemeMode();
  runApp(MyApp(savedThemeMode: savedThemeMode));
}
AdaptiveTheme(
  light: lightTheme,
  dark: darkTheme,
  initial: savedThemeMode ?? AdaptiveThemeMode.light,
  builder: (theme, darkTheme) => MaterialApp(
    title: 'Adaptive Theme Demo',
    theme: theme,
    darkTheme: darkTheme,
    home: MyHomePage(),
  ),
)

Notice that I passed the retrieved theme mode to my material app so that I can use it while initializing the default theme. This helps avoiding theme change flickering on app startup.

Listen to the theme mode changes

You can listen to the changes in the theme mode via a ValueNotifier. This can be useful when designing theme settings screen or developing ui to show theme status.

AdaptiveTheme.of(context).modeChangeNotifier.addListener(() {
  // do your thing.
});

Or you can utilize it to react on UI with

ValueListenableBuilder(
  valueListenable: AdaptiveTheme.of(context).modeChangeNotifier,
  builder: (_, mode, child) {
    // update your UI
    return Container();
  },
);

Ceveats

Non-Persist theme changes

This is only useful in scenarios where you load your themes dynamically from network in the splash screen or some initial screens of the app. Please note that AdaptiveTheme does not persist the themes, it only persists the theme modes(light/dark/system). Any changes made to the provided themes won't be persisted and you will have to do the same changes at the time of the initialization if you want them to apply every time app is opened. e.g changing the accent color.

Using SharedPreferences

This package uses shared_preferences plugin internally to persist theme mode changes. If your app uses shared_preferences which might be the case all the time, clearing your shared_preferences at the time of logging out or signing out might clear these preferences too. Be careful not to clear these preferences if you want it to be persisted.

/// Do not remove this key from preferences
AdaptiveTheme.prefKey

You can use above key to exclude it while clearing the all the preferences.

Or you can call AdaptiveTheme.persist() method after clearing the preferences to make it persistable again as shown below.

final prefs = await SharedPreferences.getInstance();
await pref.clear();
AdaptiveTheme.persist();

Using CupertinoTheme

Wrap your CupertinoApp with CupertinoAdaptiveTheme in order to apply themes.

import 'package:adaptive_theme/adaptive_theme.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return CupertinoAdaptiveTheme(
      light: CupertinoThemeData(
        brightness: Brightness.light,
      ),
      dark: CupertinoThemeData(
        brightness: Brightness.dark,
      ),
      initial: AdaptiveThemeMode.light,
      builder: (theme) => CupertinoApp(
        title: 'Adaptive Theme Demo',
        theme: theme,
        darkTheme: darkTheme,
        home: MyHomePage(),
      ),
    );
  }
}

Changing Cupertino Theme

// sets dark theme
CupertinoAdaptiveTheme.of(context).setDark();

// sets light theme
CupertinoAdaptiveTheme.of(context).setLight();

// sets system default theme
CupertinoAdaptiveTheme.of(context).setSystem();

Contribution

You are most welcome to contribute to this project!

Please have a look at Contributing Guidelines, before contributing and proposing a change.

Liked Adaptive Theme?

Show some love and support by starring the repository.

Or You can

Buy Me A Coffee

License

Copyright © 2020 Birju Vachhani

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • getting current theme return null

    getting current theme return null

    using AdaptiveTheme.getThemeMode() or AdaptiveTheme.of(context).mode.isLight and AdaptiveTheme.of(context).mode.isDark return null when theme in not persisted

    opened by kephren226 22
  • App theme doesn't update if app is started while the system was in dark mode

    App theme doesn't update if app is started while the system was in dark mode

    Describe the bug App theme doesn't update if the app is started while the system was in dark mode. I have only tested this on an Android 11 phone, the Oneplus Nord.

    The code

    class MyApp extends StatelessWidget
    {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context)
      {
        SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
    
        // Auto-reset immersive mode on UI change after 1 sec
        SystemChrome.setSystemUIChangeCallback
        (
          (systemOverlaysAreVisible) => Future.delayed
          (
            const Duration(seconds: 2),
            ()
            {
              SystemChrome.restoreSystemUIOverlays();
            }
          )
        );
    
        return AdaptiveTheme
        (
          light: AppTheme.lightTheme, // Custom Material theme overrides
          dark: AppTheme.darkTheme,
          initial: AdaptiveThemeMode.system,
          builder: (theme, darkTheme)
          {
            return MaterialApp
            (
              supportedLocales: const
              [
                Locale('en'),
                Locale('fr'), // Fallback lang
              ],
    
              localizationsDelegates:
              [
                FlutterI18nDelegate
                  (
                  translationLoader: FileTranslationLoader
                    (
                      basePath: 'assets/i18n',
                      fallbackFile: 'fr'
                  ),
                  missingTranslationHandler: (key, locale)
                  {
                    if (kDebugMode)
                    {
                      print("i18n --- Missing Key: $key, languageCode: ${locale?.languageCode}");
                    }
                  },
                ),
                GlobalMaterialLocalizations.delegate,
                GlobalWidgetsLocalizations.delegate
              ],
    
              debugShowCheckedModeBanner: true,
              title: 'My App',
              initialRoute: '/',
              routes: AppRoutes.appRoutes,
              theme: theme,
              darkTheme: darkTheme,
            );
          }
        );
      }
    }
    

    Environment

    • OS: Android 11
    • adaptive_theme: 2.3.0

    Additional info

    • I've noticed that, if I change the system from light/dark mode when the theme isn't updating, I don't even get a log message in my flutter run session. I do get logs notifying a theme change when I start the app when the system is in light mode, however.

    • So far I don't know if the issue is with my code or your package, I'll be very grateful if you could help me on this.

    • Note that the issue appears regardless if the app is in release or debug mode.

    opened by Sandai64 14
  • System status bar not changing color on iOS

    System status bar not changing color on iOS

    When light theme mode or dark theme mode is chosen, the system status bar on an iOS device keeps the system color. For example, when light theme mode is active and i change the system theme, the color of the status bar text changes with it, instead of keeping the black text color. The same thing happens on dark theme mode. On system theme mode it works perfectly. Im using adaptive_theme: ^2.1.1. Flutter version 2.0.3.

    opened by Klkikok 10
  • ♻️  Remove unnecessary null checks, which result in compiler warnings.

    ♻️ Remove unnecessary null checks, which result in compiler warnings.

    According to the Dart flow analysis, the following null-checks are not needed. Removing them to get rid of these compiler warnings.

    ../../../Dev/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_theme-2.3.1/lib/src/cupertino_adaptive_theme.dart:122:20: Warning: Operand of null-aware operation '?.' has type 'WidgetsBinding' which excludes null.
     - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../../Dev/flutter/packages/flutter/lib/src/widgets/binding.dart').
        WidgetsBinding.instance?.addObserver(this);
                       ^
    
    ../../../Dev/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_theme-2.3.1/lib/src/cupertino_adaptive_theme.dart:144:43: Warning: Operand of null-aware operation '!' has type 'SchedulerBinding' which excludes null.
     - 'SchedulerBinding' is from 'package:flutter/src/scheduler/binding.dart' ('../../../Dev/flutter/packages/flutter/lib/src/scheduler/binding.dart').
          final brightness = SchedulerBinding.instance!.window.platformBrightness;
                                              ^
    ../../../Dev/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_theme-2.3.1/lib/src/cupertino_adaptive_theme.dart:221:43: Warning: Operand of null-aware operation '!' has type 'SchedulerBinding' which excludes null.
     - 'SchedulerBinding' is from 'package:flutter/src/scheduler/binding.dart' ('../../../Dev/flutter/packages/flutter/lib/src/scheduler/binding.dart').
    
          final brightness = SchedulerBinding.instance!.window.platformBrightness;
                                              ^
    ../../../Dev/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_theme-2.3.1/lib/src/cupertino_adaptive_theme.dart:231:20: Warning: Operand of null-aware operation '?.' has type 'WidgetsBinding' which excludes null.
     - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../../Dev/flutter/packages/flutter/lib/src/widgets/binding.dart').
        WidgetsBinding.instance?.removeObserver(this);
                       ^
    ../../../Dev/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_theme-2.3.1/lib/src/adaptive_theme.dart:119:20: Warning: Operand of null-aware operation '?.' has type 'WidgetsBinding' which excludes null.
     - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../../Dev/flutter/packages/flutter/lib/src/widgets/binding.dart').
        WidgetsBinding.instance?.addObserver(this);
                       ^
    ../../../Dev/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_theme-2.3.1/lib/src/adaptive_theme.dart:139:43: Warning: Operand of null-aware operation '!' has type 'SchedulerBinding' which excludes null.
     - 'SchedulerBinding' is from 'package:flutter/src/scheduler/binding.dart' ('../../../Dev/flutter/packages/flutter/lib/src/scheduler/binding.dart').
          final brightness = SchedulerBinding.instance!.window.platformBrightness;
    
                                              ^
    ../../../Dev/flutter/.pub-cache/hosted/pub.dartlang.org/adaptive_theme-2.3.1/lib/src/adaptive_theme.dart:218:20: Warning: Operand of null-aware operation '?.' has type 'WidgetsBinding' which excludes null.
    
     - 'WidgetsBinding' is from 'package:flutter/src/widgets/binding.dart' ('../../../Dev/flutter/packages/flutter/lib/src/widgets/binding.dart').
        WidgetsBinding.instance?.removeObserver(this);
                       ^
    

    Requirements

    • Filling out the template is required. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion.
    • All new code requires tests to ensure against regressions

    Description of the Change

    Alternate Designs

    Why Should This Be In Core?

    Benefits

    Possible Drawbacks

    Verification Process

    Applicable Issues

    enhancement 
    opened by Phil9l 8
  • unable to change to light mode

    unable to change to light mode

    happening on iOS haven't tested on other platforms; trying to change the initial value to light or system doesn't work even when MediaQuery reads the theme correctly.

    not sure what im doing wrong here

    Widget build(BuildContext context) {
        return AdaptiveTheme(
          light: ThemeData.light().copyWith(
              brightness: Brightness.light,
              primaryColor: (Platform.isIOS || Platform.isMacOS)
                  ? CupertinoTheme.of(context).primaryColor
                  : Theme.of(context).primaryColor,
              dividerColor: CupertinoColors.inactiveGray,
              scaffoldBackgroundColor: CupertinoColors.white,
              cardColor: CupertinoColors.systemGroupedBackground,
              primaryIconTheme:
                  Theme.of(context).primaryIconTheme.copyWith(color: Colors.black),
              textTheme: Theme.of(context).textTheme.copyWith(
                  bodyText1: Theme.of(context)
                      .textTheme
                      .bodyText1!
                      .copyWith(color: CupertinoColors.black),
                  subtitle1: Theme.of(context)
                      .textTheme
                      .subtitle1!
                      .copyWith(color: CupertinoColors.black),
                  subtitle2: Theme.of(context).textTheme.subtitle2!.copyWith(
                      color: CupertinoTheme.of(context)
                          .textTheme
                          .tabLabelTextStyle
                          .color),
                  headline6: Theme.of(context).textTheme.headline6!.copyWith(
                        fontWeight: CupertinoTheme.of(context)
                            .textTheme
                            .navLargeTitleTextStyle
                            .fontWeight,
                        color: (Platform.isIOS || Platform.isMacOS)
                            ? CupertinoTheme.of(context).textTheme.textStyle.color
                            : Theme.of(context).textTheme.subtitle1!.color,
                      ),
                  headline4: Theme.of(context).textTheme.headline4!.copyWith(
                      fontWeight: CupertinoTheme.of(context)
                          .textTheme
                          .navLargeTitleTextStyle
                          .fontWeight,
                      color: (Platform.isIOS || Platform.isMacOS)
                          ? CupertinoColors.white
                          : Theme.of(context).textTheme.subtitle1!.color)),
              appBarTheme: Theme.of(context).appBarTheme.copyWith(
                  backgroundColor: CupertinoTheme.of(context).barBackgroundColor,
                  titleTextStyle: CupertinoTheme.of(context)
                      .textTheme
                      .navTitleTextStyle
                      .copyWith(color: CupertinoColors.black),
                  textTheme: Theme.of(context).textTheme.copyWith(
                      bodyText1: Theme.of(context)
                          .textTheme
                          .bodyText1!
                          .copyWith(color: CupertinoColors.black),
                      subtitle1: Theme.of(context)
                          .textTheme
                          .subtitle1!
                          .copyWith(color: CupertinoColors.black),
                      subtitle2: Theme.of(context).textTheme.subtitle2!.copyWith(
                          color: CupertinoTheme.of(context)
                              .textTheme
                              .tabLabelTextStyle
                              .color),
                      headline6:
                          Theme.of(context).textTheme.headline6!.copyWith(fontWeight: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle.fontWeight, color: (Platform.isIOS || Platform.isMacOS) ? CupertinoColors.black : Theme.of(context).textTheme.subtitle1!.color)),
                  toolbarTextStyle: CupertinoTheme.of(context).textTheme.actionTextStyle)),
          dark: ThemeData.dark().copyWith(
              brightness: Brightness.dark,
              //backgroundColor: Theme.of(context).scaffoldBackgroundColor,
              primaryColor: (Platform.isIOS || Platform.isMacOS)
                  ? CupertinoTheme.of(context).primaryColor
                  : Theme.of(context).primaryColor,
              dividerColor: CupertinoColors.inactiveGray,
              scaffoldBackgroundColor: CupertinoColors.black,
              cardColor: CupertinoColors.darkBackgroundGray,
              textTheme: Theme.of(context).textTheme.copyWith(
                  bodyText1: Theme.of(context)
                      .textTheme
                      .bodyText1!
                      .copyWith(color: CupertinoColors.white),
                  subtitle1: Theme.of(context)
                      .textTheme
                      .subtitle1!
                      .copyWith(color: CupertinoColors.white),
                  subtitle2: Theme.of(context).textTheme.subtitle2!.copyWith(
                      color: CupertinoTheme.of(context)
                          .textTheme
                          .tabLabelTextStyle
                          .color),
                  headline6: Theme.of(context).textTheme.headline6!.copyWith(
                      fontWeight: CupertinoTheme.of(context)
                          .textTheme
                          .navLargeTitleTextStyle
                          .fontWeight,
                      color: (Platform.isIOS || Platform.isMacOS)
                          ? CupertinoColors.white
                          : Theme.of(context).textTheme.subtitle1!.color),
                  headline4: Theme.of(context).textTheme.headline4!.copyWith(
                      fontWeight: CupertinoTheme.of(context)
                          .textTheme
                          .navLargeTitleTextStyle
                          .fontWeight,
                      color: (Platform.isIOS || Platform.isMacOS)
                          ? CupertinoColors.white
                          : Theme.of(context).textTheme.subtitle1!.color)),
              appBarTheme: Theme.of(context)
                  .appBarTheme
                  .copyWith(backgroundColor: CupertinoTheme.of(context).barBackgroundColor, titleTextStyle: CupertinoTheme.of(context).textTheme.navTitleTextStyle.copyWith(color: CupertinoColors.white), textTheme: Theme.of(context).textTheme.copyWith(bodyText1: Theme.of(context).textTheme.bodyText1!.copyWith(color: CupertinoColors.white), subtitle1: Theme.of(context).textTheme.subtitle1!.copyWith(color: CupertinoColors.white), subtitle2: Theme.of(context).textTheme.subtitle2!.copyWith(color: CupertinoTheme.of(context).textTheme.tabLabelTextStyle.color), headline6: Theme.of(context).textTheme.headline6!.copyWith(fontWeight: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle.fontWeight, color: (Platform.isIOS || Platform.isMacOS) ? CupertinoColors.white : Theme.of(context).textTheme.subtitle1!.color)), toolbarTextStyle: CupertinoTheme.of(context).textTheme.actionTextStyle)),
          initial: AdaptiveThemeMode.dark,
          builder: (theme, darkTheme) => MaterialApp(
            title: 'Flutter',
            theme: theme,
            darkTheme: darkTheme,
            home: LoginScreen(),
          ),
        );
      }
    
    opened by kyleorin 7
  • [AdaptiveTheme] builder parameters

    [AdaptiveTheme] builder parameters

    Describe the bug The builder functions gives 2 parameters, both are Themes. According to the documentation and the examples like: builder: (theme, darkTheme) => MaterialApp(... the first one is always Light Theme and the second one is always Dark Theme. But its currently not working that way, both parameters are sending the same twice. When the app is on Light mode both params are Light Theme, and when the app is in dark mode, both params are Dark Theme.

    To Reproduce Steps to reproduce the behavior:

    1. Create an AdaptiveTheme with dark and light themes
    2. At the AdaptiveTheme's "builder" function call a print with both theme params and check they are the same at both app modes.

    Expected behavior A clear and concise description of what you expected to happen.

    Screenshots image image

    Desktop (please complete the following information): Doesnt matter

    Smartphone (please complete the following information): Doesnt matter

    Additional context Add any other context about the problem here.

    opened by IvoBiaus 7
  • Fix Cupertino theme changes

    Fix Cupertino theme changes

    Requirements

    None.

    Description of the Change

    I have noticed that, with CupertinoApp, whenever you switched light/dark theme, the application did not update the theme. Moreover, setting "initial" to "AdaptiveMode.system", the app always started in dark mode despite the light mode on the device. I have made three mayors updates:

    1. In the CupertinoAdaptiveTheme's build method it now checks whether the theme is light because intentionally set white or because was set system and the device is in light mode. Giving that, the app is fully capable to detect the correct theme to set.
    2. I have created an initState method in CupertinoAdaptiveTheme that set an onPlatformBrightnessChanged method in order to catch the variation of the light/dark mode and so update accordingly.
    3. I have updated the README since there was a mistake: CupertinoApp does not have a "darkMode" property to be set.
    opened by glofru 7
  • Runtime error

    Runtime error

    Trying to run the example application on an Android phone, I am getting the following error:

    "package:flutter/src/ material/theme_data.dart': Failed assertion: line 346 pos 12: colorScheme?.brightness == null || brightness I| colorScheme!.brightness = brightness': is not true. See also: https://flutter.dev/docs /testing/errorS == null

    To Reproduce Just download the package from github, and run [flutter create .] follow by [flutter run]

    Screenshotsimage

    Smartphone (please complete the following information):

    • Device: Samsung Galaxy A50
    • OS: 11
    opened by detzioni 7
  • Change Android Navigation Bar Color on System Dark Mode toggle

    Change Android Navigation Bar Color on System Dark Mode toggle

    When using AdaptiveTheme.of(context).modeChangeNotifier.addListener, I can change my android's navigation bar color like this:

    AdaptiveTheme.of(context).modeChangeNotifier.addListener(() async {
          //This gets the system's platform brightness.
          final platformBrightness = MediaQuery.of(context).platformBrightness;
    
          final themeMode = AdaptiveTheme.of(context).mode;
          late Color color;
          late Brightness brightness;
    
          switch (themeMode) {
            case AdaptiveThemeMode.light:
              color = Colors.white;
              brightness = Brightness.dark;
              break;
            case AdaptiveThemeMode.dark:
              color = Colors.black;
              brightness = Brightness.light;
              break;
            case AdaptiveThemeMode.system:
              color = (platformBrightness == Brightness.dark)
                  ? Colors.black
                  : Colors.white;
              brightness = (platformBrightness == Brightness.dark)
                  ? Brightness.light
                  : Brightness.dark;
              break;
            default:
              break;
          }
    
          SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
              systemNavigationBarColor: color,
              systemNavigationBarIconBrightness: brightness));
    });
    

    However, the navigation bar color does not change when I toggle dark mode from my Notification Centre. I tried finding a way to listen for platform brightness here by using WidgetsBinding.instance.handlePlatformBrightnessChanged();, but this would disable the dynamic theming of the app provided in your package (As I realised that I am probably overriding your code).

    Is there a way I can change the navigation bar color, when toggling dark mode from notification centre?

    Example (Gif was too large to show here, sorry)

    opened by iamhx 6
  • Adaptive_Theme on windows has problem with shared_preferences

    Adaptive_Theme on windows has problem with shared_preferences

    Describe the bug I try to use adaptive_theme first time with windows and ran into following issue:

    To Reproduce Steps to reproduce the behavior:

    1. add adaptive_theme to project in version ^3.0.0
    2. run the app with windows as target.

    Expected behavior The app starts up without error.

    Screenshots

    [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: 'package:shared_preferences/shared_preferences.dart': Failed assertion: line 169 pos 14: 'key.startsWith(_prefix)': is not true.
    #0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:51:61)
    #1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
    #2      SharedPreferences._getSharedPreferencesMap (package:shared_preferences/shared_preferences.dart:169:14)
    <asynchronous suspension>
    #3      SharedPreferences.getInstance (package:shared_preferences/shared_preferences.dart:33:13)
    <asynchronous suspension>
    #4      ThemePreferences.fromPrefs (package:adaptive_theme/src/adaptive_theme_preferences.dart:62:21)
    <asynchronous suspension>
    #5      AdaptiveTheme.getThemeMode (package:adaptive_theme/src/adaptive_theme.dart:91:13)
    <asynchronous suspension>
    ==> #6      main (package:spaceup_ui/main.dart:18:26) <==
    <asynchronous suspension>
    

    That's following line in my code image

    I also use shared_prefences_settings. Might this be an issue? On Linux, Android and web there is no issue.

    opened by ThraaxSession 6
  • Notify listener when changing theme mode

    Notify listener when changing theme mode

    Describe the bug Widgets that depend on AdaptiveTheme.of(context) don't rebuild automatically after changing the theme. I guess it is because we are not using an InheritedWidget. The problem is especially annoying for a larger app, where one has to call setState manually everywhere.

    Example

    import 'package:adaptive_theme/adaptive_theme.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter/widgets.dart';
    
    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      final savedThemeMode = await AdaptiveTheme.getThemeMode();
      runApp(MyApp(savedThemeMode: savedThemeMode));
    }
    
    class MyApp extends StatelessWidget {
      final AdaptiveThemeMode? savedThemeMode;
    
      const MyApp({Key? key, this.savedThemeMode}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return AdaptiveTheme(
          light: ThemeData(
            brightness: Brightness.light,
            primarySwatch: Colors.red,
            accentColor: Colors.amber,
          ),
          dark: ThemeData(
            brightness: Brightness.dark,
            primarySwatch: Colors.red,
            accentColor: Colors.amber,
          ),
          initial: savedThemeMode ?? AdaptiveThemeMode.light,
          builder: (theme, darkTheme) => MaterialApp(
            title: 'Adaptive Theme Demo',
            theme: theme,
            darkTheme: darkTheme,
            home: MyHomePage(),
          ),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        final theme = AdaptiveTheme.of(context);
        return Scaffold(
          appBar: AppBar(title: Text('Adaptive Theme Demo')),
          body: Center(
            child: TextButton(
              onPressed: () {
                showDialog(context: context, builder: (_) => const ThemeDialog());
              },
              child: Icon(
                theme.mode == AdaptiveThemeMode.light
                    ? Icons.wb_sunny_outlined
                    : theme.mode == AdaptiveThemeMode.dark
                        ? Icons.bedtime_outlined
                        : Icons.brightness_auto_outlined,
              ),
            ),
          ),
        );
      }
    }
    
    class ThemeDialog extends StatefulWidget {
      const ThemeDialog({Key? key}) : super(key: key);
    
      @override
      _ThemeDialogState createState() => _ThemeDialogState();
    }
    
    class _ThemeDialogState extends State<ThemeDialog> {
      @override
      Widget build(BuildContext context) {
        final adaptiveTheme = AdaptiveTheme.of(context);
        return AlertDialog(
          title: const Text('Theme'),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              RadioListTile<AdaptiveThemeMode>(
                autofocus: true,
                selected: true,
                dense: true,
                title: const Text('Light', style: TextStyle(fontSize: 14)),
                value: AdaptiveThemeMode.light,
                onChanged: (value) => adaptiveTheme.setThemeMode(value!),
                groupValue: adaptiveTheme.mode,
              ),
              RadioListTile<AdaptiveThemeMode>(
                autofocus: true,
                selected: true,
                dense: true,
                title: const Text('Dark', style: TextStyle(fontSize: 14)),
                value: AdaptiveThemeMode.dark,
                onChanged: (value) => adaptiveTheme.setThemeMode(value!),
                groupValue: adaptiveTheme.mode,
              ),
              RadioListTile<AdaptiveThemeMode>(
                autofocus: true,
                selected: true,
                dense: true,
                title: const Text('System', style: TextStyle(fontSize: 14)),
                value: AdaptiveThemeMode.system,
                onChanged: (value) => adaptiveTheme.setThemeMode(value!),
                groupValue: adaptiveTheme.mode,
              ),
            ],
          ),
          actions: <Widget>[
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: Text(
                MaterialLocalizations.of(context).okButtonLabel,
                style: Theme.of(context).primaryTextTheme.button,
              ),
            ),
          ],
        );
      }
    }
    

    Expected behavior I expected that when I change the theme, widget that depend on AdaptiveTheme.of(context) will rebuild itself automatically. But unfortunately this is not the case and I have to call setState manually. This is especially noticeable when I switch between e.g. Light and System mode (and the System mode is Light).

    opened by friebetill 6
Releases(3.1.1)
  • 3.1.1(Jul 25, 2022)

  • 3.1.0(Jun 23, 2022)

    • CupertinoAdaptiveThemeManager is now deprecated and replaced with AdaptiveThemeManager<CupertinoThemeData> in favor of supporting theming for other UI frameworks. (e.g. Fluent UI). This will be removed in v4.0.0.
    • AdaptiveThemeManager is now generic typed where the generic type represents the type of the theme data object. Replace AdaptiveThemeManager with AdaptiveThemeManager<ThemeData>
    • AdaptiveThemeManager is now a mixin instead of an abstract class to reduce code duplication.
    Source code(tar.gz)
    Source code(zip)
  • 3.0.0(May 17, 2022)

  • 2.3.1(Apr 3, 2022)

  • 2.3.0(Oct 16, 2021)

    • Fixed Cupertino theme not changing when on system mode.
    • Internal code cleanup.
    • Removed isDefault option from setTheme method. Default are meant to come from AdaptiveTheme widget itself.
    • Added flutter lints.
    • Fixed doc comments and typos.
    • Added reset and custom theme options in the example app.
    • Fixed AdaptiveTheme's brightness and theme getters.
    • Fixed CupertinoAdaptiveTheme's brightness and theme getters.
    • Added Tests.
    Source code(tar.gz)
    Source code(zip)
    Adaptive.Theme.Demo.v2.3.0.apk(15.94 MB)
  • 2.2.0(Apr 16, 2021)

  • 2.1.1(Apr 9, 2021)

  • 2.1.0(Apr 5, 2021)

  • 2.0.0(Mar 12, 2021)

    • Improved documentation
    • Stable null safety support
    • Calling AdaptiveTheme.of(context).toggleThemeMode() now will sequentially loop through AdaptiveThemeMode.light, AdaptiveThemeMode.dark and AdaptiveThemeMode.system instead of just AdaptiveThemeMode.light and AdaptiveThemeMode.dark.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0-nullsafety.1(Mar 2, 2021)

  • 1.1.0(Oct 29, 2020)

    • Removed hard coded shared_preferences version.
    • Hide public constructors for ThemePreferences.
    • AdaptiveTheme.of() now returns instance of AdaptiveThemeManager instead of AdaptiveThemeState to set restrictions for accessing state directly.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Aug 1, 2020)

  • 0.1.1(May 4, 2020)

  • 0.1.0(May 3, 2020)

    • Supports theme modes: light, dart, system default.
    • Persists theme modes across app restarts.
    • Allows to toggle theme mode between light and dark.
    • Allows to set default theme.
    • Allows to reset to default theme.
    Source code(tar.gz)
    Source code(zip)
Owner
Birju Vachhani
Sr. Software Engineer @CodelesslyInc | Android | Flutter | Kotlin | Dart | Ruby
Birju Vachhani
The easiest way to create your animated splash screen in a fully customizable way.

Animated Splash Screen Check it out at Pub.Dev Do it your way Assets image Custom Widget Url image IconData Or just change PageTransition and/or Splas

Clean Code 104 Nov 10, 2022
Deepak Sharma 149 Dec 10, 2022
Chat Messaging App Light and Dark Theme

Chat/Messaging App Light and Dark Theme - Flutter UI Watch it on YouTube Complete Source Code (Patreon only) Packages we are using: goole_fonts: link

Abu Anwar 1.4k Jan 6, 2023
Custom Clock App With GetX And Dark Theme & Light Mode

Clock App ✍?? Clock App with GetX [MVC pattern] ????‍?? Clock App app is open-source app for Android & ios. It is built with Dart on top of Google's F

null 12 Oct 21, 2022
This is a message/chat app with light and dark theme options

this is a message/chat app #ui using #flutter that runs both Android and iOS devices also has a dark and light theme. We create in total 4 screens all

Enes Aydoğdu 17 Dec 30, 2022
Chat messaging app for multiple users in light/dark theme with ios/android.

Chat/Messaging App Light and Dark Theme - Flutter UI Watch it on YouTube Complete Source Code (Patreon only) Packages we are using: goole_fonts: link

null 7 Dec 3, 2022
Flutter Image add drag sort, Image add drag sort, support click event, delete, add, long press drag sort.

flutter_image_add_drag_sort Flutter Image add drag sort, Image add drag sort, support click event, delete, add, long press drag sort, support video fi

null 5 Jun 23, 2020
This perfect starter kit is an app based on React Native and UI Kitten library with Light and Dark themes support.

Kitten Tricks This perfect starter kit is an app based on React Native and UI Kitten library with Light and Dark themes support. It’s completely free

Akveo 7k Dec 30, 2022
Shoes-Store-App-UI-Flutter - Beautiful Shoes Store App UI with support for dark and light mode

Flutter Shoes Store App UI with support for dark and light mode. Flutter 2.8.1 N

Jakub Sobański 4 Nov 23, 2022
Hotel-Booking-App-UI - Beautiful Hotel Booking App UI with support for dark and light mode

Flutter Hotel Booking App UI with support for dark and light mode. Flutter 2.8.1

Martin Gogołowicz 11 Nov 1, 2022
This library provides the optimized and easiest way to authenticate with Mastodon's OAuth 2.0 in your Flutter app 🎯

The Optimized and Easiest Way to Integrate OAuth 2.0 with Mastodon API in Flutter ?? 1. Guide ?? 1.1. Getting Started ⚡ 1.1.1. Install Library 1.1.2.

Mastodon.dart 11 Jul 7, 2023
Flutter ui boilerplate is easiest way to create new flutter project with clean code and well organized file folder.

Flutter UI Boilerplate "Sharing for fun" Flutter ui boilerplate is easiest way to create new flutter project with clean code and well organized file f

Dimas Ibnu Malik 122 Dec 1, 2022
The easiest way to use navigation, context less and useful methods.

Starlight Utils The easiest way to use navigation, context less and useful methods. Features Name Status Context Less Navigation Service ✅ Context Les

Ye Myo Aung 5 Jul 10, 2022
The easiest way to style custom text snippets in flutter

Super Rich Text Check it out at Pub.Dev The easiest way to style custom text snippets Help Maintenance I've been maintaining quite many repos these da

Woton Sampaio 14 Nov 4, 2022
This library provides the easiest way to integrate Twitter Cards in Flutter web apps 🐦

The Easiest Way to Integrate Twitter Cards into Your Flutter Web App ?? 1. Guide ?? 1.1. Features ?? 1.2. Getting Started ⚡ 1.2.1. Install Library 1.2

Twitter.dart 3 Aug 7, 2022
Use the easiest way to create a dotted line view 👀!

fdottedline Use the easiest way to create a dotted line view ?? ! [FDottedLine] provides developers with the ability to create dashed lines. It also s

Fliggy Mobile 122 Jul 17, 2022
An awesome flutter app which artistically animates light and dark mode 😍

Light Dark Toggle Made with ?? in India This flutter app is based on the design made by Matthieu Souteyrand on Dribble.He describes the design as: Bac

Shubham Soni 221 Nov 9, 2022
Widget for selecting between ThemeMode.dark and ThemeMode.light

ThemeModeSelector Widget I am currently working with the concept of Theme's in Flutter and I wanted to build a widget which would allow me to switch b

null 10 Oct 26, 2022