I am creating a Login , Logout Page in flutter when i use Stream and Provider . I get Some Errors.
Help me out of this
in the main.dart when i use the StreamProvider it says the intial data cannot be null, according to my Tutorial there is no intialdata and in auth.dart when i use the authStatchanges().map it gives me 'The argument type 'Userid Function(User)' can't be assigned to the parameter type 'Userid Function(User?)'
Error Places - auth change user stream & and StreamProvider in main.dart
Thanks
Auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:wasthu/Services/user.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
//create userobject based on firebase user
Userid? _userFromFirebaseUser(User user) {
return user != null ? Userid(uid: user.uid) : null;
}
// auth change user stream
Stream<Userid> get user {
return _auth
.authStateChanges()
.map((User user) => _userFromFirebaseUser(user));
}
//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;
}
}
//signout
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:wasthu/Screens/Home/wrapper.dart';
import 'package:wasthu/Services/auth.dart';
import 'package:wasthu/Services/user.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MaterialApp(
home: MyApp(),
debugShowCheckedModeBanner: false,
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamProvider<Userid>.value(
value: AuthService().user,
initialData: null,
child: MaterialApp(
home: Wrapper(),
),
);
}
}
user.dart
class Userid {
final String uid;
Userid({required this.uid});
}
Related
Im experimenting and learning on a small project and im trying to implement an authentication workflow. Ive implemented everything and by printing my steps everything should just work fine. Im wondering why my BlocBuilder isn't going to update. The project is really small so I can provide you everything easy. Since im learning bloc, i appreciate every hint, approach and I want to thank you in advance.
terminal output when the app is starting:
flutter: building main.dart
flutter: AppLoaded()
flutter: user is NOT signed in
flutter: false
flutter: Transition { currentState: AuthInitial(), event: AppLoaded(), nextState: UnauthenticatedState() }
flutter: block says user is NOT authenticated
This is completely fine since im checking at the beginning if there is any user data valid. Now when I press on the Login Textbutton in my home.dart my Blocbuilder should show that im logged in, but it doesnt. This is the terminal output:
flutter: AppLoaded()
flutter: signed id with credentials: User{id: 1, socketId: 123, userName: Logged in User}
flutter: user is signed in
flutter: true
flutter: currentuser is not empty: User{id: 1, socketId: 123, userName: Logged in User}
flutter: Transition { currentState: AuthInitial(), event: AppLoaded(), nextState: AuthenticatedState() }
flutter: block says user is authenticated
main.dart
import 'package:fl_auth/bloc/auth/auth_bloc.dart';
import 'package:fl_auth/repositories/user_repository.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'bloc/bloc_observer.dart';
import 'home.dart';
import 'models/auth.dart';
void main() {
BlocOverrides.runZoned(
() {
runApp(const MyApp());
},
blocObserver: SimpleBlocObserver(),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Auth _auth = Auth.instance;
UserRepository _userRepository = UserRepository(auth: _auth);
print('building main.dart');
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BlocProvider(
create: (context) =>
AuthBloc(userRepository: _userRepository)..add(AppLoaded()),
child: Home(),
),
);
}
}
home.dart
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'bloc/auth/auth_bloc.dart';
import 'models/auth.dart';
import 'repositories/user_repository.dart';
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
Auth _auth = Auth.instance;
UserRepository _userRepository = UserRepository(auth: _auth);
AuthBloc authBloc = AuthBloc(userRepository: _userRepository);
return Scaffold(
body: SizedBox(
height: 500,
child: Column(
children: [
Container(
height: 200,
child: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is UnauthenticatedState) {
return Center(child: Text('User is unauthenticated'));
} else if (state is AuthenticatedState) {
return Center(child: Text('YEAH logged in!'));
} else {
return Center(child: Text('something went wrong'));
}
}),
),
TextButton(
onPressed: () => {
authBloc.userRepository.signIn(),
authBloc.add(AppLoaded())
},
child: Text('Login')),
],
)));
}
}
auth_event.dart
part of 'auth_bloc.dart';
abstract class AuthEvent extends Equatable {
const AuthEvent();
#override
List<Object> get props => [];
}
class AppLoaded extends AuthEvent {}
auth_state.dart
// ignore_for_file: public_member_api_docs, sort_constructors_first
part of 'auth_bloc.dart';
abstract class AuthState extends Equatable {
const AuthState();
#override
List<Object> get props => [];
}
class AuthInitial extends AuthState {}
class AuthenticatedState extends AuthState {
User user;
AuthenticatedState({
required this.user,
});
}
class UnauthenticatedState extends AuthState {}
auth.bloc
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:fl_auth/repositories/user_repository.dart';
import '../../models/user.dart';
part 'auth_event.dart';
part 'auth_state.dart';
class AuthBloc extends Bloc<AuthEvent, AuthState> {
UserRepository userRepository;
AuthBloc({required this.userRepository}) : super(AuthInitial()) {
on<AppLoaded>((event, emit) async {
try {
var isSignedIn = await userRepository.isSignedIn();
print(isSignedIn);
if (isSignedIn) {
var user = await userRepository.getCurrentUser();
emit(AuthenticatedState(user: user));
print('block says user is authenticated');
} else {
emit(UnauthenticatedState());
print('block says user is NOT authenticated');
}
} catch (e) {
emit(UnauthenticatedState());
}
});
}
}
user_repository.dart
import 'package:fl_auth/models/user.dart';
import '../models/auth.dart';
class UserRepository {
Auth auth = Auth.instance;
UserRepository({required this.auth});
// sign in with username
//TODO: change hardcoded username to email and passwort later on
Future<User> signIn() async {
try{
await Future.delayed(Duration(seconds: 1));
var credentials = User(id: 1, socketId: '123', userName: 'Logged in User');
print('signed id with credentials: ${auth.currentUser}');
auth.currentUser = credentials;
return auth.currentUser;
}catch(e){
print(e.toString());
throw e;
}
}
// check signed in status
Future<bool> isSignedIn() async {
try{
await Future.delayed(const Duration(seconds: 1));
var currentUser = auth.currentUser;
if(currentUser.isNotEmpty){
print('user is signed in');
return true;
} else {
print('user is NOT signed in');
return false;
}
}catch(e){
print(e.toString());
throw e;
}
}
// get user
Future<User> getCurrentUser() async {
try{
await Future.delayed(const Duration(seconds: 1));
var currentUser = auth.currentUser;
if(currentUser.isNotEmpty){
print('currentuser is not empty: $currentUser');
return currentUser;
} else {
var message = 'User is empty';
print('currentuser IS empty: $currentUser');
throw message;
}
}catch(e){
print(e.toString());
throw e;
}
}
}
auth.dart
import 'user.dart';
class Auth {
/// private constructor
Auth._();
/// the one and only instance of this singleton
static final instance = Auth._();
//ChatBloc chatBloc = ChatBloc(DatabaseApi.db);
// Create a User instance. Actually it would be better if this is empty so I can notice if a user is valid or not and can react by checking if the user has values and
// if not log the user out later on
User currentUser = User.empty;
}
user.dart
import 'package:equatable/equatable.dart';
/// {#template user}
/// User model
///
/// [User.empty] represents an unauthenticated user.
/// {#endtemplate}
class User extends Equatable {
/// {#macro user}
const User({
required this.id,
this.socketId,
this.userName,
});
/// The current user's scoket id.
final String? socketId;
/// The current user's id.
final int id;
/// The current user's name (display name).
final String? userName;
/// Empty user which represents an unauthenticated user.
static const empty = User(id: 0);
/// Convenience getter to determine whether the current user is empty.
bool get isEmpty => this == User.empty;
/// Convenience getter to determine whether the current user is not empty.
bool get isNotEmpty => this != User.empty;
#override
List<Object?> get props => [id, socketId, userName];
// Convert a user into a Map. The keys must correspond to the names of the
// columns in the database.
Map<String, dynamic> toMap() {
return {
'id': id,
'socketId': socketId,
'userName': userName,
};
}
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id'] as int,
socketId: map['socketId'] as String,
userName: map['userName'] as String,
);
}
// Implement toString to make it easier to see information about
// each user when using the print statement.
#override
String toString() {
return 'User{id: $id, socketId: $socketId, userName: $userName}';
}
}
The issue is In your OnTap Function you can call Event like this. I have checked and It's working as expected.
TextButton(
onPressed: () => {
authBloc.userRepository.signIn(),
context.read<AuthBloc>().add(AppLoaded())
},
child: const Text('Login')),
Firebase Auth is working properly, I'm able to log in, Sign in but I want to preserve the state of the application. For state persistence, I'm using Share preferences.
I'm using sharedpreferences. I made a class and defined some keys and methods to fetch and set the data in the keys at the time of login and use it later in the app.
Please help me out with an easy approch how to do this.
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class CurrentUser {
static SharedPreferences? mypreferences;
static const emailKey = 'emailKey';
static const passwordKey = 'paswordKey';
static const loginStatusKey = 'loginStatusKey';
static Future init() async {
mypreferences = await SharedPreferences.getInstance();
}
static Future setUserEmail(String? emailValue) async {
return await mypreferences?.setString(emailKey, emailValue!);
}
static Future setUserPassword(String? passwordValue) async {
return await mypreferences?.setString(passwordKey, passwordValue!);
}
static Future setLoginStatus(bool status) async {
return await mypreferences?.setBool(loginStatusKey, status);
}
static String? getUserEmail() {
return mypreferences?.getString(emailKey);
}
static String? getUserPassword() {
return mypreferences?.getString(passwordKey);
}
static bool? getUserLoginStatus(){
if(loginStatusKey==null){
mypreferences?.setBool(loginStatusKey, false);
}
return mypreferences?.getBool(loginStatusKey);
}
}```
// storing the value during login //
``` myLogIn() async {
try {
UserCredential myuser= await FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password);
// print(myuser);
// print(myuser.user?.email);
CurrentUser.setUserEmail(myuser.user?.email);
CurrentUser.setUserPassword(password);
CurrentUser.setLoginStatus(true);
Navigator.pushReplacementNamed(context, MyRoutes.homeRoute);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('user is not registered');
ScaffoldMessenger.of(context).showSnackBar(
MySnackBar.showcustomSnackbar('user is not registered'));
} else if (e.code == 'wrong-password') {
print('wrong password');
ScaffoldMessenger.of(context)
.showSnackBar(MySnackBar.showcustomSnackbar('wrong password'));
}
}
}```
// using the store login status in main file to show login page and home page accordingly.
```import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
// import 'firebase_options.dart';
import './pages/login.dart';
import './pages/signup.dart';
import './pages/homepage.dart';
import './utils/my_theme.dart';
import './utils/my_routes.dart';
import './pages/forgot_password.dart';
import './utils/my_user.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
CurrentUser.init();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// const MyApp({ Key? key }) : super(key: key);
final Future<FirebaseApp> initializeMyFirebaseApp = Firebase.initializeApp();
bool? isLogin = CurrentUser.getUserLoginStatus();
#override
void initState() {
// TODO: implement initState
isLogin = CurrentUser.getUserLoginStatus();
super.initState();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: initializeMyFirebaseApp,
builder: (context, snaphot) {
//Error checking
if (snaphot.hasError) {
print("Something went wrong!");
}
//If snapshot state is in waiting or so
if (snaphot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
//else we will show the normal login page.
return MaterialApp(
theme: MyTheme.lightTheme(context),
//isUserLoggedIn !=null ? isUserLoggedIn ? Home() : SignUp() : SignIn(),
home:isLogin!=null ?
isLogin! ? HomePage() : Login() : Login(),
// Login(),
routes: {
// "/":(context) => Login(),
MyRoutes.loginRoute: (context) => Login(),
MyRoutes.signupRoute: (context) => SignUp(),
MyRoutes.homeRoute: (context) => HomePage(),
MyRoutes.forgotpasswordRoute: (context) => ForgotPassword(),
},
);
});
}
}
```
I'm create a project on Flutter. And I'm using a provider to change screens in my app.
Here is my main.dart file:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/services/auth_service.dart';
import 'package:school_app/wrapper.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthService().auth,
child: MaterialApp(
home: Wrapper(),
),
);
}
}
Also this is my wrapper.dart file where the screens choose:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/screens/authenticate/auth.dart';
import 'package:school_app/models/user.dart';
import 'package:school_app/screens/school/home.dart';
import 'package:school_app/services/auth_service.dart';
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<AuthProvider>(context);
print(user.auth);
if(!user.auth) return Auth();
return Home();
}
}
And it is my AuthProvider class:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthService {
/* AuthUser _user(User user) {
return user != null ? AuthUser(uid: user.uid) : null;
}*/
AuthProvider auth = new AuthProvider();
//sign in
Future signIn(String username, String password) async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
var dio = Dio();
Response user = await dio.post('url', data: {
'username': username,
'password': password
});
if(user.data['success'] == false) return user.data['msg'];
await prefs.setString('token', user.data['token']);
auth.setAuth(true);
print("SUCCESS");
} catch(e) {
print('Error ' + e.toString());
}
}
}
class AuthProvider with ChangeNotifier {
bool _auth;
AuthProvider() {
_auth = false;
}
bool get auth => _auth;
void setAuth(bool auth) {
_auth = auth;
notifyListeners();
}
}
And when I call a function in AuthProvider class setAuth, nothing changed. Can you help me and find my mistake?
EDIT
I'm making all changes that you writes but it is not working. Here is my main.dart:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/services/auth_service.dart';
import 'package:school_app/wrapper.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthProvider(),
child: MaterialApp(
home: Wrapper(),
),
);
}
}
Also wrapper.dart:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/screens/authenticate/auth.dart';
import 'package:school_app/screens/school/home.dart';
import 'package:school_app/services/auth_service.dart';
class Wrapper extends StatefulWidget {
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
#override
void initState() {
// TODO: implement initState
super.initState();
AuthService().auth;
}
#override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(builder: (context, authProvider, child) {
print(authProvider.auth);
if (!authProvider.auth) {
return Auth();
} else {
return Home();
}
});
}
}
And AuthService and AuthProvider classes:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthService {
/* AuthUser _user(User user) {
return user != null ? AuthUser(uid: user.uid) : null;
}*/
AuthProvider auth = new AuthProvider();
//sign in
Future signIn(String username, String password) async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
var dio = Dio();
Response user = await dio.post('url', data: {
'username': username,
'password': password
});
if(user.data['success'] == false) return user.data['msg'];
await prefs.setString('token', user.data['token']);
auth.setAuth(true);
print("SUCCESS");
} catch(e) {
print('Error ' + e.toString());
}
}
}
class AuthProvider with ChangeNotifier {
bool _auth;
AuthProvider() {
_auth = false;
}
bool get auth => _auth;
void setAuth(bool auth) {
_auth = auth;
notifyListeners();
}
}
Notice, that here two classes and in AuthService I'm calling function .setAuth(true).
In your current implementation of Wrapper, you are rendering the widget once and not listening to whether the values changed. You could use Consumer as suggested above. You could also choose to watch the value for changes - like this:
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = context.watch<AuthProvider>();
print(user.auth);
if(!user.auth) return Auth();
return Home();
}
}
When you use a watch or Consumer pattern, the widget will be rendered when the values of the underlying store (which is AuthProvider here) gets changed.
The only missing part here is that you never Consume the AuthProvider to listen to the notifyListeners() trigger.
The correct implementation looks like the following (I didn't try it, you may have to correct some typo errors, but you'll get the idea !)
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(
builder: (context, authProvider, child) {
if (!authProvider.auth) {
return Auth();
} else {
return Home();
}
}
);
}
}
EDIT
I didn't notice you weren't injecting the right Class in your ChangeNotifierProvider. You'll also have to update your widget MyApp
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthProvider(),
child: MaterialApp(
home: Wrapper(),
),
);
}
And in this case you probably should transform your Wrapper widget to a Stateful widget, and in the initState method you should call AuthService().auth.
I strongly recommend you to read the official documentation of Provider, looks like things aren't crystal clear yet in your mind
EDIT 2
You're still missing the point of the Provider library.
The goal of this lib is to provide an instance of a class to your widget tree so you don't have to re-create an instance in each widget.
Here, in AuthService class you're re-creating a AuthProvider with AuthProvider auth = new AuthProvider(); instead of referring to the existing instance created in the parent Widget.
To refer to a previously created instance, you should use Provider.of<AuthProvider>(context); in the AuthService class, or, even better, pass the instance of AuthProvider as a parameter in the signIn method.
I'm trying to navigate to a screen where depending on 3 factors:
If the app has run before or not
If the user is null or not
If the email is verified or not.
import 'package:client/providers/auth_provider.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../screens/home_screen.dart';
import '../screens/login_screen.dart';
class Wrapper extends StatefulWidget {
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
FirebaseAuth auth = FirebaseAuth.instance;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext ctx) {
return FutureBuilder(
future: hasAlreadyStarted(),
builder: (ctx, snapshot) {
return Provider.of<User>(ctx) != null &&
snapshot.data == true &&
AuthProvider().isEmailVerified
? HomeScreen()
: LoginScreen();
});
}
Future<bool> hasAlreadyStarted() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
try {
if (prefs.getBool("hasRun") == null) {
await AuthProvider().logout();
setState(() {
prefs.setBool("hasRun", true);
});
return true;
} else {
return true;
}
} catch (error) {
setState(() {
prefs.setBool("hasRun", null);
});
return false;
}
}
}
The screen works fine on it's own, but when i Navigate from a different screen it gives me the error.
Could not find the correct Provider<User> above this FutureBuilder<bool> Widget
Can you explain the error and give me a solution. Thanks :D
I just needed to wrap the entire MaterialApp with the StreamProvider
I am trying to auto login a user if they haven't expressly signed out from the app. I am using firebase for authentication and provider package from pub to monitor the auth status changes.
I have a service dart file (originally from TheNetNinja tutorials) which exposes a stream and wrapped the main.dart file with a stream provider. As I understand that in provider 4.0.1, one can no longer use .value and supply the value like below:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return StreamProvider<User>.value(
value: AuthService().user,
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Brewzz',
home: Wrapper(),
),
);
}
}
but to change to something of this sort, using create instead of value like below:
class FoodMart extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return StreamProvider(
create: (_) => AuthService().user,
child: MaterialApp(
title: 'Flutter Demo',
onGenerateRoute: Router.generateRoute,
home: Landing(),
),
);
}
}
I have closed and re-opened the app but still not re-directing to home page. Am I doing this wrong?
Here's the implementation of AuthService.dart class:
import 'dart:async';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:food_mart/models/users.dart';
import 'package:food_mart/services/database.dart';
class AuthService {
FirebaseAuth _mAuth = FirebaseAuth.instance;
Stream<User> get user {
return _mAuth.onAuthStateChanged.map(_mapUserFromFirebase);
}
User _mapUserFromFirebase(FirebaseUser firebaseUser) {
return firebaseUser != null ? User(userId: firebaseUser.uid) : null;
}
Future createUser(String email, String pwd, String role) async{
try {
AuthResult result = await _mAuth.createUserWithEmailAndPassword(email: email, password: pwd);
FirebaseUser firebaseUser = result.user;
await DatabaseService(userId: firebaseUser.uid).setUserData(email: email, role: role);
return _mapUserFromFirebase(firebaseUser);
} catch(e){
print(e.toString());
return e;
}
}
Future loginUser(String email, String pwd) async{
try {
AuthResult authResult = await _mAuth.signInWithEmailAndPassword(email: email, password: pwd);
FirebaseUser firebaseUser = authResult.user;
return _mapUserFromFirebase(firebaseUser);
} catch(e){
print(e.toString());
return null;
}
}
Future signOut() async {
try {
return await _mAuth.signOut();
} catch(e){
print(e.toString());
return null;
}
}
}
The User model has been left out for brevity. Any suggestions please? Thanks
I had a similar issue but the code above works.
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
if(user == null){
return Landing();
}else{
return Index();
}
}
}
Just like you it didn't change the page for me. Turns out the code was working all along, only I was logging in the user from another page called LoginWithEmail which was pushed into the stack on a button event from the Landing class. I just did a Navigator.pop() on LoginWithEmail after logging in to realize that the Wrapper class changed into Index.
//code call inside login button onpressed from LoginWithEmail class
AuthService _authService = AuthService();
_authService.loginUser(email, password).then((value) {
User user = value;
if(user!=null){
Navigator.pop();
}
}