首页 > 解决方案 > 根据是新登录用户还是返回用户在 Flutter 中导航屏幕

问题描述

注册后,我希望用户被带到 WelcomeScreen() 并在登录后被带到 Sessions()。但是,以我的根页面当前的结构方式,实现起来有点困难。

我怎样才能做到这一点?请参阅下面的代码片段和说明。

在我的 main.dart 文件中,我的 RootPage 设置为 initialRoute。RootPage 检查是否存在有效会话并因此重定向到 PaymentScreen,否则重定向到处理登录和注销视图的 Sessions.dart。

//root_page.dart
// ignore: must_be_immutable
class RootPage extends StatelessWidget {
  static const String id = 'root_page';

  Widget buildWaitingScreen() {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
      ),
    );
  }

  @override
  // ignore: missing_return
  Widget build(BuildContext context) {
    final BaseAuth auth = AuthProvider.of(context).auth;
    return StreamBuilder<String>(
      stream: auth.onAuthStateChanged,
      builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
        if (snapshot.connectionState == ConnectionState.active) {
          final bool isLoggedIn = snapshot.hasData;

          return isLoggedIn ? WelcomeEmail() : Sessions();
//          return isLoggedIn ? PaymentScreen() : Sessions();
        }
        return buildWaitingScreen();
      },
    );
  }
}

我的 AuthProvider...

class AuthProvider extends InheritedWidget {
  AuthProvider({
    Key key,
    @required this.auth,
    @required Widget child,
  })  : assert(auth != null),
        assert(child != null),
        super(key: key, child: child);

  final BaseAuth auth;

  @override
  bool updateShouldNotify(AuthProvider old) => auth != old.auth;

  //this static class allows us to access AuthProvider anywhere in our code using AuthProvider.of(context).auth
  static AuthProvider of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<AuthProvider>();
  }
}

我的 auth.dart

abstract class BaseAuth {
  Stream<User> get user;
  Stream<String> get onAuthStateChanged;
  Future<String> handleSignIn(String email, String password);
  Future<String> handleSignUp(String email, String password);
  Future<String> currentUser();
}

class Auth implements BaseAuth {
  final _auth = FirebaseAuth.instance;

  //create a new user object based on FirebaseUser
  User _userFromFirebaseUser(FirebaseUser user) {
    return user != null ? User(uid: user.uid) : null;
  }

  //auth change user stream
  Stream<User> get user {
    return _auth.onAuthStateChanged.map(_userFromFirebaseUser);
  }

  @override
  Stream<String> get onAuthStateChanged {
    return _auth.onAuthStateChanged.map((user) => user?.uid);
  }

  //sign in with email and password
  Future<String> handleSignIn(String email, String password) async {
    AuthResult result = await FirebaseAuth.instance
        .signInWithEmailAndPassword(email: email, password: password)
        .catchError((error) => print(error));

    if (result != null) {
      FirebaseUser user = result.user;
      if (user != null) {
        print('From handleSignIn, Log in: ${user.email}');
      }
      return user.uid;
    }
  }

  //sign up with email and password
  Future<String> handleSignUp(String email, String password) async {
    AuthResult result = await FirebaseAuth.instance
        .createUserWithEmailAndPassword(email: email, password: password)
        .catchError((error) => print(error));
    FirebaseUser user = result.user;
    if (user != null) {
      print('From handleSignUp, New user email: ${user.email}');
    }

    return user.uid;
  }
}

我的 session.dart 文件

class Sessions extends StatefulWidget {
  static const String id = 'sessions';

  @override
  _SessionsState createState() => _SessionsState();
}

enum SessionType { signIn, signUp, reset }

class _SessionsState extends State<Sessions> {
  String email, password, _warning;

  bool showSpinner = false;
  final _formKey = GlobalKey<FormState>();
  var args;

  SessionType _sessionType = SessionType.signIn;

  setArguments(args) async {
    _sessionType = args[0];
  }

