如何在颤振中使用 Bloc 模式处理用户注册错误


  • 这是我尝试过的一些代码。 在此代码中,我使用了 bloc。 但我想在此注册页面中进行错误处理。
  • 当用户注册时,如果注册成功,那么只需要打开OTP对话框
  • 当用户注册失败时,用户将获得适当的 meesage。
  • 如果注册过程中,应指示加载。
  • 成功注册后。 它将显示一个OTP。 输入OTP后,它将重定向另一个警报对话框。希望你理解这个问题,请帮助我。我尝试了很多时间错误处理,也在此代码中发现了错误处理,但这并不合适。我希望你能帮助我。你这个小小的帮助可以让我度过一天。

这是完整的源代码 https://github.com/rutvikgumasana/signup/tree/master

.

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:flutter_masked_text/flutter_masked_text.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:passcode/passcode.dart';
import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tudo/src/modules/signup/_models/countries.dart';
import 'package:tudo/src/modules/signup/index.dart';
import 'package:tudo/src/styles/colors.dart';
import 'package:tudo/src/utils/app_constants_value.dart';
import 'package:tudo/src/utils/navigation_helper.dart';
import 'package:tudo/src/utils/roundrectbutton.dart';
import 'package:tudo/src/utils/validator.dart';
import 'package:tudo/src/widgets/loader.dart';
import 'package:tudo/src/widgets/toast.dart';
import 'dart:math' as math;
class SignupScreen extends StatefulWidget {
const SignupScreen({
Key key,
@required SignupBloc signupBloc,
})  : _signupBloc = signupBloc,
super(key: key);
final SignupBloc _signupBloc;
@override
SignupScreenState createState() {
return new SignupScreenState(_signupBloc);
}
}
class SignupScreenState extends State<SignupScreen>
with TickerProviderStateMixin {
String submittedString = "";
final changeNotifier = StreamController<Functions>.broadcast();
final SignupBloc _signupBloc;
SignupScreenState(this._signupBloc);
final formKey = new GlobalKey<FormState>();
bool _validate = false;
List<Country> _countries = [];
bool _isError = false;
bool _isLoading = false;
bool _obscureText = true;
Person person = new Person();
var controller = new MaskedTextController(mask: '(000)-000-0000');
String passcode;
final _emailFocusNode = new FocusNode();
final _passwordFocusNode = new FocusNode();
final _fnameFocuNode = new FocusNode();
final _lnameFocusNode = new FocusNode();
final TextEditingController _email = new TextEditingController();
final TextEditingController _add = new TextEditingController();
final TextEditingController _fn = new TextEditingController();
final TextEditingController _ln = new TextEditingController();
final TextEditingController _pho = new TextEditingController();
final TextEditingController _pass = new TextEditingController();
TextEditingController phoneController = new TextEditingController();
static List<CountryModel> _dropdownItems = new List();
String otpWaitTimeLabel = "";
CountryModel _dropdownValue;
TextEditingController otpcontroller = TextEditingController();
String thisText = "";
int pinLength = 6;
bool hasError = false;
bool showAlertBox = false;
String errorMessage;
SharedPreferences prefs;
DateTime target;
String timeLeft = "";
bool running = true;
@override
void initState() {
super.initState();
this._signupBloc.dispatch(LoadSignupEvent());
}
@override
void dispose() {
prefs.setInt('target', target.millisecondsSinceEpoch);
running = false;
super.dispose();
}
void _toggle() {
setState(() {
_obscureText = !_obscureText;
});
}
Widget _buildLogo() {
return new Image(
image: new AssetImage("assets/logo.png"),
height: 150,
width: 150,
);
}
Widget _buildEmailField() {
return TextFormField(
controller: _email,
focusNode: _emailFocusNode,
decoration: new InputDecoration(
prefixIcon: Icon(
Icons.email,
),
labelText: AppConstantsValue.appConst['signup']['email']['translation'],
border: UnderlineInputBorder(),
filled: false,
hintText: 'Your email address',
),
keyboardType: TextInputType.emailAddress,
validator: Validators().validateEmail,
onSaved: (String value) {
person.email = value;
},
);
}
Widget _buildCountry(List<Country> countries) {
if (countries.length > 0 && _dropdownItems.length != countries.length - 1) {
print("countries list");
print(countries[0].name);
for (int i = 0; i < countries.length; i++) {
if (countries[i].name.toLowerCase() != 'world') {
_dropdownItems.add(
CountryModel(
country: countries[i].name, countryCode: countries[i].isdCode),
);
}
}
}
return FormBuilder(
autovalidate: true,
initialValue: {},
child: FormBuilderCustomField(
attribute: "Country",
validators: [
FormBuilderValidators.required(),
],
formField: FormField(
builder: (FormFieldState<dynamic> field) {
return DropdownButtonHideUnderline(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new InputDecorator(
decoration: InputDecoration(
filled: false,
hintText: 'Choose Country',
prefixIcon: Icon(Icons.location_on),
labelText: _dropdownValue == null
? 'Where are you from'
: 'From',
errorText: field.errorText,
),
isEmpty: _dropdownValue == null,
child: new DropdownButton<CountryModel>(
value: _dropdownValue,
isDense: true,
onChanged: (CountryModel newValue) {
print('value change');
print(newValue);
person.country = newValue.country;
person.countryCode = newValue.countryCode;
setState(() {
_dropdownValue = newValue;
phoneController.text = _dropdownValue.countryCode;
field.didChange(newValue);
});
},
items: _dropdownItems.map(
(CountryModel value) {
return DropdownMenuItem<CountryModel>(
value: value,
child: Text(value.country),
);
},
).toList(),
),
),
],
),
);
},
),
),
);
}
Widget _buildPhonefiled() {
return Row(
children: <Widget>[
new Expanded(
child: new TextFormField(
controller: phoneController,
enabled: false,
decoration: InputDecoration(
filled: false,
prefixIcon: Icon(FontAwesomeIcons.globe),
labelText: 'code',
hintText: "Country code",
),
),
flex: 2,
),
new SizedBox(
width: 10.0,
),
new Expanded(
child: new TextFormField(
controller: controller,
keyboardType: TextInputType.number,
validator: Validators().validateMobile,
decoration: InputDecoration(
filled: false,
labelText: 'mobile',
hintText: "Mobile number",
prefixIcon: new Icon(Icons.mobile_screen_share),
),
onSaved: (String value) {
person.phoneNumber = value;
},
),
flex: 5,
),
],
);
}
Widget _buildFnamefiled() {
return TextFormField(
controller: _fn,
focusNode: _fnameFocuNode,
decoration: new InputDecoration(
filled: false,
hintText: 'Enter your First name',
prefixIcon: Icon(
Icons.account_circle,
//  size: 28.0,
),
labelText: AppConstantsValue.appConst['signup']['firstname']
['translation']),
keyboardType: TextInputType.text,
validator: Validators().validateName,
onSaved: (String value) {
person.firstname = value;
},
);
}
Widget _buildLnamefiled() {
return TextFormField(
validator: Validators().validateName,
controller: _ln,
focusNode: _lnameFocusNode,
decoration: new InputDecoration(
filled: false,
hintText: 'Enter your Last name',
prefixIcon: Icon(
Icons.account_circle,
//  size: 28.0,
),
labelText: AppConstantsValue.appConst['signup']['lastname']
['translation']),
keyboardType: TextInputType.text,
onSaved: (String value) {
person.lastname = value;
},
);
}
Widget _buildPasswordfiled() {
return TextFormField(
validator: Validators().validatePassword,
obscureText: _obscureText,
controller: _pass,
focusNode: _passwordFocusNode,
decoration: new InputDecoration(
filled: false,
hintText: 'Enter your password',
prefixIcon: Icon(
Icons.vpn_key,
),
suffixIcon: GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onTap: _toggle,
child: Icon(
_obscureText ? Icons.visibility : Icons.visibility_off,
semanticLabel: _obscureText
? AppConstantsValue.appConst['login']['show_password']
['translation']
: AppConstantsValue.appConst['login']['hide_password']
['translation'],
),
),
labelText: AppConstantsValue.appConst['signup']['password']
['translation'],
),
onSaved: (String value) {
person.password = value;
},
);
}
Widget _buildTermsAndContionsCheck() {
return FormField(
builder: (FormFieldState state) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Checkbox(
value: person.termsAndCondition,
onChanged: (bool value) {
setState(() {
person.termsAndCondition = value;
});
},
),
Text(
AppConstantsValue.appConst['signup']['termsandcondition']
['translation'],
),
],
);
},
);
}
_onAlertotp() {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Enter OTP'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height / 2.4,
width: MediaQuery.of(context).size.width,
alignment: Alignment.center,
child: ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
'We have Texted and/or Emailed OTP (One Time Pin) to your registered cell phone and/ or email account. Please check and enter OTP below to activate your TUDO account.',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 15),
textAlign: TextAlign.center,
),
),
Center(
child: Text(
"timerString",
style: TextStyle(fontSize: 25),
),
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 8.0, horizontal: 30),
child: PinCodeTextField(
length: 6, // must be greater than 0
obsecureText: false, //optional, default is false
shape: PinCodeFieldShape
.underline, //optional, default is underline
onDone: (String value) {
setState(() {
passcode = value;
print(value);
});
},
textStyle: TextStyle(
fontWeight: FontWeight
.bold), //optinal, default is TextStyle(fontSize: 18, color: Colors.black, fontWeight: FontWeight.bold)
onErrorCheck: (bool value) {
setState(() {
hasError = value;
});
},
shouldTriggerFucntions:
changeNotifier.stream.asBroadcastStream(),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 30.0),
child: Text(
hasError
? "*Please fill up all the cells and press VERIFY again"
: "",
style: TextStyle(
color: Colors.red.shade300, fontSize: 12),
),
),
SizedBox(
height: 5,
),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: "Didn't receive the code? ",
style:
TextStyle(color: Colors.black54, fontSize: 15),
children: [
TextSpan(
text: " RESEND",
// recognizer: onTapRecognizer,
style: TextStyle(
color: colorStyles["primary"],
fontWeight: FontWeight.bold,
fontSize: 16))
]),
),
SizedBox(
height: 7,
),
Container(
margin: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 30),
child: ButtonTheme(
height: 50,
child: FlatButton(
onPressed: () async {
_onAlertrunnigbusiness(context);
},
child: Center(
child: Text(
"VERIFY".toUpperCase(),
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
)),
),
),
decoration: BoxDecoration(
color: colorStyles["primary"],
borderRadius: BorderRadius.circular(5),
),
),
],
),
),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
_onAlertrunnigbusiness(context) {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Are you running Business?'),
content: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: 10,
),
Text(
"TUDO.App aims at Businesses bridging gaps between Business Service Providers and Consumers collaborate on unique technology platform. If you own a business, we strongly recommend, provide your business information to grow your customer base and expand your business services. Any questions? Call us @1-800-888-TUDO"),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('No'),
color: colorStyles["primary"],
textColor: Colors.white,
padding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
NavigationHelper.navigatetoMainscreen(context);
},
),
SizedBox(height: 10),
FlatButton.icon(
icon: Icon(FontAwesomeIcons.arrowCircleRight),
label: Text('Yes'),
color: colorStyles["primary"],
textColor: Colors.white,
padding:
EdgeInsets.symmetric(vertical: 10, horizontal: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
onPressed: () {
NavigationHelper.navigatetoBspsignupcreen(context);
},
),
],
)
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Close'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
Widget _buildClearButton() {
return new FlatButton(
onPressed: () {
_email.clear();
_fn.clear();
_ln.clear();
_pho.clear();
_add.clear();
_pass.clear();
_isError = false;
setState(() {
_isError = false;
});
},
child: Text(
AppConstantsValue.appConst['signup']['clear']['translation'],
style: TextStyle(letterSpacing: 1.5),
),
);
}

