From b925f7c8d4a8966de7008a0216e9558c41761fd6 Mon Sep 17 00:00:00 2001 From: NaiJi Date: Wed, 18 Dec 2024 13:07:35 +0200 Subject: [PATCH] feat: Add amazing backups card description (#595) - Resolves: #587 Reviewed-on: https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/pulls/595 Reviewed-by: Inex Code Co-authored-by: NaiJi Co-committed-by: NaiJi --- assets/translations/en.json | 8 +++- lib/logic/bloc/backups/backups_state.dart | 13 +++++++ lib/ui/pages/providers/providers.dart | 45 ++++++++++++++++++++--- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index bf1db1e8..ce8c9438 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -221,7 +221,13 @@ }, "backup": { "card_title": "Backup", - "card_subtitle": "Manage your backups", + "card_subtitle": "Last backup was {numericValue}{measurement} ago", + "measurement": { + "seconds": "sec", + "minutes": "min", + "hours": "h", + "days": "d" + }, "description": "Will save your day in case of incident: hackers attack, server deletion, etc.", "reupload_key": "Force reupload key", "reuploaded_key": "Key reuploaded", diff --git a/lib/logic/bloc/backups/backups_state.dart b/lib/logic/bloc/backups/backups_state.dart index 8a1032fc..e7c87d82 100644 --- a/lib/logic/bloc/backups/backups_state.dart +++ b/lib/logic/bloc/backups/backups_state.dart @@ -20,6 +20,8 @@ sealed class BackupsState extends Equatable { List serviceBackups(final String serviceId) => []; + Duration? timeSinceLastBackup() => null; + Duration? get autobackupPeriod => null; AutobackupQuotas? get autobackupQuotas => null; @@ -125,6 +127,17 @@ class BackupsInitialized extends BackupsState { ? null : _backupConfig?.autobackupPeriod; + @override + Duration? timeSinceLastBackup() { + if (backups.isEmpty) { + return null; + } + final timeNow = DateTime.now(); + final timeLastBackup = backups.first.time; + final delta = timeNow.difference(timeLastBackup); + return Duration(seconds: delta.inSeconds); + } + @override @Deprecated('Infer the initializations status from state') bool get isInitialized => true; diff --git a/lib/ui/pages/providers/providers.dart b/lib/ui/pages/providers/providers.dart index 5cb0c4e9..7abdbd6b 100644 --- a/lib/ui/pages/providers/providers.dart +++ b/lib/ui/pages/providers/providers.dart @@ -15,6 +15,7 @@ import 'package:selfprivacy/ui/molecules/cards/server_outdated_card.dart'; import 'package:selfprivacy/ui/organisms/headers/brand_header.dart'; import 'package:selfprivacy/ui/router/router.dart'; import 'package:selfprivacy/utils/breakpoints.dart'; +import 'package:selfprivacy/utils/extensions/duration.dart'; import 'package:skeletonizer/skeletonizer.dart'; GlobalKey navigatorKey = GlobalKey(); @@ -33,6 +34,7 @@ class _ProvidersPageState extends State { final bool isReady = context.watch().state is ServerInstallationFinished; final BackupsState backupsState = context.watch().state; + final DnsRecordsStatus dnsStatus = context.watch().state.dnsState; @@ -127,12 +129,7 @@ class _ProvidersPageState extends State { : StateType.uninitialized, icon: BrandIcons.save, title: 'backup.card_title'.tr(), - subtitle: backupsState is BackupsInitialized - ? 'backup.card_subtitle'.tr() - : backupsState is BackupsLoading || - backupsState is BackupsInitial - ? 'basis.loading'.tr() - : '', + subtitle: _backupsCardSubtitle(backupsState), onTap: isClickable() ? () => context.pushRoute(const BackupDetailsRoute()) : null, @@ -142,4 +139,40 @@ class _ProvidersPageState extends State { ), ); } + + String _backupsCardSubtitle(final BackupsState backupsState) { + if (backupsState is BackupsInitialized) { + final timeSince = backupsState.timeSinceLastBackup(); + if (timeSince == null) { + return ''; + } + + int numericValue = 0; + String measurement = 'backup.measurement.seconds'.tr(); + if (timeSince.inMinutes < 1) { + numericValue = timeSince.inSeconds; + } else if (timeSince.inHours < 1) { + numericValue = timeSince.inMinutes; + measurement = 'backup.measurement.minutes'.tr(); + } else if (timeSince.inDays < 1) { + numericValue = timeSince.inHours; + measurement = 'backup.measurement.hours'.tr(); + } else { + numericValue = timeSince.inDays; + measurement = 'backup.measurement.days'.tr(); + } + + return 'backup.card_subtitle'.tr( + namedArgs: { + 'numericValue': numericValue.toString(), + 'measurement': measurement, + }, + ); + } else if (backupsState is BackupsLoading || + backupsState is BackupsInitial) { + return 'basis.loading'.tr(); + } else { + return ''; + } + } }