LateInitializationError error in firebase auth code in flutter [duplicate] - android

This is the middle part of the main that is expected to cause the error. If you are not logged in on the splash screen, this code goes to MyHomePage and logs in. If you are logged in, it goes to MainScreen and switches to the main screen of the app.
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
final FirebaseAuth auth = FirebaseAuth.instance;
final User? user = FirebaseAuth.instance.currentUser;
#override
void initState() {
super.initState();
_initUser().whenComplete((){
setState(() {});
});
}
_initUser() async {
if (auth.currentUser != null) {
Timer(
Duration(seconds: 2),
() => Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) =>
MainScreen(user!)),
(Route<dynamic> route) => false),
);
} else {
Timer(Duration(seconds: 1),
() => Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) =>
MyHomePage()),
(Route<dynamic> route) => false),
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text("Splash Screen"),
),
);
}
}
This is the MyHomePage widget that is passed when you are not logged in.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextButton(
onPressed: (){
FirebaseService().signup(context);
},
child: Text('Google'),
),
)
);
}
}
class FirebaseService{
final FirebaseAuth auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
Future<void> signup(BuildContext context) async {
final GoogleSignInAccount? googleSignInAccount = await googleSignIn.signIn();
if (googleSignInAccount != null) {
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential authCredential = GoogleAuthProvider.credential(
idToken: googleSignInAuthentication.idToken,
accessToken: googleSignInAuthentication.accessToken);
// Getting users credential
UserCredential result = await auth.signInWithCredential(authCredential);
User? user = result.user;
if (user != null) {
Navigator.push(
context, MaterialPageRoute(builder: (context) => MainScreen(user)));
} // if result not null we simply call the MaterialpageRoute,
// for go to the HomePage screen
}
}
Future<void> signOutFromGoogle() async{
await googleSignIn.signOut();
await auth.signOut();
}
}
This is the content of the error
The following LateError was thrown building MainScreen(dirty, dependencies: [_InheritedProviderScope<Pro?>], state: _MainScreenState#d95a0):
LateInitializationError: Field '_instance#640075166' has not been initialized.
The relevant error-causing widget was:
MainScreen MainScreen:file:///F:/flutter%20project/good_man/lib/main.dart:75:25
When the exception was thrown, this was the stack:
Sorry, I forgot the mainscreen code. Below is the mainscreen code
class MainScreen extends StatefulWidget {
const MainScreen(this.user);
final User user;
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
#override
Widget build(BuildContext context) {
final User user = widget.user;
final pro = Provider.of<Pro>(context);
return DefaultTabController(
length: 3,
child: Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(60.0), // here the desired height
child: AppBar(
iconTheme: IconThemeData(color: Colors.black),
backgroundColor: pro.backColor_main,
elevation: 0.0,
centerTitle: true,
title: Text('aaa',
style: TextStyle(
fontFamily: 'Gugi',
fontSize: 20.sp,
color: Colors.black,
),),
),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.white
),
),
ListTile(
title: Text('aaa'),
onTap: () {
Navigator.pop(context);
},
),
],
),
),
bottomNavigationBar: BottomBar(),
body: Stack(children: [
TabBarView(
children: [
MainTest(),
Text(''),
Main_User(user),
],
),
])),
);
}
}
Sorry for posting all the code. There is no part that uses late , but the error code is displayed as late, and I try to delete the caches and start

Actually error is in Initialisation of current user...
You have to understand Life cycle of stateful widget...
initState is not holding flow. it just initialise some some instance value...And you try to delay for 2 sec... So that's the issue.
Use FutureBuilder for _initUser() and when it fetch all data then proceed for the next screen.

