Flutter Themedata Refrector - flutter

How can write readable and clean code flutter ThemeData for light mode and dark mode.
I already wrote but that is not readable how should i write for themedata for lightmode and darkmode readable, maintain and clearly?

You can easily store your theme preference in form of a string and then at the start of your app check if there is value stored on file system, if so apply that theme as shown below.
StorageManager.dart
import 'package:shared_preferences/shared_preferences.dart';
class StorageManager {
static void saveData(String key, dynamic value) async {
final prefs = await SharedPreferences.getInstance();
if (value is int) {
prefs.setInt(key, value);
} else if (value is String) {
prefs.setString(key, value);
} else if (value is bool) {
prefs.setBool(key, value);
} else {
print("Invalid Type");
}
}
static Future<dynamic> readData(String key) async {
final prefs = await SharedPreferences.getInstance();
dynamic obj = prefs.get(key);
return obj;
}
static Future<bool> deleteData(String key) async {
final prefs = await SharedPreferences.getInstance();
return prefs.remove(key);
}
}
Define your theme properties in a theme variable like below and initialize your _themedata variable on the basis of value inside storage.
ThemeManager.dart
import 'package:flutter/material.dart';
import '../services/storage_manager.dart';
class ThemeNotifier with ChangeNotifier {
final darkTheme = ThemeData(
primarySwatch: Colors.grey,
primaryColor: Colors.black,
brightness: Brightness.dark,
backgroundColor: const Color(0xFF212121),
accentColor: Colors.white,
accentIconTheme: IconThemeData(color: Colors.black),
dividerColor: Colors.black12,
);
final lightTheme = ThemeData(
primarySwatch: Colors.grey,
primaryColor: Colors.white,
brightness: Brightness.light,
backgroundColor: const Color(0xFFE5E5E5),
accentColor: Colors.black,
accentIconTheme: IconThemeData(color: Colors.white),
dividerColor: Colors.white54,
);
ThemeData _themeData;
ThemeData getTheme() => _themeData;
ThemeNotifier() {
StorageManager.readData('themeMode').then((value) {
print('value read from storage: ' + value.toString());
var themeMode = value ?? 'light';
if (themeMode == 'light') {
_themeData = lightTheme;
} else {
print('setting dark theme');
_themeData = darkTheme;
}
notifyListeners();
});
}
void setDarkMode() async {
_themeData = darkTheme;
StorageManager.saveData('themeMode', 'dark');
notifyListeners();
}
void setLightMode() async {
_themeData = lightTheme;
StorageManager.saveData('themeMode', 'light');
notifyListeners();
}
}
Wrap your app with themeProvider and then apply theme using consumer. By doing so whenever you change the value of theme and call notify listeners widgets rebuild to sync changes.
Main.dart
void main() {
return runApp(ChangeNotifierProvider<ThemeNotifier>(
create: (_) => new ThemeNotifier(),
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<ThemeNotifier>(
builder: (context, theme, _) => MaterialApp(
theme: theme.getTheme(),
home: Scaffold(
appBar: AppBar(
title: Text('Hybrid Theme'),
),
body: Row(
children: [
Container(
child: FlatButton(
onPressed: () => {
print('Set Light Theme'),
theme.setLightMode(),
},
child: Text('Set Light Theme'),
),
),
Container(
child: FlatButton(
onPressed: () => {
print('Set Dark theme'),
theme.setDarkMode(),
},
child: Text('Set Dark theme'),
),
),
],
),
),
),
);
}
}
Here is the link to github repository.

Related

How to use SharedPreferences on switch with changing the theme flutter

I've implemented the theme for the app theme_managers.dart and I've done SharedPreferences on the theme.dart. But the problem is the SharedPreferences on the switch it's working when. I reopen the app it still getting data from last action but the theme(dark mode) get reset all the time when reopen the app.
I don’t understand if I need to put the SharedPreferences on the theme_manager.dart or not. If you know Please point out the problem or some code. Thanks
Please look though my code and you’ll understand the problem.
In theme.dart(some) :
bool colorMode = false;
#override
void initState() {
super.initState();
getSwitchValues();
}
getSwitchValues() async {
colorMode = await loadbool();
setState(() {});
}
Future<bool> savebool(bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
themeManager.toggleTheme(value);
prefs.setBool("colorMode", value);
return prefs.setBool("colorMode", value);
}
Future<bool> loadbool() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool? colorMode = prefs.getBool("colorMode");
return colorMode!;
}
//Switch
Switch(
activeColor: Colors.grey,
value: colorMode,
onChanged: (bool value) {
setState(() {
themeManager.toggleTheme(value);
colorMode = value;
savebool(value);
});
}),
In theme_manager.dart :
class ThemeManager extends ChangeNotifier {
ThemeMode _themeMode = ThemeMode.light;
get themeMode => _themeMode;
toggleTheme(bool isDark){
_themeMode = isDark? ThemeMode.dark :ThemeMode.light;
notifyListeners();
}
}
In main.dart(some) :
ThemeManager themeManager = ThemeManager();
#override
void initState() {
themeManager.addListener(themeListener);
super.initState();
}
#override
void dispose() {
themeManager.removeListener(themeListener);
super.dispose();
}
themeListener() {
if (mounted) {
setState(() {});
}
}
MultiProvider(
Provider(create: (_) => User),
ChangeNotifierProvider(create: (context) => themeManager)
],
child: MaterialApp(
title: 'My app',
themeMode: themeManager.themeMode,
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
home: const LoginScreen(),
debugShowCheckedModeBanner: false,
),
);
I forgot to mention my theme_constant.dart :
const colorPrimary = Colors.black;
const colorAccent = Colors.black;
ThemeData lightTheme = ThemeData(
brightness: Brightness.light,
primaryColor: colorPrimary,
floatingActionButtonTheme:
const FloatingActionButtonThemeData(backgroundColor: colorAccent),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ButtonStyle(
padding: MaterialStateProperty.all<EdgeInsetsGeometry>(
const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20.0)),
shape: MaterialStateProperty.all<OutlinedBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0))),
backgroundColor: MaterialStateProperty.all<Color>(colorAccent))),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: BorderSide.none),
filled: true,
fillColor: Colors.grey.withOpacity(0.1)));
ThemeData darkTheme = ThemeData(
brightness: Brightness.dark,
switchTheme: SwitchThemeData(
trackColor: MaterialStateProperty.all<Color>(Colors.black),
thumbColor: MaterialStateProperty.all<Color>(Colors.black),
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(0.0),
borderSide: BorderSide.none),
filled: true,
fillColor: Colors.black.withOpacity(0.0)),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ButtonStyle(
padding: MaterialStateProperty.all<EdgeInsetsGeometry>(
const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20.0)),
shape: MaterialStateProperty.all<OutlinedBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0))),
backgroundColor: MaterialStateProperty.all<Color>(Colors.white),
foregroundColor: MaterialStateProperty.all<Color>(Colors.black),
overlayColor: MaterialStateProperty.all<Color>(Colors.black))),
);
I am not sure If the problem is from here too?
Try to load the ThemeMode before calling runApp() in your main method, e. g. by adding this to your main method:
void main() async {
ThemeManager themeManager = ThemeManager();
await themeManager.loadTheme(); // load the theme before running the app
runApp(
MultiProvider(
providers: [
Provider(create: (_) => User),
ChangeNotifierProvider(create: (context) => themeManager),
],
child: MaterialApp(
title: 'My app',
themeMode: themeManager.themeMode, // now the theme mode is the one loaded from shared prefs
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
home: const LoginScreen(),
debugShowCheckedModeBanner: false,
),
),
);
}
And for this to work, add the loadTheme() method to your ThemeManager class:
class ThemeManager extends ChangeNotifier {
ThemeMode _themeMode = ThemeMode.light;
get themeMode => _themeMode;
toggleTheme(bool isDark){
_themeMode = isDark? ThemeMode.dark :ThemeMode.light;
notifyListeners();
}
Future<void> loadTheme() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isDark = prefs.getBool("colorMode") ?? false;
_themeMode = isDark ? ThemeMode.dark : ThemeMode.light;
}
}
Material directly using themeManager.themeMode which returns the ThemeMode.light
themeMode: themeManager.themeMode,
You might create a method, and make sure to get data from this future before providing on materialApp
class ThemeManager extends ChangeNotifier {
ThemeMode _themeMode = ThemeMode.light;
ThemeMode get themeMode => _themeMode;
Future<void> initTheme() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
bool? colorMode = prefs.getBool("colorMode");
// switch if needed
_themeMode = colorMode == true ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}

