Flutter Error: Provider cannot access route in navigation - flutter

When I run this I keep getting the same error , kindly assist.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(App());
}
class App extends StatelessWidget {
final Color primaryColor = Color(0xff18203d);
#override
Widget build(BuildContext context) {
// ignore: todo
// TODO: implement build
return MultiProvider(
providers: [
Provider<AuthenticationService>(
create: (_) => AuthenticationService(FirebaseAuth.instance),
),
StreamProvider(
create: (_context) =>
_context.read<AuthenticationService>().authStateChanges,
initialData: null,
),
],
child: MaterialApp(
title: 'Mboka Horticulture',
theme: ThemeData(
primaryColor: primaryColor,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: AuthenticationWrapper(),
));
}
}
class AuthenticationWrapper extends StatelessWidget {
const AuthenticationWrapper({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
// ignore: todo
// TODO: implement build
final firebaseuser = context.watch<User>();
if (firebaseuser != null) {
return Dashboard();
}
return Login();
}
}
This is the error I keep getting and I don't understand.
**Providers are "scoped". So if you insert of provider inside a
route, then
other routes will not be able to access that provider.
- You used a `BuildContext` that is an ancestor of the provider you are trying to read.
Make sure that AuthenticationWrapper is under your MultiProvider/Provider<User>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:**

Related

Could not find the correct Provider above the BlocListener Widget

I'm trying to use Bloc provider for user authentication in my flutter app. When I try to access the data i'm always getting this error even though I double checked all the files.
This is the error i'm getting:
Error: Could not find the correct Provider<StateStreamable<Object?>> above this
BlocListener<StateStreamable<Object?>, Object?> Widget
This happens because you used a `BuildContext` that does not include the provider
main.dart:
void main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => AuthBloc(LoginInitState(), AuthRepository()))
],
child: MaterialApp(
title: 'Flutter app',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity),
home: const LoginPage(),
),
);
}
}
parts from login.dart:
#override
void initState() {
authBloc = BlocProvider.of<AuthBloc>(context);
super.initState();
}
######################################################
return Scaffold(
backgroundColor: Colors.grey[300],
body: BlocListener(
listener: (context, state) {
if (state is UserLoginSuccessState) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const HomeScreen()));
}
},
child: SafeArea...
I'm still new to flutter and struggling with the state management part, I'd be glad if anybody can help!
In your BlocListener you're missing the State and the Bloc
Here's what I mean
BlocListener<AuthBloc, AuthState>(
listener: (context, state) {
if (state is UserLoginSuccessState) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const HomeScreen()));
}
},
child: SafeArea...

Error: Could not find the correct Provider<MessageDao> above this MessageList Widget

I am trying to find the problem, I even did a hot restart but its not working I'm stuck on it, Someone please look at it
The following ProviderNotFoundException was thrown building MessageList(dirty, state: MessageListState#24cda):
Error: Could not find the correct Provider above this MessageList Widget
This happens because you used a BuildContext that does not include the provider
Main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const App());
}
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<UserDao>(
lazy: false,
create: (_) => UserDao(),
),
],
child: Builder(builder: (context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'RayChat',
theme: ThemeData(primaryColor: const Color(0xFF3D814A)),
home: Consumer<UserDao>(builder: (context, userDao, child) {
if (userDao.isLoggedIn()) {
return const MessageList();
} else {
return const Login();
}
}),
);
}),
);
}
}
I found that I was missing the provider for messagedao so I added a provider under UserDao
Provider<MessageDao>(
create: (_) => MessageDao(),
lazy: false,
)

Error: Could not find the correct Provider<SignInProvider> above this MyApp Widget

im trying to use StreamProvider with MultiProvider in MaterialApp
when I try accessing the provider, I get the following error:
Error: Could not find the correct Provider above this MyApp Widget
main.dart
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
final provider = Provider.of<SignInProvider>(context, listen: false);
return MultiProvider(
providers: [
StreamProvider<UserModel>.value(value: provider.authStateChange())
],
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: primaryColor,
accentColor: secondaryColor,
textTheme: customTextTheme
),
home: AuthHandler()
),
);
}
}
class AuthHandler extends StatelessWidget {
#override
Widget build(BuildContext context) {
UserModel _userModel = Provider.of<UserModel>(context);
return (_userModel != null) ? HomeScreen() : LoginScreen();
}
}
user_model.dart
class UserModel {
String uid;
String displayName;
String photoURL;
String email;
UserModel({ this.uid, this.displayName, this.photoURL, this.email, });
}
signin_provider.dart
Stream<UserModel> authStateChange() {
return firebaseAuth.authStateChanges().map((User user) => (user != null) ? UserModel(uid: user.uid) : null);
}
Go to main.dart and Add Your Provider :
Example :
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ThemeBloc>(
create: (_) => ThemeBloc(),
child: Consumer<ThemeBloc>(
builder: (_, mode, child) {
return MultiProvider(
providers: [
ChangeNotifierProvider<SignInBloc>(
create: (context) => SignInBloc(),
),
ChangeNotifierProvider<NewsDataBloc>(
create: (context) => NewsDataBloc(),
),
ChangeNotifierProvider<PopularDataBloc>(
create: (context) => PopularDataBloc(),
),
],
child: MaterialApp(
home: MyHomePage()),
);
},
),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return WelcomePage();
}
}

