I am trying to implement a simple login/signup screen on flutter, connected to firebase. The flow is supposed to be as follows:
- Main => Wrapper
- Wrappper => if user==NULL, then Authenticate, else Home
- Authenticate => Login or Signup
The issue is occuring in the Wrapper file. When the code is run, initially the user will be NULL and has to go to the Login screen. However, my code goes directly to the Home screen.
The codes for each file are as follows:
main.dart
void main() async {
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamProvider<MyUser>.value(
value: AuthService().user,
initialData: null,
child: MaterialApp(
home: Wrapper(),
debugShowCheckedModeBanner: false,
)
);
}
}
wrapper.dart
class Wrapper extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = Provider.of<MyUser>(context);
if (user == null) {
return Authenticate();
} else {
//return PatientHome();
}
}
}
authenticate.dart
class Authenticate extends StatefulWidget {
@override
_AuthenticateState createState() => _AuthenticateState();
}
class _AuthenticateState extends State<Authenticate> {
bool showSignIn = true;
void toggleView() {
setState(() => showSignIn = !showSignIn);
}
@override
Widget build(BuildContext context) {
if (showSignIn) {
return Login(toggleView: toggleView);
} else {
return Register(toggleView: toggleView);
}
}
}
auth.dart
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
// create user obj based on firebase user
MyUser _userFromFirebaseUser(User user) {
return user != null ? MyUser(uid: user.uid) : null;
}
// auth change user stream
Stream<MyUser> get user {
return _auth.authStateChanges()
//.map((FirebaseUser user) => _userFromFirebaseUser(user));
.map(_userFromFirebaseUser);
}
// 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 _userFromFirebaseUser(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()+"oollala");
return null;
}
}
// sign out
Future signOut() async {
try {
return await _auth.signOut();
} catch (error) {
print(error.toString());
return null;
}
}
}
register.dart
class Register extends StatefulWidget {
final Function toggleView;
Register({this.toggleView});
@override
RegisterPatient createState() => RegisterPatient();
}
class RegisterPatient extends State<Register> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
bool loading = false;
String email = '';
String password = '';
String error = '';
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.deepPurple,
elevation: 0.0,
title: Text('Register'),
actions: <Widget>[
TextButton.icon(
onPressed: () => widget.toggleView(),
icon: Icon(Icons.person),
label: Text('Register as Patient'))
],
),
body: Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 50.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
SizedBox(height: 20.0),
TextFormField(
validator: (val) => val.isEmpty ? 'Enter email' : null,
onChanged: (val) {
setState(() => email = val);
},
),
SizedBox(height: 20.0),
TextFormField(
obscureText: true,
validator: (val) => val.length < 6 ? 'Enter a password 6+ chars long' : null,
onChanged: (val) {
setState(() => password = val);
},
),
SizedBox(height: 20.0),
RaisedButton(
color: Colors.deepPurple,
child: Text(
'Register',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
if(_formKey.currentState.validate()){
setState(() => loading = true);
dynamic result = await _auth.registerWithEmailAndPassword(email, password);
if(result == null) {
setState(() {
error = 'Email/password incorrect';
loading = false;
});
} else {
Navigator.of(context).pop();
loading = false;
}
}
}
),
SizedBox(height: 12.0),
Text(
error,
style: TextStyle(color: Colors.red, fontSize: 14.0),
)
],
),
),
),
);
}
}
login.dart similar to register.dart
The issue is that whenever I run this code, it always takes me to HomePage, even though it is supposed to go through the Authenticate file as user is supposed to be NULL.
EDIT 1: I thought it was directing to Homepage rather than to Authenticate, however my screen is simply white. It does not do anything other than that. Any idea what could be the issue?
EDIT 2: The code runs like so, shows a white screen, and never terminated unless I forcibly do so. I changed from emulator to my phone, but it still the same. Any idea what could be the issue? I'm fairly new to flutter so I don't understand the error...
Launching lib\main.dart on sdk gphone x86 arm in debug mode...
Running Gradle task 'assembleDebug'...
√ Built build\app\outputs\flutter-apk\app-debug.apk.
Debug service listening on ws://127.0.0.1:64181/vsky5JbFCKM=/ws
Syncing files to device sdk gphone x86 arm...
E/flutter ( 8057): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: Null check operator used on a null value
E/flutter ( 8057): #0 MethodChannel.binaryMessenger (package:flutter/src/services/platform_channel.dart:142:86)
E/flutter ( 8057): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:148:36)
E/flutter ( 8057): #2 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:331:12)
E/flutter ( 8057): #3 MethodChannel.invokeListMethod (package:flutter/src/services/platform_channel.dart:344:41)
E/flutter ( 8057): #4 MethodChannelFirebase._initializeCore (package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart:30:37)
E/flutter ( 8057): #5 MethodChannelFirebase.initializeApp (package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart:77:13)
E/flutter ( 8057): #6 Firebase.initializeApp (package:firebase_core/src/firebase.dart:41:47)
E/flutter ( 8057): #7 main (package:hospicare_mobile/main.dart:14:18)
E/flutter ( 8057): #8 _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:142:25)
E/flutter ( 8057): #9 _rootRun (dart:async/zone.dart:1354:13)
E/flutter ( 8057): #10 _CustomZone.run (dart:async/zone.dart:1258:19)
E/flutter ( 8057): #11 _runZoned (dart:async/zone.dart:1789:10)
E/flutter ( 8057): #12 runZonedGuarded (dart:async/zone.dart:1777:12)
E/flutter ( 8057): #13 _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:138:5)
E/flutter ( 8057): #14 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:283:19)
E/flutter ( 8057): #15 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
E/flutter ( 8057):