Code Monkey home page Code Monkey logo

animated_theme_switcher's Introduction

animated_theme_switcher

Pub

Animated theme switcher.

This library starts from Peyman's stackoverflow question how-to-add-animation-for-theme-switching-in-flutter

demo

Getting started

Add animated_theme_switcher: "^2.0.8" in your pubspec.yaml dependencies.

dependencies:
 animated_theme_switcher: "^2.0.8"

How To Use

Import the following package in your dart file

import 'package:animated_theme_switcher/animated_theme_switcher.dart';

Wrap MaterialApp with ThemeProvider widget, as it has shown in the following example:

  ThemeProvider(
      initTheme: initTheme,
      builder: (context, myTheme) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: myTheme,
          home: MyHomePage(),
        );
      }),
    ),

But if all you want is to provide a theme, use as follows:

  ThemeProvider(
      initTheme: initTheme,
      child: SomeCoolPage(),
    ),

Wrap the screen where you whant to make them switch with ThemeSwitchingArea widget, as it has shown in the following example:

    ThemeSwitchingArea(
      child: Builder(builder: (context) {
        return ...,
      },
    );

Wrap every switcher with ThemeSwitcher builder, and use ThemeSwitcher.of(context).changeTheme function to switch themes;

    ThemeData newTheme = ThemeData(
      primaryColor: Colors.amber
    );
    ...
    ThemeSwitcher(
      builder: (context) {
        ...
        onTap: () => ThemeSwitcher.of(context).changeTheme(
          theme: newTheme,
          isReversed: false // default: false 
        );
        ...
      },
    );

Alternatively you could use ThemeSwitcher.switcher() or ThemeSwitcher.withTheme().
Builders of this constructors already provide you ThemeSwitcher.
ThemeSwitcher.withTheme() also provides current theme:

    ThemeSwitcher.switcher(
      builder: (context, switcher) {
        ...
        onTap: () => switcher.changeTheme(
          theme: newTheme,
        );
        ...
      },
    );
    
    ThemeSwitcher.withTheme(
      builder: (context, switcher, theme) {
        ...
        onTap: () => switcher.changeTheme(
          theme: theme.brightness == Brightness.light
              ? darkTheme
              : lightTheme,
        );
        ...
      },
    );

Use optional named parameter clipper to pass the custom clippers.

    ...
    ThemeSwitcher(
      clipper: ThemeSwitcherBoxClipper(),
      builder: (context) {
        ...
      },
    );

Notes:

  1. This package is not intended to persist selected theme on the local device. But we added special example to show how to do it using shared_preferences package.

  2. Use the CanvasKit rendering engine to use it on web, more about it..

animated_theme_switcher's People

Contributors

ascenio avatar baiama avatar dan99dm avatar estepiuk avatar hesham-dev-ly avatar issakl avatar kherel avatar mahdidahouei avatar namanshergill avatar sxdpz23 avatar viper-bit avatar vodemn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

animated_theme_switcher's Issues

Bug once theme switcher is actived and showModalBottomSheet is used

I have a listview, and a theme switcher in the appbar.

when the switch is done, changing the theme, and i call showModalBottomSheet(), it also somehow includes the first item of the listview

see image.

not sure if it's the prob of this lib or flutter. it worked before.

my content is also a stack widget.

showModalBottomSheet(
                  context: context,
                  clipBehavior: Clip.antiAliasWithSaveLayer,
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(10.0))),
                  builder: (context) => Wrap(
                    children: [
                      _getRemoveAdsBox(),
                    ],
                  );

ss

it doesn't work on WEB .. yet

as this comment states , this isnt working flutter web yet as RenderRepaintBoundary.toImage is not supported for web, so with window.devicePixelRatio it throws a not supported error .

Can redundant Builder be removed?

When using the theme switcher, we have to wrap out MaterialApp widget with a Builder widget as shown in the example from the docs.

ThemeProvider(
  initTheme: initTheme,
  child: Builder(builder: (context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeProvider.of(context),
      home: MyHomePage(),
    );
  }
)

We do this because the ThemeProvider.of(context) method uses context.dependOnInheritedWidgetOfExactType() which apparently cannot find the State<ThemeProvider> object from the immediate child's context.

Is there not any pattern for returning the ThemeProviderState when context.dependOnInheritedWidgetOfExactType() returns null? It's created in the same class as the static .of method, so it seems like we could store a reference and return it from there?

I realize there must be a flaw in my logic as no one does this, but I was curious as to why.

I am getting exception since I updated to flutter 2.0

console log when from my app

E/flutter ( 6436): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: Invalid argument(s) (value): Must not be null
E/flutter ( 6436): #0      ArgumentError.checkNotNull (dart:core/errors.dart:185:27)
E/flutter ( 6436): #1      SharedPreferences._setValue
package:shared_preferences/shared_preferences.dart:147
E/flutter ( 6436): #2      SharedPreferences.setString
package:shared_preferences/shared_preferences.dart:133
E/flutter ( 6436): #3      ThemeService.save
package:tartib_app/…/theme/theme_service.dart:52
E/flutter ( 6436): #4      ThemeSwitcherButton.build.<anonymous closure>.<anonymous closure>
package:tartib_app/…/home/category_page.dart:230
E/flutter ( 6436): <asynchronous suspension>
E/flutter ( 6436):

When I run the example app also got exeptions:

D8: Program type already present: com.kherel.animated_theme_switcher_example.MainActivity


com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: 
Learn how to resolve the issue at https://developer.android.com/studio/build/dependencies#duplicate_classes.


Program type already present: com.kherel.animated_theme_switcher_example.MainActivity


	at com.android.builder.dexing.D8DexArchiveMerger.getExceptionToRethrow(D8DexArchiveMerger.java:131)


	at com.android.builder.dexing.D8DexArchiveMerger.mergeDexArchives(D8DexArchiveMerger.java:118)
	at com.android.build.gradle.internal.transforms.DexMergerTransformCallable.call(DexMergerTransformCallable.java:102)


	at com.android.build.gradle.internal.tasks.DexMergingTaskRunnable.run(DexMergingTask.kt:444)


	at com.android.build.gradle.internal.tasks.Workers$ActionFacade.run(Workers.kt:335)
	at org.gradle.workers.internal.AdapterWorkAction.execute(AdapterWorkAction.java:50)


	at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:47)


	at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1$1.create(NoIsolationWorkerFactory.java:65)


	at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1$1.create(NoIsolationWorkerFactory.java:61)


	at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:98)
	at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.execute(NoIsolationWorkerFactory.java:61)


	at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)


	at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)


	at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416)


	at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165)


	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250)


	at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158)


	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102)


	at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36)
	at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)


	at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:56)


	at org.gradle.workers.internal.DefaultWorkerExecutor$3.call(DefaultWorkerExecutor.java:215)


	at org.gradle.workers.internal.DefaultWorkerExecutor$3.call(DefaultWorkerExecutor.java:210)


	at java.util.concurrent.FutureTask.run(FutureTask.java:266)


	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:215)


	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
	at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:131)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)


	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)


	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)


	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)


	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)


	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)


	at java.lang.Thread.run(Thread.java:748)


