Multiple ScopedModels in flutter - flutter

I followed a tutorial from a flutter app with login system using a scope_model. Then, I added a new scope_model called Group to use in a new "route" called opportunities.
But in my new route I can't call the scope_model Group and I allways see the same error:
Error: Could not find the correct ScopedModel.
I think that my mistake is in main.dart. I don't know how to "invoque" my new scope_model.
Here is my code.
file opportuinity.dart
import 'package:scoped_model/scoped_model.dart';
import 'package:business_maker/data/models/group_api.dart';
(...)
#override
Widget build(BuildContext context) {
final _group = ScopedModel.of<GroupModel>(context, rebuildOnChange: true);
file main.dart
#override
Widget build(BuildContext context) {
return ScopedModel<ThemeModel>(
model: _model,
child: new ScopedModelDescendant<ThemeModel>(
builder: (context, child, theme) => ScopedModel<AuthModel>(
model: _auth,
child: MaterialApp(
theme: theme.theme,
home: new ScopedModelDescendant<AuthModel>(
builder: (context, child, model) {
if (model?.user != null) return Home();
return LoginPage();
}),
routes: <String, WidgetBuilder>{
"/login": (BuildContext context) => LoginPage(),
"/menu": (BuildContext context) => Home(),
"/home": (BuildContext context) => Home(),
"/settings": (BuildContext context) => SettingsPage(),
"/opportunities": (BuildContext context) => OpportunityPage()
},
),
),
));
}
thank you

If you want to use models in different routes then you need to place the model above the Navigator which is usually created in a WidgetsApp/MaterialApp/CupertinoApp
In your code I do not see a ScopedModel<Group> that's placed above the navigator. Or anywhere, actually. You need to add the group model above the navigator (something the materialapp creates for you).
Widget build(BuildContext context) {
return ScopedModel<ThemeModel>(
model: _model,
child: ScopedModel<Group>(
model: _yourGroupModel,
child: new ScopedModelDescendant<ThemeModel>(
builder: (context, child, theme) => ScopedModel<AuthModel>(
model: _auth,
child: MaterialApp(
theme: theme.theme,
home: new ScopedModelDescendant<AuthModel>(
builder: (context, child, model) {
if (model?.user != null) return Home();
return LoginPage();
}),
routes: <String, WidgetBuilder>{
"/login": (BuildContext context) => LoginPage(),
"/menu": (BuildContext context) => Home(),
"/home": (BuildContext context) => Home(),
"/settings": (BuildContext context) => SettingsPage(),
"/opportunities": (BuildContext context) => OpportunityPage()
},
),
),
)
)
);
}

Related

flutter package easyloading with ResponsiveWrapper

I have a problem. I'm using the easyloading package with responsivewrapper. but i can't put them together please help me
builder: EasyLoading.init(context, child) =>
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: const Size(360, 690),
minTextAdapt: true,
splitScreenMode: true,
builder: (context, child) {
return MaterialApp(
initialRoute: '/',
builder: EasyLoading.init(context, child) => ResponsiveWrapper.builder(child,
defaultScale: true,
breakpoints: [
ResponsiveBreakpoint.resize(480, name: MOBILE),
ResponsiveBreakpoint.autoScale(800, name: TABLET),
ResponsiveBreakpoint.resize(1000, name: DESKTOP),
],
background: Container(color: Color(0xFFF5F5F5))),
debugShowCheckedModeBanner: false,
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => MainPage(),
'/CusSearchAtcp': (BuildContext context) => const CusSearchAtcp(),
},
);
});
}
The builder parameter must return one widget. If you like to do initialization or return two widgets, you've to nest them yourself inside the builder:
builder: (context, child) {
// do your initialization here
child = EasyLoading.init(); // assuming this is returning a widget
child = ResponsiveWrapper.builder(/*your required code here*/);
return child;
}
Or you should try to use 2nd way by ResponsiveWrapper.builder or EasyLoading such as:
builder: EasyLoading.init(builder: ResponsiveWrapper.builder(/*your required code here*/)),

Flutter Error: The method 'setContext' isn't defined for the type 'ScreenUtil'

