Rutvik Gumasana
Rutvik Gumasana

Reputation: 1630

How to store theme in shared preferences in flutter

Here I've one screen where I've some button when I press the button it will change the color of application but it will reset when I restart the app. I want that it will not reset until I am changing the color from the App. so for that, I want to store THemedata in shared preferences and I want to get theme data from shared preferences so whenever I restart the app it needs to take the theme from Shared preferences.

Here is some code I've tried,

ThemeBloc.dart

class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
  @override
  ThemeState get initialState =>
      ThemeState(themeData: appThemeData[AppTheme.GreenLight]);

  @override
  Stream<ThemeState> mapEventToState(
    ThemeEvent event,
  ) async* {
    if (event is ThemeChanged) {
      yield ThemeState(themeData: appThemeData[event.theme]);
    }
  }
}

ThemeEvent.dart

abstract class ThemeEvent extends Equatable {
  ThemeEvent([List props = const <dynamic>[]]) : super(props);
}

class ThemeChanged extends ThemeEvent {
  final AppTheme theme;

  ThemeChanged({
    this.theme,
  }) : super([theme]);
}

ThemeState.dart

@immutable
class ThemeState extends Equatable {
  final ThemeData themeData;

  ThemeState({
    @required this.themeData,
  }) : super([themeData]);
}

AppTheme.dart

enum AppTheme {
  GreenLight,
  GreenDark,
  BlueLight,
  BlueGrey,
  Amber,
}

final appThemeData = {
  AppTheme.GreenLight: ThemeData(
    brightness: Brightness.light,
    primaryColor: Colors.teal,
  ),
  AppTheme.GreenDark: ThemeData(
    brightness: Brightness.light,
    primaryColor: Colors.orange,
  ),
};

Upvotes: 1

Views: 4720

Answers (3)

md-siam
md-siam

Reputation: 225

Use ThemeProvider for providing themes data. There is an example. For detailed information, you can run this app from this GitHub

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

ThemeData light_mode = ThemeData(
  brightness: Brightness.light,
);

ThemeData dark_mode = ThemeData(
  brightness: Brightness.dark,
);

class ThemeNotifier extends ChangeNotifier {
  final String key = "theme";
  SharedPreferences? _preferences;
  bool? _darkMode;

  bool? get darkMode => _darkMode;

  ThemeNotifier() {
    _darkMode = false;
    _loadFromPreferences();
  }

  _initialPreferences() async {
    _preferences ??= await SharedPreferences.getInstance();
  }

  _savePreferences() async {
    await _initialPreferences();
    _preferences!.setBool(key, _darkMode!);
  }

  _loadFromPreferences() async {
    await _initialPreferences();
    _darkMode = _preferences!.getBool(key) ?? true;
    notifyListeners();
  }

  toggleChangeTheme(bool isOn) {
    darkMode==isOn ? _darkMode! : _darkMode = !_darkMode!;
    _savePreferences();
    notifyListeners();
  }
}

Upvotes: 1

Mohammad Gayashuddin
Mohammad Gayashuddin

Reputation: 21

// Your AppTheme.dart
enum AppTheme {
  GreenLight,
  GreenDark,
  BlueLight,
  BlueGrey,
  Amber,
}

final appThemeData = {
  AppTheme.GreenLight: ThemeData(
    brightness: Brightness.light,
    primaryColor: Colors.teal,
  ),
  AppTheme.GreenDark: ThemeData(
    brightness: Brightness.light,
    primaryColor: Colors.orange,
  ),
};

Let's begun

SharedPreferences

// shared_prefs.dart
class SharedPrefs {
  static late SharedPreferences _sharedPrefs;

  factory SharedPrefs() => SharedPrefs._internal();

  SharedPrefs._internal();

  Future<void> init() async {
    _sharedPrefs = await SharedPreferences.getInstance();
  }

  int? get getThemeIndex => _sharedPrefs.getInt(selectedThemeIndex);

  set setThemeIndex(int? value) {
    _sharedPrefs.setInt(selectedThemeIndex, value!);  // Using selectedThemeIndex from constant
  }
}

// constants.dart
const String selectedThemeIndex = "selected_theme_index";

main.dart file

// main.dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SharedPrefs().init();   // Call sharedpreference class here
  return runApp(MyApp());
}

theme_bloc.dart file

//theme_bloc.dart
class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
  ThemeBloc() : super(ThemeState(themeData: appThemeData[AppTheme.values[SharedPrefs().getThemeIndex ?? 0]]!));

  @override
  Stream<ThemeState> mapEventToState(
    ThemeEvent event,
  ) async* {
    if (event is ThemeChanged) {
      // I am storing theme index
      SharedPrefs().setThemeIndex = event.theme.index;  // Trigger when you change the theme
      yield ThemeState(themeData: appThemeData[event.theme]!);
    }
  }
}

Upvotes: 0

Slah Layouni
Slah Layouni

Reputation: 740

You can simply save/retrieve a theme id that can be used to identify wich theme is selected when starting the app, something like

class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {

  // at this point you should be already have a mainSharedPreferences already initialized, could be in SplashScreen
  // to prevent async calls in the initialState

  @override
  ThemeState get initialState => ThemeState(
      themeData: appThemeData[
          MyApp.mainSharedPreferences.getInt("selectedThemeIndex") ??
              AppTheme.GreenLight]);

  @override
  Stream<ThemeState> mapEventToState(
    ThemeEvent event,
  ) async* {
    if (event is ThemeChanged) {
      await _persistTheme(event.theme);
      yield ThemeState(themeData: appThemeData[event.theme]);
    }
  }

  _persistTheme(AppTheme theme) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setInt("selectedThemeIndex", theme.index);
    // or you could save the theme.toString()
    // prefs.setString("selectedTheme", theme.toString());
  }
}

How to prepare SharedPreferences to avoid the Future<SharedPreferences>

class MyApp extends StatefulWidget {
  static SharedPreferences mainSharedPreferences;

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



class _MyAppState extends State<MyApp> {

_loadApp() async {
    MyApp.mainSharedPreferences = await SharedPreferences.getInstance();
    // you can load here any other data or external data that your app might need
  }

  @override
  void initState() { 
    super.initState();
    _loadApp();
  }

@override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      localizationsDelegates: [
      // ...

Then you can use it anywhere from your app like so

// to save value
MyApp.mainSharedPreferences.setInt("selectedThemeIndex", value);

// to get the saved value
MyApp.mainSharedPreferences.getInt("selectedThemeIndex");

Upvotes: 3

Related Questions