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 <inex.code@selfprivacy.org>
Co-authored-by: NaiJi <naijiworld@protonmail.com>
Co-committed-by: NaiJi <naijiworld@protonmail.com>
This commit is contained in:
NaiJi 2024-12-18 13:07:35 +02:00 committed by Inex Code
parent 35cbcebacb
commit b925f7c8d4
3 changed files with 59 additions and 7 deletions

View file

@ -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",

View file

@ -20,6 +20,8 @@ sealed class BackupsState extends Equatable {
List<Backup> 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;

View file

@ -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<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@ -33,6 +34,7 @@ class _ProvidersPageState extends State<ProvidersPage> {
final bool isReady = context.watch<ServerInstallationCubit>().state
is ServerInstallationFinished;
final BackupsState backupsState = context.watch<BackupsBloc>().state;
final DnsRecordsStatus dnsStatus =
context.watch<DnsRecordsCubit>().state.dnsState;
@ -127,12 +129,7 @@ class _ProvidersPageState extends State<ProvidersPage> {
: 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<ProvidersPage> {
),
);
}
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 '';
}
}
}