How to load multiple future in flutter

I'm creating a flutter application that needs to load email and theme from preferences settings. Loading email will check whether the user is authenticated while loading the theme will check whether the theme is light or dark mode. The problem I'm facing is that dark or light mode is getting applied after the interface has been created. I know that using the future builder can help solve this but I have no idea on how to use it in theme.dart file. Any help please.
theme.dart file
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
CustomTheme customTheme = CustomTheme();
class CustomTheme extends ChangeNotifier {
static bool isDarkTheme = false;
ThemeData get currentTheme => isDarkTheme
? ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: Colors.grey.shade900,
primaryColor: Colors.white,
accentColor: Colors.blue,
iconTheme: const IconThemeData(color: Colors.white, opacity: 0.8),
)
: ThemeData(
brightness: Brightness.light,
scaffoldBackgroundColor: Colors.white,
primaryColor: Colors.black,
accentColor: Colors.blue,
iconTheme: const IconThemeData(color: Colors.black, opacity: 0.8),
dividerColor: Colors.black12,
);
CustomTheme() {
loadPrefs();
}
void toggleTheme() {
isDarkTheme = !isDarkTheme;
savePrefs();
notifyListeners();
}
void savePrefs() async {
SharedPreferences _prefs = await SharedPreferences.getInstance();
_prefs.setBool('theme', isDarkTheme);
}
void loadPrefs() async {
SharedPreferences _prefs = await SharedPreferences.getInstance();
isDarkTheme = _prefs.getBool('theme') ?? false;
notifyListeners();
}
}
main.dart file
import 'package:chatapp/home.dart';
import 'package:chatapp/login.dart';
import 'package:chatapp/themes.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:shared_preferences/shared_preferences.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
Future<String> getSharedPrefs() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String _email = prefs.getString('email') ?? '';
return _email;
}
#override
void initState() {
super.initState();
customTheme.addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: customTheme.currentTheme,
home: FutureBuilder<String>(
future: getSharedPrefs(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
} else if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return const Text('Error');
} else if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return Home();
} else {
return Login();
}
} else {
return Text('State: ${snapshot.connectionState}');
}
},
),
);
}
}
Try below code hope its helpful to you.used Future.wait([]) method for that refer here
FutureBuilder(
future: Future.wait([
getSharedPrefs(),
// call your extra future method here
]),
builder:
),

