From e986557d8751f6a4508a7bc98725fb876538ad86 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Tue, 18 Nov 2025 17:05:20 -0800 Subject: [PATCH] replace remaining legacy playqueue add functions --- .../feature-carousel/feature-carousel.tsx | 20 ++--- .../components/album-detail-content.tsx | 31 ++++++-- .../albums/components/album-detail-header.tsx | 29 ++++--- .../albums/routes/album-detail-route.tsx | 13 +--- .../routes/dummy-album-detail-route.tsx | 13 +--- .../album-artist-detail-content.tsx | 63 ++++++--------- .../components/album-artist-detail-header.tsx | 30 +++++--- ...um-artist-detail-top-songs-list-header.tsx | 9 +-- .../routes/album-artist-detail-route.tsx | 13 +--- .../player/components/center-controls.tsx | 4 - .../components/full-screen-player-image.tsx | 76 +++++++++++-------- .../player/components/shuffle-all-modal.tsx | 63 ++------------- .../player/hooks/use-playqueue-add.ts | 8 -- .../search/components/command-palette.tsx | 7 +- .../components/library-command-item.tsx | 19 ++--- 15 files changed, 171 insertions(+), 227 deletions(-) delete mode 100644 src/renderer/features/player/hooks/use-playqueue-add.ts diff --git a/src/renderer/components/feature-carousel/feature-carousel.tsx b/src/renderer/components/feature-carousel/feature-carousel.tsx index 647949729..3152921d7 100644 --- a/src/renderer/components/feature-carousel/feature-carousel.tsx +++ b/src/renderer/components/feature-carousel/feature-carousel.tsx @@ -8,10 +8,10 @@ import { generatePath, Link } from 'react-router'; import styles from './feature-carousel.module.css'; -import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { PlayButton } from '/@/renderer/features/shared/components/play-button'; import { AppRoute } from '/@/renderer/router/routes'; -import { usePlayButtonBehavior } from '/@/renderer/store'; +import { useCurrentServer, usePlayButtonBehavior } from '/@/renderer/store'; import { Badge } from '/@/shared/components/badge/badge'; import { Button } from '/@/shared/components/button/button'; import { Group } from '/@/shared/components/group/group'; @@ -43,7 +43,8 @@ interface FeatureCarouselProps { export const FeatureCarousel = ({ data }: FeatureCarouselProps) => { const { t } = useTranslation(); - const handlePlayQueueAdd = usePlayQueueAdd(); + const { addToQueueByFetch } = usePlayer(); + const server = useCurrentServer(); const [itemIndex, setItemIndex] = useState(0); const [direction, setDirection] = useState(0); const playType = usePlayButtonBehavior(); @@ -131,15 +132,14 @@ export const FeatureCarousel = ({ data }: FeatureCarouselProps) => { onClick={(e) => { e.preventDefault(); e.stopPropagation(); - if (!currentItem) return; + if (!currentItem || !server?.id) return; - handlePlayQueueAdd?.({ - byItemType: { - id: [currentItem.id], - type: LibraryItem.ALBUM, - }, + addToQueueByFetch( + server.id, + [currentItem.id], + LibraryItem.ALBUM, playType, - }); + ); }} variant="outline" > diff --git a/src/renderer/features/albums/components/album-detail-content.tsx b/src/renderer/features/albums/components/album-detail-content.tsx index e13a7d37b..725ed0d75 100644 --- a/src/renderer/features/albums/components/album-detail-content.tsx +++ b/src/renderer/features/albums/components/album-detail-content.tsx @@ -12,6 +12,8 @@ import { ItemTableList } from '/@/renderer/components/item-list/item-table-list/ import { ItemTableListColumn } from '/@/renderer/components/item-list/item-table-list/item-table-list-column'; import { albumQueries } from '/@/renderer/features/albums/api/album-api'; import { AlbumInfiniteCarousel } from '/@/renderer/features/albums/components/album-infinite-carousel'; +import { ContextMenuController } from '/@/renderer/features/context-menu/context-menu-controller'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { LibraryBackgroundOverlay } from '/@/renderer/features/shared/components/library-background-overlay'; import { ListConfigMenu } from '/@/renderer/features/shared/components/list-config-menu'; import { PlayButton } from '/@/renderer/features/shared/components/play-button'; @@ -33,7 +35,7 @@ import { Spoiler } from '/@/shared/components/spoiler/spoiler'; import { Stack } from '/@/shared/components/stack/stack'; import { Text } from '/@/shared/components/text/text'; import { AlbumListSort, LibraryItem, Song, SortOrder } from '/@/shared/types/domain-types'; -import { ItemListKey, ListDisplayType, Play } from '/@/shared/types/types'; +import { ItemListKey, ListDisplayType } from '/@/shared/types/types'; interface AlbumDetailContentProps { background?: string; @@ -89,10 +91,29 @@ export const AlbumDetailContent = ({ background }: AlbumDetailContentProps) => { ]; const playButtonBehavior = usePlayButtonBehavior(); - const handlePlay = async (playType?: Play) => {}; + const { addToQueueByFetch, setFavorite } = usePlayer(); + + const handlePlay = () => { + if (!server?.id) return; + addToQueueByFetch(server.id, [albumId], LibraryItem.ALBUM, playButtonBehavior); + }; const handleFavorite = () => { if (!detailQuery?.data) return; + setFavorite( + detailQuery.data._serverId, + [detailQuery.data.id], + LibraryItem.ALBUM, + !detailQuery.data.userFavorite, + ); + }; + + const handleMoreOptions = (e: React.MouseEvent) => { + if (!detailQuery?.data) return; + ContextMenuController.call({ + cmd: { items: [detailQuery.data], type: LibraryItem.ALBUM }, + event: e, + }); }; const showGenres = detailQuery?.data?.genres ? detailQuery?.data?.genres.length !== 0 : false; @@ -107,7 +128,7 @@ export const AlbumDetailContent = ({ background }: AlbumDetailContentProps) => {
- handlePlay(playButtonBehavior)} /> + { /> { - if (!detailQuery?.data) return; - }} + onClick={handleMoreOptions} size="lg" variant="transparent" /> diff --git a/src/renderer/features/albums/components/album-detail-header.tsx b/src/renderer/features/albums/components/album-detail-header.tsx index 3a929d3f1..2ce356831 100644 --- a/src/renderer/features/albums/components/album-detail-header.tsx +++ b/src/renderer/features/albums/components/album-detail-header.tsx @@ -4,8 +4,8 @@ import { useTranslation } from 'react-i18next'; import { generatePath, Link, useParams } from 'react-router'; import { albumQueries } from '/@/renderer/features/albums/api/album-api'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { LibraryHeader } from '/@/renderer/features/shared/components/library-header'; -import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-mutation'; import { AppRoute } from '/@/renderer/router/routes'; import { useCurrentServer } from '/@/renderer/store'; import { formatDateAbsoluteUTC, formatDurationString, titleCase } from '/@/renderer/utils'; @@ -95,19 +95,26 @@ export const AlbumDetailHeader = forwardRef { if (!detailQuery?.data) return; - updateRatingMutation.mutate({ - apiClientProps: { serverId: detailQuery.data._serverId }, - query: { - id: [detailQuery.data.id], - rating, - type: LibraryItem.ALBUM, - }, - }); + if (detailQuery.data.userRating === rating) { + return setRating( + detailQuery.data._serverId, + [detailQuery.data.id], + LibraryItem.ALBUM, + 0, + ); + } + + return setRating( + detailQuery.data._serverId, + [detailQuery.data.id], + LibraryItem.ALBUM, + rating, + ); }; return ( @@ -130,7 +137,7 @@ export const AlbumDetailHeader = forwardRef )} diff --git a/src/renderer/features/albums/routes/album-detail-route.tsx b/src/renderer/features/albums/routes/album-detail-route.tsx index f8a8acd8b..234d1be1f 100644 --- a/src/renderer/features/albums/routes/album-detail-route.tsx +++ b/src/renderer/features/albums/routes/album-detail-route.tsx @@ -6,7 +6,7 @@ import { NativeScrollArea } from '/@/renderer/components/native-scroll-area/nati import { albumQueries } from '/@/renderer/features/albums/api/album-api'; import { AlbumDetailContent } from '/@/renderer/features/albums/components/album-detail-content'; import { AlbumDetailHeader } from '/@/renderer/features/albums/components/album-detail-header'; -import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page'; import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar'; import { useFastAverageColor } from '/@/renderer/hooks'; @@ -29,17 +29,12 @@ const AlbumDetailRoute = () => { src: detailQuery.data?.imageUrl, srcLoaded: !detailQuery.isLoading, }); - const handlePlayQueueAdd = usePlayQueueAdd(); + const { addToQueueByFetch } = usePlayer(); const playButtonBehavior = usePlayButtonBehavior(); const handlePlay = () => { - handlePlayQueueAdd?.({ - byItemType: { - id: [albumId], - type: LibraryItem.ALBUM, - }, - playType: playButtonBehavior, - }); + if (!server?.id) return; + addToQueueByFetch(server.id, [albumId], LibraryItem.ALBUM, playButtonBehavior); }; const backgroundUrl = detailQuery.data?.imageUrl || ''; diff --git a/src/renderer/features/albums/routes/dummy-album-detail-route.tsx b/src/renderer/features/albums/routes/dummy-album-detail-route.tsx index 0e0f12dca..634c313dd 100644 --- a/src/renderer/features/albums/routes/dummy-album-detail-route.tsx +++ b/src/renderer/features/albums/routes/dummy-album-detail-route.tsx @@ -8,7 +8,7 @@ import styles from './dummy-album-detail-route.module.css'; import { api } from '/@/renderer/api'; import { queryKeys } from '/@/renderer/api/query-keys'; -import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page'; import { LibraryHeader } from '/@/renderer/features/shared/components/library-header'; import { PlayButton } from '/@/renderer/features/shared/components/play-button'; @@ -53,7 +53,7 @@ const DummyAlbumDetailRoute = () => { src: detailQuery.data?.imageUrl, srcLoaded: !detailQuery.isLoading, }); - const handlePlayQueueAdd = usePlayQueueAdd(); + const { addToQueueByFetch } = usePlayer(); const playButtonBehavior = usePlayButtonBehavior(); const createFavoriteMutation = useCreateFavorite({}); @@ -96,13 +96,8 @@ const DummyAlbumDetailRoute = () => { const comment = detailQuery?.data?.comment; const handlePlay = () => { - handlePlayQueueAdd?.({ - byItemType: { - id: [albumId], - type: LibraryItem.SONG, - }, - playType: playButtonBehavior, - }); + if (!server?.id) return; + addToQueueByFetch(server.id, [albumId], LibraryItem.SONG, playButtonBehavior); }; const metadataItems = [ diff --git a/src/renderer/features/artists/components/album-artist-detail-content.tsx b/src/renderer/features/artists/components/album-artist-detail-content.tsx index 72d5236d8..98b6ed4bd 100644 --- a/src/renderer/features/artists/components/album-artist-detail-content.tsx +++ b/src/renderer/features/artists/components/album-artist-detail-content.tsx @@ -8,11 +8,10 @@ import styles from './album-artist-detail-content.module.css'; import { AlbumInfiniteCarousel } from '/@/renderer/features/albums/components/album-infinite-carousel'; import { artistsQueries } from '/@/renderer/features/artists/api/artists-api'; import { AlbumArtistGridCarousel } from '/@/renderer/features/artists/components/album-artist-grid-carousel'; -import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add'; +import { ContextMenuController } from '/@/renderer/features/context-menu/context-menu-controller'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { LibraryBackgroundOverlay } from '/@/renderer/features/shared/components/library-background-overlay'; import { PlayButton } from '/@/renderer/features/shared/components/play-button'; -import { useCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation'; -import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation'; import { useContainerQuery } from '/@/renderer/hooks'; import { useGenreRoute } from '/@/renderer/hooks/use-genre-route'; import { AppRoute } from '/@/renderer/router/routes'; @@ -48,8 +47,8 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten artistId?: string; }; const routeId = (artistId || albumArtistId) as string; - const { ref, ...cq } = useContainerQuery(); - const handlePlayQueueAdd = usePlayQueueAdd(); + const { ref } = useContainerQuery(); + const { addToQueueByFetch, setFavorite } = usePlayer(); const server = useCurrentServer(); const genrePath = useGenreRoute(); @@ -183,38 +182,31 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten const playButtonBehavior = usePlayButtonBehavior(); const handlePlay = async (playType?: Play) => { - handlePlayQueueAdd?.({ - byItemType: { - id: [routeId], - type: albumArtistId ? LibraryItem.ALBUM_ARTIST : LibraryItem.ARTIST, - }, - playType: playType || playButtonBehavior, - }); + if (!server?.id) return; + addToQueueByFetch( + server.id, + [routeId], + albumArtistId ? LibraryItem.ALBUM_ARTIST : LibraryItem.ARTIST, + playType || playButtonBehavior, + ); }; - const createFavoriteMutation = useCreateFavorite({}); - const deleteFavoriteMutation = useDeleteFavorite({}); - const handleFavorite = () => { if (!detailQuery?.data) return; + setFavorite( + detailQuery.data._serverId, + [detailQuery.data.id], + LibraryItem.ALBUM_ARTIST, + !detailQuery.data.userFavorite, + ); + }; - if (detailQuery.data.userFavorite) { - deleteFavoriteMutation.mutate({ - apiClientProps: { serverId: detailQuery.data._serverId }, - query: { - id: [detailQuery.data.id], - type: LibraryItem.ALBUM_ARTIST, - }, - }); - } else { - createFavoriteMutation.mutate({ - apiClientProps: { serverId: detailQuery.data._serverId }, - query: { - id: [detailQuery.data.id], - type: LibraryItem.ALBUM_ARTIST, - }, - }); - } + const handleMoreOptions = (e: React.MouseEvent) => { + if (!detailQuery?.data) return; + ContextMenuController.call({ + cmd: { items: [detailQuery.data], type: LibraryItem.ALBUM_ARTIST }, + event: e, + }); }; const albumCount = detailQuery?.data?.albumCount; @@ -251,18 +243,13 @@ export const AlbumArtistDetailContent = ({ background }: AlbumArtistDetailConten iconProps={{ fill: detailQuery?.data?.userFavorite ? 'primary' : undefined, }} - loading={ - createFavoriteMutation.isPending || deleteFavoriteMutation.isPending - } onClick={handleFavorite} size="lg" variant="transparent" /> { - if (!detailQuery?.data) return; - }} + onClick={handleMoreOptions} size="lg" variant="transparent" /> diff --git a/src/renderer/features/artists/components/album-artist-detail-header.tsx b/src/renderer/features/artists/components/album-artist-detail-header.tsx index 2ef933fdb..9a180d884 100644 --- a/src/renderer/features/artists/components/album-artist-detail-header.tsx +++ b/src/renderer/features/artists/components/album-artist-detail-header.tsx @@ -4,8 +4,8 @@ import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router'; import { artistsQueries } from '/@/renderer/features/artists/api/artists-api'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { LibraryHeader } from '/@/renderer/features/shared/components/library-header'; -import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-mutation'; import { AppRoute } from '/@/renderer/router/routes'; import { useCurrentServer } from '/@/renderer/store'; import { formatDurationString } from '/@/renderer/utils'; @@ -65,18 +65,26 @@ export const AlbumArtistDetailHeader = forwardRef( }, ]; - const updateRatingMutation = useSetRating({}); + const { setRating } = usePlayer(); const handleUpdateRating = (rating: number) => { if (!detailQuery?.data) return; - updateRatingMutation.mutate({ - apiClientProps: { serverId: detailQuery?.data.serverId }, - query: { - item: [detailQuery.data], - rating, - }, - }); + if (detailQuery.data.userRating === rating) { + return setRating( + detailQuery.data._serverId, + [detailQuery.data.id], + LibraryItem.ALBUM_ARTIST, + 0, + ); + } + + return setRating( + detailQuery.data._serverId, + [detailQuery.data.id], + LibraryItem.ALBUM_ARTIST, + rating, + ); }; const showRating = detailQuery?.data?._serverType === ServerType.NAVIDROME; @@ -104,9 +112,7 @@ export const AlbumArtistDetailHeader = forwardRef( diff --git a/src/renderer/features/artists/components/album-artist-detail-top-songs-list-header.tsx b/src/renderer/features/artists/components/album-artist-detail-top-songs-list-header.tsx index 00d549027..3cc2b4c30 100644 --- a/src/renderer/features/artists/components/album-artist-detail-top-songs-list-header.tsx +++ b/src/renderer/features/artists/components/album-artist-detail-top-songs-list-header.tsx @@ -1,7 +1,7 @@ import { useTranslation } from 'react-i18next'; import { PageHeader } from '/@/renderer/components/page-header/page-header'; -import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar'; import { usePlayButtonBehavior } from '/@/renderer/store/settings.store'; import { Badge } from '/@/shared/components/badge/badge'; @@ -21,14 +21,11 @@ export const AlbumArtistDetailTopSongsListHeader = ({ title, }: AlbumArtistDetailTopSongsListHeaderProps) => { const { t } = useTranslation(); - const handlePlayQueueAdd = usePlayQueueAdd(); + const { addToQueueByData } = usePlayer(); const playButtonBehavior = usePlayButtonBehavior(); const handlePlay = async (playType: Play) => { - handlePlayQueueAdd?.({ - byData: data, - playType, - }); + addToQueueByData(data, playType); }; return ( diff --git a/src/renderer/features/artists/routes/album-artist-detail-route.tsx b/src/renderer/features/artists/routes/album-artist-detail-route.tsx index 0c6e0a585..378e76929 100644 --- a/src/renderer/features/artists/routes/album-artist-detail-route.tsx +++ b/src/renderer/features/artists/routes/album-artist-detail-route.tsx @@ -6,7 +6,7 @@ import { NativeScrollArea } from '/@/renderer/components/native-scroll-area/nati import { artistsQueries } from '/@/renderer/features/artists/api/artists-api'; import { AlbumArtistDetailContent } from '/@/renderer/features/artists/components/album-artist-detail-content'; import { AlbumArtistDetailHeader } from '/@/renderer/features/artists/components/album-artist-detail-header'; -import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page'; import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar'; import { useFastAverageColor } from '/@/renderer/hooks'; @@ -27,7 +27,7 @@ const AlbumArtistDetailRoute = () => { const routeId = (artistId || albumArtistId) as string; - const handlePlayQueueAdd = usePlayQueueAdd(); + const { addToQueueByFetch } = usePlayer(); const playButtonBehavior = usePlayButtonBehavior(); const detailQuery = useQuery( artistsQueries.albumArtistDetail({ @@ -46,13 +46,8 @@ const AlbumArtistDetailRoute = () => { const background = (artistBackground && `url(${backgroundUrl})`) || backgroundColor; const handlePlay = () => { - handlePlayQueueAdd?.({ - byItemType: { - id: [routeId], - type: LibraryItem.ALBUM_ARTIST, - }, - playType: playButtonBehavior, - }); + if (!server?.id) return; + addToQueueByFetch(server.id, [routeId], LibraryItem.ALBUM_ARTIST, playButtonBehavior); }; return ( diff --git a/src/renderer/features/player/components/center-controls.tsx b/src/renderer/features/player/components/center-controls.tsx index 93be5b806..7a025cd4a 100644 --- a/src/renderer/features/player/components/center-controls.tsx +++ b/src/renderer/features/player/components/center-controls.tsx @@ -7,7 +7,6 @@ import { PlayButton, PlayerButton } from '/@/renderer/features/player/components import { PlayerbarSlider } from '/@/renderer/features/player/components/playerbar-slider'; import { openShuffleAllModal } from '/@/renderer/features/player/components/shuffle-all-modal'; import { usePlayer } from '/@/renderer/features/player/context/player-context'; -import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add'; import { usePlayerRepeat, usePlayerShuffle, @@ -39,8 +38,6 @@ export const CenterControls = () => { toggleShuffle, } = usePlayer(); - const handlePlayQueueAdd = usePlayQueueAdd(); - return ( <>
@@ -170,7 +167,6 @@ export const CenterControls = () => { icon={} onClick={() => openShuffleAllModal({ - handlePlayQueueAdd, queryClient, }) } diff --git a/src/renderer/features/player/components/full-screen-player-image.tsx b/src/renderer/features/player/components/full-screen-player-image.tsx index b5f4ddf2f..a6c4e9738 100644 --- a/src/renderer/features/player/components/full-screen-player-image.tsx +++ b/src/renderer/features/player/components/full-screen-player-image.tsx @@ -8,7 +8,7 @@ import styles from './full-screen-player-image.module.css'; import { useFastAverageColor } from '/@/renderer/hooks'; import { AppRoute } from '/@/renderer/router/routes'; -import { usePlayerData, usePlayerStore } from '/@/renderer/store'; +import { subscribeCurrentTrack, usePlayerData, usePlayerStoreBase } from '/@/renderer/store'; import { useSettingsStore } from '/@/renderer/store/settings.store'; import { Badge } from '/@/shared/components/badge/badge'; import { Center } from '/@/shared/components/center/center'; @@ -18,7 +18,6 @@ import { Icon } from '/@/shared/components/icon/icon'; import { Stack } from '/@/shared/components/stack/stack'; import { Text } from '/@/shared/components/text/text'; import { useSetState } from '/@/shared/hooks/use-set-state'; -import { PlayerData, QueueSong } from '/@/shared/types/domain-types'; const imageVariants: Variants = { closed: { @@ -91,22 +90,27 @@ export const FullScreenPlayerImage = () => { const albumArtRes = useSettingsStore((store) => store.general.albumArtRes); - const { queue } = usePlayerData(); - const currentSong = queue.current; + const { currentSong, nextSong } = usePlayerData(); const { background } = useFastAverageColor({ algorithm: 'dominant', - src: queue.current?.imageUrl, + src: currentSong?.imageUrl, srcLoaded: true, }); const imageKey = `image-${background}`; const [imageState, setImageState] = useSetState({ - bottomImage: scaleImageUrl(mainImageDimensions.idealSize, queue.next?.imageUrl), + bottomImage: scaleImageUrl(mainImageDimensions.idealSize, nextSong?.imageUrl), current: 0, - topImage: scaleImageUrl(mainImageDimensions.idealSize, queue.current?.imageUrl), + topImage: scaleImageUrl(mainImageDimensions.idealSize, currentSong?.imageUrl), }); const updateImageSize = useCallback(() => { if (mainImageRef.current) { + const state = usePlayerStoreBase.getState(); + const playerData = state.getQueue(); + const currentIndex = state.player.index; + const current = playerData.items[currentIndex]; + const next = playerData.items[currentIndex + 1]; + setMainImageDimensions({ idealSize: albumArtRes || @@ -114,46 +118,54 @@ export const FullScreenPlayerImage = () => { }); setImageState({ - bottomImage: scaleImageUrl(mainImageDimensions.idealSize, queue.next?.imageUrl), + bottomImage: scaleImageUrl(mainImageDimensions.idealSize, next?.imageUrl), current: 0, - topImage: scaleImageUrl(mainImageDimensions.idealSize, queue.current?.imageUrl), + topImage: scaleImageUrl(mainImageDimensions.idealSize, current?.imageUrl), }); } - }, [mainImageDimensions.idealSize, queue, setImageState, albumArtRes]); + }, [mainImageDimensions.idealSize, setImageState, albumArtRes]); useLayoutEffect(() => { updateImageSize(); }, [updateImageSize]); + // Use ref to track current image state to avoid recreating subscription + const imageStateRef = useRef(imageState); useEffect(() => { - const unsubSongChange = usePlayerStore.subscribe( - (state) => [state.current.song, state.actions.getPlayerData().queue], - (state) => { - const isTop = imageState.current === 0; - const queue = state[1] as PlayerData['queue']; + imageStateRef.current = imageState; + }, [imageState]); - const currentImageUrl = scaleImageUrl( - mainImageDimensions.idealSize, - queue.current?.imageUrl, - ); - const nextImageUrl = scaleImageUrl( - mainImageDimensions.idealSize, - queue.next?.imageUrl, - ); + useEffect(() => { + const unsubSongChange = subscribeCurrentTrack(({ index, song }, prev) => { + // Only update if the song actually changed + if (song?._uniqueId === prev.song?._uniqueId) { + return; + } - setImageState({ - bottomImage: isTop ? currentImageUrl : nextImageUrl, - current: isTop ? 1 : 0, - topImage: isTop ? nextImageUrl : currentImageUrl, - }); - }, - { equalityFn: (a, b) => (a[0] as QueueSong)?.id === (b[0] as QueueSong)?.id }, - ); + // Use ref to get current state without causing dependency issues + const isTop = imageStateRef.current.current === 0; + const state = usePlayerStoreBase.getState(); + const queue = state.getQueue(); + const currentSong = queue.items[index]; + const nextSong = queue.items[index + 1]; + + const currentImageUrl = scaleImageUrl( + mainImageDimensions.idealSize, + currentSong?.imageUrl, + ); + const nextImageUrl = scaleImageUrl(mainImageDimensions.idealSize, nextSong?.imageUrl); + + setImageState({ + bottomImage: isTop ? currentImageUrl : nextImageUrl, + current: isTop ? 1 : 0, + topImage: isTop ? nextImageUrl : currentImageUrl, + }); + }); return () => { unsubSongChange(); }; - }, [imageState, mainImageDimensions.idealSize, queue, setImageState]); + }, [mainImageDimensions.idealSize, setImageState]); return ( useShuffleAllStore((state) => sta interface ShuffleAllModalProps { genres: GenreListResponse | undefined; - handlePlayQueueAdd: ((options: PlayQueueAddOptions) => void) | undefined; - musicFolders: MusicFolderListResponse | undefined; queryClient: QueryClient; server: null | ServerListItem; } -export const ShuffleAllModal = ({ - genres, - handlePlayQueueAdd, - musicFolders, - queryClient, - server, -}: ShuffleAllModalProps) => { +export const ShuffleAllModal = ({ genres, queryClient, server }: ShuffleAllModalProps) => { + const { addToQueueByData } = usePlayer(); const { t } = useTranslation(); const { enableMaxYear, enableMinYear, genre, limit, maxYear, minYear, musicFolderId, played } = useShuffleAllStore(); @@ -114,10 +107,7 @@ export const ShuffleAllModal = ({ staleTime: 0, }); - handlePlayQueueAdd?.({ - byData: res?.items || [], - playType, - }); + addToQueueByData(res?.items || [], playType); closeAllModals(); }; @@ -137,14 +127,6 @@ export const ShuffleAllModal = ({ }); }, [genres, server?.type]); - const musicFolderData = useMemo(() => { - if (!musicFolders) return []; - return musicFolders.items.map((musicFolder) => ({ - label: musicFolder.name, - value: String(musicFolder.id), - })); - }, [musicFolders]); - return ( setStore({ genre: e || '' })} value={genre} /> - , -) => { +export const openShuffleAllModal = async (props: Pick) => { const server = useAuthStore.getState().currentServer; const genres = await props.queryClient.fetchQuery({ @@ -270,28 +241,8 @@ export const openShuffleAllModal = async ( staleTime: 1000 * 60 * 60 * 4, }); - const musicFolders = await props.queryClient.fetchQuery({ - gcTime: 1000 * 60 * 5, - queryFn: ({ signal }) => - api.controller.getMusicFolderList({ - apiClientProps: { - serverId: server?.id || '', - signal, - }, - }), - queryKey: queryKeys.musicFolders.list(server?.id), - staleTime: 1000 * 60 * 60 * 4, - }); - openModal({ - children: ( - - ), + children: , size: 'sm', title: i18n.t('player.playRandom', { postProcess: 'sentenceCase' }) as string, }); diff --git a/src/renderer/features/player/hooks/use-playqueue-add.ts b/src/renderer/features/player/hooks/use-playqueue-add.ts deleted file mode 100644 index bfda2a7bf..000000000 --- a/src/renderer/features/player/hooks/use-playqueue-add.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { useContext } from 'react'; - -import { PlayQueueHandlerContext } from '/@/renderer/features/player/context/play-queue-handler-context'; - -export const usePlayQueueAdd = () => { - const { handlePlayQueueAdd } = useContext(PlayQueueHandlerContext); - return handlePlayQueueAdd; -}; diff --git a/src/renderer/features/search/components/command-palette.tsx b/src/renderer/features/search/components/command-palette.tsx index dd0b1caab..18fc4cf9b 100644 --- a/src/renderer/features/search/components/command-palette.tsx +++ b/src/renderer/features/search/components/command-palette.tsx @@ -3,7 +3,7 @@ import { Fragment, useCallback, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { generatePath, useNavigate } from 'react-router'; -import { usePlayQueueAdd } from '/@/renderer/features/player/hooks/use-playqueue-add'; +import { usePlayer } from '/@/renderer/features/player/context/player-context'; import { searchQueries } from '/@/renderer/features/search/api/search-api'; import { Command, CommandPalettePages } from '/@/renderer/features/search/components/command'; import { CommandItemSelectable } from '/@/renderer/features/search/components/command-item-selectable'; @@ -70,8 +70,6 @@ export const CommandPalette = ({ modalProps }: CommandPaletteProps) => { const showArtistGroup = isHome && Boolean(query && data && data?.albumArtists?.length > 0); const showTrackGroup = isHome && Boolean(query && data && data?.songs?.length > 0); - const handlePlayQueueAdd = usePlayQueueAdd(); - return ( { > {({ isHighlighted }) => ( { {({ isHighlighted }) => ( { > {({ isHighlighted }) => ( void; id: string; imageUrl: null | string; isHighlighted?: boolean; @@ -24,7 +25,6 @@ interface LibraryCommandItemProps { export const LibraryCommandItem = ({ disabled, - handlePlayQueueAdd, id, imageUrl, isHighlighted, @@ -33,20 +33,17 @@ export const LibraryCommandItem = ({ title, }: LibraryCommandItemProps) => { const { t } = useTranslation(); + const { addToQueueByFetch } = usePlayer(); + const server = useCurrentServer(); const handlePlay = useCallback( (e: SyntheticEvent, id: string, playType: Play) => { e.stopPropagation(); e.preventDefault(); - handlePlayQueueAdd?.({ - byItemType: { - id: [id], - type: itemType, - }, - playType, - }); + if (!server?.id) return; + addToQueueByFetch(server.id, [id], itemType, playType); }, - [handlePlayQueueAdd, itemType], + [addToQueueByFetch, itemType, server?.id], ); const [isHovered, setIsHovered] = useState(false);