1

I am trying to implement a simple login/signup screen on flutter, connected to firebase. The flow is supposed to be as follows:

  1. Main => Wrapper
  2. Wrappper => if user==NULL, then Authenticate, else Home
  3. 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): 
hek18
  • 57
  • 1
  • 8

1 Answers1

0

I think using shared preferences might help for saving some data inside the app even though the app is closed or restarted by the user .Even you can retrieve it again and if it has something in it you can navigate to homepage , if it is null you can navigate to authenticate page.

Visit : https://pub.dev/packages/shared_preferences

Follow the steps to use it: Add the following inside your authenticate page or signin page

   SharedPreferences 
   data=awaitSharedPreferences.getInstance();
   data.setString('your_key',your_data);

Add the following inside the main function before runapp function and make the main function as async

SharedPreferences data = await 
SharedPreferences.getInstance();
var your_variable = data.getString('your_key');
Saffron-codes
  • 158
  • 1
  • 9
  • Could you please guide me how to implement it in the code? I'm fairly new to flutter dev – hek18 Jun 23 '21 at 12:50
  • thank you for the detailed answer! I tried but this did not work :/ I edited in my error to the end of the question, do you know what could possibly be wrong? – hek18 Jun 24 '21 at 05:03