监听 helper class 中的变量变化

Listen for variable change in helper class

我正在尝试使用 firebase 为我的应用构建登录屏幕。我的登录功能运行良好,但我在登录失败时无法显示一些错误文本。

这是身份验证助手的代码class:

class AuthenticationService {

  final FirebaseAuth _firebaseAuth;

  String errorText = "";

  AuthenticationService(this._firebaseAuth);

  Stream<User> get authStateChanges => _firebaseAuth.authStateChanges();

  Future<void> signOut() async {
    await _firebaseAuth.signOut();
  }

  Future<String> signIn({String email, String password}) async {
    try {
      await _firebaseAuth.signInWithEmailAndPassword(email: email, password: password);
      return "Signed in";
    }
    on FirebaseAuthException catch (e) {
      errorText = e.message;
      return e.message;
    }
  }

  Future<String> signUp({String email, String password}) async {
    try {
      await _firebaseAuth.createUserWithEmailAndPassword(email: email, password: password);
      signIn(email: email, password: password);
      return "Account created";
    }
    on FirebaseAuthException catch (e) {
      errorText = e.message;
      return e.message;
    }
  }
}

这是我的登录小部件的代码:

class SignIn extends StatefulWidget {
  final TextEditingController emailController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();

  @override
  State<StatefulWidget> createState() => _SignInWidgetState();
}

class _SignInWidgetState extends State<SignIn> {
  final TextEditingController errorController = TextEditingController();
  bool _isErrorContainerVisible = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Sign In"),
      ),
      body: Column(
        children: [
          TextField(
            controller: widget.emailController,
            decoration: InputDecoration(
              labelText: "Email",
              hintText: "example@gmail.com",
              contentPadding: EdgeInsets.all(20.0),
            ),
          ),
          TextField(
            controller: widget.passwordController,
            obscureText: true,
            decoration: InputDecoration(
              labelText: "Password",
              hintText: "password",
              contentPadding: EdgeInsets.all(20.0),
            ),
          ),
          Visibility(
            child: Container(
              child: Text(
                errorController.text,
                style: TextStyle(
                  color: Colors.red,
                ),
              ),
              padding: const EdgeInsets.all(20.0),
            ),
            visible: _isErrorContainerVisible,
          ),
          RaisedButton(
            onPressed: () {
              context.read<AuthenticationService>().signIn(
                  email: widget.emailController.text.trim(),
                  password: widget.passwordController.text.trim());
            },
            child: Text("Sign In"),
          ),
          RaisedButton(
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(builder: (context) {
                  return SignUp(widget.emailController.text.trim().toString(),
                      widget.passwordController.text.trim().toString());
                }),
              );
            },
            child: Text("Sign Up"),
          )
        ],
      ),
    );
  }
}

基本上,如果 AuthenticationService 中的 errorText 出现错误(因为用户登录失败),我想做的是在 Visibility 小部件中显示文本。我意识到的问题是 signIn 方法是 Future,因此不会立即设置错误(我想我需要某种类型的变量侦听器)。我遵循了一些使用 TextEditingController 的示例 here,这种方法可以正常工作,但我需要再次单击登录按钮以显示错误,而不是第一次出现错误。任何帮助将不胜感激。

我最终找到了答案并希望分享以防其他人需要帮助。

基本上,我需要让我的 AuthenticationHelper class 扩展一个 ChangeNotifier,这样我就可以在发生任何 firebase 身份验证异常时调用 notifyListeners()

接下来,我需要使用 Provider 库创建一个 context.select(documentation),它允许我监视 notifyListeners() 何时被调用。一旦检测到错误文本发生变化,我将 _isErrorContainerVisible 设置为 true 并显示错误。