mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
handle image drag from item detail list
This commit is contained in:
@@ -196,6 +196,17 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.image-wrapper-outer {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-wrapper-outer.image-wrapper-dragging {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
.image-wrapper {
|
.image-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -32,10 +32,12 @@ import styles from './item-detail-list.module.css';
|
|||||||
|
|
||||||
import { ItemCardControls } from '/@/renderer/components/item-card/item-card-controls';
|
import { ItemCardControls } from '/@/renderer/components/item-card/item-card-controls';
|
||||||
import { ItemImage } from '/@/renderer/components/item-image/item-image';
|
import { ItemImage } from '/@/renderer/components/item-image/item-image';
|
||||||
|
import { getDraggedItems } from '/@/renderer/components/item-list/helpers/get-dragged-items';
|
||||||
import { useDefaultItemListControls } from '/@/renderer/components/item-list/helpers/item-list-controls';
|
import { useDefaultItemListControls } from '/@/renderer/components/item-list/helpers/item-list-controls';
|
||||||
import {
|
import {
|
||||||
ItemListStateActions,
|
ItemListStateActions,
|
||||||
ItemListStateItemWithRequiredProperties,
|
ItemListStateItemWithRequiredProperties,
|
||||||
|
useItemDraggingState,
|
||||||
useItemListState,
|
useItemListState,
|
||||||
useItemSelectionState,
|
useItemSelectionState,
|
||||||
} from '/@/renderer/components/item-list/helpers/item-list-state';
|
} from '/@/renderer/components/item-list/helpers/item-list-state';
|
||||||
@@ -62,6 +64,7 @@ import { usePlayer } from '/@/renderer/features/player/context/player-context';
|
|||||||
import { useIsMutatingCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
|
import { useIsMutatingCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
|
||||||
import { useIsMutatingDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
|
import { useIsMutatingDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
|
||||||
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
import { songsQueries } from '/@/renderer/features/songs/api/songs-api';
|
||||||
|
import { useDragDrop } from '/@/renderer/hooks/use-drag-drop';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { useSettingsStore, useShowRatings } from '/@/renderer/store';
|
import { useSettingsStore, useShowRatings } from '/@/renderer/store';
|
||||||
import { formatDateAbsoluteUTC, formatDurationString } from '/@/renderer/utils';
|
import { formatDateAbsoluteUTC, formatDurationString } from '/@/renderer/utils';
|
||||||
@@ -422,6 +425,61 @@ const MetadataSection = memo(
|
|||||||
const [isImageHovered, setIsImageHovered] = useState(false);
|
const [isImageHovered, setIsImageHovered] = useState(false);
|
||||||
const [isMetadataHovered, setIsMetadataHovered] = useState(false);
|
const [isMetadataHovered, setIsMetadataHovered] = useState(false);
|
||||||
|
|
||||||
|
const getId = useCallback(() => {
|
||||||
|
const draggedItems = getDraggedItems(item, internalState, false);
|
||||||
|
return draggedItems.map((i) => i.id);
|
||||||
|
}, [item, internalState]);
|
||||||
|
|
||||||
|
const getItem = useCallback(() => {
|
||||||
|
return getDraggedItems(item, internalState, false);
|
||||||
|
}, [item, internalState]);
|
||||||
|
|
||||||
|
const onDragStart = useCallback(() => {
|
||||||
|
const draggedItems = getDraggedItems(item, internalState, false);
|
||||||
|
internalState?.setDragging(draggedItems);
|
||||||
|
}, [item, internalState]);
|
||||||
|
|
||||||
|
const onDrop = useCallback(() => {
|
||||||
|
internalState?.setDragging([]);
|
||||||
|
}, [internalState]);
|
||||||
|
|
||||||
|
const drag = useMemo(() => {
|
||||||
|
const playlistSongs = (item as { _playlistSongs?: Song[] })._playlistSongs;
|
||||||
|
if (playlistSongs && playlistSongs.length > 0) {
|
||||||
|
return {
|
||||||
|
getId,
|
||||||
|
getItem: () => playlistSongs,
|
||||||
|
itemType: LibraryItem.SONG,
|
||||||
|
onDragStart,
|
||||||
|
onDrop,
|
||||||
|
operation: [DragOperation.ADD],
|
||||||
|
target: DragTarget.SONG,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getId,
|
||||||
|
getItem,
|
||||||
|
itemType: item._itemType,
|
||||||
|
onDragStart,
|
||||||
|
onDrop,
|
||||||
|
operation: [DragOperation.ADD],
|
||||||
|
target: DragTarget.ALBUM,
|
||||||
|
};
|
||||||
|
}, [getId, getItem, item, onDragStart, onDrop]);
|
||||||
|
|
||||||
|
const { isDragging: isDraggingLocal, ref: dragRef } = useDragDrop<HTMLDivElement>({
|
||||||
|
drag,
|
||||||
|
isEnabled: !!item,
|
||||||
|
});
|
||||||
|
const isDraggingState = useItemDraggingState(internalState, item.id);
|
||||||
|
const isDragging = isDraggingState || isDraggingLocal;
|
||||||
|
|
||||||
|
const handleLinkDragStart = useCallback((e: React.DragEvent<HTMLAnchorElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const isFavorite = item.userFavorite ?? false;
|
const isFavorite = item.userFavorite ?? false;
|
||||||
const userRating = item.userRating ?? null;
|
const userRating = item.userRating ?? null;
|
||||||
const hasRating = showRatings && userRating !== null && userRating > 0;
|
const hasRating = showRatings && userRating !== null && userRating > 0;
|
||||||
@@ -483,39 +541,48 @@ const MetadataSection = memo(
|
|||||||
onMouseEnter={() => setIsMetadataHovered(true)}
|
onMouseEnter={() => setIsMetadataHovered(true)}
|
||||||
onMouseLeave={() => setIsMetadataHovered(false)}
|
onMouseLeave={() => setIsMetadataHovered(false)}
|
||||||
>
|
>
|
||||||
<Link
|
<div
|
||||||
className={styles.imageWrapper}
|
className={clsx(styles.imageWrapperOuter, {
|
||||||
onMouseEnter={() => setIsImageHovered(true)}
|
[styles.imageWrapperDragging]: isDragging,
|
||||||
onMouseLeave={() => setIsImageHovered(false)}
|
|
||||||
state={{ item }}
|
|
||||||
to={generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, {
|
|
||||||
albumId: item.id,
|
|
||||||
})}
|
})}
|
||||||
|
ref={dragRef ?? undefined}
|
||||||
>
|
>
|
||||||
<ItemImage
|
<Link
|
||||||
className={styles.image}
|
className={styles.imageWrapper}
|
||||||
explicitStatus={item.explicitStatus}
|
draggable={false}
|
||||||
id={item.imageId}
|
onDragStart={handleLinkDragStart}
|
||||||
itemType={item._itemType}
|
onMouseEnter={() => setIsImageHovered(true)}
|
||||||
serverId={item._serverId}
|
onMouseLeave={() => setIsImageHovered(false)}
|
||||||
type="itemCard"
|
state={{ item }}
|
||||||
/>
|
to={generatePath(AppRoute.LIBRARY_ALBUMS_DETAIL, {
|
||||||
{isFavorite && <div className={styles.favoriteBadge} />}
|
albumId: item.id,
|
||||||
{hasRating && <div className={styles.ratingBadge}>{userRating}</div>}
|
})}
|
||||||
<AnimatePresence>
|
>
|
||||||
{controls && isImageHovered && (
|
<ItemImage
|
||||||
<ItemCardControls
|
className={styles.image}
|
||||||
controls={controls}
|
explicitStatus={item.explicitStatus}
|
||||||
enableExpansion={false}
|
id={item.imageId}
|
||||||
internalState={internalState}
|
itemType={item._itemType}
|
||||||
item={item}
|
serverId={item._serverId}
|
||||||
itemType={item._itemType}
|
type="itemCard"
|
||||||
showRating={true}
|
/>
|
||||||
type="compact"
|
{isFavorite && <div className={styles.favoriteBadge} />}
|
||||||
/>
|
{hasRating && <div className={styles.ratingBadge}>{userRating}</div>}
|
||||||
)}
|
<AnimatePresence>
|
||||||
</AnimatePresence>
|
{controls && isImageHovered && (
|
||||||
</Link>
|
<ItemCardControls
|
||||||
|
controls={controls}
|
||||||
|
enableExpansion={false}
|
||||||
|
internalState={internalState}
|
||||||
|
item={item}
|
||||||
|
itemType={item._itemType}
|
||||||
|
showRating={true}
|
||||||
|
type="compact"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
<Link
|
<Link
|
||||||
className={styles.title}
|
className={styles.title}
|
||||||
state={{ item }}
|
state={{ item }}
|
||||||
|
|||||||
Reference in New Issue
Block a user