  //validate form fields input and save
  bool validateAndSave() {
    final form = _formKey.currentState;
    if (form.validate()) {
      form.save();
      print('form is valid, Email: $email, Password: $password');
      return true;
    } else {
      print('form is invalid');
      return false;
    }
  }

  //remove extra spacing before and after input text
  String trimTextInput(String value) {
    return value.toString().trim();
  }

  //validate form and sign in / sign up
  void validateAndSubmit() async {
    if (validateAndSave()) {
      setState(() {
        showSpinner = true;
      });
      try {
        final BaseAuth auth = AuthProvider.of(context).auth;
        if (_sessionType == SessionType.signIn) {
          String user = await auth.handleSignIn(
              trimTextInput(email), trimTextInput(password));
          print('Signed in: $user');

          if (user == null) {
            setState(() {
              showSpinner = false;
              _warning = 'could not sign in with those credentials';
            });
          }
        } else if (_sessionType == SessionType.reset) {
          print('password reset email sent to $email');
          await auth
              .sendPasswordResetEmail(trimTextInput(email))
              .catchError((onError) => print(onError));
          _warning = 'A password reset link has been sent to $email';
          setState(() {
            showSpinner = false;
            _sessionType = SessionType.signIn;
          });
        } else {
          String user = await auth.handleSignUp(
              trimTextInput(email), trimTextInput(password));
          print('Signed up: $user');
          if (user == null) {
            setState(() {
              showSpinner = false;
              _warning = 'could not sign up with those credentials';
            });
          }
        }
      } catch (e) {
        print('Warning message: ${e.toString()}');
      }
    }
  }

  //toggle to switch between sign up and sign in views
  void toggleFormView(String state) {
    _formKey.currentState.reset();
    if (state == 'signUp') {
      setState(() {
        _sessionType = SessionType.signUp;
      });
    } else {
      setState(() {
        _sessionType = SessionType.signIn;
      });
    }
  }