How to change theme in Flutter?

So I'm trying here to get the current theme, if it's light or dark.
So I can change widget color accordingly..
However, it doesn't work, I used if statment to know when it's dark mode..
but it's always False ..
This is the code.. btw it switch between dark & light theme..
but when i try to get current theme.. even if the theme changed to dark..
the if statments always show false...
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
bool darkModeOn = MediaQuery.of(context).platformBrightness == Brightness.dark;
Color containerColor;
if (darkModeOn == true) {
containerColor = Colors.blueGrey;
print("----------------");
print("dark mode ON");
print("----------------");
} else {
containerColor = Colors.deepPurple;
print("LIGHT mode ON");
}
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
//----switch theme---
currentTheme.switchTheme();
},
label: Text(
"Switch theme",
style: TextStyle(
),
),
icon: Icon(Icons.color_lens_outlined),
),
appBar: AppBar(
title: Text("DarkXLight"),
),
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(child: Container(
color: containerColor,
),
),
Expanded(child: Container(
color: Colors.amber,
),
),
],
),
),
);
}
}
You can't switch themes like that. You will need to handle the logic in the MaterialApp otherwise
MediaQuery.of(context).platformBrightness == Brightness.dark;
will always return true/false based on what was provided to the MaterialApp.themeMode.
Here's a sample code to get started. I used ValueListenableBuilder but you can also use provider.
Full code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final ValueNotifier<ThemeMode> _notifier = ValueNotifier(ThemeMode.light);
#override
Widget build(BuildContext context) {
return ValueListenableBuilder<ThemeMode>(
valueListenable: _notifier,
builder: (_, mode, __) {
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: mode, // Decides which theme to show, light or dark.
home: Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () => _notifier.value = mode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light,
child: Text('Toggle Theme'),
),
),
),
);
},
);
}
}
So, I was able to solve my problem..
I will put the code so if someone faced the same issue..
I simply, changed the way I used to switch themes. It was wrong..
However, here I'm posting the Correct way & this way solved the problem..
MAIN PAGE
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:practice_darkmode/theme_provider.dart';
import 'package:provider/provider.dart';
import 'MyHomePage.dart';
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => ThemeProvider(),
builder: (context, _) {
final themeProvider = Provider.of<ThemeProvider>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: MyThemes.lightTheme,
darkTheme: MyThemes.darkTheme,
themeMode: themeProvider.themeMode,
home: MyHomePage(),
);
},
);
}
}
Theme Provider class
import 'package:flutter/material.dart';
//---This to switch theme from Switch button----
class ThemeProvider extends ChangeNotifier {
//-----Store the theme of our app--
ThemeMode themeMode = ThemeMode.dark;
//----If theme mode is equal to dark then we return True----
//-----isDarkMode--is the field we will use in our switch---
bool get isDarkMode => themeMode == ThemeMode.dark;
//---implement ToggleTheme function----
void toggleTheme(bool isOn) {
themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
//---notify material app to update UI----
notifyListeners();
}
}
//---------------Themes settings here-----------
class MyThemes {
//-------------DARK THEME SETTINGS----
static final darkTheme = ThemeData(
scaffoldBackgroundColor: Colors.black45,
// colorScheme: ColorScheme.dark(),
);
//-------------light THEME SETTINGS----
static final lightTheme = ThemeData(
scaffoldBackgroundColor: Colors.white,
//colorScheme: ColorScheme.light(),
);
}
Change Theme button widget class ( this is to create a switch button)
import 'package:flutter/material.dart';
import 'package:practice_darkmode/theme_provider.dart';
import 'package:provider/provider.dart';
class ChangeThemeButtonWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
//----First we want to get the theme provider----
final themeProvider = Provider.of<ThemeProvider>(context);
return Switch.adaptive(
//---isDarkMode to return if its dark or not--true or false--
value: themeProvider.isDarkMode,
onChanged: (value) {
final provider = Provider.of<ThemeProvider>(context, listen: false);
provider.toggleTheme(value);
},
activeColor: themeProvider.isDarkMode ? Colors.purple : Colors.green,
);
}
}
Home Page
import 'package:flutter/material.dart';
import 'package:practice_darkmode/theme_provider.dart';
import 'package:provider/provider.dart';
import 'ChangeThemeButtonWidget.dart';
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
dynamic text;
dynamic textColor;
dynamic appBarColor;
dynamic btnColor;
dynamic appBarTextColor;
if (Provider.of<ThemeProvider>(context).themeMode == ThemeMode.dark) {
text = "IT'S DARK ";
textColor = Colors.cyanAccent;
appBarColor = Colors.black;
btnColor = Colors.deepPurple;
appBarTextColor = Colors.cyanAccent;
} else if (Provider.of<ThemeProvider>(context).themeMode == ThemeMode.light) {
text = "IT'S LIGHT ";
textColor = Colors.red;
appBarColor = Colors.red;
btnColor = Colors.red;
appBarTextColor = Colors.white;
}
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
},
label: Text(
"Switch theme",
style: TextStyle(
),
),
icon: Icon(Icons.color_lens_outlined),
backgroundColor: btnColor,
),
appBar: AppBar(
title: Text("DarkXLight", style: TextStyle(color: appBarTextColor),),
backgroundColor: appBarColor,
actions: [
ChangeThemeButtonWidget(),
],
),
body: Container(
child: Center(
child: Text(
"$text!",
style: (
TextStyle(
fontSize: 27,
color: textColor,
)
),
),
),
),
);
}
}
Below code will to change theme via Icon Button in appBar. Steps:
Create a stateful widget.
Add the following variables:
bool _iconBool = false;
IconData _iconLight = Icons.wb_sunny;
IconData _iconDark = Icons.nights_stay;
Create actions -> IconButton in the appBar as below:
appBar: AppBar(
title: Text("Simple Colregs"),
backgroundColor: Color(0xFF5B4B49).withOpacity(0.8),
actions: [
IconButton(icon: Icon(_iconBool ? _iconDark : _iconLight),
},)
],
), //AppBar
Add Below methods with Light and Dark themes and any custom preference is required:
// light Theme
ThemeData lightThemeData(BuildContext context) {
return ThemeData.light().copyWith(
primaryColor: Color(0xFF5B4B49),
colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Color(0xFF24A751)));
}
// dark Theme
ThemeData darkThemeData(BuildContext context) {
return ThemeData.dark().copyWith(
primaryColor: Color(0xFFFF1D00),
colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Color(0xFF24A751)));
}
Read more about ThemeData Class here.
Under IconButton, create a functionality for the button as below which will toggle the theme:
onPressed: () {
setState(() {
_iconBool = !_iconBool;
});
Finally add under Material App:
theme: _iconBool ? lightThemeData(context) : darkThemeData(context),
That's all, good to go. Hope it helps.
you can use it in initState
bool darkModeOn = brightness == Brightness.dark;
or
var brightness = MediaQuery.of(context).platformBrightness;
bool darkModeOn = brightness == Brightness.dark;

stream value does not changed after update event.. (Flutter,bloc)

I'm really new to flutter and now I'm studying bloc pattern in flutter.
so I'm trying to implement a function which user click button (blue or green), it should change the theme color blue or green.
but the problem is I set initiaData as purple color and it just shows orange theme even user click the green or blue button.
event.dart
abstract class ChangeColorEvent {}
class ChangeToGreen extends ChangeColorEvent {}
class ChangeToBlue extends ChangeColorEvent {}
bloc.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:theme_change/bloc/colorTheme/event.dart';
class ColorThemeBloc {
var _theme =
ThemeData(brightness: Brightness.light, primaryColor: Colors.orange);
final _colorStateController = StreamController();
StreamSink get _inTheme => _colorStateController.sink;
Stream get theme => _colorStateController.stream;
final _colorEventController = StreamController<ChangeColorEvent>();
Sink<ChangeColorEvent> get changeColorEventSink => _colorEventController.sink;
ColorThemeBloc() {
//wherever there's a new event we want to map it to a new state
_colorEventController.stream.listen(_mapEventToState);
}
void _mapEventToState(ChangeColorEvent event) {
print(event);
if (event is ChangeToGreen)
_theme =
ThemeData(brightness: Brightness.light, primaryColor: Colors.red);
else
_theme =
ThemeData(brightness: Brightness.light, primaryColor: Colors.pink);
_inTheme.add(_theme);
print(_theme);
}
void dispose() {
_colorEventController.close();
_colorStateController.close();
}
}
themeChange.dart
import 'package:flutter/material.dart';
import 'package:theme_change/bloc/colorTheme/bloc.dart';
import 'package:theme_change/bloc/colorTheme/event.dart';
class ThemeChange extends StatelessWidget {
// final bool isDarkThemeEnabled;
// final ThemeBloc bloc;
final _bloc = ColorThemeBloc();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
RaisedButton(
onPressed: () {
Navigator.pop(context);
},
color: Colors.grey,
child: Text('GO BACK'),
),
// ListTile(
// title: Text("Dark Theme"),
// trailing: Switch(
// value: isDarkThemeEnabled, onChanged: bloc.changeTheTheme),
// ),
RaisedButton(
onPressed: () => _bloc.changeColorEventSink.add(ChangeToBlue()),
color: Colors.blue,
child: Text('blue'),
),
RaisedButton(
onPressed: () => _bloc.changeColorEventSink.add(ChangeToGreen()),
color: Colors.green,
child: Text('Green'),
)
],
),
),
);
}
}
main.dart
class MyApp extends StatelessWidget {
final _bloc = ColorThemeBloc();
#override
Widget build(BuildContext context) {
return StreamBuilder(
initialData: ThemeData(
brightness: Brightness.light, primaryColor: Colors.purple),
stream: _bloc.theme,
builder: (context, snapshot) {
return MaterialApp(
theme: snapshot.data,
title: 'Flutter Demo',
home: DemoScreen(),
);
});
}
}
You haven't extended Equatable on Abstract Event, which is used to identify if event Object is same or not. change your event class to following :
abstract class ChangeColorEvent extends Equatable{}
class ChangeToGreen extends ChangeColorEvent {
// Add props, if you want to return data, else
}
class ChangeToBlue extends ChangeColorEvent {
// Add props, if you want to return data, else
}

