From 939c222728bc14d46665b60fac01abf01a788373 Mon Sep 17 00:00:00 2001 From: idubnori Date: Wed, 17 Dec 2025 14:27:38 +0900 Subject: [PATCH] feat(mobile): add ButtonPosition enum and update action button context --- mobile/lib/constants/enums.dart | 2 + .../asset_viewer/bottom_bar.widget.dart | 1 + mobile/lib/utils/action_button.utils.dart | 7 +- .../test/utils/action_button_utils_test.dart | 98 +++++++++++++++++++ 4 files changed, 106 insertions(+), 2 deletions(-) diff --git a/mobile/lib/constants/enums.dart b/mobile/lib/constants/enums.dart index 91ca50a2c0..674b988aa2 100644 --- a/mobile/lib/constants/enums.dart +++ b/mobile/lib/constants/enums.dart @@ -7,3 +7,5 @@ enum AssetVisibilityEnum { timeline, hidden, archive, locked } enum SortUserBy { id } enum ActionSource { timeline, viewer } + +enum ButtonPosition { bottomBar, kebabMenu, other } diff --git a/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart index f9f3c3478d..fb9c70fa1e 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart @@ -57,6 +57,7 @@ class ViewerBottomBar extends ConsumerWidget { source: ActionSource.viewer, timelineOrigin: timelineOrigin, originalTheme: originalTheme, + buttonPosition: ButtonPosition.bottomBar, ); final actions = ActionButtonBuilder.buildViewerBottomBar(buttonContext, context, ref); diff --git a/mobile/lib/utils/action_button.utils.dart b/mobile/lib/utils/action_button.utils.dart index 0af8372a8b..547591329c 100644 --- a/mobile/lib/utils/action_button.utils.dart +++ b/mobile/lib/utils/action_button.utils.dart @@ -45,6 +45,7 @@ class ActionButtonContext { final bool isCasting; final TimelineOrigin timelineOrigin; final ThemeData? originalTheme; + final ButtonPosition buttonPosition; const ActionButtonContext({ required this.asset, @@ -59,6 +60,7 @@ class ActionButtonContext { this.isCasting = false, this.timelineOrigin = TimelineOrigin.main, this.originalTheme, + this.buttonPosition = ButtonPosition.other, }); } @@ -138,7 +140,8 @@ enum ActionButtonType { context.asset.storage == AssetState.local, ActionButtonType.editImage => !context.isInLockedView && // - context.asset.type == AssetType.image, + context.asset.type == AssetType.image && + !(context.buttonPosition == ButtonPosition.bottomBar && context.currentAlbum?.isShared == true), ActionButtonType.addTo => !context.isInLockedView && // context.asset.hasRemote, @@ -296,9 +299,9 @@ class ActionButtonBuilder { ActionButtonType.share, ActionButtonType.upload, ActionButtonType.editImage, + ActionButtonType.addTo, ActionButtonType.openActivity, ActionButtonType.likeActivity, - ActionButtonType.addTo, ActionButtonType.deleteLocal, ActionButtonType.delete, ActionButtonType.removeFromLockFolder, diff --git a/mobile/test/utils/action_button_utils_test.dart b/mobile/test/utils/action_button_utils_test.dart index d93d59d3c7..0cfda00c69 100644 --- a/mobile/test/utils/action_button_utils_test.dart +++ b/mobile/test/utils/action_button_utils_test.dart @@ -962,4 +962,102 @@ void main() { expect(nonArchivedWidgets, isNotEmpty); }); }); + + group('ActionButtonBuilder.getViewerBottomBarTypes', () { + test('should return correct button types for shared album with activity', () { + final remoteAsset = createRemoteAsset(); + final album = createRemoteAlbum(isActivityEnabled: true, isShared: true); + final context = ActionButtonContext( + asset: remoteAsset, + isOwner: true, + isArchived: false, + isTrashEnabled: true, + isInLockedView: false, + currentAlbum: album, + advancedTroubleshooting: false, + isStacked: false, + source: ActionSource.viewer, + buttonPosition: ButtonPosition.bottomBar, + ); + + final types = ActionButtonBuilder.getViewerBottomBarTypes(context); + + expect(types.length, 4); + expect(types[0], ActionButtonType.share); + expect(types[1], ActionButtonType.addTo); + expect(types[2], ActionButtonType.openActivity); + expect(types[3], ActionButtonType.likeActivity); + }); + + test('should return correct button types for local only asset', () { + final localAsset = createLocalAsset(); + final context = ActionButtonContext( + asset: localAsset, + isOwner: true, + isArchived: false, + isTrashEnabled: true, + isInLockedView: false, + currentAlbum: null, + advancedTroubleshooting: false, + isStacked: false, + source: ActionSource.viewer, + buttonPosition: ButtonPosition.bottomBar, + ); + + final types = ActionButtonBuilder.getViewerBottomBarTypes(context); + + expect(types.length, 4); + expect(types[0], ActionButtonType.share); + expect(types[1], ActionButtonType.upload); + expect(types[2], ActionButtonType.editImage); + expect(types[3], ActionButtonType.deleteLocal); + }); + + test('should return correct button types for locked view', () { + final remoteAsset = createRemoteAsset(); + final context = ActionButtonContext( + asset: remoteAsset, + isOwner: true, + isArchived: false, + isTrashEnabled: false, + isInLockedView: true, + currentAlbum: null, + advancedTroubleshooting: false, + isStacked: false, + source: ActionSource.viewer, + buttonPosition: ButtonPosition.bottomBar, + ); + + final types = ActionButtonBuilder.getViewerBottomBarTypes(context); + + expect(types.length, 3); + expect(types[0], ActionButtonType.share); + expect(types[1], ActionButtonType.removeFromLockFolder); + expect(types[2], ActionButtonType.deletePermanent); + }); + + test('should return correct button types for remote only asset', () { + final remoteAsset = createRemoteAsset(); + final context = ActionButtonContext( + asset: remoteAsset, + isOwner: true, + isArchived: false, + isTrashEnabled: true, + isInLockedView: false, + currentAlbum: null, + advancedTroubleshooting: false, + isStacked: false, + source: ActionSource.viewer, + buttonPosition: ButtonPosition.bottomBar, + ); + + final types = ActionButtonBuilder.getViewerBottomBarTypes(context); + + expect(types.length, 4); + expect(types[0], ActionButtonType.share); + expect(types[1], ActionButtonType.editImage); + expect(types[2], ActionButtonType.addTo); + expect(types[3], ActionButtonType.delete); + }); + }); }