import 'package:comunic/helpers/account_helper.dart'; import 'package:comunic/helpers/server_config_helper.dart'; import 'package:comunic/helpers/settings_helper.dart'; import 'package:comunic/models/data_conservation_policy_settings.dart'; import 'package:comunic/models/server_config.dart'; import 'package:comunic/ui/dialogs/input_user_password_dialog.dart'; import 'package:comunic/ui/dialogs/multi_choices_dialog.dart'; import 'package:comunic/ui/widgets/async_screen_widget.dart'; import 'package:comunic/ui/widgets/settings/header_spacer_section.dart'; import 'package:comunic/ui/widgets/settings/multi_choices_settings_tile.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:settings_ui/settings_ui.dart'; /// Account privacy settings /// /// @author Pierre HUBERT class AccountPrivacySettings extends StatefulWidget { @override _AccountPrivacySettingsState createState() => _AccountPrivacySettingsState(); } class _AccountPrivacySettingsState extends State { final _key = GlobalKey(); ServerConfig _serverConfig; DataConservationPolicySettings _userSettings; String _cachedPassword; Future _loadSettings() async { await ServerConfigurationHelper.ensureLoaded(); _serverConfig = ServerConfigurationHelper.config; _userSettings = await SettingsHelper.getDataConservationPolicy(); } @override Widget build(BuildContext context) { return AsyncScreenWidget( key: _key, onReload: _loadSettings, onBuild: () => SettingsList(sections: [ HeadSpacerSection(), SettingsSection( title: tr("Data conservation policy"), tiles: _dataConservationPolicyTiles, ), HeadSpacerSection(), HeadSpacerSection(), SettingsSection(title: tr("Danger zone"), tiles: [ SettingsTile( title: tr("Delete your account"), subtitle: tr( "Permanently delete your account and all data related to it."), onPressed: (_) => _deleteAccount(), ) ]) ]), errorMessage: tr("Failed to load privacy settings!"), ); } List get _dataConservationPolicyTiles => [ DataConservationPolicyTile( value: _userSettings.notificationLifetime, title: tr("Automatically delete unread notifications after"), onChange: (val) { _userSettings.notificationLifetime = val; _updateDataConservationPolicy(); }, minValue: _serverConfig.dataConservationPolicy.minNotificationLifetime, ), DataConservationPolicyTile( value: _userSettings.commentsLifetime, title: tr("Automatically delete your comments after"), onChange: (val) { _userSettings.commentsLifetime = val; _updateDataConservationPolicy(); }, minValue: _serverConfig.dataConservationPolicy.minCommentsLifetime, ), DataConservationPolicyTile( value: _userSettings.postsLifetime, title: tr("Automatically delete your posts after"), onChange: (val) { _userSettings.postsLifetime = val; _updateDataConservationPolicy(); }, minValue: _serverConfig.dataConservationPolicy.minPostsLifetime, ), DataConservationPolicyTile( value: _userSettings.conversationMessagesLifetime, title: tr("Automatically delete your conversation messages after"), onChange: (val) { _userSettings.conversationMessagesLifetime = val; _updateDataConservationPolicy(); }, minValue: _serverConfig .dataConservationPolicy.minConversationMessagesLifetime, ), DataConservationPolicyTile( value: _userSettings.likesLifetime, title: tr("Automatically delete your likes after"), onChange: (val) { _userSettings.likesLifetime = val; _updateDataConservationPolicy(); }, minValue: _serverConfig.dataConservationPolicy.minLikesLifetime, ), DataConservationPolicyTile( value: _userSettings.inactiveAccountLifeTime, title: tr( "Automatically delete your account if you have been inactive for"), onChange: (val) { _userSettings.inactiveAccountLifeTime = val; _updateDataConservationPolicy(); }, minValue: _serverConfig.dataConservationPolicy.minInactiveAccountLifetime, ), ]; void _updateDataConservationPolicy() async { try { if (_cachedPassword == null) _cachedPassword = await showUserPasswordDialog(context); await SettingsHelper.setDataConservationPolicy( _cachedPassword, _userSettings); _key.currentState.refresh(); } catch (e, s) { print("Could not update data conservation policy! $e\n$s"); showSimpleSnack( context, tr("Failed to update data conservation policy!")); } } /// Permanently delete user account void _deleteAccount() async { try { // First dialog if (!await showConfirmDialog( context: context, message: tr( "Do you really want to delete your account? This operation CAN NOT be reverted!"))) return; // Ask user password dialog final password = await showUserPasswordDialog(context); if (password == null) return; // Last chance dialog if (await showCupertinoDialog( context: context, builder: (c) => _LastChanceDeleteAccountDialog()) != true) return; // Delete account await AccountHelper.deleteAccount(password); } catch (e, stack) { print("Could not delete user account! $e\n$stack"); showSimpleSnack(context, tr("Could not delete your account!")); } } } class DataConservationPolicyTile extends SettingsTile { final int value; final String title; final Function(int) onChange; final int minValue; const DataConservationPolicyTile({ @required this.value, @required this.title, @required this.onChange, @required this.minValue, }) : assert(title != null), assert(onChange != null), assert(minValue != null); @override Widget build(BuildContext context) { return MultiChoicesSettingsTile( title: title, choices: _choices, currentValue: _roundValue, onChanged: onChange, ); } int get _day => 60 * 60 * 24; int get _month => _day * 30; int get _year => _day * 365; int get _roundValue { if (this.value == null) return 0; return _choices.firstWhere((element) => element.id >= this.value).id; } List> get _choices => [ MultiChoiceEntry(id: 0, title: tr("Never"), hidden: false), MultiChoiceEntry( id: _day * 7, title: tr("7 days"), hidden: _day * 7 < minValue, ), MultiChoiceEntry( id: _day * 15, title: tr("15 days"), hidden: _day * 15 < minValue, ), MultiChoiceEntry( id: _month, title: tr("1 month"), hidden: _month < minValue, ), MultiChoiceEntry( id: _month * 3, title: tr("3 months"), hidden: _month * 3 < minValue, ), MultiChoiceEntry( id: _month * 6, title: tr("6 months"), hidden: _month * 6 < minValue, ), MultiChoiceEntry( id: _year, title: tr("1 year"), hidden: _year < minValue, ), MultiChoiceEntry( id: _year * 2, title: tr("2 years"), hidden: _year * 5 < minValue, ), MultiChoiceEntry( id: _year * 5, title: tr("5 years"), hidden: _year * 5 < minValue, ), MultiChoiceEntry( id: _year * 10, title: tr("10 years"), hidden: _year * 10 < minValue, ), MultiChoiceEntry( id: _year * 50, title: tr("50 years"), hidden: _year * 50 < minValue, ), ]; } class _LastChanceDeleteAccountDialog extends StatelessWidget { @override Widget build(BuildContext context) { return CupertinoAlertDialog( title: Text(tr("Delete your account")), content: Text(tr( "Let us ask you one last time. Do you really want to delete your account? If you decide to do so, your data will be permanently removed from our servers, so we will not be able to recover your account. If you decide to proceed, the deletion process will start immediatly and you will automatically get disconnected from your account.")), actions: [ CupertinoDialogAction( isDefaultAction: true, child: Text(tr("Cancel")), onPressed: () => Navigator.of(context).pop(false), ), CupertinoDialogAction( isDestructiveAction: true, child: Text(tr("Confirm")), onPressed: () => Navigator.of(context).pop(true), ), ], ); } }