Getx: Changing Get Theme when building

Created on 18 May 2020  路  6Comments  路  Source: jonataslaw/getx

I have a PreferencesController which loads a boolean from storage that says if the user has the in app darkmode enabled or not. When I build my Preferences Controller I would like to switch the theme based on the loaded value

        body: GetBuilder<PreferencesController>(
          init: PreferencesController(),
          builder: (preferencesController) {
            if (preferencesController.state != LoadingState.loaded) return PlatformCircularProgressIndicator();

            Get.changeThemeMode(preferencesController.isDarkMode ? ThemeMode.dark : ThemeMode.light); // tried this
            Get.changeTheme(preferencesController.isDarkMode ? DarkTheme.themeData : LightTheme.themeData); //  and tried this

But the following error is thrown

This GetBuilder<GetMaterialController> widget cannot be marked as needing to build because the

Most helpful comment

This should help with what you're trying to do in a different way:
https://medium.com/@rod.brown.au/flutter-dynamic-themes-in-3-lines-c3b375f292e3
I'm re-writing it now, but it gives you the gists for dynamic themes from shared_preferences and change them on the fly.

All 6 comments

Is it possible to do this in a hacky way for now? Or is it not possible at all at the moment?

This is a hack:

 builder: (preferencesController) {

SchedulerBinding.instance.addPostFrameCallback((_) => Get.changeTheme(preferencesController.isDarkMode ? DarkTheme.themeData : LightTheme.themeData));

But particularly, I would use the controller's onInit method to initialize preferences, and once loaded, I would use Get.changeTheme within the controller.

I don't like to see code inside builders methods.
I'm even thinking of creating a custom StreamBuilder and FutureBuilder, with callbacks for errors and loading, to avoid inserting business logic into them (ok, I'm a bit annoying with that)

This should help with what you're trying to do in a different way:
https://medium.com/@rod.brown.au/flutter-dynamic-themes-in-3-lines-c3b375f292e3
I'm re-writing it now, but it gives you the gists for dynamic themes from shared_preferences and change them on the fly.

This should help with what you're trying to do in a different way:
https://medium.com/@rod.brown.au/flutter-dynamic-themes-in-3-lines-c3b375f292e3
I'm re-writing it now, but it gives you the gists for dynamic themes from shared_preferences and change them on the fly.

I really liked the tutorial, I will add it to the Readme of Get if you allow it.

Of course!

This is a hack:

 builder: (preferencesController) {

SchedulerBinding.instance.addPostFrameCallback((_) => Get.changeTheme(preferencesController.isDarkMode ? DarkTheme.themeData : LightTheme.themeData));

But particularly, I would use the controller's onInit method to initialize preferences, and once loaded, I would use Get.changeTheme within the controller.

I don't like to see code inside builders methods.
I'm even thinking of creating a custom StreamBuilder and FutureBuilder, with callbacks for errors and loading, to avoid inserting business logic into them (ok, I'm a bit annoying with that)

I was already using these controllers

class GetStreamController<T> extends GetController {
  final Stream<T> Function() value;
  StreamController<T> _streamController = BehaviorSubject();
  StreamSubscription _streamSubscription;
  Stream<T> get stream => _streamController.stream;

  GetStreamController(this.value);

  @override
  void onInit()
  {
    super.onInit();
    _streamSubscription = value().listen((event) {
      _streamController.add(event);
    });
  }

  @override
  void onClose()
  {
    super.onClose();
    _streamSubscription.cancel();
    _streamController.close();
  }
}

and

class GetFutureController<T> extends GetController {
  Future<T> Function() _builder;
  AsyncSnapshot<T> _snapshot = AsyncSnapshot.nothing();

  AsyncSnapshot<T> get snapshot => _snapshot;

  GetFutureController(this._builder);

  @override
  void onInit()
  {
    super.onInit();
    _buildFuture();
  }

  Future<void> _buildFuture() async {
    _snapshot = AsyncSnapshot.withData(ConnectionState.waiting, null);
    update(this);
    try {
      var data = await _builder();
      _snapshot = AsyncSnapshot.withData(ConnectionState.done, data);
      update(this);
    } catch (error) {
      _snapshot = AsyncSnapshot.withError(ConnectionState.done, error);
      update(this);
    }
  }
}

Which are working quite well. But yeah the stream controller should be more of a stream builder I agree, would make the widget tree alot less messy.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

williamsilva-98 picture williamsilva-98  路  4Comments

omartinma picture omartinma  路  3Comments

GoldenSoju picture GoldenSoju  路  3Comments

R-Praveen picture R-Praveen  路  4Comments

definev picture definev  路  3Comments