import 'package:comunic/helpers/account_helper.dart'; import 'package:comunic/models/res_check_password_reset_token.dart'; import 'package:comunic/ui/dialogs/input_new_password_dialog.dart'; import 'package:comunic/ui/widgets/async_screen_widget.dart'; import 'package:comunic/ui/widgets/login_route_container.dart'; import 'package:comunic/ui/widgets/new_password_input_widget.dart'; import 'package:comunic/ui/widgets/safe_state.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/ui_utils.dart'; import 'package:flutter/material.dart'; /// Reset user password route /// /// @author Pierre HUBERT class PasswordResetRoute extends StatelessWidget { final String token; const PasswordResetRoute({ Key? key, required this.token, }) : assert(token != null), super(key: key); @override Widget build(BuildContext context) { return LoginRouteContainer( child: Scaffold( appBar: AppBar( title: Text(tr("Change your password")!), ), body: _PasswordResetBody(token: token), ), ); } } class _PasswordResetBody extends StatefulWidget { final String token; const _PasswordResetBody({Key? key, required this.token}) : assert(token != null), super(key: key); @override __PasswordResetBodyState createState() => __PasswordResetBodyState(); } enum _Status { BEFORE_CHANGE, WHILE_CHANGE, AFTER_CHANGE } class __PasswordResetBodyState extends SafeState<_PasswordResetBody> { final _key = GlobalKey(); var _status = _Status.BEFORE_CHANGE; late ResCheckPasswordToken _tokenInfo; void _setStatus(_Status s) => setState(() => _status = s); Future _validateToken() async { _status = _Status.BEFORE_CHANGE; _tokenInfo = await AccountHelper.validatePasswordResetToken(widget.token); } @override Widget build(BuildContext context) { return AsyncScreenWidget( key: _key, onReload: _validateToken, // The first time, we validate the token onBuild: _buildBody, errorMessage: tr( "Could not validate your password reset token! Maybe it has expired now...")!, ); } Widget _buildBody() { // The user has not requested yet to change his password if (_status == _Status.BEFORE_CHANGE) return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(tr("You can choose a new password.")!), OutlinedButton( onPressed: _changePassword, child: Text(tr("Choose a new password")!), ) ], )); // Password is being changed if (_status == _Status.WHILE_CHANGE) return buildCenteredProgressBar(); // Password was successfully changed! if (_status == _Status.AFTER_CHANGE) return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( tr("Congratulations! Your password has now been successfully changed!")!, textAlign: TextAlign.center, ), OutlinedButton( onPressed: _quitScreen, child: Text(tr("Login")!), ) ], )); throw Exception("Unreachable statement!"); } /// Ask the user to specify his new password void _changePassword() async { try { // Ask for new password final newPass = await showInputNewPassword( context: context, userInfo: UserInfoForPassword( firstName: _tokenInfo.firstName, lastName: _tokenInfo.lastName, email: _tokenInfo.email, ), ); if (newPass == null) return; _setStatus(_Status.WHILE_CHANGE); // Apply it await AccountHelper.changeAccountPassword(widget.token, newPass); _setStatus(_Status.AFTER_CHANGE); } catch (e, s) { print("Could not change user password! $e\n$s"); showSimpleSnack(context, tr("Could not change your password!")!); // We start everything again _key.currentState!.refresh(); } } /// Go back to login screen void _quitScreen() => Navigator.of(context).pop(); }