mirror of
https://github.com/immich-app/immich.git
synced 2026-02-28 17:49:05 +03:00
set album cover from asset
This commit is contained in:
@@ -0,0 +1,62 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/events.model.dart';
|
||||||
|
import 'package:immich_mobile/domain/utils/event_stream.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/providers/infrastructure/action.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
|
|
||||||
|
class SetAlbumCoverActionButton extends ConsumerWidget {
|
||||||
|
final String albumId;
|
||||||
|
final ActionSource source;
|
||||||
|
final bool iconOnly;
|
||||||
|
final bool menuItem;
|
||||||
|
|
||||||
|
const SetAlbumCoverActionButton({
|
||||||
|
super.key,
|
||||||
|
required this.albumId,
|
||||||
|
required this.source,
|
||||||
|
this.iconOnly = false,
|
||||||
|
this.menuItem = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
void _onTap(BuildContext context, WidgetRef ref) async {
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final result = await ref.read(actionProvider.notifier).setAlbumCover(source, albumId);
|
||||||
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
|
if (source == ActionSource.viewer) {
|
||||||
|
EventStream.shared.emit(const ViewerReloadAssetEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
final successMessage = 'album_cover_updated'.t(context: context);
|
||||||
|
|
||||||
|
if (context.mounted) {
|
||||||
|
ImmichToast.show(
|
||||||
|
context: context,
|
||||||
|
msg: result.success ? successMessage : 'scaffold_body_error_occurred'.t(context: context),
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
toastType: result.success ? ToastType.success : ToastType.error,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.image_outlined,
|
||||||
|
label: 'set_as_album_cover'.t(context: context),
|
||||||
|
iconOnly: iconOnly,
|
||||||
|
menuItem: menuItem,
|
||||||
|
onPressed: () => _onTap(context, ref),
|
||||||
|
maxWidth: 100,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -343,6 +343,26 @@ class ActionNotifier extends Notifier<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<ActionResult> setAlbumCover(ActionSource source, String albumId) async {
|
||||||
|
final assets = _getAssets(source);
|
||||||
|
if (assets.length != 1) {
|
||||||
|
return ActionResult(count: assets.length, success: false, error: 'Expected single asset for album cover');
|
||||||
|
}
|
||||||
|
|
||||||
|
final asset = assets.first;
|
||||||
|
if (asset is! RemoteAsset) {
|
||||||
|
return ActionResult(count: 1, success: false, error: 'Asset must be remote');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await _service.setAlbumCover(albumId, asset.id);
|
||||||
|
return ActionResult(count: 1, success: true);
|
||||||
|
} catch (error, stack) {
|
||||||
|
_logger.severe('Failed to set album cover', error, stack);
|
||||||
|
return ActionResult(count: 1, success: false, error: error.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<ActionResult> updateDescription(ActionSource source, String description) async {
|
Future<ActionResult> updateDescription(ActionSource source, String description) async {
|
||||||
final ids = _getRemoteIdsForSource(source);
|
final ids = _getRemoteIdsForSource(source);
|
||||||
if (ids.length != 1) {
|
if (ids.length != 1) {
|
||||||
|
|||||||
@@ -240,6 +240,12 @@ class ActionService {
|
|||||||
return _downloadRepository.downloadAllAssets(assets);
|
return _downloadRepository.downloadAllAssets(assets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> setAlbumCover(String albumId, String assetId) async {
|
||||||
|
final updatedAlbum = await _albumApiRepository.updateAlbum(albumId, thumbnailAssetId: assetId);
|
||||||
|
await _remoteAlbumRepository.update(updatedAlbum);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Future<int> _deleteLocalAssets(List<String> localIds) async {
|
Future<int> _deleteLocalAssets(List<String> localIds) async {
|
||||||
final deletedIds = await _assetMediaRepository.deleteAll(localIds);
|
final deletedIds = await _assetMediaRepository.deleteAll(localIds);
|
||||||
if (deletedIds.isEmpty) {
|
if (deletedIds.isEmpty) {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import 'package:immich_mobile/presentation/widgets/action_buttons/like_activity_
|
|||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/remove_from_album_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/remove_from_album_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/remove_from_lock_folder_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/remove_from_lock_folder_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/set_album_cover.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/similar_photos_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/similar_photos_action_button.widget.dart';
|
||||||
@@ -42,6 +43,7 @@ class ActionButtonContext {
|
|||||||
final bool isCasting;
|
final bool isCasting;
|
||||||
final TimelineOrigin timelineOrigin;
|
final TimelineOrigin timelineOrigin;
|
||||||
final ThemeData? originalTheme;
|
final ThemeData? originalTheme;
|
||||||
|
final int selectedCount;
|
||||||
|
|
||||||
const ActionButtonContext({
|
const ActionButtonContext({
|
||||||
required this.asset,
|
required this.asset,
|
||||||
@@ -56,6 +58,7 @@ class ActionButtonContext {
|
|||||||
this.isCasting = false,
|
this.isCasting = false,
|
||||||
this.timelineOrigin = TimelineOrigin.main,
|
this.timelineOrigin = TimelineOrigin.main,
|
||||||
this.originalTheme,
|
this.originalTheme,
|
||||||
|
this.selectedCount = 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +78,7 @@ enum ActionButtonType {
|
|||||||
moveToLockFolder,
|
moveToLockFolder,
|
||||||
removeFromLockFolder,
|
removeFromLockFolder,
|
||||||
removeFromAlbum,
|
removeFromAlbum,
|
||||||
|
setAlbumCover,
|
||||||
trash,
|
trash,
|
||||||
deleteLocal,
|
deleteLocal,
|
||||||
deletePermanent,
|
deletePermanent,
|
||||||
@@ -134,6 +138,11 @@ enum ActionButtonType {
|
|||||||
context.isOwner && //
|
context.isOwner && //
|
||||||
!context.isInLockedView && //
|
!context.isInLockedView && //
|
||||||
context.currentAlbum != null,
|
context.currentAlbum != null,
|
||||||
|
ActionButtonType.setAlbumCover =>
|
||||||
|
context.isOwner && //
|
||||||
|
!context.isInLockedView && //
|
||||||
|
context.currentAlbum != null && //
|
||||||
|
context.selectedCount == 1,
|
||||||
ActionButtonType.unstack =>
|
ActionButtonType.unstack =>
|
||||||
context.isOwner && //
|
context.isOwner && //
|
||||||
!context.isInLockedView && //
|
!context.isInLockedView && //
|
||||||
@@ -213,6 +222,12 @@ enum ActionButtonType {
|
|||||||
iconOnly: iconOnly,
|
iconOnly: iconOnly,
|
||||||
menuItem: menuItem,
|
menuItem: menuItem,
|
||||||
),
|
),
|
||||||
|
ActionButtonType.setAlbumCover => SetAlbumCoverActionButton(
|
||||||
|
albumId: context.currentAlbum!.id,
|
||||||
|
source: context.source,
|
||||||
|
iconOnly: iconOnly,
|
||||||
|
menuItem: menuItem,
|
||||||
|
),
|
||||||
ActionButtonType.likeActivity => LikeActivityActionButton(iconOnly: iconOnly, menuItem: menuItem),
|
ActionButtonType.likeActivity => LikeActivityActionButton(iconOnly: iconOnly, menuItem: menuItem),
|
||||||
ActionButtonType.unstack => UnStackActionButton(source: context.source, iconOnly: iconOnly, menuItem: menuItem),
|
ActionButtonType.unstack => UnStackActionButton(source: context.source, iconOnly: iconOnly, menuItem: menuItem),
|
||||||
ActionButtonType.similarPhotos => SimilarPhotosActionButton(
|
ActionButtonType.similarPhotos => SimilarPhotosActionButton(
|
||||||
|
|||||||
Reference in New Issue
Block a user