import 'package:comunic/helpers/account_helper.dart'; import 'package:comunic/helpers/settings_helper.dart'; import 'package:comunic/models/security_settings.dart'; import 'package:comunic/ui/dialogs/input_new_password_dialog.dart'; import 'package:comunic/ui/dialogs/input_user_password_dialog.dart'; import 'package:comunic/ui/widgets/dialogs/auto_sized_dialog_content_widget.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/ui_utils.dart'; import 'package:flutter/material.dart'; import 'package:settings_ui/settings_ui.dart'; /// Account security settings /// /// @author Pierre HUBERT class AccountSecuritySettingsScreen extends StatefulWidget { @override _AccountSecuritySettingsScreenState createState() => _AccountSecuritySettingsScreenState(); } class _AccountSecuritySettingsScreenState extends State { @override Widget build(BuildContext context) { return SettingsList( sections: [ SettingsSection( title: tr("Password"), tiles: [ SettingsTile( title: tr("Change password"), onTap: _changePassword, ), SettingsTile( title: tr("Change your security questions"), subtitle: tr( "Your security questions can be used to recover an access to your account when you loose your password..."), onTap: _changeSecurityQuestions, ), SettingsTile( title: tr("Disconnect all your devices"), subtitle: tr( "Disconnect all your devices from Comunic, including the current one. Use this option if one of the device you use for Comunic was stolen."), onTap: _disconnectAllDevices, ), ], ) ], ); } /// Change current user password void _changePassword() async { try { final currPassword = await showUserPasswordDialog(context); if (currPassword == null) return; final newPassword = await showInputNewPassword(context); if (newPassword == null) return; await SettingsHelper.changePassword(currPassword, newPassword); showSimpleSnack( context, tr("Your password has been successfully changed!")); } catch (e, stack) { print("Could not update current user password! $e\n$stack"); showSimpleSnack(context, tr("Could not update password!")); } } /// Change security questions void _changeSecurityQuestions() async { try { final password = await showUserPasswordDialog(context); if (password == null) return; final settings = await SettingsHelper.getSecuritySettings(password); final newSettings = await showDialog( context: context, builder: (c) => _SecurityQuestionsDialog(settings: settings)); if (newSettings == null) return; await SettingsHelper.setSecuritySettings(password, newSettings); showSimpleSnack(context, tr("You security questions have been successfully updated!")); } catch (e, stack) { print("Could not update security questions!$e\n$stack"); showSimpleSnack(context, tr("Could not update security questions!")); } } /// Disconnect all devices void _disconnectAllDevices() async { try { if (!await showConfirmDialog( context: context, message: tr( "Do you really want to disconnect all your devices from Comunic ?"))) return; await AccountHelper.disconnectAllDevices(); } catch (e, stack) { print("Could not disconnect user on all devices! $e\n$stack"); showSimpleSnack( context, tr("Could not disconnect you from all your devices!")); } } } class _SecurityQuestionsDialog extends StatefulWidget { final SecuritySettings settings; const _SecurityQuestionsDialog({Key key, @required this.settings}) : assert(settings != null), super(key: key); @override __SecurityQuestionsDialogState createState() => __SecurityQuestionsDialogState(); } class __SecurityQuestionsDialogState extends State<_SecurityQuestionsDialog> { TextEditingController _controllerQuestion1; TextEditingController _controllerAnswer1; TextEditingController _controllerQuestion2; TextEditingController _controllerAnswer2; SecuritySettings get _newSettings => SecuritySettings( securityQuestion1: _controllerQuestion1.text, securityAnswer1: _controllerAnswer1.text, securityQuestion2: _controllerQuestion2.text, securityAnswer2: _controllerAnswer2.text, ); @override void initState() { _controllerQuestion1 = TextEditingController(text: widget.settings.securityQuestion1); _controllerAnswer1 = TextEditingController(text: widget.settings.securityAnswer1); _controllerQuestion2 = TextEditingController(text: widget.settings.securityQuestion2); _controllerAnswer2 = TextEditingController(text: widget.settings.securityAnswer2); super.initState(); } @override Widget build(BuildContext context) { return AlertDialog( title: Text(tr("Update security questions")), content: AutoSizeDialogContentWidget(child: _buildContent()), actions: [ MaterialButton( onPressed: () => Navigator.of(context).pop(), child: Text(tr("Cancel").toUpperCase()), ), MaterialButton( onPressed: () => Navigator.of(context).pop(_newSettings), child: Text(tr("Update").toUpperCase()), ) ], ); } Widget _buildContent() { return Column( children: [ Text(tr( "Note: Your two questions and answers MUST be completed in order to be able to recover your account using your security questions!")), _buildTextField( controller: _controllerQuestion1, label: tr("Question 1")), _buildTextField(controller: _controllerAnswer1, label: tr("Answer 1")), _buildTextField( controller: _controllerQuestion2, label: tr("Question 2")), _buildTextField(controller: _controllerAnswer2, label: tr("Answer 2")), ], ); } Widget _buildTextField({ @required TextEditingController controller, @required String label, }) { return TextField( controller: controller, onChanged: (s) => setState(() {}), decoration: InputDecoration( alignLabelWithHint: true, labelText: label, errorText: controller.text.isNotEmpty && controller.text.length < 5 ? tr("Unsafe value!") : null, ), ); } }