whenever I add the provider to the MultipleProvider it just shows this weird error not not able to solve it after spending 4 hours.
main.dart
MultiProvider(
providers: [
Provider<HandleImageSelectionModel>(
create: (_) => HandleImageSelectionModel()),
],
child: MaterialApp(
title: 'Flutter Demo',
initialRoute: '/',
onGenerateRoute: RouteGenerator.generateRoute,
theme: ThemeData(
primarySwatch: Colors.blue,
),
),
);
Provider class
import 'package:flutter/foundation.dart';
class HandleImageSelectionModel extends ChangeNotifier {
bool isSelectionModeEnabled = false;
HandleImageSelectionModel();
toggleSelectionMode() {
isSelectionModeEnabled = !isSelectionModeEnabled;
notifyListeners();
}
}
Changing State
Provider.of<HandleImageSelectionModel>(context)
.toggleSelectionMode();
Trying to consume here
Consumer<HandleImageSelectionModel>(
builder: (context, isEnabled, child) {
print(isEnabled);
return Positioned(
child: Align(
alignment: Alignment.topRight,
child: CircularCheckBox(
value: true,
materialTapTargetSize:
MaterialTapTargetSize.padded,
onChanged: (bool x) {}),
),
);
},
)
You're using Provider when the class you pass is a ChangeNotifier.
Use ChangeNotifierProvider instead:
ChangeNotifierProxyProvider<HandleImageSelectionModel>
Related
I am developing an app in Flutter. I'm using flutter_localizations package for localization and intl package for internationalization. For this, I'm using Context in Widgets, but the problem is when I want to use internationalization inside bloc or repositories or other layers except for the UI layer.
What is the best practice for doing internationalization inside Other layers except for UI where we don't have access to Context?
I have tried to use a Singleton, but I don't know if this is the right way.
You have to pass appLocalizations. For example in the Cubits you can do something like:
main.dart
runApp(
MaterialApp(
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', ''),
const Locale('pl', ''),
],
title: 'MySuperApp',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.orange,
accentColor: Colors.deepOrangeAccent,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
initialRoute: '/',
routes: {
UserAuthScreen.routeName: (context) => const UserAuthScreen(),
HomePage.routeName: (context) => HomePage(),
...
},
builder: (context, child) {
final appLocalizations = AppLocalizations.of(context); //IMPORTANT
return MultiBlocProvider(
providers: [
BlocProvider<ConstantsCubit>(
lazy: true,
create: (context) => ConstantsCubit(
constantsRepository: ConstantsRepository(),
),
),
BlocProvider<UserAuthCubit>(
lazy: true,
create: (context) => UserAuthCubit(
localizations: appLocalizations, //THIS IS WHERE THE MAGIC HAPPENS
repository: UserAuthRepository(),
),
),
BlocProvider<DoerInfoCubit>(
lazy: true,
create: (context) => DoerInfoCubit(
doerInfoRepository: DoerInfoRepository(),
userAuthCubit: BlocProvider.of<UserAuthCubit>(context),
)),
...
],
child: child,
);
},
home:
BlocBuilder<UserAuthCubit, UserAuthState>(builder: (context, state) {
if (state is UserAuthLogged) {
return HomePage();
} else {
return const UserAuthScreen();
}
}),
),
);
In your bloc or cubit:
class UserAuthCubit extends Cubit<UserAuthState> {
final UserAuthRepository repository;
final AppLocalizations localizations;
UserAuthCubit({
#required this.repository,
#required this.localizations,
}) : super(const UserAuthInitial()) {
getUserAuthState();
}
I put provider above material app so I can use it in every widget in-app right?
so why this error
and my code is
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Cart(),
),
ChangeNotifierProvider.value(value: ProductsProvider()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.purple,
accentColor: Colors.deepOrange,
fontFamily: 'Lato',
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: ProductOverviewScreen(),
routes: {ProductDetailScreen.routeName: (ctx) => ProductDetailScreen()},
),
);
}
}
and this screen has the error
enum filterOptions { Favorites, All }
class ProductOverviewScreen extends StatefulWidget {
#override
_ProductOverviewScreenState createState() => _ProductOverviewScreenState();
}
class _ProductOverviewScreenState extends State<ProductOverviewScreen> {
var _showOnlyFavorites = false;
#override
Widget build(BuildContext context) {
//final cart = Provider.of<Cart>(context);
return Scaffold(
appBar: AppBar(
title: Text("MyShop"),
actions: [
PopupMenuButton(
onSelected: (selectedValue) {
setState(() {
if (selectedValue == filterOptions.Favorites) {
_showOnlyFavorites = true;
} else if (selectedValue == filterOptions.All) {
_showOnlyFavorites = false;
}
});
},
icon: Icon(Icons.more_vert),
itemBuilder: (_) => [
PopupMenuItem(
child: Text("Only Favorites"),
value: filterOptions.Favorites),
PopupMenuItem(
child: Text("Show All"), value: filterOptions.All),
]),
Consumer<Cart>(
builder: (_, cartData, ch) => Badge(
child: ch,
value: cartData.itemCount.toString(),
),
child: IconButton(
icon: Icon(Icons.shopping_cart),
onPressed: () {},
),
)
],
),
body: ProductsGrid(_showOnlyFavorites));
}
}
the error in the consumer is
Error: Could not find the correct Provider above this Consumer Widget
why does this screen cant know the Cart provider?
any help please ?
I don't have enough reputation to comment, but your sample works fine on my end with flutter 1.22.5 and provider 4.3.2. However, I managed to reproduce your problem when accidentally importing a package named flutter_provider and using its Consumer widget. Couldn't imagine this being your problem though.
By the way, you should avoid using the value constructor to create your ChangeNotifier. Either pass a variable or use the default constructor with the create parameter.
Good morning,
Here I have two buttons that change the theme of my application (light and dark). When I reload my app the theme is not the one I selected last. I would like the application to back up the last theme used locally. You may need to save just a number that indicates which theme used the last one. . . But I don’t know at all how to do this?
Here’s the code: main.dart
import 'package:flutter/material.dart';
import 'package:animated_splash_screen/animated_splash_screen.dart';
import 'package:watch/nav.dart';
import 'package:page_transition/page_transition.dart';
import 'package:watch/blocs/theme.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ThemeChanger>(
builder: (_) => ThemeChanger(ThemeData.dark()),
child: MaterialAppWithTheme(),
);
}
}
class MaterialAppWithTheme extends StatelessWidget {
#override
Widget build(BuildContext context) {
final theme = Provider.of<ThemeChanger>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: theme.getTheme(),
home: AnimatedSplashScreen(
duration: 3000,
splash: "",
splashTransition: SplashTransition.slideTransition,
pageTransitionType: PageTransitionType.downToUp,
nextScreen: Nav(),
),
);
}
}
settings.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:watch/blocs/theme.dart';
import 'package:watch/constants.dart';
class Parametres extends StatelessWidget {
#override
Widget build(BuildContext context) {
ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context);
return Scaffold(
appBar: AppBar(
title: Text('Paramètres', style: kAppBarStyle,),
elevation: 0,
automaticallyImplyLeading: false,
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.arrow_back,
),
),
),
body: Container(
child: Column(
children: <Widget>[
FlatButton(
onPressed: () => _themeChanger.setTheme(
ThemeData(
bottomNavigationBarTheme: bNavBar,
scaffoldBackgroundColor: kBlackMedium,
brightness: Brightness.dark,
iconTheme: bIcons,
)),
child: Text('Dark Theme')),
FlatButton(
onPressed: () => _themeChanger.setTheme(
ThemeData(
bottomNavigationBarTheme: lNavBar,
scaffoldBackgroundColor: Colors.white,
brightness: Brightness.light,
iconTheme: lIcons,
primaryColor: kWhite,
)),
child: Text('Light Theme')),
],
),
),
);
}
}
Thank you
Shared preference is best option for it. Since I don't know about your ThemeChanger class I add here my theme class first:
class MyThemeModel extends ChangeNotifier{
ThemeData _themedata;
MyThemeModel(bool isActive){
if(isActive == null){
getThemeData;
}
else{
if(isActive){
_themedata = sleepTheme;
}
else{
_themedata = morningTheme;
}
}
}
ThemeData get getThemeData => _themedata;
void setThemeData(ThemeData data){
_themedata = data;
notifyListeners();
}
}
In main.dart
void main() async{
var isSleepActive;
if(SharedPrefHelper.prefInstance.checkContains(SharedPrefKeys.ISMORNING)){
isSleepActive = SharedPrefHelper.prefInstance.getBool(SharedPrefKeys.ISMORNING);
}
else{
isSleepActive = false;
}
runApp(MultiProvider(
providers: [
ChangeNotifierProvider(
builder: (context) => MyThemeModel(isSleepActive),
)
],
child: MyApp(),
)
);
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: Provider.of<MyThemeModel>(context).getThemeData,
title: 'Theme App',
home: AnimatedSplashScreen(
duration: 3000,
splash: "",
splashTransition: SplashTransition.slideTransition,
pageTransitionType: PageTransitionType.downToUp,
nextScreen: Nav(),
),
debugShowCheckedModeBanner: false,
);
}
In order to change theme with flat button:
FlatButton(
onPressed: () => myThemeModel.setThemeData(
ThemeData(
bottomNavigationBarTheme: lNavBar,
scaffoldBackgroundColor: Colors.white,
brightness: Brightness.light,
iconTheme: lIcons,
primaryColor: kWhite,
)),
child: Text('Light Theme')),
Use the Shared Preference package and there you can store simple values as key pair values.Load that data in the init of the initial screen so that you can display the screen according to the theme
You should use local memory to save theme.
You can use shared preference or hive db or sqflite or other database system.
About changing theme you can use Cubit,Bloc,Provider or etc or even if ValueNotifier.
However you should wrap your MaterialApp or CupertinoApp with "your state management widget"
And add some Logic
OR you can use some library
Library to change theme
I am receiving the following error -
I/flutter (18695): The following StackOverflowError was thrown building Consumer(dirty, dependencies:
I/flutter (18695): [_DefaultInheritedProviderScope]):
I/flutter (18695): Stack Overflow
This seems to relate to error in my Consumer. I am using Provider plugin to try to create a toggle button for Dark Mode in Flutter.
See below for my files -
appstatenotifier.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
ThemeData light = ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.indigo,
accentColor: Colors.pink,
scaffoldBackgroundColor: Color(0xfff1f1f1)
);
ThemeData dark = ThemeData(
brightness: Brightness.dark,
primarySwatch: Colors.indigo,
accentColor: Colors.pink,
);
class ThemeNotifier with ChangeNotifier {
final String key = "theme";
SharedPreferences prefs;
bool _darkTheme;
bool get darkTheme => darkTheme;
ThemeNotifier() {
_darkTheme = false;
}
toggleTheme() {
_darkTheme = !_darkTheme;
notifyListeners();
}
}
Below is my main.dart relevant Widgets
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
var themeData = ThemeData(
primarySwatch: Colors.blue,
);
return ChangeNotifierProvider(
create: (_) => ThemeNotifier(),
child: Consumer<ThemeNotifier>(
builder: (context, ThemeNotifier notifier, child) {
return MaterialApp(
theme: notifier.darkTheme ? dark : light,
title: 'Work Out Log',
routes: MyApp.routes,
);
}
),
);
}
}
Widget buildDrawer(context) {
return Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text('Dark Theme'),
trailing: Consumer<ThemeNotifier>(
builder: (context, notifier, child) => SwitchListTile(
title: Text("Dark mode"),
onChanged: (val) {
notifier.toggleTheme();
},
value: notifier.darkTheme,
),
),
),
],
),
);
}
Any idea why it's throwing this error?
As Viren V Varasadiya pointed out, your getter for darkTheme is incorrect:
bool get darkTheme => darkTheme;
Presumably, you meant to point it at _darkTheme, but instead you have the getter that is returning itself. This means that any time you call darkTheme, the getter looks up the value of darkTheme, which makes the getter look up the value of darkTheme, which makes the getter look up the value of darkTheme, which makes the getter look up the value of darkTheme, which makes the getter look up... (hopefully you get the idea).
You just need to change the getter to return the correct thing:
bool get darkTheme => _darkTheme;
You Must be Retruning the same thing as the class name
This screen is a Drawer screen which take the auth bloc in order to provide user the info and enable him of logout.
I got this error although I am using the correct provider
The following ProviderNotFoundError was thrown building Pets4allDrawer(dirty):
I/flutter (32011): Error: Could not find the correct Provider<AuthService> above this Pets4allDrawer Widget
I/flutter (32011): To fix, please:
I/flutter (32011): * Ensure the Provider<AuthService> is an ancestor to this Pets4allDrawer Widget
I/flutter (32011): * Provide types to Provider<AuthService>
I/flutter (32011): * Provide types to Consumer<AuthService>
I/flutter (32011): * Provide types to Provider.of<AuthService>()
I/flutter (32011): * Ensure the correct `context` is being used.
I want to know the problem why using Provider.of(context) does not work, It can not be found while calling it.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:pets4all/blocs/authBloc.dart';
import 'package:provider/provider.dart';
class Pets4allDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
final AuthService authService = Provider.of<AuthService>(context);
final user$ = authService.user.where((user) => user != null);
return StreamBuilder<FirebaseUser>(
stream: user$,
builder: (context, snap) {
final user = snap.data;
if (snap.hasData) {
return Drawer(
child: ListView(
children: <Widget>[
ListTile(
leading: Icon(Icons.person_outline),
title: Text(user.displayName),
onTap: null,
),
ListTile(
leading: Icon(Icons.home),
title: Text("Home"),
onTap: null,
),
Align(
heightFactor: 3.5,
alignment: Alignment.bottomLeft,
child: FlatButton(
child: Text(
'Log out',
style: TextStyle(color: Colors.redAccent),
),
onPressed: () {
Navigator.pop(context);
authService.signOut();
},
),
),
],
),
);
} else {
return CircularProgressIndicator();
}
},
);
}
}
and this is where I am calling the drawer
class TabScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
List<String> lol = ["questions", "events"];
return StatefulProvider<ForumServices>(
valueBuilder: (BuildContext context) => ForumServices(),
child: Consumer<ForumServices>(
builder: (BuildContext context, forumServices) {
return StreamBuilder<List<String>>(
stream: forumServices.forumsTypes$,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
List<String> types = snapshot.data;
num tabLen = types.length;
return DefaultTabController(
length: tabLen,
child: Scaffold(
drawer: Pets4allDrawer(),
Check whether you have registered the provider in some ancestor Widget, as in the example:
return MultiProvider(
providers: [
ChangeNotifierProvider(
builder: (_) => FirebaseNotificationNotifier(),
),],
Update:
provider version provider: ^6.0.0
Declaration of provider in main myApp()
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => LoginProvider()),
ChangeNotifierProvider(create: (_) => SignupProvider()),
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
),
);
if you using multiple providers, you should add those to main.dart.
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Car(),
),
ChangeNotifierProvider.value(
value: Van(),
),
ChangeNotifierProvider.value(
value: Bus(),
),
],
child: MaterialApp(
title: 'MyApp',
home: MyHome(),
),
);