diff --git a/assets/translations/en.json b/assets/translations/en.json index fc7e1eb2..f1ef524f 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -34,7 +34,8 @@ "apply": "Apply", "done": "Done", "continue": "Continue", - "alert": "Alert" + "alert": "Alert", + "copied_to_clipboard": "Copied to clipboard!" }, "more_page": { "configuration_wizard": "Setup wizard", @@ -196,6 +197,7 @@ "autobackup_custom_hint": "Enter custom period in minutes", "autobackup_set_period": "Set period", "autobackup_period_set": "Period set", + "backups_encryption_key": "Encryption key", "pending_jobs": "Currently running backup jobs", "snapshots_title": "Snapshot list" }, @@ -536,4 +538,4 @@ "reset_onboarding_description": "Reset onboarding switch to show onboarding screen again", "cubit_statuses": "Cubit loading statuses" } -} +} \ No newline at end of file diff --git a/assets/translations/ru.json b/assets/translations/ru.json index 12c161b9..e906e838 100644 --- a/assets/translations/ru.json +++ b/assets/translations/ru.json @@ -34,6 +34,7 @@ "done": "Готово", "continue": "Продолжить", "alert": "Уведомление", + "copied_to_clipboard": "Скопировано в буфер обмена!", "app_name": "SelfPrivacy" }, "more_page": { @@ -197,6 +198,7 @@ "autobackup_custom_hint": "Введите период в минутах", "autobackup_set_period": "Установить период", "autobackup_period_set": "Период установлен", + "backups_encryption_key": "Ключ шифрования", "snapshots_title": "Список снимков" }, "storage": { @@ -536,4 +538,4 @@ "ignore_tls_description": "Приложение не будет проверять сертификаты TLS при подключении к серверу.", "ignore_tls": "Не проверять сертификаты TLS" } -} +} \ No newline at end of file diff --git a/lib/ui/pages/backups/backup_details.dart b/lib/ui/pages/backups/backup_details.dart index e3fe427b..54136412 100644 --- a/lib/ui/pages/backups/backup_details.dart +++ b/lib/ui/pages/backups/backup_details.dart @@ -16,6 +16,7 @@ import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; import 'package:selfprivacy/ui/helpers/modals.dart'; import 'package:selfprivacy/ui/pages/backups/change_period_modal.dart'; +import 'package:selfprivacy/ui/pages/backups/copy_encryption_key_modal.dart'; import 'package:selfprivacy/ui/pages/backups/create_backups_modal.dart'; import 'package:selfprivacy/ui/router/router.dart'; import 'package:selfprivacy/utils/extensions/duration.dart'; @@ -144,6 +145,34 @@ class BackupDetailsPage extends StatelessWidget { : 'backup.autobackup_period_never'.tr(), ), ), + ListTile( + onTap: preventActions + ? null + : () { + showModalBottomSheet( + useRootNavigator: true, + context: context, + isScrollControlled: true, + builder: (final BuildContext context) => + DraggableScrollableSheet( + expand: false, + maxChildSize: 0.6, + minChildSize: 0.3, + initialChildSize: 0.3, + builder: (final context, final scrollController) => + CopyEncryptionKeyModal( + scrollController: scrollController, + ), + ), + ); + }, + leading: const Icon( + Icons.key_outlined, + ), + title: Text( + 'backup.backups_encryption_key'.tr(), + ), + ), const SizedBox(height: 16), if (backupJobs.isNotEmpty) Column( diff --git a/lib/ui/pages/backups/copy_encryption_key_modal.dart b/lib/ui/pages/backups/copy_encryption_key_modal.dart new file mode 100644 index 00000000..5421b2a8 --- /dev/null +++ b/lib/ui/pages/backups/copy_encryption_key_modal.dart @@ -0,0 +1,88 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:selfprivacy/config/get_it_config.dart'; +import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; +import 'package:selfprivacy/logic/cubit/backups/backups_cubit.dart'; +import 'package:selfprivacy/logic/cubit/server_jobs/server_jobs_cubit.dart'; + +class CopyEncryptionKeyModal extends StatefulWidget { + const CopyEncryptionKeyModal({ + required this.scrollController, + super.key, + }); + + final ScrollController scrollController; + + @override + State createState() => _CopyEncryptionKeyModalState(); +} + +class _CopyEncryptionKeyModalState extends State { + bool isKeyVisible = false; + @override + Widget build(final BuildContext context) { + final String encryptionKey = + context.watch().state.backblazeBucket!.encryptionKey; + return ListView( + controller: widget.scrollController, + padding: const EdgeInsets.all(16), + children: [ + const SizedBox(height: 16), + Text( + 'backup.backups_encryption_key'.tr(), + style: Theme.of(context).textTheme.headlineSmall, + textAlign: TextAlign.center, + ), + const SizedBox(height: 8), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IconButton( + icon: Icon( + isKeyVisible + ? Icons.visibility_outlined + : Icons.visibility_off_outlined, + ), + onPressed: () { + setState( + () { + isKeyVisible = !isKeyVisible; + }, + ); + }, + ), + IconButton( + icon: const Icon(Icons.copy_all_outlined), + onPressed: () { + getIt() + .showSnackBar('basis.copied_to_clipboard'.tr()); + Clipboard.setData( + ClipboardData( + text: encryptionKey, + ), + ); + }, + ), + ], + ), + Flexible( + child: isKeyVisible + ? SelectableText( + encryptionKey, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: Theme.of(context).colorScheme.onBackground, + ), + ) + : Text( + ''.padLeft(encryptionKey.length, '●'), + style: Theme.of(context).textTheme.titleMedium?.copyWith( + color: Theme.of(context).colorScheme.onBackground, + ), + ), + ), + ], + ); + } +}