gpt4 book ai didi

flutter - 将 BLOC 模式用于身份验证表单

转载 作者:IT王子 更新时间:2023-10-29 07:00:07 25 4
gpt4 key购买 nike

我正在尝试在包含登录和注册的基本身份验证表单上使用 BLOC 模式,其中登录和注册之间的唯一区别是注册有一个额外的 Confirm Password 字段,这也有助于是否应启用 Signup 按钮。

我有两个问题:1.这是个问题。目前,如果我输入一些通过 Login 验证的登录名,然后切换到 Signup 表单,则启用 Signup 按钮,这是错误的,因为 Confirm Password 仍然是空的。如何解决这个问题?2. 我觉得有比我所做的更好的方法来实现 Confirm Password 验证和 Signup 按钮验证。我最初尝试为 Confirm Password 创建一个验证器,但它应该将 both 密码和确认密码作为输入,但无法使其作为 StreamTransformer 只带一个入参。执行此操作的更好方法是什么?

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:rxdart/rxdart.dart';


void main() => runApp(AuthProvider(child: MaterialApp(home: Auth())));

enum AuthMode { Signup, Login }

class Auth extends StatefulWidget {
@override
_AuthState createState() => _AuthState();
}

class _AuthState extends State<Auth> {
AuthMode authMode = AuthMode.Login;
bool get _isLoginMode => authMode == AuthMode.Login;
TextEditingController confirmPasswordCtrl = TextEditingController();

@override
Widget build(BuildContext context) {
final bloc = AuthProvider.of(context);
return Scaffold(
body: Container(
margin: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
emailField(bloc),
passwordField(bloc),
confirmPasswordField(bloc),
Container(
margin: EdgeInsets.only(top: 40.0),
),
FlatButton(
child: Text('Switch to ${_isLoginMode ? 'Signup' : 'Login'}'),
onPressed: swithAuthMode,
),
loginOrSignupButton(bloc),
],
),
),
);
}

void swithAuthMode() {
setState(() {
authMode = authMode == AuthMode.Login ? AuthMode.Signup : AuthMode.Login;
});
}

Widget confirmPasswordField(AuthBloc bloc) {
return _isLoginMode
? Container()
: StreamBuilder(
stream: bloc.passwordConfirmed,
builder: (context, snapshot) {
return TextField(
obscureText: true,
onChanged: bloc.changeConfirmPassword,
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: 'Confirm Password',
errorText: snapshot.hasData && !snapshot.data ? 'password mismatch' : null,
),
);
},
);
}

Widget emailField(AuthBloc bloc) {
return StreamBuilder(
stream: bloc.email,
builder: (context, snapshot) {
return TextField(
keyboardType: TextInputType.emailAddress,
onChanged: bloc.changeEmail,
decoration: InputDecoration(
hintText: 'your email',
labelText: 'Email',
errorText: snapshot.error,
),
);
},
);
}

Widget loginOrSignupButton(AuthBloc bloc) {
return StreamBuilder(
stream: _isLoginMode ? bloc.submitValid : bloc.signupValid,
builder: (context, snapshot) {
print('hasData: ${snapshot.hasData}, data: ${snapshot.data}');
return RaisedButton(
onPressed: // The problem is, after entering some login details then switching from login to signup, the Signup button is enabled.
!snapshot.hasData || !snapshot.data ? null : () => onSubmitPressed(bloc, context),
color: Colors.blue,
child: Text('${_isLoginMode ? 'Log in' : 'Sign up'}'),
);
},
);
}

void onSubmitPressed(AuthBloc bloc, BuildContext context) async {
var response = await bloc.submit(_isLoginMode);
if (response.success) {
Navigator.pushReplacementNamed(context, '/home');
} else {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Error'),
content: Text(response.message),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
}
}

Widget passwordField(AuthBloc bloc) {
return StreamBuilder(
stream: bloc.password,
builder: (_, snapshot) {
return TextField(
obscureText: true,
onChanged: bloc.changePassword,
decoration: InputDecoration(
labelText: 'Password',
errorText: snapshot.error,
hintText: 'at least 6 characters',
),
);
},
);
}
}

class AuthProvider extends InheritedWidget {
final bloc;

AuthProvider({Key key, Widget child}) :
bloc = AuthBloc(), super(key:key, child: child);

@override
bool updateShouldNotify(InheritedWidget oldWidget) => true;

static AuthBloc of(BuildContext context) => (context.inheritFromWidgetOfExactType(AuthProvider) as AuthProvider).bloc;

}

class Repository {
// this will call whatever backend to authenticate users.
Future<AuthResult> signupUser(String email, String password) => null;
Future<AuthResult> loginUser(String email, String password) => null;
}


class AuthBloc extends Object with AuthValidator {
final _emailController = BehaviorSubject<String>();
final _passwordController = BehaviorSubject<String>();
final _confirmPasswordController = BehaviorSubject<String>();
final _signupController = PublishSubject<Map<String, dynamic>>();
final Repository _repository = Repository();

Stream<String> get email => _emailController.stream.transform(validateEmail);

Stream<String> get password =>
_passwordController.stream.transform(validatePassword);

Stream<bool> get submitValid =>
Observable.combineLatest2(email, password, (e, p) => true);

// Is there a better way of doing passwordConfirmed and signupValid?
Stream<bool> get passwordConfirmed =>
Observable.combineLatest2(password, _confirmPasswordController.stream, (p, cp) => p == cp);

Stream<bool> get signupValid =>
Observable.combineLatest2(submitValid, passwordConfirmed, (s, p) => s && p);


// sink
Function(String) get changeEmail => _emailController.sink.add;
Function(String) get changePassword => _passwordController.sink.add;
Function(String) get changeConfirmPassword =>
_confirmPasswordController.sink.add;

Future<AuthResult> submit(bool isLogin) async {
final validEmail = _emailController.value;
final validPassword = _passwordController.value;
if (!isLogin)
return await _repository.signupUser(validEmail, validPassword);

return await _repository.loginUser(validEmail, validPassword);
}

void dispose() {
_emailController.close();
_passwordController.close();
_signupController.close();
_confirmPasswordController.close();
}
}

class AuthResult {
bool success;
String message;
AuthResult(this.success, this.message);
}

// demo validator
class AuthValidator {
final validateEmail = StreamTransformer<String, String>.fromHandlers(
handleData: (email, sink) {
if (email.contains('@')) sink.add(email);
else sink.addError('Email is not valid');
}
);

final validatePassword = StreamTransformer<String, String>.fromHandlers(
handleData: (password, sink) {
if (password.length >= 6) sink.add(password);
else sink.addError('Password must be at least 6 characters');
}
);
}

最佳答案

在您的情况下,执行 passwordConfirmed 的更好方法是:

Stream<String> get passwordConfirmed => _confirmPasswordController.stream
.transform(validatePassword).doOnData((String confirmPassword){
if(0 != _passwordController.value.compareTo(confirmPassword)){
_confirmPasswordController.addError("Passwords do not match");
}
});

根据 boeledi 建议 here .

关于flutter - 将 BLOC 模式用于身份验证表单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52545188/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com