I am using flutter screenutil and The following code used to work, but it gives me this error now.
The method 'setContext' isn't defined for the type 'ScreenUtil'. Try correcting the name to the name of an existing method, or defining a method named 'setContext'.
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) {
return themeChanger;
},
),
ChangeNotifierProvider(
create: (_) {
return settingChanger;
},
),
ChangeNotifierProvider(create: (_) {
return locationChanger;
})
],
child: Consumer2<DarkThemeProvider, AdvancedSettingsProvider>(
builder: (context, value1, value2, child) {
return ScreenUtilInit(
designSize: Size(1080, 2160),
builder: (_) => MaterialApp(
builder: (context, widget) {
ScreenUtil.setContext(context);
return MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1),
child: widget!);
},
theme: Styles.themeData(
themeChanger.darkTheme, context, themeChanger.color),
debugShowCheckedModeBanner: false,
home: (widget.payload.isEmpty)
? Skeleton()
: AccessedByNotifPage(
payload: widget.payload,
),
),
);
}),
);
}
}```
[![This image shows the error](https://imgur.com/a/l9B5fDJ)
Use init() function instead of setContext()
it's in the new update.
example:
builder: (context, widget) {
ScreenUtil.init(context);
}
You need to upgrade screenUtil version in pubsic.yaml to
flutter_screenutil: ^5.4.0
then flutter clean, flutter pub get and put this code in material app
builder: (ctx, child) {
ScreenUtil.setContext(ctx);
return MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
child: child!,
);
}

The argument type 'MaterialApp Function()' can't be assigned to the parameter type 'Widget Function(BuildContext)'

I am using flutter_screenutil and
The following code used to work, but it gives me this error when I try to run it:
Error: The argument type 'MaterialApp Function()' can't be assigned to the parameter type 'Widget Function(BuildContext)'.
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) {
return themeChanger;
},
),
ChangeNotifierProvider(
create: (_) {
return settingChanger;
},
),
ChangeNotifierProvider(create: (_) {
return locationChanger;
})
],
child: Consumer2<DarkThemeProvider, AdvancedSettingsProvider>(
builder: (context, value1, value2, child) {
return
ScreenUtilInit(
designSize: Size(1080, 2160),
builder: () =>
MaterialApp(
builder: (context, widget) {
ScreenUtil.setContext(context);
return MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1),
child: widget!);
},
theme: Styles.themeData(
themeChanger.darkTheme, context, themeChanger.color),
debugShowCheckedModeBanner: false,
home: (widget.payload.isEmpty)
? Skeleton()
[enter image description here][1] : AccessedByNotifPage(
payload: widget.payload,
),
),
);
}),
);
}
}
This image shows the error:
If you use ScreenUtilInit, you must have to provide Buildcontext or pass a value in the builder function callback.
Use:
return ScreenUtilInit(
designSize: Size(1080, 2160),
builder: (BuildContext context,child) => MaterialApp(
or:
return ScreenUtilInit(
designSize: Size(1080, 2160),
builder: (_,child) => MaterialApp(
ScreenUtilInit: builder provides BuildContext on callback,
On line 162 do builder: (_) => MaterialApp or
return ScreenUtilInit(
designSize: Size(1080, 2160),
builder: (BuildContext c) => MaterialApp(
In your code simply change
builder: (context, value1, value2, child){
with
create: (context, value1, value2, child) {
ScreenUtilInit(
designSize: const Size(360, 740),
builder: (BuildContext context, child) => MaterialApp(
))

multi provider not changing state

I am developing a chat app and all was fine when i was using only a stream provider which takes user id stream from firebase, but as i want real time changes when i add a chat, so i added multi provider, and gives it stream provider and change notfier provider, now both are not working, i have to hot restart the app for changes.
Widget build(BuildContext context) {
return MultiProvider(
providers: [
// authentication provider
StreamProvider<User?>(
create: (context) => AuthController().userStream(),
initialData: null,
),
//states provider
ChangeNotifierProvider(create: (context) => Cloud()),
],
builder: (context, _) => MaterialApp(
theme: ThemeData(
primaryColor: Colors.deepPurpleAccent,
textTheme: TextTheme(button: TextStyle(color: Colors.white)),
primarySwatch: Colors.deepPurple),
home: Scaffold(
body: Wrapper(),
),
));
}
You can Simply Use SteamBuilder & Firestore :
#override Widget build(BuildContext context) {
var streamBuilder = StreamBuilder<List<Message>>(
stream: getData(),
builder: (BuildContext context, AsyncSnapshot<List<Message>> messagesSnapshot) {
if (messagesSnapshot.hasError)
return new Text('Error: ${messagesSnapshot.error}');
switch (messagesSnapshot.connectionState) {
case ConnectionState.waiting: return new Text("Loading...");
default:
return new ListView(
children: messagesSnapshot.data.map((Message msg) {
return new ListTile(
title: new Text(msg.message),
subtitle: new Text(DateTime.fromMillisecondsSinceEpoch(msg.timestamp).toString()
+"\n"+(msg.user ?? msg.uid)),
);
}).toList()
);
}
}
);
return streamBuilder; }

Flutter: Dynamic Initial Route

Dears,
I am using provider dart package which allows listeners to get notified on changes to models per se.
I am able to detect the change inside my main app root tree, and also able to change the string value of initial route however my screen is not updating. Kindly see below the code snippet and the comments lines:
void main() => runApp(_MyAppMain());
class _MyAppMain extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<UserProvider>.value(
value: UserProvider(),
),
ChangeNotifierProvider<PhoneProvider>.value(
value: PhoneProvider(),
)
],
child: Consumer<UserProvider>(
builder: (BuildContext context, userProvider, _) {
return FutureBuilder(
future: userProvider.getUser(),
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
final User user = snapshot.data;
String initialScreen = LoginScreen.path;
// (1) I am able to get into the condition
if (user.hasActiveLogin()) {
initialScreen = HomeOneScreen.path;
}
return MaterialApp(
title: 'MyApp',
theme: ThemeData(
primarySwatch: Colors.green,
accentColor: Colors.blueGrey,
),
initialRoute: initialScreen,
// (2) here the screen is not changing...?
routes: {
'/': (context) => null,
LoginScreen.path: (context) => LoginScreen(),
RegisterScreen.path: (context) => RegisterScreen(),
HomeOneScreen.path: (context) => HomeOneScreen(),
HomeTwoScreen.path: (context) => HomeTwoScreen(),
RegisterPhoneScreen.path: (context) => RegisterPhoneScreen(),
VerifyPhoneScreen.path: (context) => VerifyPhoneScreen(),
},
);
},
);
},
),
);
}
}
Kindly Note the Below:
These are are paths static const strings
LoginScreen.path = "login"
RegisterScreen.path = "/register-screen"
HomeOneScreen.path = "home-one-screen"
HomeTwoScreen.path = "home-two-screen"
RegisterPhoneScreen.path = "/register-phone-screen"
VerifyPhoneScreen.path = "/verify-phone-screen"
What I am missing for dynamic initialRoute to work?
Many Thanks
According to this issue described on github issues it is not permissible to have initial route changes. At least this is what I understood. However what I did is that I replaced the initialRoute attribute with home attr. Thus this change mandates that initialScreen becomes a widget var.
The changes is shown below:
void main() => runApp(_MyAppMain());
class _MyAppMain extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<UserProvider>.value(
value: UserProvider(),
),
ChangeNotifierProvider<PhoneProvider>.value(
value: PhoneProvider(),
)
],
child: Consumer<UserProvider>(
builder: (BuildContext context, userProvider, _) {
return FutureBuilder(
future: userProvider.getUser(),
builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
final User user = snapshot.data;
// (1) This becomes a widget
Widget initialScreen = LoginScreen();
if (user.hasActiveLogin()) {
initialScreen = HomeOneScreen();
}
return MaterialApp(
title: 'MyApp',
theme: ThemeData(
primarySwatch: Colors.green,
accentColor: Colors.blueGrey,
),
home: initialScreen,
// (2) here the initial route becomes home attr.
routes: {
'/': (context) => null,
LoginScreen.path: (context) => LoginScreen(),
RegisterScreen.path: (context) => RegisterScreen(),
HomeOneScreen.path: (context) => HomeOneScreen(),
HomeTwoScreen.path: (context) => HomeTwoScreen(),
RegisterPhoneScreen.path: (context) => RegisterPhoneScreen(),
VerifyPhoneScreen.path: (context) => VerifyPhoneScreen(),
},
);
},
);
},
),
);
}
}
Also note on my RegistrationScreen on success api response I did Navigator.of(context).pop()
Thanks