From 4cf0d88f356ed3be26534771fae074f8c2690e9f Mon Sep 17 00:00:00 2001 From: Santo Shakil Date: Fri, 24 Jul 2026 00:48:42 +0600 Subject: [PATCH] fix(mobile): show a partial success message when local copies are kept --- i18n/en.json | 1 + .../move_to_lock_folder_action_button.widget.dart | 10 ++++++---- .../lib/providers/infrastructure/action.provider.dart | 2 +- .../providers/infrastructure/action_provider_test.dart | 10 ++++++---- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/i18n/en.json b/i18n/en.json index 81c3a21775..b8d139a3d6 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1459,6 +1459,7 @@ "move_to": "Move to", "move_to_device_trash": "Move to device trash", "move_to_lock_folder_action_prompt": "{count} added to the locked folder", + "move_to_lock_folder_partial_prompt": "{count} added to the locked folder, {kept} local copies were kept", "move_to_locked_folder": "Move to locked folder", "move_to_locked_folder_confirmation": "These photos and video will be removed from all albums, and only viewable from the locked folder", "move_to_locked_folder_local_ios": "These items will be deleted from Photos, but will still be available on the Immich server. They will be in Recently Deleted for 30 days.", diff --git a/mobile/lib/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart index 4bc78a958d..89a5620512 100644 --- a/mobile/lib/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart @@ -27,10 +27,12 @@ Future performMoveToLockFolderAction(BuildContext context, WidgetRef ref, ref.read(multiSelectProvider.notifier).reset(); - final successMessage = 'move_to_lock_folder_action_prompt'.t( - context: context, - args: {'count': result.count.toString()}, - ); + final successMessage = result.failedCount > 0 + ? 'move_to_lock_folder_partial_prompt'.t( + context: context, + args: {'count': result.count.toString(), 'kept': result.failedCount.toString()}, + ) + : 'move_to_lock_folder_action_prompt'.t(context: context, args: {'count': result.count.toString()}); if (context.mounted) { ImmichToast.show( diff --git a/mobile/lib/providers/infrastructure/action.provider.dart b/mobile/lib/providers/infrastructure/action.provider.dart index 6e1cc0c8c2..f9f2edb961 100644 --- a/mobile/lib/providers/infrastructure/action.provider.dart +++ b/mobile/lib/providers/infrastructure/action.provider.dart @@ -201,7 +201,7 @@ class ActionNotifier extends Notifier { try { final deletedCount = await _service.moveToLockFolder(ids, localIds); - return ActionResult(count: ids.length, success: deletedCount == localIds.length); + return ActionResult(count: ids.length, success: true, failedCount: localIds.length - deletedCount); } catch (error, stack) { _logger.severe('Failed to move assets to lock folder', error, stack); return ActionResult(count: ids.length, success: false, error: error.toString()); diff --git a/mobile/test/providers/infrastructure/action_provider_test.dart b/mobile/test/providers/infrastructure/action_provider_test.dart index 1a60d6ae07..37addbcb25 100644 --- a/mobile/test/providers/infrastructure/action_provider_test.dart +++ b/mobile/test/providers/infrastructure/action_provider_test.dart @@ -138,18 +138,19 @@ void main() { return result; } - testWidgets('reports failure when local deletion is cancelled', (tester) async { + testWidgets('keeps success and reports kept local copies when the OS delete is declined', (tester) async { final asset = _asset.copyWith(localId: 'local-owned'); container.read(multiSelectProvider.notifier).selectAsset(asset); when(() => actionService.moveToLockFolder(any(), any())).thenAnswer((_) async => 0); final result = await runAction(tester); - expect(result?.success, isFalse); + expect(result?.success, isTrue); + expect(result?.failedCount, 1); verify(() => actionService.moveToLockFolder(['asset-1'], ['local-owned'])).called(1); }); - testWidgets('reports failure when only some local copies are deleted', (tester) async { + testWidgets('reports kept local copies when only some are deleted', (tester) async { final first = _asset.copyWith(localId: 'local-1'); final second = _asset.copyWith(id: 'asset-2', localId: 'local-2', checksum: 'checksum-2'); container.read(multiSelectProvider.notifier) @@ -159,7 +160,8 @@ void main() { final result = await runAction(tester); - expect(result?.success, isFalse); + expect(result?.success, isTrue); + expect(result?.failedCount, 1); }); testWidgets('deletes only owned local copies from a mixed selection', (tester) async {