  @override
  void initState() {
    super.initState();
    Future.delayed(Duration.zero, () {
      setState(() {
        args = ModalRoute.of(context).settings.arguments;
      });
      // _sessionType = args.sessionType;
      print('Session type: $_sessionType');
      // setArguments(args);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: ModalProgressHUD(
          inAsyncCall: showSpinner,
          child: SafeArea(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                showAlert(),
                buildHeaderText(_warning, 3, kHeading1TextStyle),
                SizedBox(height: 8.0),
                Flexible(
                  child: Hero(
                    tag: 'logo',
                    child: Container(
                      height: 80.0,
                      child: Image.asset('images/logo.png'),
                    ),
                  ),
                ),
                SizedBox(height: 7.0),
                Container(
                  padding: EdgeInsets.symmetric(horizontal: 20.0),
                  child: Form(
                    key: _formKey,
                    child: Column(
                      children: buildInputFields() + submitButtons(),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget showAlert() {
    if (_warning != null) {
      return Container(
        alignment: Alignment.topCenter,
        color: Colors.amberAccent,
        width: double.infinity,
        padding: EdgeInsets.all(8.0),
        child: Row(
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.only(right: 8.0),
              child: Icon(Icons.error_outline),
            ),
            Expanded(
              child: warningText(),
            ),
            Padding(
              padding: const EdgeInsets.only(left: 8.0),
              child: IconButton(
                icon: Icon(Icons.close),
                onPressed: () {
                  setState(() {
                    _warning = null;
                  });
                },
              ),
            )
          ],
        ),
      );
    }
    return SizedBox(
      height: 0,
    );
  }

  Widget warningText() {
    return Text(
      _warning,
      textAlign: TextAlign.center,
      style: kRegularTextStyle,
      maxLines: 3,
    );
  }

  Widget buildHeaderText(String headerText, int maxLines, TextStyle style) {
    if (_sessionType == SessionType.signUp) {
      headerText = "Create New Account";
    } else if (_sessionType == SessionType.reset) {
      headerText = "Reset Password";
    } else {
      headerText = "Sign In";
    }
    return Text(
      headerText,
      textAlign: TextAlign.center,
      style: style,
      maxLines: maxLines,
    );
  }

  List<Widget> buildInputFields() {
    if (_sessionType == SessionType.reset) {
      return [
        TextFormField(
          key: Key('email'),
          keyboardType: TextInputType.emailAddress,
          textAlign: TextAlign.left,
          onSaved: (value) => email = value,
          validator: EmailFieldValidator.validate,
          decoration:
              kTextFieldDecoration.copyWith(hintText: 'enter your email'),
        ),
      ];
    } else {
      return [
        TextFormField(
          key: Key('email'),
          keyboardType: TextInputType.emailAddress,
          textAlign: TextAlign.left,
          onSaved: (value) => email = value,
          validator: EmailFieldValidator.validate,
          decoration:
              kTextFieldDecoration.copyWith(hintText: 'enter your email'),
        ),
        SizedBox(height: 8.0),
        TextFormField(
          key: Key('password'),
          obscureText: true,
          textAlign: TextAlign.left,
          validator: PasswordFieldValidator.validate,
          onSaved: (value) => password = value,
          decoration:
              kTextFieldDecoration.copyWith(hintText: 'enter your password'),
        ),
        SizedBox(height: 8.0),
      ];
    }
  }

  List<Widget> submitButtons() {
    bool _showForgotPassword = false;

    if (_sessionType == SessionType.signIn) {
      _showForgotPassword = true;
      return [
        Buttons(
          key: Key('signIn'),
          buttonLabel: 'Sign In',
          buttonColour: kThemeStyleButtonFillColour,
          buttonTextStyle: kThemeStyleButton,
          onPressedButton: validateAndSubmit,
        ),
        showForgotPassword(_showForgotPassword),
        PaddedClickableText(
          myText: 'Don\'t have an account? Sign up now',
          onTap: () => toggleFormView('signUp'),
        ),
      ];
    } else if (_sessionType == SessionType.reset) {
      return [
        Buttons(
          key: Key('submit'),
          buttonLabel: 'Submit',
          buttonColour: kThemeStyleButtonFillColour,
          buttonTextStyle: kThemeStyleButton,
          onPressedButton: validateAndSubmit,
        ),
        PaddedClickableText(
          myText: 'Return back to sign in',
          onTap: () => toggleFormView('signIn'),
        ),
      ];
    } else {
      return [
        Buttons(
          key: Key('signUp'),
          buttonLabel: 'Sign Up',
          buttonColour: kThemeStyleButtonFillColour,
          buttonTextStyle: kThemeStyleButton,
          onPressedButton: validateAndSubmit,
        ),
        PaddedClickableText(
          myText: 'Already have an account? Sign in here',
          onTap: () => toggleFormView('signIn'),
        ),
      ];
    }
  }

  Widget showForgotPassword(bool visible) {
    return Visibility(
      visible: visible,
      child: FlatButton(
        onPressed: () {
          setState(() {
            _sessionType = SessionType.reset;
          });
        },
        child: Text(
          'Forgot password?',
          textAlign: TextAlign.center,
          style: TextStyle(
            color: kThemeTextColour,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
    );
  }
}

class EmailFieldValidator {
  static String validate(String value) {
    return value.isEmpty ? 'Email can\'t be empty' : null;
  }
}

class PasswordFieldValidator {
  static String validate(String value) {
    return value.length < 6 || value.isEmpty
        ? 'Password can\'t be empty'
        : null;
  }
}

class SessionsArguments {
  final SessionType sessionType;

  SessionsArguments(this.sessionType);
}

标签: flutterfirebase-authenticationflutter-dependenciesflutter-provider

解决方案


通常,人们使用共享首选项来存储基本登录信息,这样下次有人打开应用程序时,您就可以使用该信息路由到您想要的任何方式。

另一种方法是使用变量。如果他们注册然后将该变量设置为 true 并路由到不同的页面。

如果您需要每个代码片段,请告诉我。


推荐阅读