Flutter : Navigator operation requested with a context that does not include a Navigator

I have a scenario wherein I check the value of SharePreferences based on the value it will redirect the user to HomePage or LandingPage. I am not sure where did I got wrong? but I am getting this error below: I guess its not getting the context right any idea how do I get it?.
Unhandled Exception: Navigator operation requested with a context that does not include a Navigator.
E/flutter (11533): The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
Here is my code:
import 'package:credit/src/pages/landing.dart';
import 'package:flutter/material.dart';
import 'package:credit/src/pages/credit/home.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<MyApp> {
#override
void initState() {
super.initState();
getUserStatus().then((userStatus) {
if (userStatus == null) {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return LandingPage();
}));
} else {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return HomePage();
}));
}
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: CircularProgressIndicator(),
));
}
}
Future<String> getUserStatus() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String userStatus = prefs.getString('userstatus');
print("==On Load Check ==");
print(userStatus);
return userStatus;
}
When you call Navigator.of(context) framework goes up in widget tree attached to provided context and tries to find the closest Navigator.
The widget tree you showed does not have one, so you need to include Navigator in the widget tree.
Easiest option is to use MaterialApp with your widget passed as home. MaterialApp is creating navigator inside itself. (CupertinoApp does it too)
Updated code from original example:
import 'package:credit/src/pages/landing.dart';
import 'package:flutter/material.dart';
import 'package:credit/src/pages/credit/home.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
MyApp({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: LoadingPage(),
);
}
}
class LoadingPage extends StatefulWidget {
LoadingPage({Key key}) : super(key: key);
_LoadingPageState createState() => _LoadingPageState();
}
class _LoadingPageState extends State<LoadingPage> { // note type update
#override
void initState() {
super.initState();
getUserStatus().then((userStatus) {
if (userStatus == null) {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return LandingPage();
}));
} else {
Navigator.of(context)
.push(MaterialPageRoute<Null>(builder: (BuildContext context) {
return HomePage();
}));
}
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: CircularProgressIndicator(),
));
}
}
Future<String> getUserStatus() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String userStatus = prefs.getString('userstatus');
print("==On Load Check ==");
print(userStatus);
return userStatus;
}
I have changed my code from
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo App',
theme: ThemeData(
primarySwatch: white,
scaffoldBackgroundColor: Colors.white,
),
home: Scaffold(
appBar: AppBar(
title: Text('Demo App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
HomeScreen(title: 'Demo Home')));
},
child: Text('Open Home Screen'))
],
),
),
),
);
}
To
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Demo App',
theme: ThemeData(
primarySwatch: white,
scaffoldBackgroundColor: Colors.white,
),
home: InitScreen());
}
}
class InitScreen extends StatelessWidget {
const InitScreen({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
HomeScreen(title: 'Demo Home')));
},
child: Text('Open Home Screen'))
],
),
),
);
}
What changed?
Create a separate widget for home code in MyApp with InitScreen
What was the issue?
When we try to push Route by using Navigator.of(context), flutter will
try to find Navigator in the widget tree of the given context. In the
initial code, there was no widget that has Navigator. So, create a
separate widget for home code. And the MaterialApp widget in MyApp
will have Navigator.

Authentication Flow with Flutter

I'm new to flutter. I am trying to set up an authentication flow. if the user is not logged in, I plan to build a MaterialApp with certain routes (eg Facebook Auth, Google Auth and Email Auth). If the user is logged in, they ll see another MaterialApp with routes such as HomePage, ListPage, CreatePage etc.
I tried but below codes fail. Anyone with experience can advise? thanks in advance
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import './pages/email.dart';
import './pages/auth.dart';
import './pages/home.dart';
import './pages/list.dart';
import './pages/create.dart';
import './scoped-models/main.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
final MainModel _model = MainModel();
bool _isAuthenticated = false;
#override
void initState() {
_model.autoAuthenticate();
_model.userSubject.listen((bool isAuthenticated) {
setState(() {
_isAuthenticated = isAuthenticated;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
print(_isAuthenticated);
return ScopedModel<MainModel>(
model: _model,
child: !_isAuthenticated == true
? MaterialApp(
theme: ThemeData(
primaryColor: Colors.lime, buttonColor: Colors.teal),
routes: {
'/': (BuildContext context) => AuthPage(),
'/email': (BuildContext context) => EmailPage(),
},
)
: MaterialApp(
theme: ThemeData(
primaryColor: Colors.lime, buttonColor: Colors.teal),
routes: {
'/': (BuildContext context) => HomePage(),
'/list': (BuildContext context) => ListPage(),
'/create': (BuildContext context) => CreatePage()
},
),
);
}