1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-12-30 23:08:50 +00:00
comunicmobile/lib/ui/routes/create_account_route.dart

303 lines
8.8 KiB
Dart

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/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/ui_utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
/// Create account route
///
/// @author Pierre HUBERT
class CreateAccountRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(tr("Create an account")),
),
body: _CreateAccountRouteBody(),
);
}
}
class _CreateAccountRouteBody extends StatefulWidget {
@override
__CreateAccountRouteBodyState createState() =>
__CreateAccountRouteBodyState();
}
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 > 3;
bool get _isLastNameValid => _lastNameController.text.length > 3;
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),
error: _showErrors && !_isFirstNameValid
? tr("Invalid first name!")
: null,
),
// Last name
_InputEntry(
controller: _lastNameController,
label: tr("Last name"),
onEdited: _updateUI,
icon: Icon(Icons.perm_identity),
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 {
await showCupertinoDialog(
context: context,
builder: (c) => CupertinoAlertDialog(
title: Text(tr("Account created")),
content: Text(tr(
"Your account has been successfully created. You can now login to start to use it.")),
actions: <Widget>[
CupertinoButton(
child: Text(tr("Login")), onPressed: () => Navigator.of(c).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;
const _InputEntry({
Key key,
@required this.controller,
@required this.label,
@required this.onEdited,
this.isPassword = false,
this.error,
this.icon,
this.keyboard,
}) : 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,
decoration: InputDecoration(
alignLabelWithHint: true,
errorText: error,
labelText: label,
icon: icon,
),
);
}
}