From 8de7eed9409a68f0e2c4d28c66b79cb188dd2532 Mon Sep 17 00:00:00 2001 From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> Date: Sun, 28 Sep 2025 06:51:38 +0530 Subject: [PATCH] feat(mobile): add unstack button (#21869) * fix: add unstack button * feat: allow unstacking inside of asset viewer * chore: update tests * chore: rework unstacking in asset viewer --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: bwees --- .../unstack_action_button.widget.dart | 2 +- .../asset_viewer/bottom_sheet.widget.dart | 1 + .../archive_bottom_sheet.widget.dart | 2 + .../favorite_bottom_sheet.widget.dart | 2 + .../general_bottom_sheet.widget.dart | 2 + .../remote_album_bottom_sheet.widget.dart | 2 + .../infrastructure/action.provider.dart | 13 +++ .../timeline/multiselect.provider.dart | 2 + mobile/lib/utils/action_button.utils.dart | 27 ++--- .../test/utils/action_button_utils_test.dart | 110 ++++++++++++++++++ 10 files changed, 145 insertions(+), 18 deletions(-) diff --git a/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart b/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart index ecc8a39c74..a07803ace5 100644 --- a/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart +++ b/mobile/lib/presentation/widgets/action_buttons/unstack_action_button.widget.dart @@ -36,7 +36,7 @@ class UnStackActionButton extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return BaseActionButton( - iconData: Icons.filter_none_rounded, + iconData: Icons.layers_clear_outlined, label: "unstack".t(context: context), onPressed: () => _onTap(context, ref), ); diff --git a/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet.widget.dart index 7431290ad8..2586789beb 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/bottom_sheet.widget.dart @@ -51,6 +51,7 @@ class AssetDetailBottomSheet extends ConsumerWidget { isArchived: isArchived, isTrashEnabled: isTrashEnable, isInLockedView: isInLockedView, + isStacked: asset.hasRemote && (asset as RemoteAsset).stackId != null, currentAlbum: currentAlbum, advancedTroubleshooting: advancedTroubleshooting, source: ActionSource.viewer, diff --git a/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart index 558df4e496..f40e189e18 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart @@ -13,6 +13,7 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_act import 'package:immich_mobile/presentation/widgets/action_buttons/stack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/unarchive_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/unstack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart'; import 'package:immich_mobile/providers/server_info.provider.dart'; @@ -44,6 +45,7 @@ class ArchiveBottomSheet extends ConsumerWidget { const EditLocationActionButton(source: ActionSource.timeline), const MoveToLockFolderActionButton(source: ActionSource.timeline), if (multiselect.selectedAssets.length > 1) const StackActionButton(source: ActionSource.timeline), + if (multiselect.hasStacked) const UnStackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), diff --git a/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart index a162dbbfb2..c7a0fbab40 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart @@ -13,6 +13,7 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_act import 'package:immich_mobile/presentation/widgets/action_buttons/stack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/unfavorite_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/unstack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart'; import 'package:immich_mobile/providers/server_info.provider.dart'; @@ -44,6 +45,7 @@ class FavoriteBottomSheet extends ConsumerWidget { const EditLocationActionButton(source: ActionSource.timeline), const MoveToLockFolderActionButton(source: ActionSource.timeline), if (multiselect.selectedAssets.length > 1) const StackActionButton(source: ActionSource.timeline), + if (multiselect.hasStacked) const UnStackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), diff --git a/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart index e50ed47368..9436707c84 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart @@ -20,6 +20,7 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_b import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/stack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/unstack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart'; import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart'; @@ -117,6 +118,7 @@ class _GeneralBottomSheetState extends ConsumerState { const EditLocationActionButton(source: ActionSource.timeline), const MoveToLockFolderActionButton(source: ActionSource.timeline), if (multiselect.selectedAssets.length > 1) const StackActionButton(source: ActionSource.timeline), + if (multiselect.hasStacked) const UnStackActionButton(source: ActionSource.timeline), const DeleteActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal || multiselect.hasMerged) const DeleteLocalActionButton(source: ActionSource.timeline), diff --git a/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart b/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart index 1dcc52f349..0ab419a56b 100644 --- a/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart +++ b/mobile/lib/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart @@ -17,6 +17,7 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_b import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/stack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/unstack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart'; import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart'; @@ -102,6 +103,7 @@ class _RemoteAlbumBottomSheetState extends ConsumerState const EditLocationActionButton(source: ActionSource.timeline), const MoveToLockFolderActionButton(source: ActionSource.timeline), if (multiselect.selectedAssets.length > 1) const StackActionButton(source: ActionSource.timeline), + if (multiselect.hasStacked) const UnStackActionButton(source: ActionSource.timeline), ], if (multiselect.hasLocal) ...[ const DeleteLocalActionButton(source: ActionSource.timeline), diff --git a/mobile/lib/providers/infrastructure/action.provider.dart b/mobile/lib/providers/infrastructure/action.provider.dart index 9a343aa358..77ac6595a7 100644 --- a/mobile/lib/providers/infrastructure/action.provider.dart +++ b/mobile/lib/providers/infrastructure/action.provider.dart @@ -3,7 +3,10 @@ import 'package:background_downloader/background_downloader.dart'; import 'package:flutter/material.dart'; import 'package:immich_mobile/constants/enums.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/services/asset.service.dart'; import 'package:immich_mobile/models/download/livephotos_medatada.model.dart'; +import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart'; +import 'package:immich_mobile/providers/infrastructure/asset.provider.dart'; import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; @@ -36,6 +39,7 @@ class ActionNotifier extends Notifier { late ActionService _service; late UploadService _uploadService; late DownloadService _downloadService; + late AssetService _assetService; ActionNotifier() : super(); @@ -43,6 +47,7 @@ class ActionNotifier extends Notifier { void build() { _uploadService = ref.watch(uploadServiceProvider); _service = ref.watch(actionServiceProvider); + _assetService = ref.watch(assetServiceProvider); _downloadService = ref.watch(downloadServiceProvider); _downloadService.onImageDownloadStatus = _downloadImageCallback; _downloadService.onVideoDownloadStatus = _downloadVideoCallback; @@ -335,6 +340,14 @@ class ActionNotifier extends Notifier { final assets = _getOwnedRemoteAssetsForSource(source); try { await _service.unStack(assets.map((e) => e.stackId).nonNulls.toList()); + if (source == ActionSource.viewer) { + final updatedParent = await _assetService.getRemoteAsset(assets.first.id); + if (updatedParent != null) { + ref.read(currentAssetNotifier.notifier).setAsset(updatedParent); + ref.read(assetViewerProvider.notifier).setAsset(updatedParent); + } + } + return ActionResult(count: assets.length, success: true); } catch (error, stack) { _logger.severe('Failed to unstack assets', error, stack); diff --git a/mobile/lib/providers/timeline/multiselect.provider.dart b/mobile/lib/providers/timeline/multiselect.provider.dart index e225e0c98d..6949413cd9 100644 --- a/mobile/lib/providers/timeline/multiselect.provider.dart +++ b/mobile/lib/providers/timeline/multiselect.provider.dart @@ -28,6 +28,8 @@ class MultiSelectState { bool get hasRemote => selectedAssets.any((asset) => asset.storage == AssetState.remote || asset.storage == AssetState.merged); + bool get hasStacked => selectedAssets.any((asset) => asset is RemoteAsset && asset.stackId != null); + bool get hasLocal => selectedAssets.any((asset) => asset.storage == AssetState.local); bool get hasMerged => selectedAssets.any((asset) => asset.storage == AssetState.merged); diff --git a/mobile/lib/utils/action_button.utils.dart b/mobile/lib/utils/action_button.utils.dart index 090aeeeaa7..c5a2583531 100644 --- a/mobile/lib/utils/action_button.utils.dart +++ b/mobile/lib/utils/action_button.utils.dart @@ -16,6 +16,7 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_b import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/unarchive_action_button.widget.dart'; +import 'package:immich_mobile/presentation/widgets/action_buttons/unstack_action_button.widget.dart'; import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart'; class ActionButtonContext { @@ -24,6 +25,7 @@ class ActionButtonContext { final bool isArchived; final bool isTrashEnabled; final bool isInLockedView; + final bool isStacked; final RemoteAlbum? currentAlbum; final bool advancedTroubleshooting; final ActionSource source; @@ -33,6 +35,7 @@ class ActionButtonContext { required this.isOwner, required this.isArchived, required this.isTrashEnabled, + required this.isStacked, required this.isInLockedView, required this.currentAlbum, required this.advancedTroubleshooting, @@ -55,6 +58,7 @@ enum ActionButtonType { deleteLocal, upload, removeFromAlbum, + unstack, likeActivity; bool shouldShow(ActionButtonContext context) { @@ -110,6 +114,10 @@ enum ActionButtonType { context.isOwner && // !context.isInLockedView && // context.currentAlbum != null, + ActionButtonType.unstack => + context.isOwner && // + !context.isInLockedView && // + context.isStacked, ActionButtonType.likeActivity => !context.isInLockedView && context.currentAlbum != null && @@ -138,28 +146,13 @@ enum ActionButtonType { source: context.source, ), ActionButtonType.likeActivity => const LikeActivityActionButton(), + ActionButtonType.unstack => UnStackActionButton(source: context.source), }; } } class ActionButtonBuilder { - static const List _actionTypes = [ - ActionButtonType.advancedInfo, - ActionButtonType.share, - ActionButtonType.shareLink, - ActionButtonType.likeActivity, - ActionButtonType.archive, - ActionButtonType.unarchive, - ActionButtonType.download, - ActionButtonType.trash, - ActionButtonType.deletePermanent, - ActionButtonType.delete, - ActionButtonType.moveToLockFolder, - ActionButtonType.removeFromLockFolder, - ActionButtonType.deleteLocal, - ActionButtonType.upload, - ActionButtonType.removeFromAlbum, - ]; + static const List _actionTypes = ActionButtonType.values; static List build(ActionButtonContext context) { return _actionTypes.where((type) => type.shouldShow(context)).map((type) => type.buildButton(context)).toList(); diff --git a/mobile/test/utils/action_button_utils_test.dart b/mobile/test/utils/action_button_utils_test.dart index f8c51173d7..274176ae88 100644 --- a/mobile/test/utils/action_button_utils_test.dart +++ b/mobile/test/utils/action_button_utils_test.dart @@ -82,6 +82,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -112,6 +113,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -127,6 +129,7 @@ void main() { isInLockedView: true, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -145,6 +148,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -161,6 +165,7 @@ void main() { isInLockedView: true, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -177,6 +182,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -195,6 +201,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -211,6 +218,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -227,6 +235,7 @@ void main() { isInLockedView: true, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -243,6 +252,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -259,6 +269,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -277,6 +288,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -293,6 +305,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -309,6 +322,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -327,6 +341,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -343,6 +358,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -359,6 +375,7 @@ void main() { isInLockedView: true, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -377,6 +394,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -393,6 +411,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -411,6 +430,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -427,6 +447,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -445,6 +466,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -463,6 +485,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -481,6 +504,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -497,6 +521,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -512,6 +537,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -530,6 +556,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -548,6 +575,7 @@ void main() { isInLockedView: false, currentAlbum: album, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -563,6 +591,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -581,6 +610,7 @@ void main() { isInLockedView: false, currentAlbum: album, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -597,6 +627,7 @@ void main() { isInLockedView: false, currentAlbum: album, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -613,6 +644,7 @@ void main() { isInLockedView: false, currentAlbum: album, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -628,6 +660,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -645,6 +678,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: true, + isStacked: false, source: ActionSource.timeline, ); @@ -660,6 +694,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -668,6 +703,59 @@ void main() { }); }); + group('unstack button', () { + test('should show when owner, not locked, has remote, and is stacked', () { + final remoteAsset = createRemoteAsset(); + final context = ActionButtonContext( + asset: remoteAsset, + isOwner: true, + isArchived: false, + isTrashEnabled: true, + isInLockedView: false, + currentAlbum: null, + advancedTroubleshooting: false, + isStacked: true, + source: ActionSource.timeline, + ); + + expect(ActionButtonType.unstack.shouldShow(context), isTrue); + }); + + test('should not show when not stacked', () { + final remoteAsset = createRemoteAsset(); + final context = ActionButtonContext( + asset: remoteAsset, + isOwner: true, + isArchived: false, + isTrashEnabled: true, + isInLockedView: false, + currentAlbum: null, + advancedTroubleshooting: false, + isStacked: false, + source: ActionSource.timeline, + ); + + expect(ActionButtonType.unstack.shouldShow(context), isFalse); + }); + + test('should not show when not owner', () { + final remoteAsset = createRemoteAsset(); + final context = ActionButtonContext( + asset: remoteAsset, + isOwner: false, + isArchived: true, + isTrashEnabled: true, + isInLockedView: false, + currentAlbum: null, + advancedTroubleshooting: false, + isStacked: false, + source: ActionSource.timeline, + ); + + expect(ActionButtonType.unstack.shouldShow(context), isFalse); + }); + }); + group('ActionButtonType.buildButton', () { late BaseAsset asset; late ActionButtonContext context; @@ -682,6 +770,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); }); @@ -698,6 +787,22 @@ void main() { isInLockedView: false, currentAlbum: album, advancedTroubleshooting: false, + isStacked: false, + source: ActionSource.timeline, + ); + final widget = buttonType.buildButton(contextWithAlbum); + expect(widget, isA()); + } else if (buttonType == ActionButtonType.unstack) { + final album = createRemoteAlbum(); + final contextWithAlbum = ActionButtonContext( + asset: asset, + isOwner: true, + isArchived: false, + isTrashEnabled: true, + isInLockedView: false, + currentAlbum: album, + advancedTroubleshooting: false, + isStacked: true, source: ActionSource.timeline, ); final widget = buttonType.buildButton(contextWithAlbum); @@ -721,6 +826,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -741,6 +847,7 @@ void main() { isInLockedView: false, currentAlbum: album, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -759,6 +866,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -778,6 +886,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, ); @@ -791,6 +900,7 @@ void main() { isInLockedView: false, currentAlbum: null, advancedTroubleshooting: false, + isStacked: false, source: ActionSource.timeline, );