diff --git a/mobile/lib/domain/services/quick_action.service.dart b/mobile/lib/domain/services/quick_action.service.dart index a98e994b26..d15a67fd47 100644 --- a/mobile/lib/domain/services/quick_action.service.dart +++ b/mobile/lib/domain/services/quick_action.service.dart @@ -1,53 +1,28 @@ import 'package:immich_mobile/infrastructure/repositories/action_button_order.repository.dart'; import 'package:immich_mobile/utils/action_button.utils.dart'; -/// Service for managing quick action configurations. -/// Provides business logic for building quick action types based on context. class QuickActionService { final ActionButtonOrderRepository _repository; const QuickActionService(this._repository); - // Constants - static const int defaultQuickActionLimit = 4; - - static const List defaultQuickActionSeed = [ - ActionButtonType.share, - ActionButtonType.upload, - ActionButtonType.edit, - ActionButtonType.add, - ActionButtonType.archive, - ActionButtonType.delete, - ActionButtonType.removeFromAlbum, - ActionButtonType.likeActivity, - ]; - - static final Set _quickActionSet = Set.unmodifiable(defaultQuickActionSeed); - - static final List defaultQuickActionOrder = List.unmodifiable( - defaultQuickActionSeed, + static final Set _quickActionSet = Set.unmodifiable( + ActionButtonBuilder.defaultQuickActionOrder, ); - /// Get the list of available quick action options - // static List get quickActionOptions => defaultQuickActionOrder; - - /// Get the current quick action order List get() { return _repository.get(); } - /// Set the quick action order Future set(List order) async { final normalized = _normalizeQuickActionOrder(order); await _repository.set(normalized); } - /// Watch for changes to quick action order Stream> watch() { return _repository.watch(); } - /// Normalize quick action order by filtering valid types and ensuring all defaults are included List _normalizeQuickActionOrder(List order) { final ordered = {}; @@ -57,19 +32,20 @@ class QuickActionService { } } - ordered.addAll(defaultQuickActionSeed); + ordered.addAll(ActionButtonBuilder.defaultQuickActionOrder); return ordered.toList(growable: false); } - /// Build a list of quick action types based on context and custom order List buildQuickActionTypes( ActionButtonContext context, { List? quickActionOrder, - int limit = defaultQuickActionLimit, + int limit = ActionButtonBuilder.defaultQuickActionLimit, }) { final normalized = _normalizeQuickActionOrder( - quickActionOrder == null || quickActionOrder.isEmpty ? defaultQuickActionOrder : quickActionOrder, + quickActionOrder == null || quickActionOrder.isEmpty + ? ActionButtonBuilder.defaultQuickActionOrder + : quickActionOrder, ); final seen = {}; diff --git a/mobile/lib/infrastructure/repositories/action_button_order.repository.dart b/mobile/lib/infrastructure/repositories/action_button_order.repository.dart index 2efaeb0a75..552ee5bac8 100644 --- a/mobile/lib/infrastructure/repositories/action_button_order.repository.dart +++ b/mobile/lib/infrastructure/repositories/action_button_order.repository.dart @@ -1,60 +1,42 @@ import 'dart:convert'; - import 'package:immich_mobile/domain/models/store.model.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/utils/action_button.utils.dart'; -/// Repository for managing quick action button order persistence. -/// Handles serialization, deserialization, and storage operations. class ActionButtonOrderRepository { const ActionButtonOrderRepository(); - /// Default order for quick actions - static const List defaultOrder = [ - ActionButtonType.share, - ActionButtonType.upload, - ActionButtonType.edit, - ActionButtonType.add, - ActionButtonType.archive, - ActionButtonType.delete, - ActionButtonType.removeFromAlbum, - ActionButtonType.likeActivity, - ]; + static const storeKey = StoreKey.viewerQuickActionOrder; - /// Get the current quick action order from storage List get() { - final json = Store.tryGet(StoreKey.viewerQuickActionOrder); + final json = Store.tryGet(storeKey); if (json == null || json.isEmpty) { - return defaultOrder; + return ActionButtonBuilder.defaultQuickActionOrder; } final deserialized = _deserialize(json); - return deserialized.isEmpty ? defaultOrder : deserialized; + return deserialized.isEmpty ? ActionButtonBuilder.defaultQuickActionOrder : deserialized; } - /// Save quick action order to storage Future set(List order) async { final json = _serialize(order); - await Store.put(StoreKey.viewerQuickActionOrder, json); + await Store.put(storeKey, json); } - /// Watch for changes to quick action order Stream> watch() { - return Store.watch(StoreKey.viewerQuickActionOrder).map((json) { + return Store.watch(storeKey).map((json) { if (json == null || json.isEmpty) { - return defaultOrder; + return ActionButtonBuilder.defaultQuickActionOrder; } final deserialized = _deserialize(json); - return deserialized.isEmpty ? defaultOrder : deserialized; + return deserialized.isEmpty ? ActionButtonBuilder.defaultQuickActionOrder : deserialized; }); } - /// Serialize a list of ActionButtonType to JSON string String _serialize(List order) { return jsonEncode(order.map((type) => type.name).toList()); } - /// Deserialize a JSON string to a list of ActionButtonType List _deserialize(String json) { try { final list = jsonDecode(json) as List; 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 832b8a0221..725a382d42 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/bottom_bar.widget.dart @@ -77,10 +77,10 @@ class ViewerBottomBar extends ConsumerWidget { }); } - final actions = ActionButtonBuilder.buildQuickActions( - buttonContext, - quickActionTypes: quickActionTypes, - ).map((widget) => GestureDetector(onLongPress: openConfigurator, child: widget)).toList(growable: false); + final actions = quickActionTypes + .map((type) => type.buildButton(buttonContext)) + .map((widget) => GestureDetector(onLongPress: openConfigurator, child: widget)) + .toList(growable: false); return IgnorePointer( ignoring: opacity < 255, diff --git a/mobile/lib/presentation/widgets/asset_viewer/quick_action_configurator.widget.dart b/mobile/lib/presentation/widgets/asset_viewer/quick_action_configurator.widget.dart index 9672edfc94..eb6b3f1576 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/quick_action_configurator.widget.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/quick_action_configurator.widget.dart @@ -3,7 +3,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_reorderable_grid_view/widgets/reorderable_builder.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/domain/services/quick_action.service.dart'; import 'package:immich_mobile/providers/infrastructure/viewer_quick_action_order.provider.dart'; import 'package:immich_mobile/utils/action_button.utils.dart'; import 'package:immich_mobile/utils/action_button_visuals.dart'; @@ -42,7 +41,7 @@ class _QuickActionConfiguratorState extends ConsumerState.from(QuickActionService.defaultQuickActionOrder); + _order = List.from(ActionButtonBuilder.defaultQuickActionOrder); _hasLocalChanges = true; }); } @@ -90,7 +89,7 @@ class _QuickActionConfiguratorState extends ConsumerState { readonlyModeEnabled(StoreKey.readonlyModeEnabled, "readonlyModeEnabled", false), albumGridView(StoreKey.albumGridView, "albumGridView", false), backupRequireCharging(StoreKey.backupRequireCharging, null, false), - backupTriggerDelay(StoreKey.backupTriggerDelay, null, 30), - viewerQuickActionOrder(StoreKey.viewerQuickActionOrder, null, ''); + backupTriggerDelay(StoreKey.backupTriggerDelay, null, 30); const AppSettingsEnum(this.storeKey, this.hiveKey, this.defaultValue); @@ -74,8 +73,4 @@ class AppSettingsService { Future setSetting(AppSettingsEnum setting, T value) { return Store.put(setting.storeKey, value); } - - Stream watchSetting(AppSettingsEnum setting) { - return Store.watch(setting.storeKey).map((value) => value ?? setting.defaultValue); - } } diff --git a/mobile/lib/utils/action_button.utils.dart b/mobile/lib/utils/action_button.utils.dart index a57484735e..0761cea462 100644 --- a/mobile/lib/utils/action_button.utils.dart +++ b/mobile/lib/utils/action_button.utils.dart @@ -169,22 +169,22 @@ enum ActionButtonType { } } -/// Builder class for creating action button widgets. -/// This class provides simple factory methods for building action button widgets -/// from ActionButtonContext. Business logic for quick actions is handled by QuickActionService. class ActionButtonBuilder { static const List _actionTypes = ActionButtonType.values; - /// Build a list of quick action widgets based on context and custom order. - /// Uses QuickActionService for business logic. - static List buildQuickActions( - ActionButtonContext context, { - required List quickActionTypes, - }) { - return quickActionTypes.map((type) => type.buildButton(context)).toList(); - } + static const int defaultQuickActionLimit = 4; + + static const List defaultQuickActionOrder = [ + ActionButtonType.share, + ActionButtonType.upload, + ActionButtonType.edit, + ActionButtonType.add, + ActionButtonType.archive, + ActionButtonType.delete, + ActionButtonType.removeFromAlbum, + ActionButtonType.likeActivity, + ]; - /// Build all available action button widgets for the given context. static List build(ActionButtonContext context) { return _actionTypes.where((type) => type.shouldShow(context)).map((type) => type.buildButton(context)).toList(); } diff --git a/mobile/test/domain/services/quick_action_service_test.dart b/mobile/test/domain/services/quick_action_service_test.dart index 35d43c06a0..be236e831f 100644 --- a/mobile/test/domain/services/quick_action_service_test.dart +++ b/mobile/test/domain/services/quick_action_service_test.dart @@ -46,7 +46,7 @@ void main() { final types = service.buildQuickActionTypes(context, quickActionOrder: customOrder); - expect(types.length, lessThanOrEqualTo(QuickActionService.defaultQuickActionLimit)); + expect(types.length, lessThanOrEqualTo(ActionButtonBuilder.defaultQuickActionLimit)); expect(types.first, ActionButtonType.archive); expect(types[1], ActionButtonType.share); }); @@ -140,7 +140,7 @@ void main() { final types = service.buildQuickActionTypes( context, - quickActionOrder: QuickActionService.defaultQuickActionOrder, + quickActionOrder: ActionButtonBuilder.defaultQuickActionOrder, limit: 2, ); diff --git a/mobile/test/utils/action_button_utils_test.dart b/mobile/test/utils/action_button_utils_test.dart index c03ca2910b..a7652e7cd9 100644 --- a/mobile/test/utils/action_button_utils_test.dart +++ b/mobile/test/utils/action_button_utils_test.dart @@ -1042,9 +1042,9 @@ void main() { ], ); - final quickActions = ActionButtonBuilder.buildQuickActions(context, quickActionTypes: quickActionTypes); + final quickActions = quickActionTypes.map((type) => type.buildButton(context)).toList(); - expect(quickActions.length, QuickActionService.defaultQuickActionLimit); + expect(quickActions.length, ActionButtonBuilder.defaultQuickActionLimit); expect(quickActions.first, isA()); expect(quickActions[1], isA()); expect(quickActions[2], isA());