Caused by: com.android.tools.r8.CompilationFailedException: Compilation failed to complete


	at com.android.tools.r8.utils.t.a(:55)


	at com.android.tools.r8.D8.run(:11)
	at com.android.builder.dexing.D8DexArchiveMerger.mergeDexArchives(D8DexArchiveMerger.java:116)


	... 34 more
Caused by: com.android.tools.r8.utils.AbortException: Error: Program type already present: com.kherel.animated_theme_switcher_example.MainActivity
	at com.android.tools.r8.utils.Reporter.a(:21)
	at com.android.tools.r8.utils.Reporter.a(:7)


	at com.android.tools.r8.utils.t.a(:36)


	... 36 more


2



FAILURE: Build failed with an exception.





* What went wrong:
Execution failed for task ':app:mergeDexDebug'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade
   > com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: 


     Learn how to resolve the issue at https://developer.android.com/studio/build/dependencies#duplicate_classes.


     Program type already present: com.kherel.animated_theme_switcher_example.MainActivity

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org



BUILD FAILED in 12s


[!] The shrinker may have failed to optimize the Java bytecode.


    To disable the shrinker, pass the `--no-shrink` flag to this command.


    To learn more, see: https://developer.android.com/studio/build/shrink-code


Exception: Gradle task assembleDebug failed with exit code 1

debug needs paint

i got an issue when toggling the theme mode

E/flutter (28682): #17     GestureBinding.handlePointerEvent
package:flutter/…/gestures/binding.dart:338
E/flutter (28682): #18     GestureBinding._flushPointerEventQueue
package:flutter/…/gestures/binding.dart:296
E/flutter (28682): #19     GestureBinding._handlePointerDataPacket
package:flutter/…/gestures/binding.dart:279
E/flutter (28682): #20     _rootRunUnary (dart:async/zone.dart:1442:13)
E/flutter (28682): #21     _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (28682): #22     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
E/flutter (28682): #23     _invoke1 (dart:ui/hooks.dart:170:10)
E/flutter (28682): #24     PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:331:7)
E/flutter (28682): #25     _dispatchPointerDataPacket (dart:ui/hooks.dart:94:31)
E/flutter (28682):

Can't use implicit animations when having ThemeSwitchingArea

I have a simple code where I animate a container

  @override
  Widget build(BuildContext context) {
    return ThemeSwitchingArea(
      child: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              AnimatedContainer(
                duration: const Duration(seconds: 2),
                color: _color,
                height: _height,
                width: _width,
                curve: Curves.bounceInOut,
                child: Image.asset('assets/images/coffee.png'),
              ),
              MaterialButton(
                onPressed: () => setState(() {
                  _color = _color == Colors.red ? Colors.deepPurple : Colors.red;
                  _height = _height == 100 ? 200 : 100;
                  _width = _width == 100 ? 300 : 100;
                }),
                child: const Icon(Icons.star),
              )
            ],
          ),
        ),
      ),
    );
  }

I noticed that with ThemeSwitchingArea, there's no animation at all, and it only works once I remove the widget

With ThemeSwitchingArea

Screen.Recording.2022-09-16.at.21.47.49.mov

Without ThemeSwitchingArea

Screen.Recording.2022-09-16.at.21.48.37.mov

Any idea how to fix this issue :/

How to use this package with SharedPreferences

I know that the value from SharedPreferences needs to be set in the initTheme, but how? I save bool value in SharedPreferences, which specify theme. but how I can call this async operation when the app starts.

Web support

Hey,
Thanks for the great package!
I was wondering whether you were looking to support web? I don't think it would too difficult although I'm not sure what blockers there would be.

System controlled dark mode not working when using ThemeSwitchingArea

The system controlled dark mode doesn't work when using a ThemeSwitchingArea. I can use the plugin without the circle/box animation, but the effect is not the same.
I also tried playing with the MaterialApp themeMode parameter, but when there's a ThemeSwitchingArea, it seems that it considers only the light theme..

Maybe adding the darkTheme to ThemeSwitcher.of(context)!.changeTheme() could solve the issue. I really like your plugin, but I don't want to give up on system managed light/dark mode.

_saveScreenshot function (must include the statusBar & navigationBar)

Hi there,
thanks for this awesome package , i've check the example on the android not working like your gif example because the _saveScreenshot function take a screenshot just for previewContainer (RenderRepaintBoundary) so doesn't include the statusBar and navigationBar this caused blink the statusBar and navigationBar while changing the theme. Kind regards

It is not clear where to pass colors for each element!

It's not at all clear how to change colors !!!
The theme_config.dart only has values ​​for Checkbox ... for dark and light mode there are no parameters and cannot be added!
image

And I can't figure out where to insert so that the top status bar is transparent!

appBarTheme: AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle(
statusBarIconBrightness: Brightness.dark,
statusBarColor: Colors.transparent, ),

image

i want to set default theme when the user sing in for the first time in app ,without selected a button or a checkbox

i want to set it in mySplashScreen
but i donot kwnow where should i put this:
ThemeSwitcher.of(context).changeTheme(
theme: myTheme,
);

my Code:

import 'package:animated_theme_switcher/animated_theme_switcher.dart';
import 'package:flutter/material.dart';
import 'package:background_fetch/background_fetch.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

import '../pages/home_page.dart';
import '../pages/signin_screen.dart';
import '../pages/stepup_page.dart';
import '../flavors.dart';
import '../style/style.dart';
import '../helper/helper.dart';
import '../models/localappconfig.dart';
import '../sqliteProvider/userappconfig_provider.dart';
import '../ui/loading.dart';
import '../utils/gradientutil.dart';
import '../utils/uidata.dart';
import '../helper/dbhelper.dart';
import '../sqliteProvider/localappconfig_provider.dart';
import '../models/UserAppConfig.dart';

class SplashScreen extends StatefulWidget {
@OverRide
State createState() => new SplashScreenState();
}

