1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-22 12:59:21 +00:00

Refactor code

This commit is contained in:
Pierre HUBERT 2021-04-17 10:10:31 +02:00
parent 7bfbc85d5f
commit 92ab82d7a1
2 changed files with 291 additions and 266 deletions

View File

@ -1,13 +1,7 @@
import 'package:comunic/helpers/account_helper.dart'; import 'package:comunic/ui/widgets/create_account_widget.dart';
import 'package:comunic/helpers/server_config_helper.dart';
import 'package:comunic/models/new_account.dart';
import 'package:comunic/ui/widgets/new_password_input_widget.dart';
import 'package:comunic/utils/input_utils.dart';
import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
/// Create account route /// Create account route
/// ///
@ -32,222 +26,9 @@ class _CreateAccountRouteBody extends StatefulWidget {
} }
class __CreateAccountRouteBodyState extends State<_CreateAccountRouteBody> { class __CreateAccountRouteBodyState extends State<_CreateAccountRouteBody> {
final _firstNameController = TextEditingController();
final _lastNameController = TextEditingController();
final _emailController = TextEditingController();
final _passwordInputKey = GlobalKey<NewPasswordInputWidgetState>();
final _verifyPasswordController = TextEditingController();
bool _acceptedTOS = false;
bool _isCreating = false;
CreateAccountResult _createAccountResult;
bool _showErrors = false;
bool get _isFirstNameValid =>
_firstNameController.text.length >=
srvConfig.accountInformationPolicy.minFirstNameLength;
bool get _isLastNameValid =>
_lastNameController.text.length >=
srvConfig.accountInformationPolicy.minLastNameLength;
bool get _isEmailValid => validateEmail(_emailController.text);
bool get _isPasswordValid => _passwordInputKey.currentState.valid;
bool get _isPasswordConfirmationValid =>
_passwordInputKey.currentState != null &&
_passwordInputKey.currentState.value == _verifyPasswordController.text;
bool get _isFormValid =>
_isFirstNameValid &&
_isLastNameValid &&
_isEmailValid &&
_isPasswordValid &&
_isPasswordConfirmationValid &&
_acceptedTOS;
String get errorMessage => _createAccountResult ==
CreateAccountResult.ERROR_EXISTING_EMAIL
? tr("An account is already associated to this email address!")
: _createAccountResult == CreateAccountResult.ERROR_TOO_MANY_REQUESTS
? tr(
"Too many accounts have been created from this IP address for now. Please try again later.")
: tr(
"An error occurred while creating your account. Please try again.");
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) =>
if (_isCreating) CreateAccountWidget(onCreated: _accountCreated);
return Center(
child: CircularProgressIndicator(),
);
return Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 370),
child: ListView(
children: <Widget>[
_createAccountResult != null
? buildErrorCard(errorMessage)
: Container(),
// First name
_InputEntry(
controller: _firstNameController,
label: tr("First name"),
onEdited: _updateUI,
icon: Icon(Icons.perm_identity),
maxLength:
srvConfig.accountInformationPolicy.maxFirstNameLength,
error: _showErrors && !_isFirstNameValid
? tr("Invalid first name!")
: null,
),
// Last name
_InputEntry(
controller: _lastNameController,
label: tr("Last name"),
onEdited: _updateUI,
icon: Icon(Icons.perm_identity),
maxLength: srvConfig.accountInformationPolicy.maxLastNameLength,
error: _showErrors && !_isLastNameValid
? tr("Invalid last name!")
: null,
),
// Email address
_InputEntry(
controller: _emailController,
label: tr("Email address"),
onEdited: _updateUI,
icon: Icon(Icons.email),
keyboard: TextInputType.emailAddress,
error: _showErrors && !_isEmailValid
? tr("Invalid email address!")
: null,
),
// Password
NewPasswordInputWidget(
key: _passwordInputKey,
label: tr("Password"),
onEdited: _updateUI,
icon: Icon(Icons.lock),
user: UserInfoForPassword(
firstName: _firstNameController.text,
lastName: _lastNameController.text,
email: _emailController.text,
),
),
// Verify password
_InputEntry(
controller: _verifyPasswordController,
label: tr("Confirm your password"),
onEdited: _updateUI,
icon: Icon(Icons.lock_outline),
isPassword: true,
error: _showErrors && !_isPasswordConfirmationValid
? tr("The password and its confirmation do not match!")
: null,
),
// TOS
CheckboxListTile(
title:
Text(tr("I have read and accepted the Terms Of Service.")),
value: _acceptedTOS,
onChanged: (b) {
_acceptedTOS = b;
_updateUI();
},
subtitle: _showErrors && !_acceptedTOS
? Text(
tr("You must accept the Terms Of Service to continue."),
style: TextStyle(color: Colors.redAccent),
)
: null,
controlAffinity: ListTileControlAffinity.leading,
secondary: IconButton(
icon: Icon(Icons.open_in_new),
onPressed: _openTOS,
),
),
// Submit button
Center(
child: ElevatedButton(
onPressed: _submitForm,
child: Text("Submit"),
),
),
],
),
),
),
);
}
void _updateUI() {
setState(() {
// Nothing yet
});
}
void _submitForm() async {
if (!_isFormValid) {
_showErrors = true;
_updateUI();
return;
}
setState(() {
_isCreating = true;
});
final result = await AccountHelper().createAccount(NewAccount(
firstName: _firstNameController.text,
lastName: _lastNameController.text,
email: _emailController.text,
password: _passwordInputKey.currentState.value,
));
setState(() {
_isCreating = false;
});
if (result != CreateAccountResult.SUCCESS) {
_createAccountResult = result;
_showCreateAccountError();
_updateUI();
return;
}
_accountCreated();
}
void _openTOS() => launch(ServerConfigurationHelper.config.termsURL);
void _showCreateAccountError() async {
await showCupertinoDialog(
context: context,
builder: (c) => CupertinoAlertDialog(
title: Text(tr("Error while creating your account")),
content: Text(errorMessage),
actions: <Widget>[
CupertinoButton(
child: Text(tr("Ok").toUpperCase()),
onPressed: () => Navigator.of(context).pop(),
)
],
),
);
}
void _accountCreated() async { void _accountCreated() async {
await showCupertinoDialog( await showCupertinoDialog(
@ -266,47 +47,3 @@ class __CreateAccountRouteBodyState extends State<_CreateAccountRouteBody> {
Navigator.of(context).pop(); Navigator.of(context).pop();
} }
} }
class _InputEntry extends StatelessWidget {
final TextEditingController controller;
final String label;
final VoidCallback onEdited;
final bool isPassword;
final String error;
final Widget icon;
final TextInputType keyboard;
final int maxLength;
const _InputEntry({
Key key,
@required this.controller,
@required this.label,
@required this.onEdited,
this.isPassword = false,
this.error,
this.icon,
this.keyboard,
this.maxLength,
}) : assert(controller != null),
assert(label != null),
assert(onEdited != null),
assert(isPassword != null),
super(key: key);
@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
onChanged: (s) => onEdited(),
keyboardType: keyboard,
obscureText: isPassword,
maxLength: maxLength,
decoration: InputDecoration(
alignLabelWithHint: true,
errorText: error,
labelText: label,
icon: icon,
),
);
}
}

