diff --git a/package.json b/package.json index 1a4c93b5..748faab9 100644 --- a/package.json +++ b/package.json @@ -48,9 +48,9 @@ "@sentry/react-native": "7.0.1", "@shopify/flash-list": "^2.0.3", "@tamagui/config": "^1.132.23", - "@tanstack/query-async-storage-persister": "^5.87.1", - "@tanstack/react-query": "^5.87.1", - "@tanstack/react-query-persist-client": "^5.87.1", + "@tanstack/query-async-storage-persister": "^5.87.4", + "@tanstack/react-query": "^5.87.4", + "@tanstack/react-query-persist-client": "^5.87.4", "@testing-library/react-native": "^13.2.3", "@typedigital/telemetrydeck-react": "^0.4.1", "axios": "^1.11.0", diff --git a/src/components/Album/index.tsx b/src/components/Album/index.tsx index 5ffb31d5..56144a82 100644 --- a/src/components/Album/index.tsx +++ b/src/components/Album/index.tsx @@ -40,7 +40,7 @@ export function Album(): React.JSX.Element { const { album, discs, isPending } = useAlbumContext() const { api } = useJellifyContext() - const { useDownloadMultiple, pendingDownloads } = useNetworkContext() + const { addToDownloadQueue, pendingDownloads } = useNetworkContext() const [networkStatus] = useNetworkStatus() const streamingDeviceProfile = useStreamingDeviceProfile() const downloadingDeviceProfile = useDownloadingDeviceProfile() @@ -51,7 +51,7 @@ export function Album(): React.JSX.Element { const jellifyTracks = item.map((item) => mapDtoToTrack(api, item, [], downloadingDeviceProfile), ) - useDownloadMultiple(jellifyTracks) + addToDownloadQueue(jellifyTracks) } const playAlbum = useCallback( diff --git a/src/components/Context/index.tsx b/src/components/Context/index.tsx index 56a39628..b93a3828 100644 --- a/src/components/Context/index.tsx +++ b/src/components/Context/index.tsx @@ -202,7 +202,7 @@ function AddToQueueMenuRow({ tracks }: { tracks: BaseItemDto[] }): React.JSX.Ele function DownloadMenuRow({ items }: { items: BaseItemDto[] }): React.JSX.Element { const { api } = useJellifyContext() - const { useDownloadMultiple, pendingDownloads } = useNetworkContext() + const { addToDownloadQueue, pendingDownloads } = useNetworkContext() const useRemoveDownload = useDeleteDownloads() @@ -214,8 +214,8 @@ function DownloadMenuRow({ items }: { items: BaseItemDto[] }): React.JSX.Element if (!api) return const tracks = items.map((item) => mapDtoToTrack(api, item, [], deviceProfile)) - useDownloadMultiple(tracks) - }, [useDownloadMultiple, items]) + addToDownloadQueue(tracks) + }, [addToDownloadQueue, items]) const removeDownloads = useCallback( () => useRemoveDownload(items.map(({ Id }) => Id)), diff --git a/src/components/Player/mini-player.tsx b/src/components/Player/mini-player.tsx index 013f8781..24f6779d 100644 --- a/src/components/Player/mini-player.tsx +++ b/src/components/Player/mini-player.tsx @@ -79,19 +79,18 @@ export const Miniplayer = React.memo(function Miniplayer(): React.JSX.Element { [translateX, translateY, handleSwipe], ) + const openPlayer = useCallback( + () => navigation.navigate('PlayerRoot', { screen: 'PlayerScreen' }), + [navigation], + ) + return ( {nowPlaying && ( - - navigation.navigate('PlayerRoot', { screen: 'PlayerScreen' }) - } - > + {api && ( mapDtoToTrack(api, item, [], downloadingDeviceProfile), ) - useDownloadMultiple(jellifyTracks) + addToDownloadQueue(jellifyTracks) } const playPlaylist = (shuffled: boolean = false) => { diff --git a/src/components/Settings/components/info/index.tsx b/src/components/Settings/components/info/index.tsx index 8358b481..a224c58b 100644 --- a/src/components/Settings/components/info/index.tsx +++ b/src/components/Settings/components/info/index.tsx @@ -28,8 +28,8 @@ export default function InfoTabIndex() { { title: `Jellify ${version}`, subTitle: caption, - iconName: 'jellyfish-outline', - iconColor: '$secondary', + iconName: 'jellyfish', + iconColor: '$primary', children: ( @@ -76,7 +76,7 @@ export default function InfoTabIndex() { title: 'Powered by listeners like you', subTitle: 'Sponsor on GitHub or Patreon', iconName: 'heart', - iconColor: '$primary', + iconColor: '$secondary', children: ( activeDownloads: JellifyDownloadProgress | undefined pendingDownloads: JellifyTrack[] downloadingDownloads: JellifyTrack[] completedDownloads: JellifyTrack[] failedDownloads: JellifyTrack[] + addToDownloadQueue: (items: JellifyTrack[]) => boolean } const MAX_CONCURRENT_DOWNLOADS = 1 @@ -60,38 +59,29 @@ const NetworkContextInitializer = () => { } }, [pending, downloading]) - const addToQueue = async (items: JellifyTrack[]) => { + const addToDownloadQueue = (items: JellifyTrack[]) => { setPending((prev) => [...prev, ...items]) return true } - const { mutate: useDownloadMultiple } = useMutation({ - mutationFn: (tracks: JellifyTrack[]) => { - return addToQueue(tracks) - }, - onSuccess: (data, variables) => { - console.debug(`Added ${variables?.length} tracks to queue`) - }, - }) - return { activeDownloads: downloadProgress, downloadedTracks, - useDownloadMultiple, pendingDownloads: pending, downloadingDownloads: downloading, completedDownloads: completed, failedDownloads: failed, + addToDownloadQueue, } } const NetworkContext = createContext({ activeDownloads: {}, - useDownloadMultiple: () => {}, pendingDownloads: [], downloadingDownloads: [], completedDownloads: [], failedDownloads: [], + addToDownloadQueue: () => true, }) export const NetworkContextProvider: ({ @@ -110,7 +100,6 @@ export const NetworkContextProvider: ({ context.downloadingDownloads.length, context.completedDownloads.length, context.failedDownloads.length, - // Don't include mutation objects as they're stable ], ) diff --git a/src/providers/Player/constants/queries.ts b/src/providers/Player/constants/queries.ts index bcab3329..dece94ad 100644 --- a/src/providers/Player/constants/queries.ts +++ b/src/providers/Player/constants/queries.ts @@ -1,6 +1,11 @@ import JellifyTrack from '../../../types/JellifyTrack' import PlayerQueryKeys from '../enums/queue-keys' -import { NOW_PLAYING_QUERY_KEY, PLAY_QUEUE_QUERY_KEY, REPEAT_MODE_QUERY_KEY } from './query-keys' +import { + ACTIVE_INDEX_QUERY_KEY, + NOW_PLAYING_QUERY_KEY, + PLAY_QUEUE_QUERY_KEY, + REPEAT_MODE_QUERY_KEY, +} from './query-keys' import TrackPlayer, { Track } from 'react-native-track-player' const PLAYER_QUERY_OPTIONS = { @@ -21,7 +26,7 @@ export const QUEUE_QUERY = { } export const CURRENT_INDEX_QUERY = { - queryKey: [PlayerQueryKeys.ActiveIndex], + queryKey: ACTIVE_INDEX_QUERY_KEY, queryFn: TrackPlayer.getActiveTrackIndex, ...PLAYER_QUERY_OPTIONS, } diff --git a/src/providers/Player/functions/initialization.ts b/src/providers/Player/functions/initialization.ts index ce73c36c..4b5864d3 100644 --- a/src/providers/Player/functions/initialization.ts +++ b/src/providers/Player/functions/initialization.ts @@ -1,13 +1,14 @@ import { isUndefined } from 'lodash' -import { getActiveIndex, getPlayQueue } from '.' +import { getActiveIndex, getCurrentTrack, getPlayQueue } from '.' import TrackPlayer from 'react-native-track-player' export default async function Initialize() { const storedPlayQueue = getPlayQueue() const storedIndex = getActiveIndex() + const storedTrack = getCurrentTrack() console.debug( - `StoredIndex: ${storedIndex}, storedPlayQueue: ${storedPlayQueue?.map((track, index) => index)}`, + `StoredIndex: ${storedIndex}, storedPlayQueue: ${storedPlayQueue?.map((track, index) => index)}, track: ${storedTrack?.item.Id}`, ) if (!isUndefined(storedPlayQueue) && !isUndefined(storedIndex)) { diff --git a/src/providers/Player/functions/queue.ts b/src/providers/Player/functions/queue.ts index 5bcd8229..68fc62a8 100644 --- a/src/providers/Player/functions/queue.ts +++ b/src/providers/Player/functions/queue.ts @@ -15,6 +15,11 @@ type LoadQueueOperation = QueueMutation & { downloadedTracks: JellifyDownload[] | undefined } +type LoadQueueResult = { + finalStartIndex: number + tracks: JellifyTrack[] +} + export async function loadQueue({ index, tracklist, @@ -24,7 +29,7 @@ export async function loadQueue({ deviceProfile, networkStatus = networkStatusTypes.ONLINE, downloadedTracks, -}: LoadQueueOperation) { +}: LoadQueueOperation): Promise { setQueueRef(queueRef) setShuffled(shuffled) @@ -100,7 +105,10 @@ export async function loadQueue({ `Queued ${queue.length} tracks, starting at ${finalStartIndex}${shuffled ? ' (shuffled)' : ''}`, ) - return finalStartIndex + return { + finalStartIndex, + tracks: queue, + } } type PlayNextOperation = AddToQueueMutation & { diff --git a/src/providers/Player/hooks/mutations.ts b/src/providers/Player/hooks/mutations.ts index b63d91ea..571745a9 100644 --- a/src/providers/Player/hooks/mutations.ts +++ b/src/providers/Player/hooks/mutations.ts @@ -7,13 +7,7 @@ import { AddToQueueMutation, QueueMutation, QueueOrderMutation } from '../interf import { refetchNowPlaying, refetchPlayerQueue, invalidateRepeatMode } from '../functions/queries' import { QueuingType } from '../../../enums/queuing-type' import Toast from 'react-native-toast-message' -import { - getActiveIndex, - getPlayQueue, - setQueueRef, - setShuffled, - setUnshuffledQueue, -} from '../functions' +import { setQueueRef, setShuffled, setUnshuffledQueue } from '../functions' import { handleDeshuffle, handleShuffle } from '../functions/shuffle' import JellifyTrack from '@/src/types/JellifyTrack' import calculateTrackVolume from '../utils/normalization' @@ -25,6 +19,13 @@ import { RootStackParamList } from '../../../screens/types' import { useNavigation } from '@react-navigation/native' import { useAllDownloadedTracks } from '../../../api/queries/download' import useHapticFeedback from '../../../hooks/use-haptic-feedback' +import { queryClient } from '../../../constants/query-client' +import { QUEUE_QUERY } from '../constants/queries' +import { + ACTIVE_INDEX_QUERY_KEY, + NOW_PLAYING_QUERY_KEY, + PLAY_QUEUE_QUERY_KEY, +} from '../constants/query-keys' const PLAYER_MUTATION_OPTIONS = { retry: false, @@ -211,7 +212,7 @@ export const useLoadNewQueue = () => { await TrackPlayer.pause() }, mutationFn: (variables: QueueMutation) => loadQueue({ ...variables, downloadedTracks }), - onSuccess: async (finalStartIndex, { startPlayback }) => { + onSuccess: async ({ finalStartIndex, tracks }, { startPlayback }) => { console.debug('Successfully loaded new queue') if (isCasting && remoteClient) { await TrackPlayer.skip(finalStartIndex) @@ -222,6 +223,10 @@ export const useLoadNewQueue = () => { await TrackPlayer.skip(finalStartIndex) if (startPlayback) await TrackPlayer.play() + + queryClient.setQueryData(PLAY_QUEUE_QUERY_KEY, tracks) + queryClient.setQueryData(ACTIVE_INDEX_QUERY_KEY, finalStartIndex) + queryClient.setQueryData(NOW_PLAYING_QUERY_KEY, tracks[finalStartIndex]) }, onError: async (error: Error) => { trigger('notificationError') diff --git a/src/screens/Tabs/index.tsx b/src/screens/Tabs/index.tsx index a6736559..1675b192 100644 --- a/src/screens/Tabs/index.tsx +++ b/src/screens/Tabs/index.tsx @@ -33,8 +33,12 @@ export default function Tabs({ route, navigation }: TabProps): React.JSX.Element options={{ title: 'Home', headerShown: false, - tabBarIcon: ({ color, size }) => ( - + tabBarIcon: ({ color, size, focused }) => ( + ), tabBarButtonTestID: 'home-tab-button', }} @@ -46,8 +50,12 @@ export default function Tabs({ route, navigation }: TabProps): React.JSX.Element options={{ title: 'Library', headerShown: false, - tabBarIcon: ({ color, size }) => ( - + tabBarIcon: ({ color, size, focused }) => ( + ), tabBarButtonTestID: 'library-tab-button', }} @@ -72,8 +80,12 @@ export default function Tabs({ route, navigation }: TabProps): React.JSX.Element options={{ title: 'Discover', headerShown: false, - tabBarIcon: ({ color, size }) => ( - + tabBarIcon: ({ color, size, focused }) => ( + ), tabBarButtonTestID: 'discover-tab-button', }} @@ -86,7 +98,7 @@ export default function Tabs({ route, navigation }: TabProps): React.JSX.Element title: 'Settings', headerShown: false, tabBarIcon: ({ color, size }) => ( - + ), tabBarButtonTestID: 'settings-tab-button', }} diff --git a/yarn.lock b/yarn.lock index 43b3044f..9849953e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3394,39 +3394,39 @@ resolved "https://registry.yarnpkg.com/@tamagui/z-index-stack/-/z-index-stack-1.132.23.tgz#a74f06f3b6a6191951f396105f39a10aec0144aa" integrity sha512-djbRW7FWzuc9bCIVXG00pVa6McM8/H8R4JOL+szxSy1iAo0P2k0OzWfBb+ZbbjTye068fBPGIniq4X7+3huS1Q== -"@tanstack/query-async-storage-persister@^5.87.1": - version "5.87.1" - resolved "https://registry.yarnpkg.com/@tanstack/query-async-storage-persister/-/query-async-storage-persister-5.87.1.tgz#2483b6fa846036b65de3bec3d629e1c2ef65758e" - integrity sha512-ASIo9Jv+Tqv80Itadoda9vByD2ODotraaAgY1gB1lCeJQP7lT7Tf8G3od3TW9+0x/x90FqMZvehMJG3RisdzKg== +"@tanstack/query-async-storage-persister@^5.87.4": + version "5.87.4" + resolved "https://registry.yarnpkg.com/@tanstack/query-async-storage-persister/-/query-async-storage-persister-5.87.4.tgz#f4d4255b56ab7305a73b21ec376347446ae1561a" + integrity sha512-O12m5zSpNsMj6RT+Oy5T3JkUZSGhMcd6l6NUOlP6OWVrTvz5rro2f5PQKFo9zjXRnu/lK5lOfr3YY+MApF6png== dependencies: - "@tanstack/query-core" "5.87.1" - "@tanstack/query-persist-client-core" "5.87.1" + "@tanstack/query-core" "5.87.4" + "@tanstack/query-persist-client-core" "5.87.4" -"@tanstack/query-core@5.87.1": - version "5.87.1" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.87.1.tgz#9b8b9331714749d505a7ceb0ae52b6ad6ae8a461" - integrity sha512-HOFHVvhOCprrWvtccSzc7+RNqpnLlZ5R6lTmngb8aq7b4rc2/jDT0w+vLdQ4lD9bNtQ+/A4GsFXy030Gk4ollA== +"@tanstack/query-core@5.87.4": + version "5.87.4" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.87.4.tgz#1601d05ee5bf611328f2852cec763ed0c9a090cd" + integrity sha512-uNsg6zMxraEPDVO2Bn+F3/ctHi+Zsk+MMpcN8h6P7ozqD088F6mFY5TfGM7zuyIrL7HKpDyu6QHfLWiDxh3cuw== -"@tanstack/query-persist-client-core@5.87.1": - version "5.87.1" - resolved "https://registry.yarnpkg.com/@tanstack/query-persist-client-core/-/query-persist-client-core-5.87.1.tgz#97b987d854e3e1ceeb1c8d2994ca887799baf9a0" - integrity sha512-NL3YiHNxyz49N1+97ppKxgMtk8zITxa15Edu8a07w7XLgT/xH1lz5wzElJCGeNbe84rvdbp0/4XKwSiS9rAL9Q== +"@tanstack/query-persist-client-core@5.87.4": + version "5.87.4" + resolved "https://registry.yarnpkg.com/@tanstack/query-persist-client-core/-/query-persist-client-core-5.87.4.tgz#d44ed6220ee232db87d02164302ff41edd0415c1" + integrity sha512-71jHVxFvRBjPfiLQ4cJ71sRICCf989s+wCdynmwvAJqW6NgWx7GkdhQC1F7tXb56ZlcK19kQPPa5X2EPqP94wA== dependencies: - "@tanstack/query-core" "5.87.1" + "@tanstack/query-core" "5.87.4" -"@tanstack/react-query-persist-client@^5.87.1": - version "5.87.1" - resolved "https://registry.yarnpkg.com/@tanstack/react-query-persist-client/-/react-query-persist-client-5.87.1.tgz#206dccb3a684f2d0fe1d1c2a5996d935e96a9ffc" - integrity sha512-S3nJD31YRdv0q0n/IYY9pdeIPkEx319ygHSpDieeTbTFuYxn2b6LMUCNZhPw96ZYi182uwH53Z3KGcTGnWjzYQ== +"@tanstack/react-query-persist-client@^5.87.4": + version "5.87.4" + resolved "https://registry.yarnpkg.com/@tanstack/react-query-persist-client/-/react-query-persist-client-5.87.4.tgz#16ac7c66118d580f3de3a5052d618253cf7263ac" + integrity sha512-RFnkAfYJcQ8nEQUWx0rhcPVPdRmvHAYG+mJwcykiJKVHaFeCuiHaEoW3KseGTBZcliV//UjI07bplAaT2ElR8g== dependencies: - "@tanstack/query-persist-client-core" "5.87.1" + "@tanstack/query-persist-client-core" "5.87.4" -"@tanstack/react-query@^5.87.1": - version "5.87.1" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.87.1.tgz#074bd2238173f49ef8804a9b6d94f63374828a78" - integrity sha512-YKauf8jfMowgAqcxj96AHs+Ux3m3bWT1oSVKamaRPXSnW2HqSznnTCEkAVqctF1e/W9R/mPcyzzINIgpOH94qg== +"@tanstack/react-query@^5.87.4": + version "5.87.4" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.87.4.tgz#f0b0af38ffab642e8999c156e986dfc384662fe6" + integrity sha512-T5GT/1ZaNsUXf5I3RhcYuT17I4CPlbZgyLxc/ZGv7ciS6esytlbjb3DgUFO6c8JWYMDpdjSWInyGZUErgzqhcA== dependencies: - "@tanstack/query-core" "5.87.1" + "@tanstack/query-core" "5.87.4" "@telemetrydeck/sdk@^2.0.4": version "2.0.4"