import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/album/local_album.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart'; import 'package:immich_mobile/extensions/translate_extensions.dart'; import 'package:immich_mobile/presentation/widgets/backup/backup_toggle_button.widget.dart'; import 'package:immich_mobile/providers/backup/backup_album.provider.dart'; import 'package:immich_mobile/providers/backup/drift_backup.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/backup/backup_info_card.dart'; @RoutePage() class DriftBackupPage extends ConsumerStatefulWidget { const DriftBackupPage({super.key}); @override ConsumerState createState() => _DriftBackupPageState(); } class _DriftBackupPageState extends ConsumerState { @override void initState() { super.initState(); final currentUser = ref.read(currentUserProvider); if (currentUser == null) { return; } ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); } Future startBackup() async { final currentUser = ref.read(currentUserProvider); if (currentUser == null) { return; } await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); await ref.read(driftBackupProvider.notifier).startBackup(currentUser.id); } Future stopBackup() async { await ref.read(driftBackupProvider.notifier).cancel(); } @override Widget build(BuildContext context) { final selectedAlbum = ref .watch(backupAlbumProvider) .where( (album) => album.backupSelection == BackupSelection.selected, ) .toList(); return Scaffold( appBar: AppBar( elevation: 0, title: Text( "backup_controller_page_backup".t(), ), leading: IconButton( onPressed: () { context.maybePop(true); }, splashRadius: 24, icon: const Icon( Icons.arrow_back_ios_rounded, ), ), ), body: Stack( children: [ Padding( padding: const EdgeInsets.only( left: 16.0, right: 16, bottom: 32, ), child: ListView( children: [ const SizedBox(height: 8), const _BackupAlbumSelectionCard(), if (selectedAlbum.isNotEmpty) ...[ const _TotalCard(), const _BackupCard(), const _RemainderCard(), const Divider(), BackupToggleButton( onStart: () async => await startBackup(), onStop: () async => await stopBackup(), ), TextButton.icon( icon: const Icon(Icons.info_outline_rounded), onPressed: () => context.pushRoute( const DriftUploadDetailRoute(), ), label: Text("view_details".t(context: context)), ), ], ], ), ), ], ), ); } } class _BackupAlbumSelectionCard extends ConsumerWidget { const _BackupAlbumSelectionCard(); @override Widget build(BuildContext context, WidgetRef ref) { Widget buildSelectedAlbumName() { String text = "backup_controller_page_backup_selected".tr(); final albums = ref .watch(backupAlbumProvider) .where( (album) => album.backupSelection == BackupSelection.selected, ) .toList(); if (albums.isNotEmpty) { for (var album in albums) { if (album.name == "Recent" || album.name == "Recents") { text += "${album.name} (${'all'.tr()}), "; } else { text += "${album.name}, "; } } return Padding( padding: const EdgeInsets.only(top: 8.0), child: Text( text.trim().substring(0, text.length - 2), style: context.textTheme.labelLarge?.copyWith( color: context.primaryColor, ), ), ); } else { return Padding( padding: const EdgeInsets.only(top: 8.0), child: Text( "backup_controller_page_none_selected".tr(), style: context.textTheme.labelLarge?.copyWith( color: context.primaryColor, ), ), ); } } Widget buildExcludedAlbumName() { String text = "backup_controller_page_excluded".tr(); final albums = ref .watch(backupAlbumProvider) .where( (album) => album.backupSelection == BackupSelection.excluded, ) .toList(); if (albums.isNotEmpty) { for (var album in albums) { text += "${album.name}, "; } return Padding( padding: const EdgeInsets.only(top: 8.0), child: Text( text.trim().substring(0, text.length - 2), style: context.textTheme.labelLarge?.copyWith( color: Colors.red[300], ), ), ); } else { return const SizedBox(); } } return Card( shape: RoundedRectangleBorder( borderRadius: const BorderRadius.all(Radius.circular(20)), side: BorderSide( color: context.colorScheme.outlineVariant, width: 1, ), ), elevation: 0, borderOnForeground: false, child: ListTile( minVerticalPadding: 18, title: Text( "backup_controller_page_albums", style: context.textTheme.titleMedium, ).tr(), subtitle: Padding( padding: const EdgeInsets.only(top: 8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "backup_controller_page_to_backup", style: context.textTheme.bodyMedium?.copyWith( color: context.colorScheme.onSurfaceSecondary, ), ).tr(), buildSelectedAlbumName(), buildExcludedAlbumName(), ], ), ), trailing: ElevatedButton( onPressed: () async { await context.pushRoute(const DriftBackupAlbumSelectionRoute()); final currentUser = ref.read(currentUserProvider); if (currentUser == null) { return; } ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); }, child: const Text( "select", style: TextStyle( fontWeight: FontWeight.bold, ), ).tr(), ), ), ); } } class _TotalCard extends ConsumerWidget { const _TotalCard(); @override Widget build(BuildContext context, WidgetRef ref) { final totalCount = ref.watch(driftBackupProvider.select((p) => p.totalCount)); return BackupInfoCard( title: "total".tr(), subtitle: "backup_controller_page_total_sub".tr(), info: totalCount.toString(), ); } } class _BackupCard extends ConsumerWidget { const _BackupCard(); @override Widget build(BuildContext context, WidgetRef ref) { final backupCount = ref.watch(driftBackupProvider.select((p) => p.backupCount)); return BackupInfoCard( title: "backup_controller_page_backup".tr(), subtitle: "backup_controller_page_backup_sub".tr(), info: backupCount.toString(), ); } } class _RemainderCard extends ConsumerWidget { const _RemainderCard(); @override Widget build(BuildContext context, WidgetRef ref) { final remainderCount = ref.watch(driftBackupProvider.select((p) => p.remainderCount)); return BackupInfoCard( title: "backup_controller_page_remainder".tr(), subtitle: "backup_controller_page_remainder_sub".tr(), info: remainderCount.toString(), ); } }