From d36c26bf97c8f7fd1e1e418fcd9dabf91e734e1a Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 18 Sep 2025 15:36:43 -0500 Subject: [PATCH] chore: refresh backup stats when entering backup page (#21977) * chore: refresh backup stats when entering backup page * check for success status * remove logs * remove sync remote when toggle the button * show status immediately after navigating to screen * pr feedback --- .../lib/pages/backup/drift_backup.page.dart | 17 ++++++-- .../backup/drift_backup.provider.dart | 4 +- .../lib/widgets/backup/backup_info_card.dart | 43 +++++++++++++++++-- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/mobile/lib/pages/backup/drift_backup.page.dart b/mobile/lib/pages/backup/drift_backup.page.dart index bf9ad43f9c..8578506ced 100644 --- a/mobile/lib/pages/backup/drift_backup.page.dart +++ b/mobile/lib/pages/backup/drift_backup.page.dart @@ -12,6 +12,7 @@ import 'package:immich_mobile/presentation/widgets/backup/backup_toggle_button.w import 'package:immich_mobile/providers/background_sync.provider.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/sync_status.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'; @@ -33,7 +34,14 @@ class _DriftBackupPageState extends ConsumerState { return; } - ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); + WidgetsBinding.instance.addPostFrameCallback((_) async { + await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); + await ref.read(backgroundSyncProvider).syncRemote(); + + if (mounted) { + await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id); + } + }); } @override @@ -44,7 +52,6 @@ class _DriftBackupPageState extends ConsumerState { .toList(); final backupNotifier = ref.read(driftBackupProvider.notifier); - final backgroundManager = ref.read(backgroundSyncProvider); Future startBackup() async { final currentUser = Store.tryGet(StoreKey.currentUser); @@ -52,7 +59,6 @@ class _DriftBackupPageState extends ConsumerState { return; } - await backgroundManager.syncRemote(); await backupNotifier.getBackupStatus(currentUser.id); await backupNotifier.startBackup(currentUser.id); } @@ -235,11 +241,13 @@ class _BackupCard extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final backupCount = ref.watch(driftBackupProvider.select((p) => p.backupCount)); + final syncStatus = ref.watch(syncStatusProvider); return BackupInfoCard( title: "backup_controller_page_backup".tr(), subtitle: "backup_controller_page_backup_sub".tr(), info: backupCount.toString(), + isLoading: syncStatus.isRemoteSyncing, ); } } @@ -250,10 +258,13 @@ class _RemainderCard extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final remainderCount = ref.watch(driftBackupProvider.select((p) => p.remainderCount)); + final syncStatus = ref.watch(syncStatusProvider); + return BackupInfoCard( title: "backup_controller_page_remainder".tr(), subtitle: "backup_controller_page_remainder_sub".tr(), info: remainderCount.toString(), + isLoading: syncStatus.isRemoteSyncing, onTap: () => context.pushRoute(const DriftBackupAssetDetailRoute()), ); } diff --git a/mobile/lib/providers/backup/drift_backup.provider.dart b/mobile/lib/providers/backup/drift_backup.provider.dart index 40ec7b1077..4069cef13f 100644 --- a/mobile/lib/providers/backup/drift_backup.provider.dart +++ b/mobile/lib/providers/backup/drift_backup.provider.dart @@ -235,7 +235,9 @@ class DriftBackupNotifier extends StateNotifier { switch (update.status) { case TaskStatus.complete: if (update.task.group == kBackupGroup) { - state = state.copyWith(backupCount: state.backupCount + 1, remainderCount: state.remainderCount - 1); + if (update.responseStatusCode == 201) { + state = state.copyWith(backupCount: state.backupCount + 1, remainderCount: state.remainderCount - 1); + } } // Remove the completed task from the upload items diff --git a/mobile/lib/widgets/backup/backup_info_card.dart b/mobile/lib/widgets/backup/backup_info_card.dart index 6e34e89938..2ef7e24cd7 100644 --- a/mobile/lib/widgets/backup/backup_info_card.dart +++ b/mobile/lib/widgets/backup/backup_info_card.dart @@ -8,8 +8,17 @@ class BackupInfoCard extends StatelessWidget { final String title; final String subtitle; final String info; + final VoidCallback? onTap; - const BackupInfoCard({super.key, required this.title, required this.subtitle, required this.info, this.onTap}); + final bool isLoading; + const BackupInfoCard({ + super.key, + required this.title, + required this.subtitle, + required this.info, + this.onTap, + this.isLoading = false, + }); @override Widget build(BuildContext context) { @@ -38,8 +47,36 @@ class BackupInfoCard extends StatelessWidget { trailing: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text(info, style: context.textTheme.titleLarge), - Text("backup_info_card_assets", style: context.textTheme.labelLarge).tr(), + Stack( + children: [ + Text( + info, + style: context.textTheme.titleLarge?.copyWith( + color: context.colorScheme.onSurface.withAlpha(isLoading ? 50 : 255), + ), + ), + if (isLoading) + Positioned.fill( + child: Align( + alignment: Alignment.center, + child: SizedBox( + width: 16, + height: 16, + child: CircularProgressIndicator( + strokeWidth: 2, + color: context.colorScheme.onSurface.withAlpha(150), + ), + ), + ), + ), + ], + ), + Text( + "backup_info_card_assets", + style: context.textTheme.labelLarge?.copyWith( + color: context.colorScheme.onSurface.withAlpha(isLoading ? 50 : 255), + ), + ).tr(), ], ), ),