home screen animation and indicator improvements

This commit is contained in:
Violet Caulfield
2025-12-02 01:20:08 -06:00
parent e088249014
commit 0f8a9e91c5
5 changed files with 119 additions and 78 deletions

View File

@@ -2,7 +2,7 @@ import HorizontalCardList from '../../../components/Global/components/horizontal
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import React, { useCallback } from 'react'
import { ItemCard } from '../../../components/Global/components/item-card'
import { H5, View, XStack } from 'tamagui'
import { H5, XStack } from 'tamagui'
import Icon from '../../Global/components/icon'
import { useDisplayContext } from '../../../providers/Display/display-provider'
import { useNavigation } from '@react-navigation/native'
@@ -11,6 +11,7 @@ import { RootStackParamList } from '../../../screens/types'
import { useFrequentlyPlayedArtists } from '../../../api/queries/frequents'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
import { pickFirstGenre } from '../../../utils/genre-formatting'
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
export default function FrequentArtists(): React.JSX.Element {
const navigation = useNavigation<NativeStackNavigationProp<HomeStackParamList>>()
@@ -42,8 +43,15 @@ export default function FrequentArtists(): React.JSX.Element {
[],
)
return (
<View>
return frequentArtistsInfiniteQuery.data ? (
<Animated.View
entering={FadeIn}
exiting={FadeOut}
layout={LinearTransition.springify()}
style={{
flex: 1,
}}
>
<XStack
alignItems='center'
onPress={() => {
@@ -57,9 +65,11 @@ export default function FrequentArtists(): React.JSX.Element {
</XStack>
<HorizontalCardList
data={frequentArtistsInfiniteQuery.data?.slice(0, horizontalItems) ?? []}
data={frequentArtistsInfiniteQuery.data.slice(0, horizontalItems) ?? []}
renderItem={renderItem}
/>
</View>
</Animated.View>
) : (
<></>
)
}

View File

@@ -1,5 +1,5 @@
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
import { H5, View, XStack } from 'tamagui'
import { H5, XStack } from 'tamagui'
import HorizontalCardList from '../../../components/Global/components/horizontal-list'
import { ItemCard } from '../../../components/Global/components/item-card'
import { QueuingType } from '../../../enums/queuing-type'
@@ -13,6 +13,7 @@ import { useNetworkStatus } from '../../../stores/network'
import useStreamingDeviceProfile from '../../../stores/device-profile'
import { useFrequentlyPlayedTracks } from '../../../api/queries/frequents'
import { useApi } from '../../../stores'
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
export default function FrequentlyPlayedTracks(): React.JSX.Element {
const api = useApi()
@@ -30,8 +31,15 @@ export default function FrequentlyPlayedTracks(): React.JSX.Element {
const loadNewQueue = useLoadNewQueue()
const { horizontalItems } = useDisplayContext()
return (
<View>
return tracksInfiniteQuery.data ? (
<Animated.View
entering={FadeIn}
exiting={FadeOut}
layout={LinearTransition.springify()}
style={{
flex: 1,
}}
>
<XStack
alignItems='center'
onPress={() => {
@@ -46,8 +54,8 @@ export default function FrequentlyPlayedTracks(): React.JSX.Element {
<HorizontalCardList
data={
(tracksInfiniteQuery.data?.length ?? 0 > horizontalItems)
? tracksInfiniteQuery.data?.slice(0, horizontalItems)
tracksInfiniteQuery.data.length > horizontalItems
? tracksInfiniteQuery.data.slice(0, horizontalItems)
: tracksInfiniteQuery.data
}
renderItem={({ item: track, index }) => (
@@ -81,6 +89,8 @@ export default function FrequentlyPlayedTracks(): React.JSX.Element {
/>
)}
/>
</View>
</Animated.View>
) : (
<></>
)
}

View File

@@ -11,6 +11,7 @@ import HomeStackParamList from '../../../screens/Home/types'
import { useRecentArtists } from '../../../api/queries/recents'
import { pickFirstGenre } from '../../../utils/genre-formatting'
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
export default function RecentArtists(): React.JSX.Element {
const recentArtistsInfiniteQuery = useRecentArtists()
@@ -50,17 +51,26 @@ export default function RecentArtists(): React.JSX.Element {
[navigation, rootNavigation],
)
return (
<View>
return recentArtistsInfiniteQuery.data ? (
<Animated.View
entering={FadeIn}
exiting={FadeOut}
layout={LinearTransition.springify()}
style={{
flex: 1,
}}
>
<XStack alignItems='center' onPress={handleHeaderPress}>
<H5 marginLeft={'$2'}>Recent Artists</H5>
<Icon name='arrow-right' />
</XStack>
<HorizontalCardList
data={recentArtistsInfiniteQuery.data?.slice(0, horizontalItems) ?? []}
data={recentArtistsInfiniteQuery.data.slice(0, horizontalItems)}
renderItem={renderItem}
/>
</View>
</Animated.View>
) : (
<></>
)
}

View File

@@ -1,5 +1,5 @@
import React, { useMemo } from 'react'
import { H5, View, XStack } from 'tamagui'
import React from 'react'
import { H5, XStack } from 'tamagui'
import { ItemCard } from '../../Global/components/item-card'
import { RootStackParamList } from '../../../screens/types'
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
@@ -13,8 +13,8 @@ import HomeStackParamList from '../../../screens/Home/types'
import { useNetworkStatus } from '../../../stores/network'
import useStreamingDeviceProfile from '../../../stores/device-profile'
import { useRecentlyPlayedTracks } from '../../../api/queries/recents'
import { useCurrentTrack } from '../../../stores/player/queue'
import { useApi } from '../../../stores'
import Animated, { FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
export default function RecentlyPlayed(): React.JSX.Element {
const api = useApi()
@@ -23,8 +23,6 @@ export default function RecentlyPlayed(): React.JSX.Element {
const deviceProfile = useStreamingDeviceProfile()
const nowPlaying = useCurrentTrack()
const navigation = useNavigation<NativeStackNavigationProp<HomeStackParamList>>()
const rootNavigation = useNavigation<NativeStackNavigationProp<RootStackParamList>>()
@@ -33,60 +31,68 @@ export default function RecentlyPlayed(): React.JSX.Element {
const tracksInfiniteQuery = useRecentlyPlayedTracks()
const { horizontalItems } = useDisplayContext()
return useMemo(() => {
return (
<View>
<XStack
alignItems='center'
onPress={() => {
navigation.navigate('RecentTracks', {
tracksInfiniteQuery,
})
}}
>
<H5 marginLeft={'$2'}>Play it again</H5>
<Icon name='arrow-right' />
</XStack>
<HorizontalCardList
data={
(tracksInfiniteQuery.data?.length ?? 0 > horizontalItems)
? tracksInfiniteQuery.data?.slice(0, horizontalItems)
: tracksInfiniteQuery.data
}
renderItem={({ index, item: recentlyPlayedTrack }) => (
<ItemCard
size={'$11'}
caption={recentlyPlayedTrack.Name}
subCaption={`${recentlyPlayedTrack.Artists?.join(', ')}`}
squared
testId={`recently-played-${index}`}
item={recentlyPlayedTrack}
onPress={() => {
loadNewQueue({
api,
deviceProfile,
networkStatus,
track: recentlyPlayedTrack,
index: index,
tracklist: tracksInfiniteQuery.data ?? [recentlyPlayedTrack],
queue: 'Recently Played',
queuingType: QueuingType.FromSelection,
startPlayback: true,
})
}}
onLongPress={() => {
rootNavigation.navigate('Context', {
item: recentlyPlayedTrack,
navigation,
})
}}
marginHorizontal={'$1'}
captionAlign='left'
/>
)}
/>
</View>
)
}, [tracksInfiniteQuery.data, nowPlaying])
return tracksInfiniteQuery.data ? (
<Animated.View
entering={FadeIn}
exiting={FadeOut}
layout={LinearTransition.springify()}
style={{
flex: 1,
}}
>
<XStack
alignItems='center'
onPress={() => {
navigation.navigate('RecentTracks', {
tracksInfiniteQuery,
})
}}
>
<H5 marginLeft={'$2'}>Play it again</H5>
<Icon name='arrow-right' />
</XStack>
<HorizontalCardList
data={
(tracksInfiniteQuery.data.length ?? 0 > horizontalItems)
? tracksInfiniteQuery.data.slice(0, horizontalItems)
: tracksInfiniteQuery.data
}
renderItem={({ index, item: recentlyPlayedTrack }) => (
<ItemCard
size={'$11'}
caption={recentlyPlayedTrack.Name}
subCaption={`${recentlyPlayedTrack.Artists?.join(', ')}`}
squared
testId={`recently-played-${index}`}
item={recentlyPlayedTrack}
onPress={() => {
loadNewQueue({
api,
deviceProfile,
networkStatus,
track: recentlyPlayedTrack,
index: index,
tracklist: tracksInfiniteQuery.data ?? [recentlyPlayedTrack],
queue: 'Recently Played',
queuingType: QueuingType.FromSelection,
startPlayback: true,
})
}}
onLongPress={() => {
rootNavigation.navigate('Context', {
item: recentlyPlayedTrack,
navigation,
})
}}
marginHorizontal={'$1'}
captionAlign='left'
/>
)}
/>
</Animated.View>
) : (
<></>
)
}

View File

@@ -7,6 +7,8 @@ import FrequentlyPlayedTracks from './helpers/frequent-tracks'
import { usePreventRemove } from '@react-navigation/native'
import useHomeQueries from '../../api/mutations/home'
import { usePerformanceMonitor } from '../../hooks/use-performance-monitor'
import { useIsRestoring } from '@tanstack/react-query'
import { useRecentlyPlayedTracks } from '../../api/queries/recents'
const COMPONENT_NAME = 'Home'
@@ -17,18 +19,21 @@ export function Home(): React.JSX.Element {
usePerformanceMonitor(COMPONENT_NAME, 5)
const { isPending: refreshing, mutate: refresh } = useHomeQueries()
const { isPending: refreshing, mutateAsync: refresh } = useHomeQueries()
const { isPending: loadingInitialData } = useRecentlyPlayedTracks()
const isRestoring = useIsRestoring()
return (
<ScrollView
contentInsetAdjustmentBehavior='automatic'
contentContainerStyle={{
marginVertical: getToken('$4'),
marginHorizontal: getToken('$2'),
}}
refreshControl={
<RefreshControl
refreshing={refreshing}
refreshing={refreshing || isRestoring || loadingInitialData}
onRefresh={refresh}
tintColor={theme.primary.val}
/>