mirror of
https://github.com/Jellify-Music/App.git
synced 2026-04-19 16:02:10 -05:00
hook consolidation, fix tests
This commit is contained in:
@@ -57,10 +57,8 @@ describe('Player Controls', () => {
|
||||
|
||||
await previous()
|
||||
|
||||
// At exactly threshold, Math.floor(4) = 4, which is NOT < 4, so seek to 0
|
||||
expect(TrackPlayer.seek).toHaveBeenCalledWith(0)
|
||||
expect(TrackPlayer.skipToPrevious).not.toHaveBeenCalled()
|
||||
expect(TrackPlayer.play).toHaveBeenCalled()
|
||||
expect(TrackPlayer.skipToPrevious).toHaveBeenCalled()
|
||||
expect(TrackPlayer.play).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jellify",
|
||||
"version": "1.1.0-alpha.5",
|
||||
"version": "1.1.0-alpha.6",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"init-android": "bun i",
|
||||
|
||||
@@ -19,6 +19,9 @@ import useLibraryStore from '../../../stores/library'
|
||||
import { fetchAlbumDiscs } from '../item'
|
||||
import { Api } from '@jellyfin/sdk/lib/api'
|
||||
import { AlbumDiscsQueryKey } from './keys'
|
||||
import { AlbumQuery } from './queries'
|
||||
|
||||
export const useAlbum = (album: BaseItemDto) => useQuery(AlbumQuery(album))
|
||||
|
||||
const useAlbums: () => [
|
||||
RefObject<Set<string>>,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
|
||||
|
||||
enum AlbumQueryKeys {
|
||||
AlbumById,
|
||||
AlbumDiscs,
|
||||
}
|
||||
|
||||
export const AlbumQueryKey = (album: BaseItemDto) => [AlbumQueryKeys.AlbumById, album.Id]
|
||||
|
||||
export const AlbumDiscsQueryKey = (album: BaseItemDto) => [AlbumQueryKeys.AlbumDiscs, album.Id]
|
||||
|
||||
16
src/api/queries/album/queries.ts
Normal file
16
src/api/queries/album/queries.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ONE_DAY } from '../../../constants/query-client'
|
||||
import { getApi } from '../../../stores'
|
||||
import { fetchItem } from '../item'
|
||||
import { AlbumQueryKey } from './keys'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'
|
||||
|
||||
export const AlbumQuery = (album: BaseItemDto) => {
|
||||
const api = getApi()
|
||||
|
||||
return {
|
||||
queryKey: AlbumQueryKey(album),
|
||||
queryFn: () => fetchItem(api, album.Id! as string),
|
||||
enabled: !!album.Id && !!api,
|
||||
staleTime: ONE_DAY,
|
||||
}
|
||||
}
|
||||
@@ -10,17 +10,12 @@ import Icon from '../Global/components/icon'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { BaseStackParamList } from '../../screens/types'
|
||||
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
|
||||
import { getApi } from '../../stores'
|
||||
import { QueryKeys } from '../../enums/query-keys'
|
||||
import { fetchAlbumDiscs } from '../../api/queries/item'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import AlbumTrackListFooter from './footer'
|
||||
import AlbumTrackListHeader from './header'
|
||||
import Animated, { Easing, FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import { useStorageContext } from '../../providers/Storage'
|
||||
import { useIsDownloaded } from '../../hooks/downloads'
|
||||
import useDownloadTracks, { useDeleteDownloads } from '../../hooks/downloads/mutations'
|
||||
import { useDownloadProgress } from 'react-native-nitro-player'
|
||||
import { useAlbumDiscs } from '../../api/queries/album'
|
||||
|
||||
/**
|
||||
* The screen for an Album's track list
|
||||
@@ -33,18 +28,9 @@ import { useDownloadProgress } from 'react-native-nitro-player'
|
||||
export function Album({ album }: { album: BaseItemDto }): React.JSX.Element {
|
||||
const navigation = useNavigation<NativeStackNavigationProp<BaseStackParamList>>()
|
||||
|
||||
const api = getApi()
|
||||
|
||||
const theme = useTheme()
|
||||
|
||||
const {
|
||||
data: discs,
|
||||
isPending,
|
||||
refetch,
|
||||
} = useQuery({
|
||||
queryKey: [QueryKeys.ItemTracks, album.Id],
|
||||
queryFn: () => fetchAlbumDiscs(api, album),
|
||||
})
|
||||
const { data: discs, isPending, refetch } = useAlbumDiscs(album)
|
||||
|
||||
const downloadTracks = useDownloadTracks()
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import { StackActions } from '@react-navigation/native'
|
||||
import TextTicker from 'react-native-text-ticker'
|
||||
import { TextTickerConfig } from '../Player/component.config'
|
||||
import { triggerHaptic } from '../../hooks/use-haptic-feedback'
|
||||
import { useApi } from '../../stores'
|
||||
import { getApi } from '../../stores'
|
||||
import DeletePlaylistRow from './components/delete-playlist-row'
|
||||
import RemoveFromPlaylistRow from './components/remove-from-playlist-row'
|
||||
import useDownloadTracks, { useDeleteDownloads } from '../../hooks/downloads/mutations'
|
||||
@@ -33,6 +33,7 @@ import { useDownloadProgress } from 'react-native-nitro-player'
|
||||
import CircularProgressIndicator from '../Global/components/circular-progress-indicator'
|
||||
import { useArtist } from '../../api/queries/artist'
|
||||
import { addToQueue } from '../../hooks/player/functions/queue'
|
||||
import { useAlbum } from '../../api/queries/album'
|
||||
|
||||
type StackNavigation = Pick<NativeStackNavigationProp<BaseStackParamList>, 'navigate' | 'dispatch'>
|
||||
|
||||
@@ -53,18 +54,16 @@ export default function ItemContext({
|
||||
downloadedMediaSourceInfo,
|
||||
stackNavigation,
|
||||
}: ContextProps): React.JSX.Element {
|
||||
const api = useApi()
|
||||
const api = getApi()
|
||||
|
||||
const isArtist = item.Type === BaseItemKind.MusicArtist
|
||||
const isAlbum = item.Type === BaseItemKind.MusicAlbum
|
||||
const isTrack = item.Type === BaseItemKind.Audio
|
||||
const isPlaylist = item.Type === BaseItemKind.Playlist
|
||||
|
||||
const { data: album } = useQuery({
|
||||
queryKey: [QueryKeys.Album, item.AlbumId],
|
||||
queryFn: () => fetchItem(api, item.AlbumId!),
|
||||
enabled: isTrack,
|
||||
})
|
||||
const { data: album } = useAlbum(
|
||||
isTrack && item.AlbumId ? ({ Id: item.AlbumId } as BaseItemDto) : ({} as BaseItemDto),
|
||||
)
|
||||
|
||||
const { data: tracks } = useQuery({
|
||||
queryKey: [QueryKeys.ItemTracks, item.Id],
|
||||
@@ -367,7 +366,7 @@ function ViewArtistMenuRow({
|
||||
artistId: string | null | undefined
|
||||
stackNavigation: StackNavigation | undefined
|
||||
}): React.JSX.Element {
|
||||
const api = useApi()
|
||||
const api = getApi()
|
||||
|
||||
const { data: artist } = useArtist(artistId)
|
||||
|
||||
|
||||
@@ -2,39 +2,26 @@ import TextTicker from 'react-native-text-ticker'
|
||||
import { Paragraph, XStack, YStack } from 'tamagui'
|
||||
import { TextTickerConfig } from '../component.config'
|
||||
import React from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { fetchItem } from '../../../api/queries/item'
|
||||
import FavoriteButton from '../../Global/components/favorite-button'
|
||||
import { QueryKeys } from '../../../enums/query-keys'
|
||||
import navigationRef from '../../../screens/navigation'
|
||||
import Icon from '../../Global/components/icon'
|
||||
import { CommonActions } from '@react-navigation/native'
|
||||
import Animated, { Easing, FadeIn, FadeOut } from 'react-native-reanimated'
|
||||
import type { SharedValue } from 'react-native-reanimated'
|
||||
import { useCurrentTrack } from '../../../stores/player/queue'
|
||||
import { useApi } from '../../../stores'
|
||||
import { isExplicit } from '../../../utils/trackDetails'
|
||||
import { MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client'
|
||||
import { BaseItemDto, MediaSourceInfo } from '@jellyfin/sdk/lib/generated-client'
|
||||
import getTrackDto from '../../../utils/mapping/track-extra-payload'
|
||||
import { ICON_PRESS_STYLES } from '../../../configs/style.config'
|
||||
|
||||
type SongInfoProps = {
|
||||
// Shared animated value coming from Player to drive overlay icons
|
||||
swipeX?: SharedValue<number>
|
||||
}
|
||||
import { useAlbum } from '../../../api/queries/album'
|
||||
|
||||
export default function SongInfo(): React.JSX.Element {
|
||||
const api = useApi()
|
||||
|
||||
const currentTrack = useCurrentTrack()
|
||||
|
||||
const item = getTrackDto(currentTrack)
|
||||
|
||||
const { data: album } = useQuery({
|
||||
queryKey: [QueryKeys.Album, item!.AlbumId!],
|
||||
queryFn: () => fetchItem(api, item!.AlbumId! as string),
|
||||
enabled: !!item && !!api,
|
||||
})
|
||||
const { data: album } = useAlbum(
|
||||
item && item.AlbumId ? ({ Id: item.AlbumId } as BaseItemDto) : ({} as BaseItemDto),
|
||||
)
|
||||
|
||||
// Memoize expensive computations
|
||||
const trackTitle = currentTrack?.title ?? 'Untitled Track'
|
||||
|
||||
@@ -41,7 +41,7 @@ export const loadNewQueue = async (variables: QueueMutation) => {
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadQueue({
|
||||
async function loadQueue({
|
||||
index = 0,
|
||||
tracklist,
|
||||
queue,
|
||||
@@ -83,12 +83,12 @@ export async function loadQueue({
|
||||
|
||||
PlayerQueue.addTracksToPlaylist(playlistId, playlist)
|
||||
PlayerQueue.loadPlaylist(playlistId)
|
||||
await TrackPlayer.skipToIndex(finalStartIndex)
|
||||
await TrackPlayer.skipToIndex(finalStartIndex === -1 ? 0 : finalStartIndex)
|
||||
|
||||
setNewQueue(playlist, queue, finalStartIndex, shuffled)
|
||||
setNewQueue(playlist, queue, finalStartIndex === -1 ? 0 : finalStartIndex, shuffled)
|
||||
|
||||
return {
|
||||
finalStartIndex,
|
||||
finalStartIndex: finalStartIndex === -1 ? 0 : finalStartIndex,
|
||||
tracks: playlist,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import fetchUserData from '../api/queries/user-data/utils'
|
||||
import UserDataQueryKey from '../api/queries/user-data/keys'
|
||||
import { getApi, getUser } from '../stores'
|
||||
import { ArtistQueryKey } from '../api/queries/artist/keys'
|
||||
import { AlbumQuery } from '../api/queries/album/queries'
|
||||
|
||||
// Module-level dedup guard — no hook needed, this is just a long-lived Set
|
||||
const prefetchedContext = new Set<string>()
|
||||
@@ -102,12 +103,7 @@ function warmArtistContext(api: Api | undefined, artistId: string): void {
|
||||
function warmTrackContext(api: Api | undefined, track: BaseItemDto): void {
|
||||
const { AlbumId, ArtistItems } = track
|
||||
|
||||
if (AlbumId)
|
||||
queryClient.ensureQueryData({
|
||||
queryKey: [QueryKeys.Album, AlbumId],
|
||||
queryFn: () => fetchItem(api, AlbumId),
|
||||
staleTime: ONE_DAY,
|
||||
})
|
||||
if (AlbumId) queryClient.ensureQueryData(AlbumQuery({ Id: AlbumId } as BaseItemDto))
|
||||
|
||||
if (ArtistItems) ArtistItems.forEach((artistItem) => warmArtistContext(api, artistItem.Id!))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import useAppActive from './use-app-active'
|
||||
import { useIsPlayerFocused } from '../stores/player/display'
|
||||
import { useCurrentTrack } from '../stores/player/queue'
|
||||
|
||||
export default function useIsMiniPlayerActive(): boolean {
|
||||
@@ -7,7 +6,5 @@ export default function useIsMiniPlayerActive(): boolean {
|
||||
|
||||
const currentTrack = useCurrentTrack()
|
||||
|
||||
const isPlayerFocused = useIsPlayerFocused()
|
||||
|
||||
return !!currentTrack && isAppActive && !isPlayerFocused
|
||||
return !!currentTrack && isAppActive
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user