Widget _buildSignupButton(SignupBloc signupBloc, BuildContext context) {
return GestureDetector(
child: RoundrectButton.buildRoundedRectButton(
AppConstantsValue.appConst['signup']['signup']['translation'],
signUpGradients,
false),
onTap: () {
//  _submit();
final FormState form = formKey.currentState;
form.save();
if (form.validate() && person.termsAndCondition) {
setState(() {
_isLoading = true;
});
Map<String, dynamic> signupdata = {
'email': person.email,
'country': person.country,
'countyCode': person.countryCode,
'phoneNumber': person.phoneNumber,
'firstName': person.firstname,
'lastName': person.lastname,
'password': person.password,
};
_isError
? new Container(child: Text("Error"))
: widget._signupBloc.dispatch(
SignupButtonClickedEvent(signupdata: signupdata),
);
} else {
print("Toast is printed");
Errortoast().showColoredToast();
setState(() {
_isLoading = false;
_validate = true;
});
}
},
);
}
Widget _buildBackButton(BuildContext context) {
return FlatButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.arrow_back_ios),
Text(AppConstantsValue.appConst['signup']['backtologin']
['translation'])
],
),
onPressed: () => Navigator.pop(context, false),
);
}
Widget _buildLoader() {
return Loader(
color: colorStyles["primary"],
);
}
Widget content(signupBloc, context, List<Country> countries) {
return SafeArea(
top: false,
bottom: false,
child: Form(
key: formKey,
autovalidate: _validate,
child: Scrollbar(
child: SingleChildScrollView(
dragStartBehavior: DragStartBehavior.down,
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: new Container(
margin: EdgeInsets.fromLTRB(30, 0, 30, 0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_buildLogo(),
_buildEmailField(),
_buildCountry(countries),
_buildPhonefiled(),
_buildFnamefiled(),
_buildLnamefiled(),
_buildPasswordfiled(),
_buildTermsAndContionsCheck(),
SizedBox(),
_isError ? new Text('Fail to signup') : SizedBox(),
_isLoading ? _buildLoader() : SizedBox(),
_buildClearButton(),
_buildSignupButton(signupBloc, context),
_buildBackButton(context),
],
),
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
return BlocBuilder<SignupBloc, SignupState>(
bloc: widget._signupBloc,
builder: (
BuildContext context,
SignupState currentState,
) {
if (currentState is UnSignupState) {
return Container(
height: MediaQuery.of(context).size.height / 1.10,
width: MediaQuery.of(context).size.width / 1.10,
child: Center(
child: _buildLoader(),
),
);
}
if (currentState is ErrorSignupState) {
_isLoading = false;
_isError = true;
showAlertBox = false;
return Container(
child: content(_signupBloc, context, _countries),
);
}
if (currentState is InSignupState) {
_countries = currentState.countries.countries;
return Container(child: content(_signupBloc, context, _countries));
}
if (currentState is SignupButtonClickedEvent) {
print('SignupButtonClickedEvent clicked');
return Container();
}
if (currentState is SignupSuccessState) {
print(
' You are awesome. you have successfully registered without confirmation');
print(currentState.signupUser.toJson());
print("Hey Otp Is opned");
WidgetsBinding.instance.addPostFrameCallback((_) {
// _never();
_onAlertotp();
});
_isLoading = false;
showAlertBox = true;
return Container(
child: content(_signupBloc, context, _countries),
);
}
if (currentState is SignupVerficationOtp) {
print('signup verficitaion otp button clicked');
return Container();
}
return Container(child: content(_signupBloc, context, _countries));
},
);
}
}
class Person {
String email = '';
String country = '';
String countryCode = '';
String phoneNumber = '';
String firstname = '';
String lastname = '';
String password = '';
bool termsAndCondition = false;
}
class CountryModel {
String country = '';
String countryCode = '';
CountryModel({
this.country,
this.countryCode,
});
}

首先,如果你使用的是Bloc Pattern,你就不能使用setState。另一件事是你应该为一个集团创建一个新类。在您的情况下注册集团。然后导入 RxDart。

class SignupBloc{
String _nameValue;
BehaviourSubject<String> _nameSubject = BehaviourSubject<String>();
Stream<String> get nameStream => _nameSubject.stream;
StreamController<String> _name = StreamController<String>();
Sink<String> get nameSink => _name.sink;
SignupBloc(){
//Inside the StreamController you can do anything to your value
_name.stream.listen((name){
if(name == "" || name == null){
_nameSubject.addError("Please Enter Your Name");
}else{
_nameValue = name;
}
}
}

确保你创建你的集团的实例

SignUpBloc _signUpBloc = SignInBloc();

您的文本字段应如下所示

StreamBuilder<String>(
stream: _signUpBloc.nameStream,
builder: (context, snapshot) {
return TextField(
onChanged: (value) => _signUpBloc.nameSink.add(value),
decoration: InputDecoration(
labelText: "label", errorText: snapshot.error),
);
}
);

相关内容

  • 没有找到相关文章

最新更新