mirror of
https://github.com/anultravioletaurora/Jellify.git
synced 2026-01-05 21:30:53 -06:00
context sheet prefetching
player style fixes
This commit is contained in:
@@ -12,7 +12,7 @@ import Icon from '../Global/components/icon'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { QueryKeys } from '../../enums/query-keys'
|
||||
import { fetchItem, fetchItems } from '../../api/queries/item'
|
||||
import { fetchAlbumDiscs, fetchItem, fetchItems } from '../../api/queries/item'
|
||||
import { useJellifyContext } from '../../providers'
|
||||
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api'
|
||||
import { useAddToQueueContext } from '../../providers/Player/queue'
|
||||
@@ -38,20 +38,10 @@ interface ContextProps {
|
||||
}
|
||||
|
||||
export default function ItemContext({ item, stackNavigation }: ContextProps): React.JSX.Element {
|
||||
const { api, user, library } = useJellifyContext()
|
||||
const { api } = useJellifyContext()
|
||||
|
||||
const { bottom } = useSafeAreaInsets()
|
||||
|
||||
const bottomMargin = useMemo(() => {
|
||||
const isAndroid = Platform.OS === 'android'
|
||||
|
||||
let finalMargin = bottom
|
||||
|
||||
if (isAndroid) finalMargin += getTokenValue('$12')
|
||||
|
||||
return finalMargin
|
||||
}, [bottom])
|
||||
|
||||
const isArtist = item.Type === BaseItemKind.MusicArtist
|
||||
const isAlbum = item.Type === BaseItemKind.MusicAlbum
|
||||
const isTrack = item.Type === BaseItemKind.Audio
|
||||
@@ -74,6 +64,13 @@ export default function ItemContext({ item, stackNavigation }: ContextProps): Re
|
||||
if (data.Items) return data.Items
|
||||
else return []
|
||||
}),
|
||||
enabled: isPlaylist,
|
||||
})
|
||||
|
||||
const { data: discs } = useQuery({
|
||||
queryKey: [QueryKeys.ItemTracks, item.Id],
|
||||
queryFn: () => fetchAlbumDiscs(api, item),
|
||||
enabled: isAlbum,
|
||||
})
|
||||
|
||||
const renderAddToQueueRow = isTrack || (isAlbum && tracks) || (isPlaylist && tracks)
|
||||
@@ -84,10 +81,22 @@ export default function ItemContext({ item, stackNavigation }: ContextProps): Re
|
||||
|
||||
return (
|
||||
<ScrollView>
|
||||
<YGroup unstyled marginBottom={bottomMargin}>
|
||||
<YGroup unstyled marginBottom={bottom}>
|
||||
<FavoriteContextMenuRow item={item} />
|
||||
|
||||
{renderAddToQueueRow && <AddToQueueMenuRow tracks={isTrack ? [item] : tracks!} />}
|
||||
{renderAddToQueueRow && (
|
||||
<AddToQueueMenuRow
|
||||
tracks={
|
||||
isTrack
|
||||
? [item]
|
||||
: isAlbum && discs
|
||||
? discs.flatMap((data) => data.data)
|
||||
: isPlaylist && tracks
|
||||
? tracks
|
||||
: []
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
{renderAddToPlaylistRow && <AddToPlaylistRow track={item} />}
|
||||
|
||||
@@ -100,7 +109,7 @@ export default function ItemContext({ item, stackNavigation }: ContextProps): Re
|
||||
|
||||
{!isPlaylist && (
|
||||
<ViewArtistMenuRow
|
||||
artists={isArtist ? [item] : item.ArtistItems ? item.ArtistItems : []}
|
||||
artists={isArtist ? [item] : itemArtists}
|
||||
stackNavigation={stackNavigation}
|
||||
/>
|
||||
)}
|
||||
@@ -109,29 +118,6 @@ export default function ItemContext({ item, stackNavigation }: ContextProps): Re
|
||||
)
|
||||
}
|
||||
|
||||
function ItemContextBackground({ item }: { item: BaseItemDto }): React.JSX.Element {
|
||||
return (
|
||||
<ZStack flex={1}>
|
||||
<BackgroundBlur item={item} />
|
||||
|
||||
<BackgroundGradient />
|
||||
</ZStack>
|
||||
)
|
||||
}
|
||||
|
||||
function BackgroundBlur({ item }: { item: BaseItemDto }): React.JSX.Element {
|
||||
const blurhash = getPrimaryBlurhashFromDto(item)
|
||||
|
||||
return (
|
||||
<Blurhash
|
||||
blurhash={blurhash!}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function AddToPlaylistRow({ track }: { track: BaseItemDto }): React.JSX.Element {
|
||||
return (
|
||||
<ListItem
|
||||
|
||||
@@ -85,7 +85,7 @@ function getBorderRadius(circular: boolean | undefined, width: Token | number |
|
||||
} else if (!isUndefined(width)) {
|
||||
borderRadius =
|
||||
typeof width === 'number'
|
||||
? width / 6
|
||||
? width / 25
|
||||
: getTokenValue(width) / (getTokenValue(width) / 6)
|
||||
} else borderRadius = '5%'
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { QueryKeys } from '../../../enums/query-keys'
|
||||
import { getQualityParams } from '../../../utils/mappings'
|
||||
import { useStreamingQualityContext } from '../../../providers/Settings'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { fetchItem } from '../../../api/queries/item'
|
||||
import { fetchAlbumDiscs, fetchItem } from '../../../api/queries/item'
|
||||
|
||||
interface CardProps extends TamaguiCardProps {
|
||||
caption?: string | null | undefined
|
||||
@@ -36,15 +36,36 @@ export function ItemCard(props: CardProps) {
|
||||
queryKey: [QueryKeys.MediaSources, streamingQuality, props.item.Id],
|
||||
queryFn: () => fetchMediaInfo(api, user, getQualityParams(streamingQuality), props.item),
|
||||
staleTime: Infinity, // Don't refetch media info unless the user changes the quality
|
||||
enabled: props.item.Type === 'Audio',
|
||||
enabled: props.item.Type === BaseItemKind.Audio,
|
||||
})
|
||||
|
||||
/**
|
||||
* Fire query for a track's album
|
||||
*
|
||||
* Referenced later in the context sheet
|
||||
*/
|
||||
useQuery({
|
||||
queryKey: [QueryKeys.Album, props.item.AlbumId],
|
||||
queryFn: () => fetchItem(api, props.item.AlbumId!),
|
||||
enabled: props.item.Type === BaseItemKind.Audio && !!props.item.AlbumId,
|
||||
})
|
||||
|
||||
/**
|
||||
* Fire query for an album's tracks
|
||||
*
|
||||
* Referenced later in the context sheet
|
||||
*/
|
||||
useQuery({
|
||||
queryKey: [QueryKeys.ItemTracks, props.item.Id],
|
||||
queryFn: () => fetchAlbumDiscs(api, props.item),
|
||||
enabled: !!props.item.Id && props.item.Type === BaseItemKind.MusicAlbum,
|
||||
})
|
||||
|
||||
/**
|
||||
* Fire query for an playlist's tracks
|
||||
*
|
||||
* Referenced later in the context sheet
|
||||
*/
|
||||
useQuery({
|
||||
queryKey: [QueryKeys.ItemTracks, props.item.Id],
|
||||
queryFn: () =>
|
||||
@@ -54,7 +75,7 @@ export function ItemCard(props: CardProps) {
|
||||
if (data.Items) return data.Items
|
||||
else return []
|
||||
}),
|
||||
enabled: !!props.item.Id && props.item.Type === BaseItemKind.MusicAlbum,
|
||||
enabled: !!props.item.Id && props.item.Type === BaseItemKind.Playlist,
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
@@ -18,7 +18,7 @@ import { useStreamingQualityContext } from '../../../providers/Settings'
|
||||
import navigationRef from '../../../../navigation'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { BaseStackParamList } from '../../../screens/types'
|
||||
import { fetchItem } from '../../../api/queries/item'
|
||||
import { fetchAlbumDiscs, fetchItem } from '../../../api/queries/item'
|
||||
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api'
|
||||
|
||||
interface ItemRowProps {
|
||||
@@ -79,6 +79,17 @@ export default function ItemRow({
|
||||
*
|
||||
* Referenced later in the context sheet
|
||||
*/
|
||||
useQuery({
|
||||
queryKey: [QueryKeys.ItemTracks, item.Id],
|
||||
queryFn: () => fetchAlbumDiscs(api, item),
|
||||
enabled: !!item.Id && item.Type === BaseItemKind.MusicAlbum,
|
||||
})
|
||||
|
||||
/**
|
||||
* Fire query for an playlist's tracks
|
||||
*
|
||||
* Referenced later in the context sheet
|
||||
*/
|
||||
useQuery({
|
||||
queryKey: [QueryKeys.ItemTracks, item.Id],
|
||||
queryFn: () =>
|
||||
@@ -88,7 +99,7 @@ export default function ItemRow({
|
||||
if (data.Items) return data.Items
|
||||
else return []
|
||||
}),
|
||||
enabled: !!item.Id && item.Type === BaseItemKind.MusicAlbum,
|
||||
enabled: !!item.Id && item.Type === BaseItemKind.Playlist,
|
||||
})
|
||||
|
||||
const gestureCallback = () => {
|
||||
|
||||
@@ -129,7 +129,7 @@ export default function Track({
|
||||
item: track,
|
||||
})
|
||||
}
|
||||
}, [onLongPress, navigation, track, isNested])
|
||||
}, [onLongPress, track, isNested])
|
||||
|
||||
const handleIconPress = useCallback(() => {
|
||||
if (showRemove) {
|
||||
@@ -139,7 +139,7 @@ export default function Track({
|
||||
item: track,
|
||||
})
|
||||
}
|
||||
}, [showRemove, onRemove, navigation, track, isNested])
|
||||
}, [showRemove, onRemove, track, isNested])
|
||||
|
||||
// Only fetch media info if needed (for streaming)
|
||||
useQuery({
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { InstantMixProps } from '../../screens/types'
|
||||
import { FlatList } from 'react-native'
|
||||
import Track from '../Global/components/track'
|
||||
import { Separator } from 'tamagui'
|
||||
import { FlashList } from '@shopify/flash-list'
|
||||
|
||||
export default function InstantMix({ route, navigation }: InstantMixProps): React.JSX.Element {
|
||||
const { mix } = route.params
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
<FlashList
|
||||
contentInsetAdjustmentBehavior='automatic'
|
||||
data={mix}
|
||||
ItemSeparatorComponent={() => <Separator />}
|
||||
renderItem={({ item, index }) => (
|
||||
<Track
|
||||
navigation={navigation}
|
||||
showArtwork
|
||||
track={item}
|
||||
index={index}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useNowPlayingContext } from '../../../providers/Player'
|
||||
import { useQueueRefContext } from '../../../providers/Player/queue'
|
||||
import { XStack, YStack, Spacer, useTheme, getTokenValue, TamaguiElement } from 'tamagui'
|
||||
import { XStack, YStack, Spacer, useTheme, getTokenValue } from 'tamagui'
|
||||
import { Text } from '../../Global/helpers/text'
|
||||
import React, { useMemo, useRef } from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import ItemImage from '../../Global/components/image'
|
||||
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'
|
||||
import { Platform } from 'react-native'
|
||||
import { useSafeAreaFrame } from 'react-native-safe-area-context'
|
||||
import MaterialDesignIcons from '@react-native-vector-icons/material-design-icons'
|
||||
import navigationRef from '../../../../navigation'
|
||||
|
||||
export default function PlayerHeader(): React.JSX.Element {
|
||||
const imageBounds = getTokenValue('$20') * 2
|
||||
@@ -26,7 +26,12 @@ export default function PlayerHeader(): React.JSX.Element {
|
||||
|
||||
return (
|
||||
<YStack flexGrow={1} justifyContent='flex-start' maxHeight={'80%'}>
|
||||
<XStack flexShrink={1} alignContent='flex-start' justifyContent='center'>
|
||||
<XStack
|
||||
alignContent='flex-start'
|
||||
flexShrink={1}
|
||||
justifyContent='center'
|
||||
onPress={() => navigationRef.goBack()}
|
||||
>
|
||||
<MaterialDesignIcons
|
||||
color={theme.color.val}
|
||||
name={Platform.OS === 'android' ? 'chevron-left' : 'chevron-down'}
|
||||
@@ -44,23 +49,18 @@ export default function PlayerHeader(): React.JSX.Element {
|
||||
<Spacer flex={1} />
|
||||
</XStack>
|
||||
|
||||
<YStack
|
||||
flexGrow={1}
|
||||
marginVertical={'auto'}
|
||||
maxHeight={'65%'}
|
||||
paddingVertical={Platform.OS === 'android' ? '$2' : undefined}
|
||||
paddingHorizontal={Platform.OS === 'ios' ? '$3' : '$2'}
|
||||
maxWidth={'100%'}
|
||||
>
|
||||
<YStack flexGrow={1} justifyContent='center'>
|
||||
<Animated.View
|
||||
entering={FadeIn}
|
||||
exiting={FadeOut}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
key={`${nowPlaying!.item.AlbumId}-item-image`}
|
||||
>
|
||||
<ItemImage item={nowPlaying!.item} testID='player-image-test-id' />
|
||||
<ItemImage
|
||||
item={nowPlaying!.item}
|
||||
testID='player-image-test-id'
|
||||
width={360}
|
||||
height={360}
|
||||
/>
|
||||
</Animated.View>
|
||||
</YStack>
|
||||
</YStack>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack'
|
||||
import { BaseStackParamList } from '../types'
|
||||
import { Queue } from '../../player/types/queue-item'
|
||||
import { NavigatorScreenParams } from '@react-navigation/native'
|
||||
|
||||
type LibraryStackParamList = BaseStackParamList & {
|
||||
|
||||
Reference in New Issue
Block a user