import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:selfprivacy/config/brand_colors.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/models/json/backup.dart'; import 'package:selfprivacy/logic/models/state_types.dart'; import 'package:selfprivacy/ui/components/action_button/action_button.dart'; import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart'; import 'package:selfprivacy/ui/components/brand_button/brand_button.dart'; import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart'; import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; import 'package:selfprivacy/ui/components/brand_cards/brand_cards.dart'; GlobalKey navigatorKey = GlobalKey(); class BackupDetails extends StatefulWidget { const BackupDetails({final super.key}); @override State createState() => _BackupDetailsState(); } class _BackupDetailsState extends State with SingleTickerProviderStateMixin { @override Widget build(final BuildContext context) { final bool isReady = context.watch().state is ServerInstallationFinished; final bool isBackupInitialized = context.watch().state.isInitialized; final BackupStatusEnum backupStatus = context.watch().state.status; final StateType providerState = isReady && isBackupInitialized ? (backupStatus == BackupStatusEnum.error ? StateType.warning : StateType.stable) : StateType.uninitialized; final bool preventActions = context.watch().state.preventActions; final double backupProgress = context.watch().state.progress; final String backupError = context.watch().state.error; final List backups = context.watch().state.backups; final bool refreshing = context.watch().state.refreshing; return BrandHeroScreen( heroIcon: BrandIcons.save, heroTitle: 'providers.backup.card_title'.tr(), heroSubtitle: 'providers.backup.bottom_sheet.1'.tr(), children: [ if (isReady && !isBackupInitialized) BrandButton.rised( onPressed: preventActions ? null : () async { await context.read().createBucket(); }, text: 'providers.backup.initialize'.tr(), ), if (backupStatus == BackupStatusEnum.initializing) BrandText.body1('providers.backup.waitingForRebuild'.tr()), if (backupStatus != BackupStatusEnum.initializing && backupStatus != BackupStatusEnum.noKey) BrandCards.outlined( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (backupStatus == BackupStatusEnum.initialized) ListTile( onTap: preventActions ? null : () async { await context.read().createBackup(); }, leading: const Icon( Icons.add_circle_outline_rounded, ), title: Text( 'providers.backup.create_new'.tr(), style: Theme.of(context).textTheme.headline6, ), ), if (backupStatus == BackupStatusEnum.backingUp) ListTile( title: Text( 'providers.backup.creating'.tr( args: [(backupProgress * 100).round().toString()], ), style: Theme.of(context).textTheme.headline6, ), subtitle: LinearProgressIndicator( value: backupProgress, backgroundColor: Colors.grey.withOpacity(0.2), ), ), if (backupStatus == BackupStatusEnum.restoring) ListTile( title: Text( 'providers.backup.restoring'.tr( args: [(backupProgress * 100).round().toString()], ), style: Theme.of(context).textTheme.headline6, ), subtitle: LinearProgressIndicator( backgroundColor: Colors.grey.withOpacity(0.2), ), ), if (backupStatus == BackupStatusEnum.error) ListTile( leading: const Icon( Icons.error_outline, color: BrandColors.red1, ), title: Text( 'providers.backup.error_pending'.tr(), style: Theme.of(context).textTheme.headline6, ), ), ], ), ), const SizedBox(height: 16), // Card with a list of existing backups // Each list item has a date // When clicked, starts the restore action if (backupStatus != BackupStatusEnum.initializing && backupStatus != BackupStatusEnum.noKey) BrandCards.outlined( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ListTile( leading: const Icon( Icons.refresh, ), title: Text( 'providers.backup.restore'.tr(), style: Theme.of(context).textTheme.headline6, ), ), const Divider( height: 1.0, ), if (backups.isEmpty) ListTile( leading: const Icon( Icons.error_outline, ), title: Text('providers.backup.no_backups'.tr()), ), if (backups.isNotEmpty) Column( children: backups .map( (final Backup backup) => ListTile( onTap: preventActions ? null : () { final NavigationService nav = getIt(); nav.showPopUpDialog( BrandAlert( title: 'providers.backup.restoring'.tr(), contentText: 'providers.backup.restore_alert'.tr( args: [backup.time.toString()], ), actions: [ ActionButton( text: 'basis.cancel'.tr(), ), ActionButton( onPressed: () => { context .read() .restoreBackup(backup.id) }, text: 'modals.yes'.tr(), ) ], ), ); }, title: Text( '${MaterialLocalizations.of(context).formatShortDate(backup.time)} ${TimeOfDay.fromDateTime(backup.time).format(context)}', ), ), ) .toList(), ), ], ), ), const SizedBox(height: 16), BrandCards.outlined( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ListTile( title: Text( 'providers.backup.refresh'.tr(), ), onTap: refreshing ? null : () => {context.read().updateBackups()}, enabled: !refreshing, ), if (providerState != StateType.uninitialized) Column( children: [ const Divider( height: 1.0, ), ListTile( title: Text( 'providers.backup.refetchBackups'.tr(), ), onTap: preventActions ? null : () => { context .read() .forceUpdateBackups() }, ), const Divider( height: 1.0, ), ListTile( title: Text( 'providers.backup.reuploadKey'.tr(), ), onTap: preventActions ? null : () => {context.read().reuploadKey()}, ), ], ), ], ), ), if (backupStatus == BackupStatusEnum.error) BrandText.body1(backupError.toString()), ], ); } }