View File

@ -0,0 +1,288 @@
import 'package:comunic/helpers/account_helper.dart';
import 'package:comunic/helpers/server_config_helper.dart';
import 'package:comunic/models/new_account.dart';
import 'package:comunic/utils/input_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'new_password_input_widget.dart';
/// Create account widget
///
/// @author Pierre Hubert
class CreateAccountWidget extends StatefulWidget {
final void Function() onCreated;
const CreateAccountWidget({Key key, @required this.onCreated})
: super(key: key);
@override
_CreateAccountWidgetState createState() => _CreateAccountWidgetState();
}
class _CreateAccountWidgetState extends State<CreateAccountWidget> {
final _firstNameController = TextEditingController();
final _lastNameController = TextEditingController();
final _emailController = TextEditingController();
final _passwordInputKey = GlobalKey<NewPasswordInputWidgetState>();
final _verifyPasswordController = TextEditingController();
bool _acceptedTOS = false;
bool _isCreating = false;
CreateAccountResult _createAccountResult;
bool _showErrors = false;
bool get _isFirstNameValid =>
_firstNameController.text.length >=
srvConfig.accountInformationPolicy.minFirstNameLength;
bool get _isLastNameValid =>
_lastNameController.text.length >=
srvConfig.accountInformationPolicy.minLastNameLength;
bool get _isEmailValid => validateEmail(_emailController.text);
bool get _isPasswordValid => _passwordInputKey.currentState.valid;
bool get _isPasswordConfirmationValid =>
_passwordInputKey.currentState != null &&
_passwordInputKey.currentState.value == _verifyPasswordController.text;
bool get _isFormValid =>
_isFirstNameValid &&
_isLastNameValid &&
_isEmailValid &&
_isPasswordValid &&
_isPasswordConfirmationValid &&
_acceptedTOS;
String get errorMessage => _createAccountResult ==
CreateAccountResult.ERROR_EXISTING_EMAIL
? tr("An account is already associated to this email address!")
: _createAccountResult == CreateAccountResult.ERROR_TOO_MANY_REQUESTS
? tr(
"Too many accounts have been created from this IP address for now. Please try again later.")
: tr(
"An error occurred while creating your account. Please try again.");
@override
Widget build(BuildContext context) {
if (_isCreating)
return Center(
child: CircularProgressIndicator(),
);
return Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 370),
child: ListView(
children: <Widget>[
_createAccountResult != null
? buildErrorCard(errorMessage)
: Container(),
// First name
_InputEntry(
controller: _firstNameController,
label: tr("First name"),
onEdited: _updateUI,
icon: Icon(Icons.perm_identity),
maxLength:
srvConfig.accountInformationPolicy.maxFirstNameLength,
error: _showErrors && !_isFirstNameValid
? tr("Invalid first name!")
: null,
),
// Last name
_InputEntry(
controller: _lastNameController,
label: tr("Last name"),
onEdited: _updateUI,
icon: Icon(Icons.perm_identity),
maxLength: srvConfig.accountInformationPolicy.maxLastNameLength,
error: _showErrors && !_isLastNameValid
? tr("Invalid last name!")
: null,
),
// Email address
_InputEntry(
controller: _emailController,
label: tr("Email address"),
onEdited: _updateUI,
icon: Icon(Icons.email),
keyboard: TextInputType.emailAddress,
error: _showErrors && !_isEmailValid
? tr("Invalid email address!")
: null,
),
// Password
NewPasswordInputWidget(
key: _passwordInputKey,
label: tr("Password"),
onEdited: _updateUI,
icon: Icon(Icons.lock),
user: UserInfoForPassword(
firstName: _firstNameController.text,
lastName: _lastNameController.text,
email: _emailController.text,
),
),
// Verify password
_InputEntry(
controller: _verifyPasswordController,
label: tr("Confirm your password"),
onEdited: _updateUI,
icon: Icon(Icons.lock_outline),
isPassword: true,
error: _showErrors && !_isPasswordConfirmationValid
? tr("The password and its confirmation do not match!")
: null,
),
// TOS
CheckboxListTile(
title:
Text(tr("I have read and accepted the Terms Of Service.")),
value: _acceptedTOS,
onChanged: (b) {
_acceptedTOS = b;
_updateUI();
},
subtitle: _showErrors && !_acceptedTOS
? Text(
tr("You must accept the Terms Of Service to continue."),
style: TextStyle(color: Colors.redAccent),
)
: null,
controlAffinity: ListTileControlAffinity.leading,
secondary: IconButton(
icon: Icon(Icons.open_in_new),
onPressed: _openTOS,
),
),
// Submit button
Center(
child: ElevatedButton(
onPressed: _submitForm,
child: Text(tr("Create account")),
),
),
],
),
),
),
);
}
void _updateUI() {
setState(() {
// Nothing yet
});
}
void _submitForm() async {
if (!_isFormValid) {
_showErrors = true;
_updateUI();
return;
}
setState(() {
_isCreating = true;
});
final result = await AccountHelper().createAccount(NewAccount(
firstName: _firstNameController.text,
lastName: _lastNameController.text,
email: _emailController.text,
password: _passwordInputKey.currentState.value,
));
setState(() {
_isCreating = false;
});
if (result != CreateAccountResult.SUCCESS) {
_createAccountResult = result;
_showCreateAccountError();
_updateUI();
return;
}
_accountCreated();
}
void _openTOS() => launch(ServerConfigurationHelper.config.termsURL);
void _showCreateAccountError() async {
await showCupertinoDialog(
context: context,
builder: (c) => CupertinoAlertDialog(
title: Text(tr("Error while creating your account")),
content: Text(errorMessage),
actions: <Widget>[
CupertinoButton(
child: Text(tr("Ok").toUpperCase()),
onPressed: () => Navigator.of(context).pop(),
)
],
),
);
}
}
class _InputEntry extends StatelessWidget {
final TextEditingController controller;
final String label;
final VoidCallback onEdited;
final bool isPassword;
final String error;
final Widget icon;
final TextInputType keyboard;
final int maxLength;
const _InputEntry({
Key key,
@required this.controller,
@required this.label,
@required this.onEdited,
this.isPassword = false,
this.error,
this.icon,
this.keyboard,
this.maxLength,
}) : assert(controller != null),
assert(label != null),
assert(onEdited != null),
assert(isPassword != null),
super(key: key);
@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
onChanged: (s) => onEdited(),
keyboardType: keyboard,
obscureText: isPassword,
maxLength: maxLength,
decoration: InputDecoration(
alignLabelWithHint: true,
errorText: error,
labelText: label,
icon: icon,
),
);
}
}