How to use SharedPreferences on switch with changing the theme flutter - 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();
}

Related

Flutter Themedata Refrector

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.

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:
),

trying to do color picker in flutter

I was trying to do a Color Picker for my app in flutter...
i installed the Mtaerial Color Picker package from pub dev...
then i tried to make a Provider like i made for my Dark Mode...
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ThemeProvider with ChangeNotifier {
ThemeData _selectedTheme;
int primaryValue;
static Color secondaryColor;
ThemeProvider({
bool isDarkMode,
int primaryValue,
}) {
this._selectedTheme = isDarkMode ? dark : light;
this.primaryValue = colorValue;
}
static int colorValue;
ThemeData light = ThemeData.light().copyWith(
primaryColor: Color(colorValue) ?? Colors.teal[700],
);
ThemeData dark = ThemeData.dark().copyWith();
void changeColor(int value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
colorValue = value;
primaryValue = colorValue;
print(colorValue);
prefs.setInt('PrimaryColor', primaryValue);
notifyListeners();
}
void swapTheme() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (_selectedTheme == dark) {
_selectedTheme = light;
prefs.setBool('isDarkTheme', false);
print(prefs.getBool('isDarkTheme'));
} else {
_selectedTheme = dark;
prefs.setBool('isDarkTheme', true);
print(prefs.getBool('isDarkTheme'));
}
notifyListeners();
}
ThemeData get getTheme => _selectedTheme;
}
the swapTheme() is for my dark Mode and the change Color it is For my problem i get the Color int from my picker like that:
MaterialColorPicker(
circleSize: 50,
selectedColor:
_selectedColor ?? Colors.teal[700],
onColorChange: (Color color) {
setState(() {
_selectedColor = color;
String primaryColorString =
_selectedColor.toString();
String valueString = primaryColorString
.split('(0x')[1]
.split(')')[0];
int value =
int.parse(valueString, radix: 16);
themeProvider.changeColor(value);
});
},
),
and when i choose a color it just activate the change color function where it should rebuild my app because i am using provider in my main.dart thats how my Dark Mode is working
return runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (BuildContext context) => ThemeProvider(
isDarkMode: prefs.getBool('isDarkTheme') ?? false,
primaryValue: prefs.getInt('PrimaryColor') ?? 4293467747,
),
),
],
child: MyApp(),
),
);
}
return Consumer<ThemeProvider>(
builder: (context, themeProvider, _) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: themeProvider.getTheme,
tho its giving me This Error
The method '&' was called on null.
Receiver: null Tried calling:
&(4294967295)
and this too
Bad state: Tried to read a provider that threw during the creation of its value.
The exception occurred during the creation of type ThemeProvider.
okay so it should be done this way this is my darkMode changer the theme one :
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class DarkModeProvider with ChangeNotifier {
ThemeData _selectedTheme;
DarkModeProvider({
bool isDarkMode,
}) {
this._selectedTheme = isDarkMode ? dark : light;
}
ThemeData light = ThemeData.light();
ThemeData dark = ThemeData.dark();
void swapDarkMode() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
if (_selectedTheme == dark) {
_selectedTheme = light;
prefs.setBool('isDarkMode', false);
} else {
_selectedTheme = dark;
prefs.setBool('isDarkMode', true);
}
notifyListeners();
}
ThemeData get getTheme => _selectedTheme;
}
my color changer file:
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class ColorChanger with ChangeNotifier {
int primary;
int secondary;
ColorChanger({
this.primary,
this.secondary,
});
void changePrimaryColor(int prim) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
primary = prim;
prefs.setInt('Primary', primary);
notifyListeners();
}
void changeSecondaryColor(int second) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
secondary = second;
prefs.setInt('Secondary', secondary);
notifyListeners();
}
int get getPrimColor => primary;
int get getSecondColor => secondary;
}
where i change both is my setting page you put the widgets in any page...
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_material_color_picker/flutter_material_color_picker.dart';
import '../providers/color_provider.dart';
import '../providers/dark_mode_provider.dart';
class SettingsScreen extends StatefulWidget {
static const routeName = '/settings';
#override
_SettingsScreenState createState() => _SettingsScreenState();
}
class _SettingsScreenState extends State<SettingsScreen> {
bool _darkValue = false;
Color _selectedPrimaryColor;
Color _selectedSecondaryColor;
_onBackPressed() {
Navigator.of(context).pushReplacementNamed('/home');
}
getSharedPrefs() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var value = prefs.getBool('isDarkMode') ?? false;
if (value == false) {
setState(() {
_darkValue = false;
});
} else {
setState(() {
_darkValue = true;
});
}
}
#override
void initState() {
super.initState();
getSharedPrefs();
}
#override
Widget build(BuildContext context) {
DarkModeProvider darkModeProvider = Provider.of<DarkModeProvider>(
context,
listen: false,
);
ColorChanger colorChanger = Provider.of<ColorChanger>(
context,
listen: false,
);
return WillPopScope(
onWillPop: () {
return _onBackPressed();
},
child: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
_onBackPressed();
},
),
),
body: Container(
margin: EdgeInsets.symmetric(
horizontal: 20,
vertical: 5,
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Container(
child: Text(
'Dark Mode',
style: TextStyle(
fontSize: 20,
),
),
),
),
Switch(
value: _darkValue,
onChanged: (toggle) {
darkModeProvider.swapDarkMode();
getSharedPrefs();
}),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Container(
child: Text(
'Primary Colors',
style: TextStyle(
fontSize: 20,
),
),
),
),
TextButton(
onPressed: () {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
actions: <Widget>[
IconButton(
onPressed: () {
Navigator.of(context).pop(true);
},
icon: Icon(Icons.check),
),
],
content: SingleChildScrollView(
child: Container(
height:
MediaQuery.of(context).size.height * 0.35,
child: MaterialColorPicker(
circleSize: 50,
selectedColor:
Color(colorChanger.getPrimColor) ??
Colors.teal[700],
onColorChange: (Color color) {
setState(() {
_selectedPrimaryColor = color;
colorChanger.changePrimaryColor(
_selectedPrimaryColor.value);
});
},
),
),
),
);
},
);
},
child: CircleAvatar(
child: Icon(
Icons.color_lens,
color: Colors.white54,
),
backgroundColor:
Color(colorChanger.getPrimColor) ?? Colors.teal[700],
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Container(
child: Text(
'Secondary Colors',
style: TextStyle(
fontSize: 20,
),
),
),
),
TextButton(
onPressed: () {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
actions: <Widget>[
IconButton(
onPressed: () {
Navigator.of(context).pop(true);
},
icon: Icon(Icons.check),
),
],
content: SingleChildScrollView(
child: Container(
height:
MediaQuery.of(context).size.height * 0.35,
child: MaterialColorPicker(
circleSize: 50,
selectedColor:
Color(colorChanger.getSecondColor) ??
Colors.amber,
onColorChange: (Color color) {
setState(() {
_selectedSecondaryColor = color;
colorChanger.changeSecondaryColor(
_selectedSecondaryColor.value);
});
},
),
),
),
);
},
);
},
child: CircleAvatar(
child: Icon(
Icons.color_lens,
color: Colors.white54,
),
backgroundColor:
Color(colorChanger.getSecondColor) ?? Colors.amber,
),
),
],
),
],
),
),
),
);
}
}
here i used shared prefs.. so i can see my switch button functioning with the shared prefs
and here how you can use the both provider in the Themedata in the main dart:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:todo/providers/task_provider.dart';
import 'package:todo/screens/add_task_screen.dart';
import './screens/settings_screen.dart';
import './providers/color_provider.dart';
import './providers/dark_mode_provider.dart';
import './screens/home_screen.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
return runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (BuildContext context) => TaskProvider(),
),
ChangeNotifierProvider(
create: (BuildContext context) => DarkModeProvider(
isDarkMode: prefs.getBool('isDarkTheme') ?? false,
),
),
ChangeNotifierProvider(
create: (BuildContext context) => ColorChanger(
primary: prefs.getInt('Primary') ?? Colors.teal[700].value,
secondary: prefs.getInt('Secondary') ?? Colors.amber.value,
),
),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
return Consumer2<DarkModeProvider, ColorChanger>(
builder: (context, darkmode, colorChanger, _) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: darkmode.getTheme.copyWith(
primaryColor: Color(colorChanger.getPrimColor),
accentColor: Color(colorChanger.getSecondColor),
),
home: HomeScreen(),
routes: {
HomeScreen.routeName: (context) => HomeScreen(),
SettingsScreen.routeName: (context) => SettingsScreen(),
AddTaskScreen.routeNamed: (context) => AddTaskScreen(),
},
);
});
}
}
i guess its helpful i used it in my app..
thank you guys..