Don't initialise the async task into the initState. Because of Flutter Life Cycle it can not await the flow...
For more about the lIfe Cycle please visit this:
Life Cycle of Widget
So Solution is...
Use the FutureBuilder for awaiting the widget....
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
final FirebaseAuth auth = FirebaseAuth.instance;
final User? user = FirebaseAuth.instance.currentUser;
_initUser() async {
if (auth.currentUser != null) {
Timer(
Duration(seconds: 2),
() => Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) =>
MainScreen(user!)),
(Route<dynamic> route) => false),
);
} else {
Timer(Duration(seconds: 1),
() => Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) =>
MyHomePage() ),
(Route<dynamic> route) => false),
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _initUser(),
builder: (context, snapshot) {
if(snapshot.hasData){
//You you finish the initialization
return Text("You Get the Data");
}
//Until the data get
return Center(child: Text("Splash Screen"),);
},
),
);
}
}

Related

Undefined name '_image'. Try correcting the name to one that is defined, or defining the name

Please help.
I'm trying to display the photo captured in 'Generated1Group1Widget1.dart' to 'GeneratedResultsWidget.dart'. However, 'main.dart' is having some errors.
GeneratedGroup1Widget1.dart
class GeneratedGroup1Widget1 extends StatefulWidget {
#override
_GeneratedGroup1Widget1State createState() => _GeneratedGroup1Widget1State();
}
class _GeneratedGroup1Widget1State extends State<GeneratedGroup1Widget1> {
XFile? _image;
Future _pickImage() async {
final imageSource = await showDialog<ImageSource>(
context: context,
builder: (context) => SimpleDialog(
title: const Text('Select Image Source'),
children: [
SimpleDialogOption(
onPressed: () => Navigator.pop(context, ImageSource.camera),
child: const Text('Camera'),
),
SimpleDialogOption(
onPressed: () => Navigator.pop(context, ImageSource.gallery),
child: const Text('Gallery'),
),
],
),
);
if (imageSource != null) {
final image = await ImagePicker().pickImage(source: imageSource);
setState(() {
_image = image;
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => GeneratedResultsWidget(image: _image),
),
);
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _pickImage(),
...
GeneratedResultsWidget.dart
class GeneratedResultsWidget extends StatelessWidget {
final XFile? image;
GeneratedResultsWidget({
required this.image,
});
#override
Widget build(BuildContext context) {
return Material(
child: ClipRRect(
...
main.dart
void main() {
runApp(food_classifierApp());
}
class food_classifierApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: Size(360, 640),
builder: (BuildContext context,child) => MaterialApp(
title: 'food-classifier',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/GeneratedHomepageWidget',
routes: {
'/GeneratedScanWidget': (context) => GeneratedScanWidget(),
'/GeneratedResultsWidget': (context) => GeneratedResultsWidget(image: _image),
'/GeneratedHomepageWidget': (context) => GeneratedHomepageWidget(),
'/GeneratedFoodlistWidget': (context) => GeneratedFoodlistWidget(),
},
),
);
}
}
Error
Undefined name '_image'.
Try correcting the name to one that is defined, or defining the name.
I already searched up google but I can't find answers to my question. Thanks in advance!
Where exactly you define _image variable in your food_classifierApp class?
You should use state management to access your image or ... in every where of your app
You need to create model to store your picked image file from GeneratedGroup1Widget1.
class AppModel {
String fileName;
AppModel(this.fileName);
}
Now you can call it from GeneratedGroup1Widget1
Navigator.pushNamed(context, '/GeneratedResultsWidget',
arguments: AppModel('your file or file name'));
And recieve it here
class GeneratedResultsWidget extends StatelessWidget {
const GeneratedResultsWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments as AppModel;
return Scaffold(body: Center(child: Text(args.fileName)));
}
}
Route should be
routes: {
//***
'/GeneratedResultsWidget': (context) => GeneratedResultsWidget(),
//***
}

Passing captured image between pages in flutter

I'm having problems with my code as I'm getting undefined_identifier errors.
I'm trying to pass the image I captured from 'GeneratedGroup1Widget1.dart' using 'flutter_screenutils' to 'GeneratedResultsWidget.dart'. However, my route in 'main.dart' doesn't define the image variable inside my parameter. I've been trying to fix this error for 10 hours now. Please help. Thanks in advance!
Error: (main.dart)
Undefined name 'image'.
Try correcting the name to one that is defined, or defining the name.
Here are my codes:
'GeneratedGroup1Widget1.dart'
class GeneratedGroup1Widget1 extends StatefulWidget {
#override
_GeneratedGroup1Widget1State createState() => _GeneratedGroup1Widget1State();
}
class _GeneratedGroup1Widget1State extends State<GeneratedGroup1Widget1> {
Future _pickImage() async {
final imageSource = await showDialog<ImageSource>(
context: context,
builder: (context) => SimpleDialog(
title: const Text('Select Image Source'),
children: [
SimpleDialogOption(
onPressed: () => Navigator.pop(context, ImageSource.camera),
child: const Text('Camera'),
),
SimpleDialogOption(
onPressed: () => Navigator.pop(context, ImageSource.gallery),
child: const Text('Gallery'),
),
],
),
);
if (imageSource != null) {
final image = await ImagePicker().pickImage(source: imageSource);
Navigator.pushNamed(context, '/GeneratedResultsWidget', arguments: image);
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _pickImage(),
child: Container(
....
'GeneratedResultsWidget.dart'
class GeneratedResultsWidget extends StatelessWidget {
final XFile file;
const GeneratedResultsWidget({required Key key, required this.file})
: super(key: key);
#override
Widget build(BuildContext context) {
if (file == null) {
return Scaffold(body: Center(child: Text('No Image selected')));
} else {
return Scaffold(body: Center(child: Text(file.path)));
}
}
}
class GeneratedResultsWidget1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Material(
...
'main.dart'
void main() {
runApp(FoodClassifierApp());
}
class FoodClassifierApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ScreenUtilInit(
designSize: Size(360, 640),
builder: (BuildContext context, child) => MaterialApp(
title: 'food-classifier',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/GeneratedHomepageWidget',
routes: {
'/GeneratedScanWidget': (context) => GeneratedScanWidget(),
'/GeneratedResultsWidget': (context) =>
GeneratedResultsWidget(key: UniqueKey(), file: image),
'/GeneratedHomepageWidget': (context) => GeneratedHomepageWidget(),
'/GeneratedFoodlistWidget': (context) => GeneratedFoodlistWidget(),
},
),
);
}
}
This is my first time coding in flutter and I used figma to generate my widgets.

Sending data to other page with bloc cubit

My problem is this. I created cubit for 2 different pages. When I am on the first page, I can fill the list inside the 2nd page and I can read it from the log. However, when I go to the second page, the list I filled in from the previous page is still empty.
Main.dart
home:
MultiBlocProvider(
providers: [
BlocProvider(create: (_) => HomeCubit(PhotoService())),
BlocProvider(create: (_)=> FavoritesCubit())//Gerekiyor,homeviewda içerisindeki methoda erişmem gerekiyor
],
child: const HomeView())
HomeView.dart
where I run the function in favoritescubit and add it to the list
onTap: () {
BlocProvider.of<FavoritesCubit>(context).addFavorite(
context,
state.selectItem![index],
);
print(state.selectItem?[index].isSelected);
context.read<FavoritesCubit>().getAllFavorites();
// print("UI --- ${state.selectItem![index].isSelected}");
// context.read<FavoriteBloc>().add(
// AddFavorite(photoList, photoList.isSelected));
// print(" ispressed ${photoList.isSelected}");
},
FavoritesCubit.dart
class FavoritesCubit extends Cubit<FavoritesState> {
FavoritesCubit() : super(const FavoritesState());
final List<PhotoModel> favoriteList = <PhotoModel>[];
Future<void> getAllFavorites() async {
print("FavoriteList : ${favoriteList.length}");
emit(state.copyWith(favoriteList: favoriteList));
}
Future<void> addFavorite(
BuildContext context,
PhotoModel photo,
) async {
photo.isSelected = !photo.isSelected;
if (favoriteList.contains(photo) == false) {
favoriteList.add(photo);
emit(state.copyWith(
favoriteList: favoriteList, isFavorite: photo.isSelected));
print("${state.favoriteList!.length}asdasd");
} else if (favoriteList.contains(photo) == true) {
favoriteList.remove(photo);
emit(state.copyWith(
favoriteList: favoriteList, isFavorite: photo.isSelected));
print("${state.favoriteList!.length}asdasd");
}
FavoriteView.dart
class FavoriteView extends StatefulWidget {
const FavoriteView({Key? key}) : super(key: key);
#override
State<FavoriteView> createState() => _FavoriteViewState();
}
class _FavoriteViewState extends State<FavoriteView> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => FavoritesCubit()..getAllFavorites(),
child: Scaffold(
appBar: AppBar(
title: const Text("Bloc Example"),
),
body: buildFavoriteList(context),
),
);
}
}
Widget buildFavoriteList(BuildContext context) {
return BlocConsumer<FavoritesCubit, FavoritesState>(
listener: (context, state) {
// TODO: implement listener
},
builder: (context, state) {
return ListView.builder(
itemCount: state.favoriteList?.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: (() {
// navigateToPostDetailPage(context, photos[index]);
}),
child: Padding(
padding: const EdgeInsets.all(10),
child: PhotoListTile(
isPressed: state.favoriteList![index].isSelected,
imageUrl: state.favoriteList![index].thumbnailUrl.toString(),
title: state.favoriteList![index].title.toString(),
url: state.favoriteList![index].url.toString(),
onTap: () {
// context.read<HomeCubit>().addFavorite(
// context,
// state.favoriteList![index],
// state.favoriteList![index].isSelected);
// context
// .read<FavoriteBloc>()
// .add(RemoveFavorite(photos[index]));
},
),
),
);
});
},
);
Okey, now with your added information about your FavoriteView it is clear what the problem is.
In your FavoriteView you create a new cubit, which is not the same as you created in the MultiBlocProvider. That is why it is always empty on your FavoriteView
create: (context) => FavoritesCubit()..getAllFavorites(), // This is the issue
Make sure that your FavoriteView is a child somewhere under your MultiBlocProvider and remove the creation of a new FavoritesCubit in that view. I.e. remove the BlocProvider in your FavoriteView

Firebase auth not persisting on iOS or Android in Flutter

To start, I have gone through more than 20 different questions and solutions here on Stack Overflow about this topic (most of them are related to the web version), I have also tried twitter, and even the FlutterDev Discord server and cannot seem to find this issue.
I am using firebase for mobile authentication for my app, and no matter what I try, I cannot seem to get the persistent auth state to work on iOS or Android.
Here is my main:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MultiProvider(
...
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
final const ColorScheme colorScheme = ColorScheme(
...
);
#override
Widget build(BuildContext context) {
bool isDebug = false;
if (Constants.DEBUG_BANNER == 'true') {
isDebug = true;
}
return MaterialApp(
theme: ThemeData(
...
),
routes: {
// This is a general layout of how all my routes are in case this is the issue
Screen.route: (BuildContext context) => const Screen(),
},
home: const HomeScreen(),
debugShowCheckModeBanner: isDebug,
);
}
}
the ... is just code that I think is unrelated to my question and so I am hiding it for brevity. Mostly themes, and private data
Let's just start with my google-sign-in-button and if necessary I can share others if it is important. We are using Facebook, Google, and Apple for iOS.
class GoogleSignInButton extends StatefulWidget {
const GoogleSignInButton({Key? key}) : super(key: key);
#override
_GoogleSignInButtonState createState() => _GoogleSignInButtonState();
}
class _GoogleSignInButtonState extends State<GoogleSignInButton> {
bool _isSigningIn = false;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: _isSigningIn
? CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(MRRM.colorScheme.primary),
)
: OutlinedButton(
key: const Key('google_sign_in_button'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
),
),
onPressed: () async {
setState(() {
_isSigningIn = true;
});
context.read<Member>().signInWithGoogle(context: context).then<void>((void user) {
setState(() {
_isSigningIn = false;
});
Navigator.pushReplacementNamed(context, UserInfoScreen.route);
});
},
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Image(
image: AssetImage('assets/images/png/google_logo.png'),
height: 35.0,
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
'Sign in with Google',
style: TextStyle(
fontSize: 20,
color: MRRM.colorScheme.secondary,
fontWeight: FontWeight.w600,
),
))
],
),
),
),
);
}
}
I am using the provider pub, which is what context.read<Object?>() is from.
Here is the signInWithGoogle function;
Future<String> signInWithGoogle({required BuildContext context}) async {
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
final GoogleSignInAccount? googleSignInAccount =
await googleSignIn.signIn();
if (googleSignInAccount != null) {
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
try {
final UserCredential userCredential =
await _auth.signInWithCredential(credential);
_firebaseUser = userCredential.user!;
_authType = AuthType.Google;
_uuId = _firebaseUser.uid;
notifyListeners();
} on FirebaseAuthException catch (e) {
if (e.code == 'account-exists-with-different-credential') {
ScaffoldMessenger.of(context).showSnackBar(
customSnackBar(
content: 'The account already exists with different credentials.',
),
);
} else if (e.code == 'invalid-credential') {
ScaffoldMessenger.of(context).showSnackBar(
customSnackBar(
content: 'Error occurred while accessing credentials. Try again.',
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
customSnackBar(
content: 'Error occurred using Google Sign-In. Try again.',
),
);
}
}
return getMemberLogin();
}
This is contained in my Member object, which just stores all of the Auth data as well as the Member specific data that comes from one of our internal API's, and the member data is stored as an App State object in provider, which is linked in the main.dart file
The getMemberLogin() function is just taking the UUID from the auth and sending it to an API and getting internal member data, I would hope that a simple post request isn't what is causing this. but if you think it might let me know and I will try to post it while obfuscating any NDA related data.
This is the home/splash Screen that handles the initial routing and goes to the loadingScreen that is supposed to be checking if there is a persisted login and going to the UserInfo screen instead of the Auth Screen.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
static const String route = '/home';
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
key: const Key('Home'),
children: <Widget>[
Expanded(
child: Image.asset('assets/images/png/Retail_Rebel_Primary.png'),
),
BlinkingTextButton(
key: const Key('blinking_text_button'),
textButton: TextButton(
child: Text(
'Tap to continue',
style: TextStyle(
color: MRRM.colorScheme.primary,
fontSize: 16.0,
),
),
onPressed: () {
Navigator.of(context).pushReplacementNamed(LoadingScreen.route);
},
),
),
Container(
height: 8.0,
),
],
),
);
}
}
And lastly, this is the LoadingScreen that the HomeScreen navigates to:
class LoadingScreen extends StatelessWidget {
const LoadingScreen({Key? key}) : super(key: key);
static const String route = '/loadingScreen';
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
if (snapshot.hasData) {
print('user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
});
return const Text('');
} else {
print('no user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
});
return const Text('');
}
}
return const SplashScreen();
},
);
}
}
Not sure if possibly the way that I am handing routing may be the issue, but it is very common for me to use Navigator.of(context).pushReplacementNamed(); unless popping is necessary then I will typically just use Navigator.of(context).pop();. I usually only use .pop() for modals/alertDialogs, and for things like QR scanners to return to previous screen.
Sorry if this is too much info, or I forgot a ton of stuff. I have been working on trying to get this fixed for a little over a week now and am kind of getting frustrated.
Thank you for any and all responses.
Just because I think it is important to see what I have looked at already, here is a list of a couple of other questions I have looked through that did not help.
This one I believe is dated as of August 2020, especially considering that onAuthStateChanges has been changed to a stream authStateChanges().
I have also tried just implementing auth in the exact way described in the docs here but same issue.
I also tried just using:
FirebaseAuth.instance.authStateChanges().then((User? user) {
if (user != null) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
} else {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
}
Which didn't work. I have also attempted to just simply check if there is a current user with:
User user = FirebaseAuth.instance.currentUser;
if (user != null && user.uid != null) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
} else {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
}
which still always went to AuthScreen I have also tried all of these methods as asynchronous tasks to see if maybe it is just taking a second to load, and same issue. The weirdest one is with the current method if I take out the if(snapshot.connectionState == ConnectionState.waiting) from the LoadingScreen it will print out no user is logged in immediately followed by user is logged in and then no user is logged in again and then it will navigate to AuthScreen
If you follow what I have done up above, and make a single change, it will work with persisted logins.
change:
class LoadingScreen extends StatelessWidget {
const LoadingScreen({Key? key}) : super(key: key);
static const String route = '/loadingScreen';
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
if (snapshot.hasData) {
print('user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
});
return const Text('');
} else {
print('no user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
});
return const Text('');
}
}
return const SplashScreen();
},
);
}
}
to
class LoadingScreen extends StatelessWidget {
const LoadingScreen({Key? key}) : super(key: key);
static const String route = '/loadingScreen';
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.hasData) {
print('user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
});
return const Text('');
} else {
print('no user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
});
return const Text('');
}
}
return const SplashScreen();
},
);
}
}