class SplashScreenState extends State {
ThemeData myTheme;

@OverRide
void initState() {
super.initState();
checkLogin();
initPlatformState();
Helper.notificationPermission();
// _configureSelectNotificationSubject();
}

@OverRide
void didChangeDependencies() {
super.didChangeDependencies();
setInitTheme();
}
// void _configureSelectNotificationSubject() {
// final selectNotification = BehaviorSubject();

// selectNotification.stream.listen((String payload) async {
// await Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => WarePage()),
// );
// });
// }

@OverRide
Widget build(BuildContext context) {
ScreenUtil.init(context, width: 750, height: 1334, allowFontScaling: true);

return ThemeSwitchingArea(
  child: Scaffold(
      body: Container(
    height: double.infinity,
    width: double.infinity,
    decoration: BoxDecoration(
      gradient: PAGE_BACKGROUND,
    ),
    child: new Stack(
      fit: StackFit.expand,
      children: <Widget>[
        new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Container(
              width: 400.w,
              height: 400.h,
              decoration: new BoxDecoration(
                  image: new DecorationImage(
                      image: new AssetImage(UIData.imageSorooshan),
                      fit: BoxFit.fill)),
            ),
            new Text(F.companyInfo.appCompanyName,
                style: Style.styleTextBlack(TEXT_SIZE_50, FontWeight.w700))
          ],
        ),
        new Padding(
          padding: const EdgeInsets.only(bottom: 30),
          child: new Align(
            alignment: Alignment.bottomCenter,
            child: LoadingSpinner(Theme.of(context).primaryColor),
          ),
        ),
      ],
    ),
  )),
);

}

Future checkLogin() async {
DbHelper dbHelper = new DbHelper();
var count = await dbHelper.getCount('LocalAppConfig');
if (count == null || (count != null && count == 0)) {
//set Default LocalAppConfig
LocalAppConfigProvider configProvider = new LocalAppConfigProvider();
LocalAppConfig config =
new LocalAppConfig(1, 0, 0.0, DateTime.now().toString());
await configProvider.insert(config);
//set Default UserAppConfig
UserAppConfig appConfig = new UserAppConfig(
sql_Apc_Id: 1,
token: "",
isOnlineDateTime: DateTime.now().toString(),
logOut: 1,
setUp: 0,
// primarycolor: "4294924066",
// accentcolor: "4294924066",
// fontsize: 22.0
);
UserAppConfigProvider userAppConfigProvider = new UserAppConfigProvider();
await userAppConfigProvider.insert(appConfig);
Helper.navigationReplace(context, SignInScreen());
} else if (count != null && count > 0) {
var mapuser = await dbHelper.getItem('UserAppConfig');
if (mapuser != null) {
UserAppConfig appConfig = new UserAppConfig.fromMapDb(mapuser);
if (appConfig != null && appConfig.logOut == 0) {
if (appConfig.setUp == 0)
Helper.navigationReplace(context, SetUpPage());
else
Helper.navigationReplace(context, HomePage());
} else
Helper.navigationReplace(context, SignInScreen());
} else
Helper.navigationReplace(context, SignInScreen());
}
}

Future initPlatformState() async {
// Configure BackgroundFetch.
BackgroundFetch.configure(
BackgroundFetchConfig(
minimumFetchInterval: 30,
stopOnTerminate: false,
startOnBoot: true,
enableHeadless: true,
requiresBatteryNotLow: false,
requiresCharging: false,
requiresStorageNotLow: false,
requiresDeviceIdle: false,
requiredNetworkType: NetworkType.ANY),
_onBackgroundFetch)
.then((int status) async {
print('[BackgroundFetch] configure success: $status');
await Helper.backServiceReception();
}).catchError((e) {
print('[BackgroundFetch] configure ERROR: $e');
});

if (!mounted) return;

}

void _onBackgroundFetch(String taskId) async {
await Helper.backServiceReception();
// IMPORTANT: You must signal completion of your fetch task or the OS can punish your app
// for taking too long in the background.
BackgroundFetch.finish(taskId);
}

void setInitTheme() async {
UserAppConfigProvider _userAppConfigProvider = UserAppConfigProvider();
await _userAppConfigProvider.getUserAppConfig().then((_userAppConfig) {
if (_userAppConfig != null && _userAppConfig.sql_Apc_Id > 0) {
myTheme = ThemeData(
// appBarTheme: ThemeData.light().appBarTheme.copyWith(color: Colors.deepOrange),
brightness: Brightness.light,
fontFamily: UIData.vazirFont,
// primaryColor: Color(int.parse(_userAppConfig.primarycolor)),
// accentColor: Color(int.parse(_userAppConfig.accentcolor)),
primaryColor: Colors.deepOrange,
accentColor: Colors.deepOrange,
// primaryTextTheme:
// TextTheme(bodyText1: TextStyle(fontSize: _userAppConfig.fontsize)),

      // canvasColor: kLightPrimaryColor,
      // backgroundColor: accentcolor,
      // iconTheme: ThemeData.light().iconTheme.copyWith(
      //       color: Color(0xFF373737),
      //     ),
      // textTheme: ThemeData.light().textTheme.apply(
      //       fontFamily: UIData.vazirFont,
      //       bodyColor: Color(0xFF373737),
      //       displayColor: Color(0xFF373737),
      //     ),
    );
  }
});
ThemeSwitcher.of(context).changeTheme(
  theme: myTheme,
);

}
}

animated theme switcher + page view = no scroll

Hello !
First of all, great widget. I'm using it all the time, love the little trick of taking the screenshot and removing it with an animation. It's simple and elegant.

With that said, I am using a PageView widget within the ThemeSwitchArea like this:

class _MyHomePageState extends State<MyHomePage> {
  PageController pc = PageController();
  @override
  Widget build(BuildContext context) {
    return ThemeSwitchingArea(
      child: PageView(
        controller: pc,
        onPageChanged: (page) {
          setState(() {
            print("PAGE CHANGED TO ->${page}");
          });
        },
        children: [
          Container(
            color: Colors.red,
          ),
          Container(
            color: Colors.blue,
          ),
          Container(
            color: Colors.green,
          )
        ],
      ),
    );
  }
}

This is what I replace the Widget Build function with, in a default flutter create project

When doing that, I can't swipe between the 3 pages anymore.
The swiping animation starts on page 1 and rolls back to page 1 instead of displaying the page 2.

It's due to the setState call in the onPageChanged.
I didn't add my entire widget which has a FutureBuilder, AnimatedContainers, AnimatedPositionned plus a series of changes which require a call to SetState between every page.

Again, great widget, neat trick !

My Flutter doctor looks like this:

❯ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.8.0, on macOS 12.0.1 21A559 darwin-x64, locale en-BE)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 13.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2020.3)
[✓] IntelliJ IDEA Community Edition (version 2021.2.3)
[✓] VS Code (version 1.63.1)
[✓] Connected device (2 available)

Demo app loses state on Hot Reload

I am not sure of the cause of this, but the default example app that is provided with the library does not preserve state on hot reload. In this case, the counter value goes back to 0, which does not happen on the normal counter demo.

Is there a fix for this?

Output of flutter doctor:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.0.5, on Arch Linux 5.18.12-arch1-1, locale en_GB.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[!] Android Studio (not installed)
[✓] Connected device (2 available)
[✓] HTTP Host Availability

Duplicate GlobalKey detected in widget tree. (ThemeSwitchingArea)

