mirror of
https://github.com/immich-app/immich.git
synced 2025-12-22 17:24:56 +03:00
refactor: clean up
This commit is contained in:
@@ -1,53 +1,28 @@
|
|||||||
import 'package:immich_mobile/infrastructure/repositories/action_button_order.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/action_button_order.repository.dart';
|
||||||
import 'package:immich_mobile/utils/action_button.utils.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 {
|
class QuickActionService {
|
||||||
final ActionButtonOrderRepository _repository;
|
final ActionButtonOrderRepository _repository;
|
||||||
|
|
||||||
const QuickActionService(this._repository);
|
const QuickActionService(this._repository);
|
||||||
|
|
||||||
// Constants
|
static final Set<ActionButtonType> _quickActionSet = Set<ActionButtonType>.unmodifiable(
|
||||||
static const int defaultQuickActionLimit = 4;
|
ActionButtonBuilder.defaultQuickActionOrder,
|
||||||
|
|
||||||
static const List<ActionButtonType> defaultQuickActionSeed = [
|
|
||||||
ActionButtonType.share,
|
|
||||||
ActionButtonType.upload,
|
|
||||||
ActionButtonType.edit,
|
|
||||||
ActionButtonType.add,
|
|
||||||
ActionButtonType.archive,
|
|
||||||
ActionButtonType.delete,
|
|
||||||
ActionButtonType.removeFromAlbum,
|
|
||||||
ActionButtonType.likeActivity,
|
|
||||||
];
|
|
||||||
|
|
||||||
static final Set<ActionButtonType> _quickActionSet = Set<ActionButtonType>.unmodifiable(defaultQuickActionSeed);
|
|
||||||
|
|
||||||
static final List<ActionButtonType> defaultQuickActionOrder = List<ActionButtonType>.unmodifiable(
|
|
||||||
defaultQuickActionSeed,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Get the list of available quick action options
|
|
||||||
// static List<ActionButtonType> get quickActionOptions => defaultQuickActionOrder;
|
|
||||||
|
|
||||||
/// Get the current quick action order
|
|
||||||
List<ActionButtonType> get() {
|
List<ActionButtonType> get() {
|
||||||
return _repository.get();
|
return _repository.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the quick action order
|
|
||||||
Future<void> set(List<ActionButtonType> order) async {
|
Future<void> set(List<ActionButtonType> order) async {
|
||||||
final normalized = _normalizeQuickActionOrder(order);
|
final normalized = _normalizeQuickActionOrder(order);
|
||||||
await _repository.set(normalized);
|
await _repository.set(normalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Watch for changes to quick action order
|
|
||||||
Stream<List<ActionButtonType>> watch() {
|
Stream<List<ActionButtonType>> watch() {
|
||||||
return _repository.watch();
|
return _repository.watch();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Normalize quick action order by filtering valid types and ensuring all defaults are included
|
|
||||||
List<ActionButtonType> _normalizeQuickActionOrder(List<ActionButtonType> order) {
|
List<ActionButtonType> _normalizeQuickActionOrder(List<ActionButtonType> order) {
|
||||||
final ordered = <ActionButtonType>{};
|
final ordered = <ActionButtonType>{};
|
||||||
|
|
||||||
@@ -57,19 +32,20 @@ class QuickActionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ordered.addAll(defaultQuickActionSeed);
|
ordered.addAll(ActionButtonBuilder.defaultQuickActionOrder);
|
||||||
|
|
||||||
return ordered.toList(growable: false);
|
return ordered.toList(growable: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a list of quick action types based on context and custom order
|
|
||||||
List<ActionButtonType> buildQuickActionTypes(
|
List<ActionButtonType> buildQuickActionTypes(
|
||||||
ActionButtonContext context, {
|
ActionButtonContext context, {
|
||||||
List<ActionButtonType>? quickActionOrder,
|
List<ActionButtonType>? quickActionOrder,
|
||||||
int limit = defaultQuickActionLimit,
|
int limit = ActionButtonBuilder.defaultQuickActionLimit,
|
||||||
}) {
|
}) {
|
||||||
final normalized = _normalizeQuickActionOrder(
|
final normalized = _normalizeQuickActionOrder(
|
||||||
quickActionOrder == null || quickActionOrder.isEmpty ? defaultQuickActionOrder : quickActionOrder,
|
quickActionOrder == null || quickActionOrder.isEmpty
|
||||||
|
? ActionButtonBuilder.defaultQuickActionOrder
|
||||||
|
: quickActionOrder,
|
||||||
);
|
);
|
||||||
|
|
||||||
final seen = <ActionButtonType>{};
|
final seen = <ActionButtonType>{};
|
||||||
|
|||||||
@@ -1,60 +1,42 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:immich_mobile/domain/models/store.model.dart';
|
import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/utils/action_button.utils.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 {
|
class ActionButtonOrderRepository {
|
||||||
const ActionButtonOrderRepository();
|
const ActionButtonOrderRepository();
|
||||||
|
|
||||||
/// Default order for quick actions
|
static const storeKey = StoreKey.viewerQuickActionOrder;
|
||||||
static const List<ActionButtonType> defaultOrder = [
|
|
||||||
ActionButtonType.share,
|
|
||||||
ActionButtonType.upload,
|
|
||||||
ActionButtonType.edit,
|
|
||||||
ActionButtonType.add,
|
|
||||||
ActionButtonType.archive,
|
|
||||||
ActionButtonType.delete,
|
|
||||||
ActionButtonType.removeFromAlbum,
|
|
||||||
ActionButtonType.likeActivity,
|
|
||||||
];
|
|
||||||
|
|
||||||
/// Get the current quick action order from storage
|
|
||||||
List<ActionButtonType> get() {
|
List<ActionButtonType> get() {
|
||||||
final json = Store.tryGet(StoreKey.viewerQuickActionOrder);
|
final json = Store.tryGet(storeKey);
|
||||||
if (json == null || json.isEmpty) {
|
if (json == null || json.isEmpty) {
|
||||||
return defaultOrder;
|
return ActionButtonBuilder.defaultQuickActionOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
final deserialized = _deserialize(json);
|
final deserialized = _deserialize(json);
|
||||||
return deserialized.isEmpty ? defaultOrder : deserialized;
|
return deserialized.isEmpty ? ActionButtonBuilder.defaultQuickActionOrder : deserialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Save quick action order to storage
|
|
||||||
Future<void> set(List<ActionButtonType> order) async {
|
Future<void> set(List<ActionButtonType> order) async {
|
||||||
final json = _serialize(order);
|
final json = _serialize(order);
|
||||||
await Store.put(StoreKey.viewerQuickActionOrder, json);
|
await Store.put(storeKey, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Watch for changes to quick action order
|
|
||||||
Stream<List<ActionButtonType>> watch() {
|
Stream<List<ActionButtonType>> watch() {
|
||||||
return Store.watch(StoreKey.viewerQuickActionOrder).map((json) {
|
return Store.watch(storeKey).map((json) {
|
||||||
if (json == null || json.isEmpty) {
|
if (json == null || json.isEmpty) {
|
||||||
return defaultOrder;
|
return ActionButtonBuilder.defaultQuickActionOrder;
|
||||||
}
|
}
|
||||||
final deserialized = _deserialize(json);
|
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<ActionButtonType> order) {
|
String _serialize(List<ActionButtonType> order) {
|
||||||
return jsonEncode(order.map((type) => type.name).toList());
|
return jsonEncode(order.map((type) => type.name).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize a JSON string to a list of ActionButtonType
|
|
||||||
List<ActionButtonType> _deserialize(String json) {
|
List<ActionButtonType> _deserialize(String json) {
|
||||||
try {
|
try {
|
||||||
final list = jsonDecode(json) as List<dynamic>;
|
final list = jsonDecode(json) as List<dynamic>;
|
||||||
|
|||||||
@@ -77,10 +77,10 @@ class ViewerBottomBar extends ConsumerWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
final actions = ActionButtonBuilder.buildQuickActions(
|
final actions = quickActionTypes
|
||||||
buttonContext,
|
.map((type) => type.buildButton(buttonContext))
|
||||||
quickActionTypes: quickActionTypes,
|
.map((widget) => GestureDetector(onLongPress: openConfigurator, child: widget))
|
||||||
).map((widget) => GestureDetector(onLongPress: openConfigurator, child: widget)).toList(growable: false);
|
.toList(growable: false);
|
||||||
|
|
||||||
return IgnorePointer(
|
return IgnorePointer(
|
||||||
ignoring: opacity < 255,
|
ignoring: opacity < 255,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_reorderable_grid_view/widgets/reorderable_builder.dart';
|
import 'package:flutter_reorderable_grid_view/widgets/reorderable_builder.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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/providers/infrastructure/viewer_quick_action_order.provider.dart';
|
||||||
import 'package:immich_mobile/utils/action_button.utils.dart';
|
import 'package:immich_mobile/utils/action_button.utils.dart';
|
||||||
import 'package:immich_mobile/utils/action_button_visuals.dart';
|
import 'package:immich_mobile/utils/action_button_visuals.dart';
|
||||||
@@ -42,7 +41,7 @@ class _QuickActionConfiguratorState extends ConsumerState<QuickActionConfigurato
|
|||||||
|
|
||||||
void _resetToDefault() {
|
void _resetToDefault() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_order = List<ActionButtonType>.from(QuickActionService.defaultQuickActionOrder);
|
_order = List<ActionButtonType>.from(ActionButtonBuilder.defaultQuickActionOrder);
|
||||||
_hasLocalChanges = true;
|
_hasLocalChanges = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -90,7 +89,7 @@ class _QuickActionConfiguratorState extends ConsumerState<QuickActionConfigurato
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'quick_actions_settings_description'.tr(
|
'quick_actions_settings_description'.tr(
|
||||||
namedArgs: {'count': QuickActionService.defaultQuickActionLimit.toString()},
|
namedArgs: {'count': ActionButtonBuilder.defaultQuickActionLimit.toString()},
|
||||||
),
|
),
|
||||||
style: theme.textTheme.bodyMedium,
|
style: theme.textTheme.bodyMedium,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ enum AppSettingsEnum<T> {
|
|||||||
readonlyModeEnabled<bool>(StoreKey.readonlyModeEnabled, "readonlyModeEnabled", false),
|
readonlyModeEnabled<bool>(StoreKey.readonlyModeEnabled, "readonlyModeEnabled", false),
|
||||||
albumGridView<bool>(StoreKey.albumGridView, "albumGridView", false),
|
albumGridView<bool>(StoreKey.albumGridView, "albumGridView", false),
|
||||||
backupRequireCharging<bool>(StoreKey.backupRequireCharging, null, false),
|
backupRequireCharging<bool>(StoreKey.backupRequireCharging, null, false),
|
||||||
backupTriggerDelay<int>(StoreKey.backupTriggerDelay, null, 30),
|
backupTriggerDelay<int>(StoreKey.backupTriggerDelay, null, 30);
|
||||||
viewerQuickActionOrder<String>(StoreKey.viewerQuickActionOrder, null, '');
|
|
||||||
|
|
||||||
const AppSettingsEnum(this.storeKey, this.hiveKey, this.defaultValue);
|
const AppSettingsEnum(this.storeKey, this.hiveKey, this.defaultValue);
|
||||||
|
|
||||||
@@ -74,8 +73,4 @@ class AppSettingsService {
|
|||||||
Future<void> setSetting<T>(AppSettingsEnum<T> setting, T value) {
|
Future<void> setSetting<T>(AppSettingsEnum<T> setting, T value) {
|
||||||
return Store.put(setting.storeKey, value);
|
return Store.put(setting.storeKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<T> watchSetting<T>(AppSettingsEnum<T> setting) {
|
|
||||||
return Store.watch(setting.storeKey).map((value) => value ?? setting.defaultValue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
class ActionButtonBuilder {
|
||||||
static const List<ActionButtonType> _actionTypes = ActionButtonType.values;
|
static const List<ActionButtonType> _actionTypes = ActionButtonType.values;
|
||||||
|
|
||||||
/// Build a list of quick action widgets based on context and custom order.
|
static const int defaultQuickActionLimit = 4;
|
||||||
/// Uses QuickActionService for business logic.
|
|
||||||
static List<Widget> buildQuickActions(
|
static const List<ActionButtonType> defaultQuickActionOrder = [
|
||||||
ActionButtonContext context, {
|
ActionButtonType.share,
|
||||||
required List<ActionButtonType> quickActionTypes,
|
ActionButtonType.upload,
|
||||||
}) {
|
ActionButtonType.edit,
|
||||||
return quickActionTypes.map((type) => type.buildButton(context)).toList();
|
ActionButtonType.add,
|
||||||
}
|
ActionButtonType.archive,
|
||||||
|
ActionButtonType.delete,
|
||||||
|
ActionButtonType.removeFromAlbum,
|
||||||
|
ActionButtonType.likeActivity,
|
||||||
|
];
|
||||||
|
|
||||||
/// Build all available action button widgets for the given context.
|
|
||||||
static List<Widget> build(ActionButtonContext context) {
|
static List<Widget> build(ActionButtonContext context) {
|
||||||
return _actionTypes.where((type) => type.shouldShow(context)).map((type) => type.buildButton(context)).toList();
|
return _actionTypes.where((type) => type.shouldShow(context)).map((type) => type.buildButton(context)).toList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ void main() {
|
|||||||
|
|
||||||
final types = service.buildQuickActionTypes(context, quickActionOrder: customOrder);
|
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.first, ActionButtonType.archive);
|
||||||
expect(types[1], ActionButtonType.share);
|
expect(types[1], ActionButtonType.share);
|
||||||
});
|
});
|
||||||
@@ -140,7 +140,7 @@ void main() {
|
|||||||
|
|
||||||
final types = service.buildQuickActionTypes(
|
final types = service.buildQuickActionTypes(
|
||||||
context,
|
context,
|
||||||
quickActionOrder: QuickActionService.defaultQuickActionOrder,
|
quickActionOrder: ActionButtonBuilder.defaultQuickActionOrder,
|
||||||
limit: 2,
|
limit: 2,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -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<ArchiveActionButton>());
|
expect(quickActions.first, isA<ArchiveActionButton>());
|
||||||
expect(quickActions[1], isA<ShareActionButton>());
|
expect(quickActions[1], isA<ShareActionButton>());
|
||||||
expect(quickActions[2], isA<EditImageActionButton>());
|
expect(quickActions[2], isA<EditImageActionButton>());
|
||||||
|
|||||||
Reference in New Issue
Block a user