This happens because you used a `BuildContext` that does not include the provider of your choice

I am Working on Flutter App Both for web and mobile and stuck at the Following Error:
======== Exception caught by widgets library =======================================================
The following ProviderNotFoundException was thrown building Products(dirty):
Error: Could not find the correct Provider<List<ProductsModel>> above this Products Widget
This happens because you used a `BuildContext` that does not include the provider
of your choice. There are a few common scenarios:
- You added a new provider in your `main.dart` and performed a hot-reload.
To fix, perform a hot-restart.
- The provider you are trying to read is in a different route.
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 Products is under your MultiProvider/Provider<List<ProductsModel>>.
This usually happens when you are creating a provider and trying to read it immediately.
For example, instead of:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// Will throw a ProviderNotFoundError, because `context` is associated
// to the widget that is the parent of `Provider<Example>`
child: Text(context.watch<Example>()),
),
}
```
consider using `builder` like so:
```
Widget build(BuildContext context) {
return Provider<Example>(
create: (_) => Example(),
// we use `builder` to obtain a new `BuildContext` that has access to the provider
builder: (context) {
// No longer throws
return Text(context.watch<Example>()),
}
),
}
```
The relevant error-causing widget was:
Products file:///E:/Flutter%20Projects/flutter_web_firebase_host/lib/screens/home/home.dart:37:63
When the exception was thrown, this was the stack:
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 236:49 throw_
packages/provider/src/provider.dart 332:7 _inheritedElementOf
packages/provider/src/provider.dart 284:30 of
packages/flutter_web_firebase_host/screens/databaseScreens/products.dart 10:31 build
packages/flutter/src/widgets/framework.dart 4569:28 build
...
====================================================================================================
Main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/model/users.dart';
import 'package:flutter_web_firebase_host/provider/product_provider.dart';
import 'package:flutter_web_firebase_host/screens/wrapper.dart';
import 'package:flutter_web_firebase_host/services/auth.dart';
import 'package:flutter_web_firebase_host/services/firestore_service.dart';
import 'package:provider/provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
final firestoreServise = FirestoreService();
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => ProductProvider(),
),
StreamProvider(
create: (context) => firestoreServise.getProducts(),
initialData: [],
),
StreamProvider<Users>.value(
value: AuthService().user,
initialData: null,
),
],
/* child: StreamProvider<Users>.value(
value: AuthService().user,
initialData: null*/
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Wrapper(),
),
);
// );
}
Product.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/model/ProductModel.dart';
import 'package:flutter_web_firebase_host/screens/databaseScreens/edit_product.dart';
import 'package:provider/provider.dart';
class Products extends StatelessWidget {
#override
Widget build(BuildContext context) {
final products = Provider.of<List<ProductsModel>>(context, listen: false);
return Scaffold(
appBar: AppBar(
title: Text('Products'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => EditProduct()));
}),
],
),
body: (products != null)
? ListView.builder(
itemCount: products.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(products[index].name),
trailing: Text(products[index].price.toString()),
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => EditProduct(products[index])));
},
);
},
)
: Center(child: CircularProgressIndicator()));
}
}
Home.dart
import 'package:flutter/material.dart';
import 'package:flutter_web_firebase_host/screens/databaseScreens/products.dart';
import 'package:flutter_web_firebase_host/services/auth.dart';
import 'package:flutter_web_firebase_host/shared/drawer.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
backgroundColor: Colors.brown[100],
appBar: AppBar(
title: Text('Brew Crew'),
backgroundColor: Colors.brown[100],
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person),
label: Text('logout'),
onPressed: () async {
await _auth.signOut();
},
),
IconButton(
icon: Icon(Icons.add, color: Colors.black),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Products()));
}),
],
),
body: SingleChildScrollView(
child: Center(
child: Column(
children: <Widget>[
Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 50, 0, 0),
child: Container(
child: Text(
'Stock Market',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
)),
),
),
Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 0, 0, 0),
child: Image.asset(
"assets/graph.jpg",
width: 500,
height: 600,
),
),
),
],
),
),
),
drawer: MyDrawer(),
),
);
}
}
product_provider.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter_web_firebase_host/model/ProductModel.dart';
import 'package:flutter_web_firebase_host/services/firestore_service.dart';
import 'package:uuid/uuid.dart';
class ProductProvider with ChangeNotifier {
final firestoreService = FirestoreService();
String _name;
double _price;
String _productId;
var uuid = Uuid();
//Geters
String get name => _name;
double get price => _price;
//Seters
changeName(String value) {
_name = value;
notifyListeners();
}
changePrice(String value) {
_price = double.parse(value);
notifyListeners();
}
loadValues(ProductsModel product) {
_name=product.name;
_price=product.price;
_productId=product.productId;
}
saveProduct() {
print(_productId);
if (_productId == null) {
var newProduct = ProductsModel(name: name, price: price, productId: uuid.v4());
firestoreService.saveProduct(newProduct);
} else {
//Update
var updatedProduct =
ProductsModel(name: name, price: _price, productId: _productId);
firestoreService.saveProduct(updatedProduct);
}
}
}
Authservise.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_web_firebase_host/model/users.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on firebase user
Users _userFromFirebaseUser(User user) {
return user != null ? Users(uid: user.uid) : null;
}
// auth change user stream
Stream<Users> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
// sign in anon
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User user = result.user;
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign in with email and password
Future signInWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.signInWithEmailAndPassword(email: email, password: password);
User user = result.user;
return user;
} catch (error) {
print(error.toString());
return null;
}
}
// register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try {
UserCredential result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
User user = result.user;
return _userFromFirebaseUser(user);
} catch (error) {
print(error.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (error) {
print(error.toString());
return null;
}
}
//sign in with google
Future<bool> loginWithGoogle() async {
try {
GoogleSignIn googleSignIn = GoogleSignIn();
GoogleSignInAccount account = await googleSignIn.signIn();
if(account == null )
return false;
UserCredential res = await _auth.signInWithCredential(GoogleAuthProvider.credential(
idToken: (await account.authentication).idToken,
accessToken: (await account.authentication).accessToken,
));
if(res.user == null)
return false;
return true;
} catch (e) {
print(e.message);
print("Error logging with google");
return false;
}
}
}
Basically my app is connect to firebase both for web app and android app. Also i send data to firestore from my app but when i click the add button to go to textfield to send data it give the error as i mention it in start. I am using multiprovider as you can see my main.dart code
Is There anything I missing. I need Help.
the way to fix this is to put MultiProvider as parent of myApp in your main like this
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => ProductProvider(),
),
StreamProvider(
create: (context) => firestoreServise.getProducts(),
initialData: [],
),
StreamProvider<Users>.value(
value: AuthService().user,
initialData: null,
),
],
child:MyApp(
));

Categories

Resources