mirror of
https://github.com/immich-app/immich.git
synced 2025-07-08 10:44:15 -04:00
refactor: actions provider (#19651)
* refactor: actions provider * chore: rename error and stack * remove empty checks --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
5011636d95
commit
21f500191a
@ -64,7 +64,7 @@ class TimelineService {
|
|||||||
}) : _assetSource = assetSource,
|
}) : _assetSource = assetSource,
|
||||||
_bucketSource = bucketSource {
|
_bucketSource = bucketSource {
|
||||||
_bucketSubscription =
|
_bucketSubscription =
|
||||||
_bucketSource().listen((_) => unawaited(_reloadBucket()));
|
_bucketSource().listen((_) => unawaited(reloadBucket()));
|
||||||
}
|
}
|
||||||
|
|
||||||
final AsyncMutex _mutex = AsyncMutex();
|
final AsyncMutex _mutex = AsyncMutex();
|
||||||
@ -74,7 +74,7 @@ class TimelineService {
|
|||||||
|
|
||||||
Stream<List<Bucket>> Function() get watchBuckets => _bucketSource;
|
Stream<List<Bucket>> Function() get watchBuckets => _bucketSource;
|
||||||
|
|
||||||
Future<void> _reloadBucket() => _mutex.run(() async {
|
Future<void> reloadBucket() => _mutex.run(() async {
|
||||||
_buffer = await _assetSource(_bufferOffset, _buffer.length);
|
_buffer = await _assetSource(_bufferOffset, _buffer.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2,12 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
|
|
||||||
class ArchiveActionButton extends ConsumerWidget {
|
class ArchiveActionButton extends ConsumerWidget {
|
||||||
@ -15,45 +14,28 @@ class ArchiveActionButton extends ConsumerWidget {
|
|||||||
|
|
||||||
const ArchiveActionButton({super.key, required this.source});
|
const ArchiveActionButton({super.key, required this.source});
|
||||||
|
|
||||||
onAction(BuildContext context, WidgetRef ref) {
|
void _onTap(BuildContext context, WidgetRef ref) async {
|
||||||
switch (source) {
|
if (!context.mounted) {
|
||||||
case ActionSource.timeline:
|
|
||||||
timelineAction(context, ref);
|
|
||||||
case ActionSource.viewer:
|
|
||||||
viewerAction(ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void timelineAction(BuildContext context, WidgetRef ref) {
|
|
||||||
final user = ref.read(currentUserProvider);
|
|
||||||
if (user == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ids = ref
|
final result = await ref.read(actionProvider.notifier).archive(source);
|
||||||
.read(multiSelectProvider.select((value) => value.selectedAssets))
|
await ref.read(timelineServiceProvider).reloadBucket();
|
||||||
.whereType<RemoteAsset>()
|
|
||||||
.where((asset) => asset.ownerId == user.id)
|
|
||||||
.map((asset) => asset.id)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (ids.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ref.read(actionProvider.notifier).archive(ids);
|
|
||||||
ref.read(multiSelectProvider.notifier).reset();
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
final toastMessage = 'archive_action_prompt'.t(
|
final successMessage = 'archive_action_prompt'.t(
|
||||||
context: context,
|
context: context,
|
||||||
args: {'count': ids.length.toString()},
|
args: {'count': result.count.toString()},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
context: context,
|
context: context,
|
||||||
msg: toastMessage,
|
msg: result.success
|
||||||
|
? successMessage
|
||||||
|
: 'scaffold_body_error_occurred'.t(context: context),
|
||||||
gravity: ToastGravity.BOTTOM,
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
toastType: result.success ? ToastType.success : ToastType.error,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +49,7 @@ class ArchiveActionButton extends ConsumerWidget {
|
|||||||
return BaseActionButton(
|
return BaseActionButton(
|
||||||
iconData: Icons.archive_outlined,
|
iconData: Icons.archive_outlined,
|
||||||
label: "archive".t(context: context),
|
label: "archive".t(context: context),
|
||||||
onPressed: () => onAction(context, ref),
|
onPressed: () => _onTap(context, ref),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
|
|
||||||
class FavoriteActionButton extends ConsumerWidget {
|
class FavoriteActionButton extends ConsumerWidget {
|
||||||
@ -15,45 +14,28 @@ class FavoriteActionButton extends ConsumerWidget {
|
|||||||
|
|
||||||
const FavoriteActionButton({super.key, required this.source});
|
const FavoriteActionButton({super.key, required this.source});
|
||||||
|
|
||||||
onAction(BuildContext context, WidgetRef ref) {
|
void _onTap(BuildContext context, WidgetRef ref) async {
|
||||||
switch (source) {
|
if (!context.mounted) {
|
||||||
case ActionSource.timeline:
|
|
||||||
timelineAction(context, ref);
|
|
||||||
case ActionSource.viewer:
|
|
||||||
viewerAction(ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void timelineAction(BuildContext context, WidgetRef ref) {
|
|
||||||
final user = ref.read(currentUserProvider);
|
|
||||||
if (user == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ids = ref
|
final result = await ref.read(actionProvider.notifier).favorite(source);
|
||||||
.read(multiSelectProvider.select((value) => value.selectedAssets))
|
await ref.read(timelineServiceProvider).reloadBucket();
|
||||||
.whereType<RemoteAsset>()
|
|
||||||
.where((asset) => asset.ownerId == user.id)
|
|
||||||
.map((asset) => asset.id)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (ids.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ref.read(actionProvider.notifier).favorite(ids);
|
|
||||||
ref.read(multiSelectProvider.notifier).reset();
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
final toastMessage = 'favorite_action_prompt'.t(
|
final successMessage = 'favorite_action_prompt'.t(
|
||||||
context: context,
|
context: context,
|
||||||
args: {'count': ids.length.toString()},
|
args: {'count': result.count.toString()},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ImmichToast.show(
|
ImmichToast.show(
|
||||||
context: context,
|
context: context,
|
||||||
msg: toastMessage,
|
msg: result.success
|
||||||
|
? successMessage
|
||||||
|
: 'scaffold_body_error_occurred'.t(context: context),
|
||||||
gravity: ToastGravity.BOTTOM,
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
toastType: result.success ? ToastType.success : ToastType.error,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,7 +49,7 @@ class FavoriteActionButton extends ConsumerWidget {
|
|||||||
return BaseActionButton(
|
return BaseActionButton(
|
||||||
iconData: Icons.favorite_border_rounded,
|
iconData: Icons.favorite_border_rounded,
|
||||||
label: "favorite".t(context: context),
|
label: "favorite".t(context: context),
|
||||||
onPressed: () => onAction(context, ref),
|
onPressed: () => _onTap(context, ref),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,11 @@ class ThumbnailTile extends ConsumerWidget {
|
|||||||
? context.primaryColor.darken(amount: 0.6)
|
? context.primaryColor.darken(amount: 0.6)
|
||||||
: context.primaryColor.lighten(amount: 0.8);
|
: context.primaryColor.lighten(amount: 0.8);
|
||||||
|
|
||||||
final multiselect = ref.watch(multiSelectProvider);
|
final isSelected = ref.watch(
|
||||||
final isSelected = multiselect.selectedAssets.contains(asset);
|
multiSelectProvider.select(
|
||||||
|
(multiselect) => multiselect.selectedAssets.contains(asset),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
|
@ -407,7 +407,7 @@ class _MultiSelectStatusButton extends ConsumerWidget {
|
|||||||
final selectCount =
|
final selectCount =
|
||||||
ref.watch(multiSelectProvider.select((s) => s.selectedAssets.length));
|
ref.watch(multiSelectProvider.select((s) => s.selectedAssets.length));
|
||||||
return ElevatedButton.icon(
|
return ElevatedButton.icon(
|
||||||
onPressed: () => ref.read(multiSelectProvider.notifier).clearSelection(),
|
onPressed: () => ref.read(multiSelectProvider.notifier).reset(),
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.close_rounded,
|
Icons.close_rounded,
|
||||||
color: context.colorScheme.onPrimary,
|
color: context.colorScheme.onPrimary,
|
||||||
|
@ -1,14 +1,36 @@
|
|||||||
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/multiselect.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/services/action.service.dart';
|
import 'package:immich_mobile/services/action.service.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
final actionProvider = NotifierProvider<ActionNotifier, void>(
|
final actionProvider = NotifierProvider<ActionNotifier, void>(
|
||||||
ActionNotifier.new,
|
ActionNotifier.new,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
actionServiceProvider,
|
actionServiceProvider,
|
||||||
|
timelineServiceProvider,
|
||||||
|
multiselectProvider,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
class ActionResult {
|
||||||
|
final int count;
|
||||||
|
final bool success;
|
||||||
|
final String? error;
|
||||||
|
|
||||||
|
const ActionResult({required this.count, required this.success, this.error});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() =>
|
||||||
|
'ActionResult(count: $count, success: $success, error: $error)';
|
||||||
|
}
|
||||||
|
|
||||||
class ActionNotifier extends Notifier<void> {
|
class ActionNotifier extends Notifier<void> {
|
||||||
|
final Logger _logger = Logger('ActionNotifier');
|
||||||
late final ActionService _service;
|
late final ActionService _service;
|
||||||
|
|
||||||
ActionNotifier() : super();
|
ActionNotifier() : super();
|
||||||
@ -18,19 +40,89 @@ class ActionNotifier extends Notifier<void> {
|
|||||||
_service = ref.watch(actionServiceProvider);
|
_service = ref.watch(actionServiceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> favorite(List<String> ids) async {
|
List<String> _getIdsForSource<T extends BaseAsset>(ActionSource source) {
|
||||||
await _service.favorite(ids);
|
final currentUser = ref.read(currentUserProvider);
|
||||||
|
if (T is RemoteAsset && currentUser == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
final Set<BaseAsset> assets = switch (source) {
|
||||||
|
ActionSource.timeline =>
|
||||||
|
ref.read(multiSelectProvider.select((s) => s.selectedAssets)),
|
||||||
|
ActionSource.viewer => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
return switch (T) {
|
||||||
|
const (RemoteAsset) => assets
|
||||||
|
.where(
|
||||||
|
(asset) => asset is RemoteAsset && asset.ownerId == currentUser!.id,
|
||||||
|
)
|
||||||
|
.cast<RemoteAsset>()
|
||||||
|
.map((asset) => asset.id)
|
||||||
|
.toList(),
|
||||||
|
const (LocalAsset) =>
|
||||||
|
assets.whereType<LocalAsset>().map((asset) => asset.id).toList(),
|
||||||
|
_ => [],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> unFavorite(List<String> ids) async {
|
Future<ActionResult> favorite(ActionSource source) async {
|
||||||
await _service.unFavorite(ids);
|
final ids = _getIdsForSource<RemoteAsset>(source);
|
||||||
|
try {
|
||||||
|
await _service.favorite(ids);
|
||||||
|
return ActionResult(count: ids.length, success: true);
|
||||||
|
} catch (error, stack) {
|
||||||
|
_logger.severe('Failed to favorite assets', error, stack);
|
||||||
|
return ActionResult(
|
||||||
|
count: ids.length,
|
||||||
|
success: false,
|
||||||
|
error: error.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> archive(List<String> ids) async {
|
Future<ActionResult> unFavorite(ActionSource source) async {
|
||||||
await _service.archive(ids);
|
final ids = _getIdsForSource<RemoteAsset>(source);
|
||||||
|
try {
|
||||||
|
await _service.unFavorite(ids);
|
||||||
|
return ActionResult(count: ids.length, success: true);
|
||||||
|
} catch (error, stack) {
|
||||||
|
_logger.severe('Failed to unfavorite assets', error, stack);
|
||||||
|
return ActionResult(
|
||||||
|
count: ids.length,
|
||||||
|
success: false,
|
||||||
|
error: error.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> unArchive(List<String> ids) async {
|
Future<ActionResult> archive(ActionSource source) async {
|
||||||
await _service.unArchive(ids);
|
final ids = _getIdsForSource<RemoteAsset>(source);
|
||||||
|
try {
|
||||||
|
await _service.archive(ids);
|
||||||
|
return ActionResult(count: ids.length, success: true);
|
||||||
|
} catch (error, stack) {
|
||||||
|
_logger.severe('Failed to archive assets', error, stack);
|
||||||
|
return ActionResult(
|
||||||
|
count: ids.length,
|
||||||
|
success: false,
|
||||||
|
error: error.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ActionResult> unArchive(ActionSource source) async {
|
||||||
|
final ids = _getIdsForSource<RemoteAsset>(source);
|
||||||
|
try {
|
||||||
|
await _service.unArchive(ids);
|
||||||
|
return ActionResult(count: ids.length, success: true);
|
||||||
|
} catch (error, stack) {
|
||||||
|
_logger.severe('Failed to unarchive assets', error, stack);
|
||||||
|
return ActionResult(
|
||||||
|
count: ids.length,
|
||||||
|
success: false,
|
||||||
|
error: error.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
@ -13,12 +12,8 @@ final multiSelectProvider =
|
|||||||
|
|
||||||
class MultiSelectState {
|
class MultiSelectState {
|
||||||
final Set<BaseAsset> selectedAssets;
|
final Set<BaseAsset> selectedAssets;
|
||||||
final int lastUpdatedTime;
|
|
||||||
|
|
||||||
const MultiSelectState({
|
const MultiSelectState({required this.selectedAssets});
|
||||||
required this.selectedAssets,
|
|
||||||
required this.lastUpdatedTime,
|
|
||||||
});
|
|
||||||
|
|
||||||
bool get isEnabled => selectedAssets.isNotEmpty;
|
bool get isEnabled => selectedAssets.isNotEmpty;
|
||||||
bool get hasRemote => selectedAssets.any(
|
bool get hasRemote => selectedAssets.any(
|
||||||
@ -30,31 +25,25 @@ class MultiSelectState {
|
|||||||
(asset) => asset.storage == AssetState.local,
|
(asset) => asset.storage == AssetState.local,
|
||||||
);
|
);
|
||||||
|
|
||||||
MultiSelectState copyWith({
|
MultiSelectState copyWith({Set<BaseAsset>? selectedAssets}) {
|
||||||
Set<BaseAsset>? selectedAssets,
|
|
||||||
int? lastUpdatedTime,
|
|
||||||
}) {
|
|
||||||
return MultiSelectState(
|
return MultiSelectState(
|
||||||
selectedAssets: selectedAssets ?? this.selectedAssets,
|
selectedAssets: selectedAssets ?? this.selectedAssets,
|
||||||
lastUpdatedTime: lastUpdatedTime ?? this.lastUpdatedTime,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() =>
|
String toString() => 'MultiSelectState(selectedAssets: $selectedAssets)';
|
||||||
'MultiSelectState(selectedAssets: $selectedAssets, lastUpdatedTime: $lastUpdatedTime)';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(covariant MultiSelectState other) {
|
bool operator ==(covariant MultiSelectState other) {
|
||||||
if (identical(this, other)) return true;
|
if (identical(this, other)) return true;
|
||||||
final listEquals = const DeepCollectionEquality().equals;
|
final listEquals = const DeepCollectionEquality().equals;
|
||||||
|
|
||||||
return listEquals(other.selectedAssets, selectedAssets) &&
|
return listEquals(other.selectedAssets, selectedAssets);
|
||||||
other.lastUpdatedTime == lastUpdatedTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => selectedAssets.hashCode ^ lastUpdatedTime.hashCode;
|
int get hashCode => selectedAssets.hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
||||||
@ -64,10 +53,7 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
|||||||
MultiSelectState build() {
|
MultiSelectState build() {
|
||||||
_timelineService = ref.read(timelineServiceProvider);
|
_timelineService = ref.read(timelineServiceProvider);
|
||||||
|
|
||||||
return const MultiSelectState(
|
return const MultiSelectState(selectedAssets: {});
|
||||||
selectedAssets: {},
|
|
||||||
lastUpdatedTime: 0,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void selectAsset(BaseAsset asset) {
|
void selectAsset(BaseAsset asset) {
|
||||||
@ -98,17 +84,8 @@ class MultiSelectNotifier extends Notifier<MultiSelectState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearSelection() {
|
|
||||||
state = state.copyWith(
|
|
||||||
selectedAssets: {},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
state = MultiSelectState(
|
state = const MultiSelectState(selectedAssets: {});
|
||||||
selectedAssets: {},
|
|
||||||
lastUpdatedTime: DateTime.now().millisecondsSinceEpoch,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bucket bulk operations
|
/// Bucket bulk operations
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/remote_asset.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/remote_asset.repository.dart';
|
||||||
@ -19,50 +18,34 @@ class ActionService {
|
|||||||
const ActionService(this._assetApiRepository, this._remoteAssetRepository);
|
const ActionService(this._assetApiRepository, this._remoteAssetRepository);
|
||||||
|
|
||||||
Future<void> favorite(List<String> remoteIds) async {
|
Future<void> favorite(List<String> remoteIds) async {
|
||||||
try {
|
await _assetApiRepository.updateFavorite(remoteIds, true);
|
||||||
await _assetApiRepository.updateFavorite(remoteIds, true);
|
await _remoteAssetRepository.updateFavorite(remoteIds, true);
|
||||||
await _remoteAssetRepository.updateFavorite(remoteIds, true);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Error favoriting assets: $e');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> unFavorite(List<String> remoteIds) async {
|
Future<void> unFavorite(List<String> remoteIds) async {
|
||||||
try {
|
await _assetApiRepository.updateFavorite(remoteIds, false);
|
||||||
await _assetApiRepository.updateFavorite(remoteIds, false);
|
await _remoteAssetRepository.updateFavorite(remoteIds, false);
|
||||||
await _remoteAssetRepository.updateFavorite(remoteIds, false);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Error unfavoriting assets: $e');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> archive(List<String> remoteIds) async {
|
Future<void> archive(List<String> remoteIds) async {
|
||||||
try {
|
await _assetApiRepository.updateVisibility(
|
||||||
await _assetApiRepository.updateVisibility(
|
remoteIds,
|
||||||
remoteIds,
|
AssetVisibilityEnum.archive,
|
||||||
AssetVisibilityEnum.archive,
|
);
|
||||||
);
|
await _remoteAssetRepository.updateVisibility(
|
||||||
await _remoteAssetRepository.updateVisibility(
|
remoteIds,
|
||||||
remoteIds,
|
AssetVisibility.archive,
|
||||||
AssetVisibility.archive,
|
);
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Error archive assets: $e');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> unArchive(List<String> remoteIds) async {
|
Future<void> unArchive(List<String> remoteIds) async {
|
||||||
try {
|
await _assetApiRepository.updateVisibility(
|
||||||
await _assetApiRepository.updateVisibility(
|
remoteIds,
|
||||||
remoteIds,
|
AssetVisibilityEnum.timeline,
|
||||||
AssetVisibilityEnum.timeline,
|
);
|
||||||
);
|
await _remoteAssetRepository.updateVisibility(
|
||||||
await _remoteAssetRepository.updateVisibility(
|
remoteIds,
|
||||||
remoteIds,
|
AssetVisibility.timeline,
|
||||||
AssetVisibility.timeline,
|
);
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('Error unarchive assets: $e');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user