I used this on two screen to test my theme but noticed if you navigate to other screen with ThemeSwitchingArea getting this error "Duplicate GlobalKey detected in widget tree".
because of wrapping scaffold with ThemeSwitchingArea as your example.
to reproduce this error I used two screen and used "Navigator.of(context).pushNamed", also in each screen I wrapped Scaffold with ThemeSwitchingArea.

Github to pub.dev source mismatch - Missing builder parameter (Latest updates not publish to pub.dev)

I think, pub dev is not up to date with github source:

with 1.0.9, getting error "parameter builder is not defined"

@override
  Widget build(BuildContext context) {
    return ThemeProvider(
      initTheme: theme,
      builder: (_, theme) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: theme,
          home: MyHomePage(),
        );
      },
    );
  }
}

Github source:

class ThemeProvider extends StatefulWidget {
  ThemeProvider({
    this.initTheme,
    Key? key,
    this.child,
    this.builder,
    this.duration = const Duration(milliseconds: 300),
  })  : assert(!(child == null && builder == null),
            'You should provide either a child or a builder'),
        super(key: key);

1.0.9 source as seen in vs code:

class ThemeProvider extends StatefulWidget {
  ThemeProvider({
    this.initTheme,
    Key key,
    @required this.child,
    this.duration = const Duration(milliseconds: 300),
  })  : assert(duration != null),
        super(key: key);

