iamshaunjp / flutter-firebase

All course files for the Flutter & Firebase tutorial playlist on The Net Ninja YouTube channel
580 stars 441 forks source link

Provider listener does update wrapper widget #37

Closed mansbjorn closed 2 years ago

mansbjorn commented 2 years ago

I have been following the netninja tutorial on Firebase Auth but I have run into a problem. My signing is working well and the listener in my wrapper send the user directly to my homepage after signing in. However, my register page doesnt send the user onwards despite successfull registration. I have to update with hotrestart for the homescreen to appear.

Any and all help on this would be appreciated.

Here is my registration page:

class SignUpWidget extends StatefulWidget {
  @override
  SignUpState createState() => SignUpState();
}

class SignUpState extends State<SignUpWidget> {
  final AuthService _auth = AuthService();
  final _formKey = GlobalKey<FormState>();
  String error = '';
  bool loading = false;

  // text field state
  String displayName = '';
  String email = '';
  String password = '';

  @override
  Widget build(BuildContext context) {
    return loading
        ? Loading()
        : Scaffold(
            backgroundColor: const Color.fromARGB(255, 69, 90, 100),
            key: _mainScaffoldKey,
            body: SafeArea(
              child: Container(
                alignment: Alignment.center,
                padding: const EdgeInsets.only(top: 40, left: 20, right: 20),
                child: Column(
                  children: <Widget>[
                    Card(
                      elevation: 2.0,
                      color: Colors.white,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(8.0),
                      ),
                      child: Form(
                        key: _formKey,
                        child: Column(
                          children: <Widget>[
                            Container(
                              padding:
                                  const EdgeInsets.only(top: 30, bottom: 30),
                              child: const Icon(
                                FontAwesomeIcons.bookOpen,
                                size: 60,
                                color: Color.fromARGB(255, 69, 90, 100),
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.only(
                                top: 1.0,
                                bottom: 1.0,
                                left: 25.0,
                                right: 25.0,
                              ),
                              child: TextFormField(
                                validator: (val) =>
                                    val!.isEmpty ? 'Enter your name' : null,
                                onChanged: (val) {
                                  setState(() => displayName = val);
                                },
                                style: const TextStyle(
                                  fontFamily: "Montserrat",
                                  fontSize: 16.0,
                                  color: Colors.black,
                                ),
                                decoration: const InputDecoration(
                                  border: InputBorder.none,
                                  icon: Icon(
                                    FontAwesomeIcons.solidUser,
                                    color: Color.fromARGB(255, 69, 90, 100),
                                    size: 22.0,
                                  ),
                                  hintText: "Enter name",
                                  hintStyle: TextStyle(
                                    fontFamily: "Montserrat",
                                    fontSize: 18.0,
                                  ),
                                ),
                              ),
                            ),
                            Container(
                              width: 250.0,
                              height: 1.0,
                              color: Colors.grey,
                            ),
                            Padding(
                              padding: const EdgeInsets.only(
                                top: 5.0,
                                bottom: 5.0,
                                left: 25.0,
                                right: 25.0,
                              ),
                              child: TextFormField(
                                validator: (val) =>
                                    val!.isEmpty ? 'Enter your email' : null,
                                onChanged: (val) {
                                  setState(() => email = val);
                                },
                                style: const TextStyle(
                                  fontFamily: "Montserrat",
                                  fontSize: 16.0,
                                  color: Colors.black,
                                ),
                                decoration: const InputDecoration(
                                  border: InputBorder.none,
                                  icon: Icon(
                                    FontAwesomeIcons.solidEnvelope,
                                    color: Color.fromARGB(255, 69, 90, 100),
                                    size: 22.0,
                                  ),
                                  hintText: "Enter email",
                                  hintStyle: TextStyle(
                                    fontFamily: "Montserrat",
                                    fontSize: 18.0,
                                  ),
                                ),
                              ),
                            ),
                            Container(
                              width: 250.0,
                              height: 1.0,
                              color: Colors.grey,
                            ),
                            Padding(
                              padding: const EdgeInsets.only(
                                top: 5.0,
                                bottom: 5.0,
                                left: 25.0,
                                right: 25.0,
                              ),
                              child: TextFormField(
                                validator: (val) => val!.length < 6
                                    ? 'Enter a password 6+ chars long'
                                    : null,
                                obscureText: true,
                                onChanged: (val) {
                                  setState(() => password = val);
                                },
                                style: const TextStyle(
                                  fontFamily: "Montserrat",
                                  fontSize: 16.0,
                                  color: Colors.black,
                                ),
                                decoration: const InputDecoration(
                                  border: InputBorder.none,
                                  icon: Icon(
                                    FontAwesomeIcons.lock,
                                    color: Color.fromARGB(255, 69, 90, 100),
                                    size: 22.0,
                                  ),
                                  hintText: "Enter password",
                                  hintStyle: TextStyle(
                                    fontFamily: "Montserrat",
                                    fontSize: 18.0,
                                  ),
                                ),
                              ),
                            ),
                            Container(
                              width: 250.0,
                              height: 1.0,
                              color: Colors.grey,
                            ),
                            Container(
                              margin: const EdgeInsets.only(top: 40.0),
                              decoration: const BoxDecoration(
                                borderRadius:
                                    BorderRadius.all(Radius.circular(5.0)),
                                boxShadow: <BoxShadow>[
                                  BoxShadow(
                                    color: AppColours.colorStart,
                                    offset: Offset(1.0, 6.0),
                                    blurRadius: 20.0,
                                  ),
                                  BoxShadow(
                                    color: AppColours.colorEnd,
                                    offset: Offset(1.0, 6.0),
                                    blurRadius: 20.0,
                                  ),
                                ],
                                gradient: LinearGradient(
                                  colors: [
                                    AppColours.colorEnd,
                                    AppColours.colorStart
                                  ],
                                  begin: FractionalOffset(0.2, 0.2),
                                  end: FractionalOffset(1.0, 1.0),
                                  stops: [0.1, 1.0],
                                  tileMode: TileMode.clamp,
                                ),
                              ),
                              child: MaterialButton(
                                highlightColor: Colors.transparent,
                                splashColor: AppColours.colorEnd,
                                child: const Padding(
                                  padding: EdgeInsets.symmetric(
                                    vertical: 10.0,
                                    horizontal: 42.0,
                                  ),
                                  child: Text(
                                    "Register",
                                    style: TextStyle(
                                      fontFamily: "Montserrat-bold",
                                      color: Colors.white,
                                      fontSize: 22.0,
                                    ),
                                  ),
                                ),
                                onPressed: () async {
                                  if (_formKey.currentState!.validate()) {
                                    setState(() => loading = true);
                                    dynamic result = await _auth
                                        .registerWithEmailandPassword(
                                            displayName, email, password);
                                    if (result == null) {
                                      setState(() {
                                        error = 'please supply a valid email';
                                        loading = false;
                                      });
                                    }
                                  }
                                },
                              ),
                            ),
                            SizedBox(
                              height: 20,
                            ),
                            Text(
                              error,
                              style: TextStyle(
                                color: Colors.red,
                                fontSize: 14,
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.only(top: 20),
                              child: Row(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: <Widget>[
                                  Container(
                                    decoration: const BoxDecoration(
                                      gradient: LinearGradient(
                                        colors: [
                                          Colors.black12,
                                          Colors.black,
                                        ],
                                        // ignore: use_named_constants
                                        begin: FractionalOffset(0.0, 0.0),
                                        // ignore: use_named_constants
                                        end: FractionalOffset(1.0, 1.0),
                                        stops: [0.0, 1.0],
                                        tileMode: TileMode.clamp,
                                      ),
                                    ),
                                    width: 100.0,
                                    height: 1.0,
                                  ),
                                  const Padding(
                                    padding: EdgeInsets.only(
                                        left: 15.0, right: 15.0),
                                    child: Text(
                                      "Or register with",
                                      style: TextStyle(
                                        color: Colors.black,
                                        decoration: TextDecoration.none,
                                        fontSize: 16.0,
                                        fontFamily: "Montserrat",
                                      ),
                                    ),
                                  ),
                                  Container(
                                    decoration: const BoxDecoration(
                                      gradient: LinearGradient(
                                        colors: [
                                          Colors.black,
                                          Colors.black12,
                                        ],
                                        begin: FractionalOffset(0.0, 0.0),
                                        end: FractionalOffset(1.0, 1.0),
                                        stops: [0.0, 1.0],
                                        tileMode: TileMode.clamp,
                                      ),
                                    ),
                                    width: 100.0,
                                    height: 1.0,
                                  ),
                                ],
                              ),
                            ),
                            Padding(
                              padding: const EdgeInsets.only(
                                top: 20,
                                bottom: 20,
                              ),
                              child: Row(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceEvenly,
                                children: <Widget>[
                                  GestureDetector(
                                    onTap: () => {},
                                    child: Container(
                                      child: const Icon(
                                        FontAwesomeIcons.facebook,
                                        color: Color(0xFF0084ff),
                                        size: 60,
                                      ),
                                    ),
                                  ),
                                  GestureDetector(
                                    onTap: () => {},
                                    child: Container(
                                      child: const Icon(
                                        FontAwesomeIcons.instagram,
                                        color: Color.fromARGB(255, 240, 58, 83),
                                        size: 60,
                                      ),
                                    ),
                                  ),
                                  GestureDetector(
                                    onTap: () => {},
                                    child: Container(
                                      child: const Icon(
                                        FontAwesomeIcons.twitter,
                                        color: Color(0xFF0084ff),
                                        size: 60,
                                      ),
                                    ),
                                  ),
                                  GestureDetector(
                                    onTap: () => {},
                                    child: Container(
                                      padding: const EdgeInsets.only(top: 5),
                                      child: const Image(
                                        height: 50,
                                        width: 50,
                                        image: AssetImage(
                                            'images/google_logo.png'),
                                      ),
                                      //FontAwesomeIcons.google,
                                      //color: const Color(0xFF0084ff),
                                      //size: 60,
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          );
  }
}

Here is my wrapper:

class Wrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final user = Provider.of<User?>(context);

    //return either homepage or Login widget
    if (user == null) {
      return LoginWidget();
    } else {
      return HomePage();
    }
  }
}

Here is my main:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(App());
}

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  final Future<FirebaseApp> _initialization = Firebase.initializeApp();

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _initialization,
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          return const SomethingWentWrong();
        }
        if (snapshot.connectionState == ConnectionState.done) {
          return const MyApp();
        }
        return const CircularProgressIndicator();
      },
    );
  }
}

class SomethingWentWrong extends StatelessWidget {
  const SomethingWentWrong({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        children: const <Widget>[
          Text('something went wrong!'),
        ],
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StreamProvider<User?>.value(
      value: AuthService().user,
      initialData: null,
      child: MaterialApp(
        title: 'The Book Club',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          canvasColor: const Color.fromARGB(255, 207, 216, 220),
          fontFamily: 'Montserrat-SemiBold',
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: Wrapper(),
      ),
    );
  }
}

and finally here is my auth:

class AuthService {
  final FirebaseAuth _auth = FirebaseAuth.instance;

  //auth change user stream
  Stream<User?> get user {
    return _auth.authStateChanges();
  }

  //sign in with email and password
  Future logInWithEmailandPassword(String email, String password) async {
    try {
      UserCredential result = await _auth.signInWithEmailAndPassword(
          email: email, password: password);
      User? user = result.user;
      return user;
    } catch (e) {
      print(e.toString());
      return null;
    }
  }

  //register with email and password
  Future registerWithEmailandPassword(
      String name, String email, String password) async {
    try {
      UserCredential result = await _auth.createUserWithEmailAndPassword(
          email: email, password: password);
      User? user = result.user;
      return user;
    } catch (e) {
      print(e.toString());
      return null;
    }
  }

  //sign out
  Future signOut() async {
    try {
      return await _auth.signOut();
    } catch (e) {
      print(
        e.toString(),
      );
      return null;
    }
  }
}

let me know if more files/details are necessary in order to answer my question, I cannot understand why it is not loading the homepage properly.

mansbjorn commented 2 years ago

I solved this by using the authenticate widget properly, like this:

import 'package:flutter/material.dart';
import 'package:the_book_club/UI/login_logout/login_widget.dart';
import 'package:the_book_club/UI/login_logout/signup_widget.dart';

class Authenticate extends StatefulWidget {
  @override
  _AuthenticateState createState() => _AuthenticateState();
}

class _AuthenticateState extends State<Authenticate> {
  bool showLogIn = true;
  void toggleView() {
    setState(() => showLogIn = !showLogIn);
  }

  @override
  Widget build(BuildContext context) {
    if (showLogIn) {
      return LoginWidget(toggleView: toggleView);
    } else {
      return SignUpWidget(toggleView: toggleView);
    }
  }
}