Flutter: How to user a DropDownButton with provider?

I have a dropDownButton where i select the theme for the entire app. I have tried two ways of actually trying to fix this. First one was using the commented line "Provider.of(context).toggleTheme();" in the "setState". Had to make the "listen" option "false" as advised in another thread but it was not working. And the second one was to just call the "toggleTheme()" inside the "Themes.dart" in order to notify listeners that way. What would be a correct implementation for a Dropdownbutton like this.
MainScreen.dart
import 'package:flutter/material.dart';
import 'package:thisismylastattempt/Misc/Themes.dart';
import 'package:provider/provider.dart';
class MainScreen extends StatefulWidget {
static const id = "main_screen";
#override
_MainScreenState createState() => _MainScreenState();
}
class ThemeOptions{
final Color themeColor;
final ThemeType enumTheme;
ThemeOptions({this.themeColor, this.enumTheme});
void callParentTheme(){
ThemeModel().changeEnumValue(enumTheme);
}
}
class _MainScreenState extends State<MainScreen> {
List<ThemeOptions> themes = [
ThemeOptions(themeColor: Colors.teal, enumTheme: ThemeType.Teal),
ThemeOptions(themeColor: Colors.green, enumTheme: ThemeType.Green),
ThemeOptions(themeColor: Colors.lightGreen, enumTheme: ThemeType.LightGreen),
];
ThemeOptions dropdownValue;
#override
void initState() {
dropdownValue = themes[0];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MainScreen'),
),
body: Column(
children: <Widget>[
Container(
child: DropdownButton<ThemeOptions>(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(
color: Colors.deepPurple
),
underline: Container(
height: 0.0,
color: Colors.deepPurpleAccent,
),
onChanged: (ThemeOptions newValue) {
setState(() {
dropdownValue = newValue;
dropdownValue.callParentTheme();
print(newValue.themeColor);
//Provider.of<ThemeModel>(context).toggleTheme();
});
},
items: themes.map((ThemeOptions colorThemeInstance) {
return DropdownMenuItem<ThemeOptions>(
value: colorThemeInstance,
child: CircleAvatar(
backgroundColor: colorThemeInstance.themeColor,
),
);
})
.toList(),
),
),
SizedBox(height: 20.0,),
],
),
);
}
}
Themes.dart
import 'package:flutter/material.dart';
enum ThemeType {Teal, Green, LightGreen}
ThemeData tealTheme = ThemeData.light().copyWith(
primaryColor: Colors.teal.shade700,
appBarTheme: AppBarTheme(
color: Colors.teal.shade700,
),
);
ThemeData greenTheme = ThemeData.light().copyWith(
primaryColor: Colors.green.shade700,
appBarTheme: AppBarTheme(
color: Colors.green.shade700,
),
);
ThemeData lightGreenTheme = ThemeData.light().copyWith(
primaryColor: Colors.lightGreen.shade700,
appBarTheme: AppBarTheme(
color: Colors.lightGreen.shade700,
),
);
class ThemeModel extends ChangeNotifier {
ThemeData currentTheme = tealTheme;
ThemeType _themeType = ThemeType.Teal;
toggleTheme() {
if (_themeType == ThemeType.Teal) {
currentTheme = tealTheme;
_themeType = ThemeType.Teal;
print('teal');
notifyListeners();
}
if (_themeType == ThemeType.Green) {
currentTheme = greenTheme;
_themeType = ThemeType.Green;
print('green');
notifyListeners();
}
if (_themeType == ThemeType.LightGreen) {
currentTheme = lightGreenTheme;
_themeType = ThemeType.LightGreen;
print('lightGreen');
notifyListeners();
}
}
ThemeType getEnumValue(){
return _themeType;
}
void changeEnumValue(ThemeType newThemeType){
_themeType = newThemeType;
toggleTheme();
}
}
main.dart
void main() => runApp(ChangeNotifierProvider<ThemeModel>(
create: (BuildContext context) => ThemeModel(), child: MyApp()));
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: MaterialApp(
theme: Provider.of<ThemeModel>(context).currentTheme,
title: 'Flutter Demo',
initialRoute: MainScreen.id,
routes: {
Wrapper.id: (context) => Wrapper(),
LoginPage.id: (context) => LoginPage(),
Registration.id: (context) => Registration(),
MainScreen.id: (context) => MainScreen(),
SwitchAuthenticationState.id: (context) =>
SwitchAuthenticationState(),
},
),
);
}
}
I managed to make it work by calling the changeEnumValue from the Provider in the callParentTheme of your ThemeOptionsclass :
class ThemeOptions {
final Color themeColor;
final ThemeType enumTheme;
ThemeOptions({this.themeColor, this.enumTheme});
// void callParentTheme() {
// ThemeModel().changeEnumValue(enumTheme);
void callParentTheme(context) {
Provider.of<ThemeModel>(context, listen: false).changeEnumValue(enumTheme);
}
call the method with the context in your DropDown onChanged method :
onChanged: (ThemeOptions newValue) {
setState(() {
dropdownValue = newValue;
dropdownValue.callParentTheme(context);
print(newValue.themeColor);
});
},
Hope It's help