  final Widget child;
  final ThemeData initTheme;
  final Duration duration;

Theme Switching doesnt work on web?

Hi,

I was trying to use this with Flutter web and I got this error

Error: Assertion failed: org-dartlang-sdk:///flutter_web_sdk/lib/_engine/engine/surface/scene_builder.dart:95:16 matrix4[0] == window.devicePixelRatio && matrix4[5] == window.devicePixelRatio is not true

How do i fix it?

Crash on change theme

When i change the theme ThemeSwitcher.

I/flutter ( 6544): When the exception was thrown, this was the stack:
I/flutter ( 6544): #0 ThemeSwitcherBoxClipper.getClip (package:animated_theme_switcher/src/clippers/theme_switcher_box_clipper.dart:14:25)
I/flutter ( 6544): #1 ThemeSwitcherClipperBridge.getClip (package:animated_theme_switcher/src/clippers/theme_switcher_clipper_bridge.dart:14:21)
I/flutter ( 6544): #2 _RenderCustomClip._updateClip (package:flutter/src/rendering/proxy_box.dart:1375:25)
I/flutter ( 6544): #3 RenderClipPath.paint (package:flutter/src/rendering/proxy_box.dart:1689:7)
I/flutter ( 6544): #4 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #5 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #6 RenderBoxContainerDefaultsMixin.defaultPaint (package:flutter/src/rendering/box.dart:2795:15)
I/flutter ( 6544): #7 RenderStack.paintStack (package:flutter/src/rendering/stack.dart:629:5)
I/flutter ( 6544): #8 RenderStack.paint (package:flutter/src/rendering/stack.dart:645:7)
I/flutter ( 6544): #9 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #10 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #11 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #12 _RenderInkFeatures.paint (package:flutter/src/material/material.dart:551:11)
I/flutter ( 6544): #13 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #14 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #15 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #16 PaintingContext.pushLayer (package:flutter/src/rendering/object.dart:394:12)
I/flutter ( 6544): #17 RenderPhysicalModel.paint (package:flutter/src/rendering/proxy_box.dart:1922:15)
I/flutter ( 6544): #18 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #19 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #20 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #21 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #22 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #23 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #24 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #25 PaintingContext._repaintCompositedChild (package:flutter/src/rendering/object.dart:139:11)
I/flutter ( 6544): #26 PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:100:5)
I/flutter ( 6544): #27 PaintingContext._compositeChild (package:flutter/src/rendering/object.dart:204:7)
I/flutter ( 6544): #28 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:185:7)
I/flutter ( 6544): #29 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #30 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #31 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #32 RenderAnimatedOpacityMixin.paint (package:flutter/src/rendering/proxy_box.dart:1016:17)
I/flutter ( 6544): #33 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #34 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #35 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #36 RenderFractionalTranslation.paint (package:flutter/src/rendering/proxy_box.dart:2723:13)
I/flutter ( 6544): #37 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #38 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #39 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #40 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #41 PaintingContext._repaintCompositedChild (package:flutter/src/rendering/object.dart:139:11)
I/flutter ( 6544): #42 PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:100:5)
I/flutter ( 6544): #43 PaintingContext._compositeChild (package:flutter/src/rendering/object.dart:204:7)
I/flutter ( 6544): #44 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:185:7)
I/flutter ( 6544): #45 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #46 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #47 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #48 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #49 RenderOffstage.paint (package:flutter/src/rendering/proxy_box.dart:3383:11)
I/flutter ( 6544): #50 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #51 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #52 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #53 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #54 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #55 _RenderTheatre.paintStack (package:flutter/src/widgets/overlay.dart:780:15)
I/flutter ( 6544): #56 _RenderTheatre.paint (package:flutter/src/widgets/overlay.dart:798:7)
I/flutter ( 6544): #57 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #58 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #59 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #60 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #61 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #62 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #63 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #64 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #65 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #66 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #67 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #68 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #69 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #70 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #71 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #72 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #73 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #74 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #75 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #76 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
I/flutter ( 6544): #77 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
I/flutter ( 6544): #78 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #79 PaintingContext._repaintCompositedChild (package:flutter/src/rendering/object.dart:139:11)
I/flutter ( 6544): #80 PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:100:5)
I/flutter ( 6544): #81 PaintingContext._compositeChild (package:flutter/src/rendering/object.dart:204:7)
I/flutter ( 6544): #82 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:185:7)
I/flutter ( 6544): #83 RenderView.paint (package:flutter/src/rendering/view.dart:200:15)
I/flutter ( 6544): #84 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
I/flutter ( 6544): #85 PaintingContext._repaintCompositedChild (package:flutter/src/rendering/object.dart:139:11)
I/flutter ( 6544): #86 PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:100:5)
I/flutter ( 6544): #87 PipelineOwner.flushPaint (package:flutter/src/rendering/object.dart:975:29)
I/flutter ( 6544): #88 RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:464:19)
I/flutter ( 6544): #89 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:876:13)
I/flutter ( 6544): #90 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:328:5)
I/flutter ( 6544): #91 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
I/flutter ( 6544): #92 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1082:9)
I/flutter ( 6544): #93 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:998:5)
I/flutter ( 6544): #97 _invoke (dart:ui/hooks.dart:163:10)
I/flutter ( 6544): #98 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:259:5)
I/flutter ( 6544): #99 _drawFrame (dart:ui/hooks.dart:126:31)
I/flutter ( 6544): (elided 3 frames from dart:async)

ThemeSwitchingArea error

When I use this as in the example I get an error:

�[38;5;248m════════ Exception caught by rendering library ═════════════════════════════════�[39;49m
�[38;5;244mThe following NoSuchMethodError was thrown during paint():�[39;49m
The getter 'dx' was called on null.
Receiver: null
Tried calling: dx

�[38;5;244mThe relevant error-causing widget was�[39;49m
    �[38;5;248mThemeSwitchingArea�[39;49m
�[38;5;244mWhen the exception was thrown, this was the stack�[39;49m
�[38;5;244m#0      Object.noSuchMethod  (dart:core-patch/object_patch.dart:53:5)�[39;49m
�[38;5;248m#1      ThemeSwitcherCircleClipper._calcMaxRadius�[39;49m
�[38;5;248m#2      ThemeSwitcherCircleClipper.getClip�[39;49m
�[38;5;248m#3      ThemeSwitcherClipperBridge.getClip�[39;49m
�[38;5;244m#4      _RenderCustomClip._updateClip�[39;49m
�[38;5;244m...�[39;49m
�[38;5;244mThe following RenderObject was being processed when the exception was fired: RenderClipPath#4c9de relayoutBoundary=up1�[39;49m
�[38;5;244mRenderObject: RenderClipPath#4c9de relayoutBoundary=up1�[39;49m
    �[38;5;244mneeds compositing�[39;49m
    �[38;5;244mparentData: not positioned; offset=Offset(0.0, 0.0) (can use size)�[39;49m
    �[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=830.9)�[39;49m
    �[38;5;244msize: Size(411.4, 830.9)�[39;49m
    �[38;5;244mchild: RenderPhysicalModel#2f2c7 relayoutBoundary=up2 NEEDS-PAINT�[39;49m
        �[38;5;244mneeds compositing�[39;49m
        �[38;5;244mparentData: <none> (can use size)�[39;49m
        �[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=830.9)�[39;49m
        �[38;5;244mlayer: PhysicalModelLayer#87699 DETACHED�[39;49m
            �[38;5;244mengine layer: PhysicalShapeEngineLayer#1686c�[39;49m
            �[38;5;244melevation: 0.0�[39;49m
            �[38;5;244mcolor: Color(0xfffafafa)�[39;49m
        �[38;5;244msize: Size(411.4, 830.9)�[39;49m
        �[38;5;244melevation: 0.0�[39;49m
        �[38;5;244mcolor: Color(0xff303030)�[39;49m
        �[38;5;244mshadowColor: Color(0xff303030)�[39;49m
        �[38;5;244mshape: BoxShape.rectangle�[39;49m
        �[38;5;244mborderRadius: BorderRadius.zero�[39;49m
        �[38;5;244mchild: _RenderInkFeatures#29c3a relayoutBoundary=up3 NEEDS-PAINT�[39;49m
            �[38;5;244mneeds compositing�[39;49m
            �[38;5;244mparentData: <none> (can use size)�[39;49m
            �[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=830.9)�[39;49m
            �[38;5;244msize: Size(411.4, 830.9)�[39;49m
            �[38;5;244mchild: RenderCustomMultiChildLayoutBox#6539a relayoutBoundary=up4 NEEDS-PAINT�[39;49m
                �[38;5;244mneeds compositing�[39;49m
                �[38;5;244mparentData: <none> (can use size)�[39;49m
                �[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=830.9)�[39;49m
                �[38;5;244msize: Size(411.4, 830.9)�[39;49m
                �[38;5;244mchild 1: RenderFlex#91f0f relayoutBoundary=up5 NEEDS-PAINT�[39;49m
                    �[38;5;244mneeds compositing�[39;49m
                    �[38;5;244mparentData: offset=Offset(0.0, 80.0); id=_ScaffoldSlot.body (can use size)�[39;49m
                    �[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=750.9)�[39;49m
                    �[38;5;244msize: Size(411.4, 750.9)�[39;49m
                    �[38;5;244mdirection: vertical�[39;49m
                    �[38;5;244mmainAxisAlignment: start�[39;49m
                    �[38;5;244mmainAxisSize: max�[39;49m
                    �[38;5;244mcrossAxisAlignment: start�[39;49m
                    �[38;5;244mtextDirection: ltr�[39;49m
                    �[38;5;244mverticalDirection: down�[39;49m
                �[38;5;244mchild 2: RenderConstrainedBox#0eebb relayoutBoundary=up5 NEEDS-PAINT�[39;49m
                    �[38;5;244mneeds compositing�[39;49m
                    �[38;5;244mparentData: offset=Offset(0.0, 0.0); id=_ScaffoldSlot.appBar (can use size)�[39;49m
                    �[38;5;244mconstraints: BoxConstraints(w=411.4, 0.0<=h<=830.9)�[39;49m
                    �[38;5;244msize: Size(411.4, 80.0)�[39;49m
                    �[38;5;244madditionalConstraints: BoxConstraints(0.0<=w<=Infinity, 0.0<=h<=80.0)�[39;49m
                �[38;5;244mchild 3: RenderStack#65589 relayoutBoundary=up5 NEEDS-PAINT�[39;49m
                    �[38;5;244mparentData: offset=Offset(395.4, 814.9); id=_ScaffoldSlot.floatingActionButton (can use size)�[39;49m
                    �[38;5;244mconstraints: BoxConstraints(0.0<=w<=411.4, 0.0<=h<=830.9)�[39;49m
                    �[38;5;244msize: Size(0.0, 0.0)�[39;49m
                    �[38;5;244malignment: centerRight�[39;49m
                    �[38;5;244mtextDirection: ltr�[39;49m
                    �[38;5;244mfit: loose�[39;49m
                    �[38;5;244moverflow: clip�[39;49m
�[38;5;248m════════════════════════════════════════════════════════════════════════════════�[39;49m

�[38;5;248m════════ Exception caught by rendering library ═════════════════════════════════�[39;49m
The getter 'dx' was called on null.
Receiver: null
Tried calling: dx
�[38;5;244mThe relevant error-causing widget was�[39;49m
    �[38;5;248mThemeSwitchingArea�[39;49m
�[38;5;248m════════════════════════════════════════════════════════════════════════════════�[39;49m

Error on changing theme in app

Facing this error while changing theme:

[log] Null check operator used on a null value
      #0      ThemeSwitcherCircleClipper.getClip (package:animated_theme_switcher/src/clippers/theme_switcher_circle_clipper.dart:15:25)
      #1      ThemeSwitcherClipperBridge.getClip (package:animated_theme_switcher/src/clippers/theme_switcher_clipper_bridge.dart:14:21)
      #2      _RenderCustomClip._updateClip (package:flutter/src/rendering/proxy_box.dart:1375:25)
      #3      RenderClipPath.paint (package:flutter/src/rendering/proxy_box.dart:1689:7)
      #4      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #5      PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #6      RenderBoxContainerDefaultsMixin.defaultPaint (package:flutter/src/rendering/box.dart:2795:15)
      #7      RenderStack.paintStack (package:flutter/src/rendering/stack.dart:629:5)
      #8      RenderStack.paint (package:flutter/src/rendering/stack.dart:645:7)
      #9      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #10     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #11     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
      #12     _RenderInkFeatures.paint (package:flutter/src/material/material.dart:551:11)
      #13     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #14     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #15     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
      #16     PaintingContext.pushLayer (package:flutter/src/rendering/object.dart:394:12)
      #17     RenderPhysicalModel.paint (package:flutter/src/rendering/proxy_box.dart:1922:15)
      #18     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #19     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #20     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
      #21     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #22     PaintingContext._repaintCompositedChild (package:flutter/src/rendering/object.dart:139:11)
      #23     PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:100:5)
      #24     PipelineOwner.flushPaint (package:flutter/src/rendering/object.dart:975:29)
      #25     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:464:19)
      #26     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:876:13)
      #27     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:328:5)
      #28     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
      #29     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1082:9)
      #30     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:998:5)
      #31     _rootRun (dart:async/zone.dart:1354:13)
      #32     _CustomZone.run (dart:async/zone.dart:1258:19)
      #33     _CustomZone.runGuarded (dart:async/zone.dart:1162:7)
      #34     _invoke (dart:ui/hooks.dart:163:10)
      #35     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:259:5)
      #36     _drawFrame (dart:ui/hooks.dart:126:31)
[log] Null check operator used on a null value
      #0      ThemeSwitcherCircleClipper.getClip (package:animated_theme_switcher/src/clippers/theme_switcher_circle_clipper.dart:15:25)
      #1      ThemeSwitcherClipperBridge.getClip (package:animated_theme_switcher/src/clippers/theme_switcher_clipper_bridge.dart:14:21)
      #2      _RenderCustomClip._updateClip (package:flutter/src/rendering/proxy_box.dart:1375:25)
      #3      RenderClipPath.paint (package:flutter/src/rendering/proxy_box.dart:1689:7)
      #4      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #5      PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #6      RenderBoxContainerDefaultsMixin.defaultPaint (package:flutter/src/rendering/box.dart:2795:15)
      #7      RenderStack.paintStack (package:flutter/src/rendering/stack.dart:629:5)
      #8      RenderStack.paint (package:flutter/src/rendering/stack.dart:645:7)
      #9      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #10     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #11     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
      #12     _RenderInkFeatures.paint (package:flutter/src/material/material.dart:551:11)
      #13     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #14     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #15     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
      #16     PaintingContext.pushLayer (package:flutter/src/rendering/object.dart:394:12)
      #17     RenderPhysicalModel.paint (package:flutter/src/rendering/proxy_box.dart:1922:15)
      #18     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #19     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #20     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
      #21     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #22     PaintingContext._repaintCompositedChild (package:flutter/src/rendering/object.dart:139:11)
      #23     PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:100:5)
      #24     PipelineOwner.flushPaint (package:flutter/src/rendering/object.dart:975:29)
      #25     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:464:19)
      #26     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:876:13)
      #27     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:328:5)
      #28     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
      #29     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1082:9)
      #30     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:998:5)
      #31     _rootRun (dart:async/zone.dart:1354:13)
      #32     _CustomZone.run (dart:async/zone.dart:1258:19)
      #33     _CustomZone.runGuarded (dart:async/zone.dart:1162:7)
      #34     _invoke (dart:ui/hooks.dart:163:10)
      #35     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:259:5)
      #36     _drawFrame (dart:ui/hooks.dart:126:31)
[log] Null check operator used on a null value
      #0      ThemeSwitcherCircleClipper.getClip (package:animated_theme_switcher/src/clippers/theme_switcher_circle_clipper.dart:15:25)
      #1      ThemeSwitcherClipperBridge.getClip (package:animated_theme_switcher/src/clippers/theme_switcher_clipper_bridge.dart:14:21)
      #2      _RenderCustomClip._updateClip (package:flutter/src/rendering/proxy_box.dart:1375:25)
      #3      RenderClipPath.paint (package:flutter/src/rendering/proxy_box.dart:1689:7)
      #4      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #5      PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #6      RenderBoxContainerDefaultsMixin.defaultPaint (package:flutter/src/rendering/box.dart:2795:15)
      #7      RenderStack.paintStack (package:flutter/src/rendering/stack.dart:629:5)
      #8      RenderStack.paint (package:flutter/src/rendering/stack.dart:645:7)
      #9      RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #10     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #11     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
      #12     _RenderInkFeatures.paint (package:flutter/src/material/material.dart:551:11)
      #13     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #14     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #15     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
      #16     PaintingContext.pushLayer (package:flutter/src/rendering/object.dart:394:12)
      #17     RenderPhysicalModel.paint (package:flutter/src/rendering/proxy_box.dart:1922:15)
      #18     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #19     PaintingContext.paintChild (package:flutter/src/rendering/object.dart:187:13)
      #20     RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:140:15)
      #21     RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2317:7)
      #22     PaintingContext._repaintCompositedChild (package:flutter/src/rendering/object.dart:139:11)
      #23     PaintingContext.repaintCompositedChild (package:flutter/src/rendering/object.dart:100:5)
      #24     PipelineOwner.flushPaint (package:flutter/src/rendering/object.dart:975:29)
      #25     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:464:19)
      #26     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:876:13)
      #27     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:328:5)
      #28     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1144:15)
      #29     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1082:9)
      #30     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:998:5)
      #31     _rootRun (dart:async/zone.dart:1354:13)
      #32     _CustomZone.run (dart:async/zone.dart:1258:19)
      #33     _CustomZone.runGuarded (dart:async/zone.dart:1162:7)
      #34     _invoke (dart:ui/hooks.dart:163:10)
      #35     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:259:5)
      #36     _drawFrame (dart:ui/hooks.dart:126:31)

Code for this page:

import 'dart:developer';

import 'package:animated_theme_switcher/animated_theme_switcher.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../app/theme_config.dart';
import '../issues/issues.dart';

import 'components/components.dart';

class IssuesPage extends StatefulWidget {
  const IssuesPage({Key? key}) : super(key: key);

  @override
  _IssuesPageState createState() => _IssuesPageState();
}

class _IssuesPageState extends State<IssuesPage> {
  @override
  Widget build(BuildContext context) {
    return ThemeSwitchingArea(
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Issues'),
          leading: _themeSwitcherButton(),
        ),
        body: const IssuesList(),
      ),
    );
  }

  Widget _themeSwitcherButton() {
    return ThemeSwitcher(
      clipper: const ThemeSwitcherCircleClipper(),
      builder: (context) {
        return IconButton(
          icon: const Icon(Icons.dark_mode),
          onPressed: () {
            ThemeSwitcher.of(context)!.changeTheme(
              theme: ThemeProvider.of(context)!.brightness == Brightness.light
                  ? darkTheme
                  : lightTheme,
            );
          },
        );
      },
    );
  }
}

Flutter version: 2.2.3

screenshot image is blurry

when switching theme screen shot is blurry.
set pixelRatio to 2.0 fixing it.
Future<void> _saveScreenshot() async { RenderRepaintBoundary boundary = _previewContainer.currentContext.findRenderObject(); image = await boundary.toImage(pixelRatio: 2.0); }

Getting error when I am using circular_clip_route.

using this custom route https://pub.dev/packages/circular_clip_route causing the exception. I know it's not related to this package but still, I would be thankful to know any workaround if possible?

════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building _BodyBuilder:
RenderBox.size accessed beyond the scope of resize, layout, or permitted parent access. RenderBox can always access its own size, otherwise, the only object that is allowed to read RenderBox.size is its parent, if they have said they will. It you hit this assert trying to access a child's size, pass "parentUsesSize: true" to that child's layout().
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1709 pos 13: 'debugDoingThisResize || debugDoingThisLayout ||
              (RenderObject.debugActiveLayout == parent && _size._canBeUsedByParent)'

My Code

  @override
  Widget build(BuildContext context) {
    final AuthService auth = Provider.of<AuthService>(context);
    return StreamBuilder<Object>(
        stream: DatabaseService(userID: auth.user.uid).getProfileDetails(),
        builder: (context, snapshot) {
          final User snapshotDate = snapshot.data;
          return ThemeSwitchingArea(
            child: Scaffold(
              body: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16.0),
                child: SingleChildScrollView(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      SizedBox(
                        height: 24,
                      ),
                      ProfilePicture(),
                      
                      ThemeSwitcher(
                        builder: (context) => FlatButton(
                          child: Text('Change Theme'),
                          onPressed: () {
                            ThemeSwitcher.of(context).changeTheme(
                              theme: ThemeProvider.of(context).brightness ==
                                      Brightness.light
                                  ? darkTheme
                                  : lightTheme,
                            );
                          },
                        ),
                      ),
                      Divider(
                        thickness: 2.0,
                      ),
                   
                    ],
                  ),
                ),
              ),
            ),
          );
        });
  }

When pushing new route

onPressed: () {
                    Navigator.of(context).push(
                      CircularClipRoute(
                          border: Border.fromBorderSide(BorderSide.none),
                          transitionDuration: const Duration(seconds: 1),
                          builder: (_) => ProfilePage(),
                          expandFrom: _avatarKey.currentContext),
                    );
                  }

InkRipple.splashFactory not working

Hello !

Thank you for the awesome package.

but one little thing is not working for me. On a clean Flutter project I am passing a ThemeData to the initTheme of the ThemeProvider with a splashFactory of type InkRipple.splashFactory. but the ripple effect it is not working/showing on the InkWell, InkRespones and bottomNavigationBar.

Any ideas??

here is a sample code

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    final isPlatformDark =
        WidgetsBinding.instance!.window.platformBrightness == Brightness.dark;
    final initTheme = isPlatformDark ? darkTheme : lightTheme;
    return ThemeProvider(
      initTheme: initTheme,
      builder: (context, lightTheme) {
        return MaterialApp(
          title: 'Flutter Demo',
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
              splashFactory: InkRipple.splashFactory),
          home: const MyHomePage(
              title: 'Flutter Demo Home Page'),
        );
      },
    );
  }
}

code for the lightTheme

ThemeData lightTheme = ThemeData.light();

ThemeData customLightTheme = lightTheme.copyWith(
  splashFactory: InkRipple.splashFactory,
)

code for the darkTheme

ThemeData darkTheme = ThemeData.dark();

ThemeData customDarkTheme = darkTheme.copyWith(
  splashFactory: InkRipple.splashFactory,
)

How to get current theme after switch?

Hi, so onPressed this is my code

ThemeSwitcher.of(context)!.changeTheme(
theme: ThemeProvider.of(context)!.brightness == Brightness.light ? Util.getThemeDark() : Util.getThemeLight(),
);

How to get the current theme? I figured there would be something like a .then() after changeTheme() but none.

So if i call it after the block of code above.

ThemeProvider.of(context)!.brightness.toString() or
WidgetsBinding.instance!.window.platformBrightness.toString()

It does not get the current theme that is being switched to. Thoughts?

Gives an exception | Multiple animations stopped working

1. Giving an exception

I'm unsure why the exception was occurring; I believe it's a framework problem. Please guide me through the solution.

Exception -

The following LateError was thrown building ThemeSwitchingArea(dirty, dependencies: [ThemeModelInheritedNotifier]):
LateInitializationError: Field 'image' has not been initialized.

The relevant error-causing widget was
ThemeSwitchingArea -----                           lib\…\shared\appbar.dart:34
When the exception was thrown, this was the stack
#0      ThemeModel.image (package:animated_theme_switcher/src/theme_provider.dart) ----    package:animated_theme_switcher/src/theme_provider.dart:1
#1      ThemeSwitchingArea.build ----                        package:animated_theme_switcher/src/theme_switching_area.dart:28
#2      StatelessElement.build ----                      package:flutter/…/widgets/framework.dart:4662

Exception Occurred
Exception

Below shown is my lib..\shared\appbar.dart file,

import 'package:animated_theme_switcher/animated_theme_switcher.dart';
import 'package:flutter/material.dart';
import 'package:flutter_vector_icons/flutter_vector_icons.dart';

import '../shared/logo.dart';
import '../../essentials/constants.dart';

class CustomAppBar extends StatefulWidget {
  const CustomAppBar({Key? key, required this.child}) : super(key: key);

  final Widget child;

  @override
  _CustomAppBarState createState() => _CustomAppBarState();
}

final double _height = totsHeight - allPaddings.top - allPaddings.bottom;

class _CustomAppBarState extends State<CustomAppBar> {
  final Duration _duration = Duration(milliseconds: 800);
  bool menu = false;

  @override
  Widget build(BuildContext context) {
    return Container(
      height: totsHeight,
      width: totsWidth,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(30.0),
        color: ThemeModelInheritedNotifier.of(context)
            .theme
            .scaffoldBackgroundColor,
      ),
      child: ThemeSwitchingArea(                                                                         /// # Line <1>
        child: Stack(children: <Widget>[
          // View
          Positioned.fill(
            child: Container(
              height: totsHeight,
              width: totsWidth,
              color: ThemeModelInheritedNotifier.of(context)
                  .theme
                  .scaffoldBackgroundColor,
              child: SingleChildScrollView(
                child: widget.child,
              ),
            ),
          ),

          // Top expandable dialog box
          Positioned(
            top: allPaddings.top,
            left: 0.0,
            right: 0.0,
            child: LimitedBox(
              maxHeight: _height * 0.6,
              child: AnimatedContainer(                                                                 /// # Line <3>
                decoration: BoxDecoration(
                  color: ThemeModelInheritedNotifier.of(context)
                      .theme
                      .scaffoldBackgroundColor,
                  boxShadow: menu
                      ? [
                          BoxShadow(
                            blurRadius: totsHeight,
                            color: Colors.black26,
                            offset: Offset(0, totsHeight * 0.1),
                          ),
                        ]
                      : [],
                  borderRadius: BorderRadius.circular(20.0),
                ),
                duration: _duration,
                width: totsWidth,
                height: menu ? _height * 0.4 : _height * 0.1,
                child: Column(
                  children: <Widget>[
                    Padding(
                      padding: EdgeInsets.only(top: 10.0),
                      child: Row(
                        children: <Widget>[
                          Padding(
                            padding: EdgeInsets.only(left: 20.0),
                            child: AnimatedRotation(                                                /// # Line <4>
                              duration: _duration,
                              turns: !menu ? 0.0 : 0.5,
                              child: IconButton(
                                icon: Icon(Feather.grid),
                                color: ThemeModelInheritedNotifier.of(context)
                                    .theme
                                    .textTheme
                                    .bodyText1!
                                    .color,
                                onPressed: () => setState(() => menu = !menu),
                                tooltip: "Menu",
                              ),
                            ),
                          ),
                          Expanded(
                            child: AnimatedSwitcher(                                               /// # Line <5>
                              child: menu
                                  ? Opacity(
                                      opacity: 0.0,
                                      child: Padding(
                                        padding: EdgeInsets.only(
                                            top: 10.0, left: 10.0),
                                        child: Logo(),
                                      ),
                                    )
                                  : Padding(
                                      padding: EdgeInsets.only(
                                          top: 10.0, left: 10.0),
                                      child: Logo(),
                                    ),
                              duration: _duration,
                            ),
                          ),
                          ThemeSwitcher(                                                                 /// # Line <2>
                              clipper: const ThemeSwitcherCircleClipper(),
                              builder: (context) => GestureDetector(
                                    onTap: () => setState(() {
                                      ThemeSwitcher.of(context).changeTheme(
                                        theme: ThemeModelInheritedNotifier.of(
                                                        context)
                                                    .theme ==
                                                socialTheme
                                            ? professionalTheme
                                            : socialTheme,
                                      );
                                      provider.mode = !provider.mode;
                                    }),
                                    child: Tooltip(
                                      message: provider.mode
                                          ? "Social Switch"
                                          : "Professional Switch",
                                      child: Container(
                                        margin: EdgeInsets.only(
                                          right: 25.0,
                                        ),
                                        height: 50.0,
                                        width: 50.0,
                                        decoration: BoxDecoration(
                                          shape: BoxShape.circle,
                                          color: provider.mode
                                              ? socialTheme
                                                  .scaffoldBackgroundColor
                                              : professionalTheme
                                                  .scaffoldBackgroundColor,
                                        ),
                                        child: Icon(
                                          provider.mode
                                              ? Feather.users
                                              : Feather.briefcase,
                                          color: provider.mode
                                              ? socialTheme
                                                  .textTheme.bodyText1!.color
                                              : professionalTheme
                                                  .textTheme.bodyText1!.color,
                                          size: 25.0,
                                        ),
                                      ),
                                    ),
                                  )),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
          // Bottom Dock Floating Action Buttons
          Positioned(
            bottom: allPaddings.bottom + 30.0,
            right: 25.0,
            child: Container(
              height: 80.0,
              width: 130.0,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: <Widget>[
                  _fab(icon: Feather.plus, label: "Add Post"),
                  SizedBox(width: 15.0),
                  _fab(icon: Feather.menu, label: "Feeds Categories"),
                ],
              ),
            ),
          ),
        ]),
      ),
    );
  }

  Widget _fab({required IconData icon, required String label}) =>
      GestureDetector(
        onTap: () {},
        child: Tooltip(
          message: label,
          child: AnimatedContainer(
            duration: _duration,
            height: 50.0,
            width: 50.0,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: ThemeModelInheritedNotifier.of(context)
                  .theme
                  .floatingActionButtonTheme
                  .backgroundColor,
            ),
            child: Icon(
              icon,
              color: ThemeModelInheritedNotifier.of(context)
                  .theme
                  .floatingActionButtonTheme
                  .foregroundColor,
              size: 20.0,
            ),
          ),
        ),
      );
}

I've implemented ThemeSwitchingArea() in Line <1> and ThemeSwitcher() in Line <2> .

2. Multiple Animations stopped working

In the above "appbar.dart", I've referenced the lines for Other Animations I embedded to the screen which stopped working after implementation of the animated_theme_switcher button. I'm unsure whether the animations stopped working due to the exception occurring on the runtime or just incompatible with the package when used. The lines referenced and their actions -
Line <3> - The dialog box should expand in that duration
Line <4> - The icon button should rotate on press when the dialog box is expanding and closing
Line <5> - The logo should fade slowly in the background when the dialog box is expanding and closing

App.Output.mp4

RangeSlider Widget Doesn't work

When RangeSlider is used under ThemeSwitchingArea It Doesn't Work or is very very laggy and updates range after 3 or 4seconds

why do we need saveScreenShot?

In ThemeProvider Class, I wonder why do we need this method?

Future<void> _saveScreenshot() async {
    final boundary = _previewContainer.currentContext!.findRenderObject()
        as RenderRepaintBoundary;
    image = await boundary.toImage(pixelRatio: ui.window.devicePixelRatio);
  }

await _saveScreenshot();

Fails Null Safety on Flutter mobile 2.2.1

Thanks for creating the plugin. The reason why I use a plugin to switch themes is that have issues converting my own theme switcher due to Null Safety issues.

Example as shown on pub.dev does not work as Null Safety fails. It fails at so many places that I have not included each detail, some examples on:

value
brightness
changeTheme

Screenshot 2021-05-30 at 08 35 35

Screenshot 2021-05-30 at 08 35 21

The circle animation doesn`t work. Theme just changing without circle

ThemeProvider(
initTheme: dark,
builder: (context, myTheme) {
return MaterialApp(
title: 'Flutter Demo',
theme: myTheme,
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
},
);

ThemeSwitcher(
clipper: ThemeSwitcherCircleClipper(),
builder: (context) {
return GestureDetector(
onTap: () {
ThemeSwitcher.of(context)!.changeTheme(
theme: Theme.of(context).brightness == Brightness.light
? dark
: light,
reverseAnimation:
Theme.of(context).brightness == Brightness.dark
? true
: false,
);
},
child: Container(
width: 50,
height: 50,
color: Theme.of(context).cardColor,
),
);
},
)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.