Why is my switch widget not sliding? I can't seem to change themes

I can't seem to figure out what is preventing the switch from changing states. I know if I set isDark to true, I get my dark theme, and if I set isDark to false I get my light theme. It might be possible that flutter is interpreting isDark as constantly being false. However, I am unsure as to how to fix that if that were the case. Regardless, something is stopping the switch and I can't figure it out. Any help is appreciated thank you.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ChangeThemeButton(),
theme: _theme,
// theme: MyThemes.lightTheme,
// darkTheme: MyThemes.darkTheme,
// themeMode: ThemeMode.system,
routes: {
'homepage': (context) => HomePage(),
'sign-in': (context) => SignIn(),
'register': (context) => RegisterPage(),
},
);
}
}
class ChangeThemeButton extends StatefulWidget {
#override
_ChangeThemeButtonState createState() => _ChangeThemeButtonState();
}
class _ChangeThemeButtonState extends State<ChangeThemeButton> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Switch(
value: isDark,
onChanged: (val) => {
setState((){
val = isDark;
themeProvider(val);
})
},
),
),
);
}
}
var _theme = (isDark == false) ? MyThemes.lightTheme : MyThemes.darkTheme;
bool val;
bool isDark = false;
bool themeProvider (bool val) {
switch (val) {
case false:
return isDark == true;
break;
case true:
return isDark == false;
break;
}
return null;
}
class MyThemes {
static final lightTheme = ThemeData(
colorScheme: ColorScheme.light(),
iconTheme: IconThemeData(color: Colors.black),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
unselectedItemColor: Colors.white,
selectedItemColor: Color(0xff9D4C8F),
showUnselectedLabels: true,
selectedIconTheme: IconThemeData(
color: Color(0xff9D4C8F),
),
unselectedIconTheme: IconThemeData(
color: Colors.white,
),
),
primaryColor: Colors.deepPurpleAccent[100],
primaryColorDark: Colors.black54,
secondaryHeaderColor: Colors.deepPurpleAccent[50],
scaffoldBackgroundColor: Colors.white,
cardColor: Colors.deepPurpleAccent,
cardTheme: CardTheme(elevation: 5));
static final darkTheme = ThemeData(
colorScheme: ColorScheme.dark(),
iconTheme: IconThemeData(color: Colors.white),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
unselectedItemColor: Colors.white38,
selectedItemColor: Color(0xff9D4C8F),
showUnselectedLabels: true,
selectedIconTheme: IconThemeData(
color: Color(0xff9D4C8F),
),
unselectedIconTheme: IconThemeData(
color: Colors.white,
),
),
primaryColor: Colors.black,
primaryColorDark: Colors.grey,
secondaryHeaderColor: Colors.deepPurpleAccent[50],
scaffoldBackgroundColor: Colors.white38,
cardColor: Colors.deepPurpleAccent,
cardTheme: CardTheme(elevation: 5)
);
}
change val = isDark; to isDark = val, or you could remove that line and change it into the provider, because now you say that even if val changes, you set it right below to isDark, so nothing changes.

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