mirror of
https://github.com/Jellify-Music/App.git
synced 2026-03-17 10:40:38 -05:00
Merge branch 'main' of github.com:Jellify-Music/App into feature/nitro-player
This commit is contained in:
2
App.tsx
2
App.tsx
@@ -24,6 +24,7 @@ import { registerAutoService } from './src/services/carplay'
|
||||
import QueryPersistenceConfig from './src/configs/query-persistence.config'
|
||||
import registerTrackPlayer from './src/services/player'
|
||||
import configureDownloadManager from './src/services/downloads'
|
||||
import { ReducedMotionConfig, ReduceMotion } from 'react-native-reanimated'
|
||||
|
||||
LogBox.ignoreAllLogs()
|
||||
|
||||
@@ -88,6 +89,7 @@ function Container(): React.JSX.Element {
|
||||
theme={getJellifyNavTheme(colorPreset, resolvedMode)}
|
||||
>
|
||||
<GestureHandlerRootView>
|
||||
<ReducedMotionConfig mode={ReduceMotion.System} />
|
||||
<TamaguiProvider config={jellifyConfig}>
|
||||
<Jellify />
|
||||
</TamaguiProvider>
|
||||
|
||||
@@ -88,8 +88,8 @@ android {
|
||||
applicationId "com.cosmonautical.jellify"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 176
|
||||
versionName "1.0.17"
|
||||
versionCode 177
|
||||
versionName "1.0.18"
|
||||
|
||||
}
|
||||
signingConfigs {
|
||||
|
||||
4
bun.lock
4
bun.lock
@@ -41,7 +41,7 @@
|
||||
"react-native-nitro-ota": "0.11.0",
|
||||
"react-native-nitro-player": "0.5.6",
|
||||
"react-native-pager-view": "8.0.0",
|
||||
"react-native-reanimated": "4.2.1",
|
||||
"react-native-reanimated": "4.1.6",
|
||||
"react-native-safe-area-context": "5.6.2",
|
||||
"react-native-screens": "4.23.0",
|
||||
"react-native-sortables": "1.9.4",
|
||||
@@ -1914,7 +1914,7 @@
|
||||
|
||||
"react-native-pager-view": ["react-native-pager-view@8.0.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-oAwlWT1lhTkIs9HhODnjNNl/owxzn9DP1MbP+az6OTUdgbmzA16Up83sBH8NRKwrH8rNm7iuWnX1qMqiiWOLhg=="],
|
||||
|
||||
"react-native-reanimated": ["react-native-reanimated@4.2.1", "", { "dependencies": { "react-native-is-edge-to-edge": "1.2.1", "semver": "7.7.3" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-worklets": ">=0.7.0" } }, "sha512-/NcHnZMyOvsD/wYXug/YqSKw90P9edN0kEPL5lP4PFf1aQ4F1V7MKe/E0tvfkXKIajy3Qocp5EiEnlcrK/+BZg=="],
|
||||
"react-native-reanimated": ["react-native-reanimated@4.1.6", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.2.1", "semver": "7.7.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*", "react-native-worklets": ">=0.5.0" } }, "sha512-F+ZJBYiok/6Jzp1re75F/9aLzkgoQCOh4yxrnwATa8392RvM3kx+fiXXFvwcgE59v48lMwd9q0nzF1oJLXpfxQ=="],
|
||||
|
||||
"react-native-safe-area-context": ["react-native-safe-area-context@5.6.2", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg=="],
|
||||
|
||||
|
||||
@@ -543,7 +543,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 284;
|
||||
CURRENT_PROJECT_VERSION = 285;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -554,7 +554,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.17;
|
||||
MARKETING_VERSION = 1.0.18;
|
||||
NEW_SETTING = "";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -585,7 +585,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 284;
|
||||
CURRENT_PROJECT_VERSION = 285;
|
||||
DEVELOPMENT_TEAM = WAH9CZ8BPG;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
@@ -595,7 +595,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.17;
|
||||
MARKETING_VERSION = 1.0.18;
|
||||
NEW_SETTING = "";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -833,7 +833,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 284;
|
||||
CURRENT_PROJECT_VERSION = 285;
|
||||
DEVELOPMENT_TEAM = WAH9CZ8BPG;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
@@ -844,7 +844,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.17;
|
||||
MARKETING_VERSION = 1.0.18;
|
||||
NEW_SETTING = "";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
|
||||
@@ -2198,7 +2198,7 @@ PODS:
|
||||
- ReactCommon/turbomodule/core
|
||||
- ReactNativeDependencies
|
||||
- Yoga
|
||||
- RNReanimated (4.2.1):
|
||||
- RNReanimated (4.1.6):
|
||||
- hermes-engine
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
@@ -2220,10 +2220,10 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- ReactNativeDependencies
|
||||
- RNReanimated/reanimated (= 4.2.1)
|
||||
- RNReanimated/reanimated (= 4.1.6)
|
||||
- RNWorklets
|
||||
- Yoga
|
||||
- RNReanimated/reanimated (4.2.1):
|
||||
- RNReanimated/reanimated (4.1.6):
|
||||
- hermes-engine
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
@@ -2245,10 +2245,10 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- ReactNativeDependencies
|
||||
- RNReanimated/reanimated/apple (= 4.2.1)
|
||||
- RNReanimated/reanimated/apple (= 4.1.6)
|
||||
- RNWorklets
|
||||
- Yoga
|
||||
- RNReanimated/reanimated/apple (4.2.1):
|
||||
- RNReanimated/reanimated/apple (4.1.6):
|
||||
- hermes-engine
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
@@ -2829,7 +2829,7 @@ SPEC CHECKSUMS:
|
||||
RNDeviceInfo: 36d7f232bfe7c9b5c494cb7793230424ed32c388
|
||||
RNGestureHandler: 07de6f059e0ee5744ae9a56feb07ee345338cc31
|
||||
RNReactNativeHapticFeedback: d7bc1bcfe68bb139c9919ea81d11d7c6e866e870
|
||||
RNReanimated: 5a8239f0bd8835225707968c1357b19b447d8681
|
||||
RNReanimated: caefad1cdf778187bc12b747ff958ee7c6d2e580
|
||||
RNScreens: 14243fa0d9842ffa7f8bb2d00b6c3cfd3ca817e8
|
||||
RNSentry: c6ec62a7d10299ac5d8e0916202913da77bb9fc7
|
||||
RNWorklets: b6bad5e2ccfdddc4751bca114acf1680dc3231d4
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jellify",
|
||||
"version": "1.0.17",
|
||||
"version": "1.0.18",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"init-android": "bun i",
|
||||
@@ -74,7 +74,7 @@
|
||||
"react-native-nitro-ota": "0.11.0",
|
||||
"react-native-nitro-player": "0.5.6",
|
||||
"react-native-pager-view": "8.0.0",
|
||||
"react-native-reanimated": "4.2.1",
|
||||
"react-native-reanimated": "4.1.6",
|
||||
"react-native-safe-area-context": "5.6.2",
|
||||
"react-native-screens": "4.23.0",
|
||||
"react-native-sortables": "1.9.4",
|
||||
|
||||
13
patches/react-native-reanimated+4.1.6.patch
Normal file
13
patches/react-native-reanimated+4.1.6.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/node_modules/react-native-reanimated/compatibility.json b/node_modules/react-native-reanimated/compatibility.json
|
||||
index f1ba9cb..ffab7fe 100644
|
||||
--- a/node_modules/react-native-reanimated/compatibility.json
|
||||
+++ b/node_modules/react-native-reanimated/compatibility.json
|
||||
@@ -4,7 +4,7 @@
|
||||
"react-native-worklets": ["nightly"]
|
||||
},
|
||||
"4.1.x": {
|
||||
- "react-native": ["0.78", "0.79", "0.80", "0.81", "0.82"],
|
||||
+ "react-native": ["0.78", "0.79", "0.80", "0.81", "0.82", "0.83", "0.84"],
|
||||
"react-native-worklets": ["0.5.x", "0.6.x", "0.7.x"]
|
||||
},
|
||||
"4.0.x": {
|
||||
@@ -1,13 +0,0 @@
|
||||
diff --git a/node_modules/react-native-reanimated/compatibility.json b/node_modules/react-native-reanimated/compatibility.json
|
||||
index e278e81..97cfddf 100644
|
||||
--- a/node_modules/react-native-reanimated/compatibility.json
|
||||
+++ b/node_modules/react-native-reanimated/compatibility.json
|
||||
@@ -5,7 +5,7 @@
|
||||
"react-native-worklets": ["nightly"]
|
||||
},
|
||||
"4.2.x": {
|
||||
- "react-native": ["0.80", "0.81", "0.82", "0.83"],
|
||||
+ "react-native": ["0.80", "0.81", "0.82", "0.83", "0.84"],
|
||||
"react-native-worklets": ["0.7.x"]
|
||||
},
|
||||
"4.1.x": {
|
||||
19
src/api/queries/search/index.ts
Normal file
19
src/api/queries/search/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { QueryKeys } from '../../../enums/query-keys'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { fetchSearchResults } from './utils'
|
||||
import { ONE_MINUTE } from '../../../constants/query-client'
|
||||
import { useJellifyLibrary } from '../../../stores'
|
||||
|
||||
const useSearchResults = (searchString: string | undefined) => {
|
||||
const [library] = useJellifyLibrary()
|
||||
|
||||
return useQuery({
|
||||
queryKey: [QueryKeys.Search, library?.musicLibraryId, searchString],
|
||||
queryFn: () => fetchSearchResults(library?.musicLibraryId, searchString),
|
||||
staleTime: ONE_MINUTE * 10, // Cache results for 10 minutes
|
||||
gcTime: ONE_MINUTE * 15, // Garbage collect after 15 minutes
|
||||
enabled: !!library?.musicLibraryId && !!searchString, // Only run if we have a library ID and a search string
|
||||
})
|
||||
}
|
||||
|
||||
export default useSearchResults
|
||||
@@ -1,9 +1,8 @@
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
|
||||
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api'
|
||||
import { isEmpty, isUndefined, trim } from 'lodash'
|
||||
import QueryConfig from '../../configs/query.config'
|
||||
import { Api } from '@jellyfin/sdk'
|
||||
import { JellifyUser } from '../../types/JellifyUser'
|
||||
import QueryConfig from '../../../../configs/query.config'
|
||||
import { getApi, getUser } from '../../../../stores'
|
||||
/**
|
||||
* Performs a search for items against the Jellyfin server, trimming whitespace
|
||||
* around the search term for the best possible results.
|
||||
@@ -11,12 +10,13 @@ import { JellifyUser } from '../../types/JellifyUser'
|
||||
* @returns A promise of a BaseItemDto array, be it empty or not
|
||||
*/
|
||||
export async function fetchSearchResults(
|
||||
api: Api | undefined,
|
||||
user: JellifyUser | undefined,
|
||||
libraryId: string | undefined,
|
||||
searchString: string | undefined,
|
||||
): Promise<BaseItemDto[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const api = getApi()
|
||||
const user = getUser()
|
||||
|
||||
if (isEmpty(searchString)) resolve([])
|
||||
|
||||
if (isUndefined(api)) return reject('Client instance not set')
|
||||
@@ -7,9 +7,9 @@ import { useNavigation } from '@react-navigation/native'
|
||||
import DiscoverStackParamList from '../../../screens/Discover/types'
|
||||
import navigationRef from '../../../../navigation'
|
||||
import { useRecentlyAddedAlbums } from '../../../api/queries/album'
|
||||
import Animated, { Easing, FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import AnimatedRow from '../../Global/helpers/animated-row'
|
||||
|
||||
export default function RecentlyAdded(): React.JSX.Element | null {
|
||||
export default function RecentlyAdded(): React.JSX.Element {
|
||||
const recentlyAddedAlbumsInfinityQuery = useRecentlyAddedAlbums()
|
||||
|
||||
const navigation = useNavigation<NativeStackNavigationProp<DiscoverStackParamList>>()
|
||||
@@ -18,15 +18,7 @@ export default function RecentlyAdded(): React.JSX.Element | null {
|
||||
recentlyAddedAlbumsInfinityQuery.data && recentlyAddedAlbumsInfinityQuery.data.length > 0
|
||||
|
||||
return recentlyAddedExists ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.easing(Easing.in(Easing.ease))}
|
||||
exiting={FadeOut.easing(Easing.out(Easing.ease))}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-recently-added'
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<AnimatedRow testID='discover-recently-added'>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
@@ -64,6 +56,8 @@ export default function RecentlyAdded(): React.JSX.Element | null {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : null
|
||||
</AnimatedRow>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import DiscoverStackParamList from '../../../screens/Discover/types'
|
||||
import navigationRef from '../../../../navigation'
|
||||
import { useJellifyServer } from '../../../stores'
|
||||
import { usePublicPlaylists } from '../../../api/queries/playlist'
|
||||
import Animated, { Easing, FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import AnimatedRow from '../../Global/helpers/animated-row'
|
||||
|
||||
export default function PublicPlaylists(): React.JSX.Element | null {
|
||||
export default function PublicPlaylists(): React.JSX.Element {
|
||||
const {
|
||||
data: playlists,
|
||||
fetchNextPage,
|
||||
@@ -29,15 +29,7 @@ export default function PublicPlaylists(): React.JSX.Element | null {
|
||||
const publicPlaylistsExist = playlists && playlists.length > 0
|
||||
|
||||
return publicPlaylistsExist ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.easing(Easing.in(Easing.ease))}
|
||||
exiting={FadeOut.easing(Easing.out(Easing.ease))}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-public-playlists'
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<AnimatedRow testID='discover-public-playlists'>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
@@ -80,6 +72,8 @@ export default function PublicPlaylists(): React.JSX.Element | null {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : null
|
||||
</AnimatedRow>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import navigationRef from '../../../../navigation'
|
||||
import { formatArtistNames } from '../../../utils/formatting/artist-names'
|
||||
import Animated, { Easing, FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import ItemCard from '../../Global/components/item-card'
|
||||
import HorizontalCardList from '../../Global/components/horizontal-list'
|
||||
import { XStack } from 'tamagui'
|
||||
@@ -10,6 +9,7 @@ import { useNavigation } from '@react-navigation/native'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import DiscoverStackParamList from '../../../screens/Discover/types'
|
||||
import { useDiscoverAlbums } from '../../../api/queries/suggestions'
|
||||
import AnimatedRow from '../../Global/helpers/animated-row'
|
||||
|
||||
export default function SuggestedAlbums() {
|
||||
const suggestedAlbumsInfiniteQuery = useDiscoverAlbums()
|
||||
@@ -20,15 +20,7 @@ export default function SuggestedAlbums() {
|
||||
suggestedAlbumsInfiniteQuery.data && suggestedAlbumsInfiniteQuery.data.length > 0
|
||||
|
||||
return suggestedAlbumsExist ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.easing(Easing.in(Easing.ease))}
|
||||
exiting={FadeOut.easing(Easing.out(Easing.ease))}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-suggested-albums'
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<AnimatedRow testID='discover-suggested-albums'>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
@@ -64,6 +56,8 @@ export default function SuggestedAlbums() {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : null
|
||||
</AnimatedRow>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ import { useNavigation } from '@react-navigation/native'
|
||||
import DiscoverStackParamList from '../../../screens/Discover/types'
|
||||
import navigationRef from '../../../../navigation'
|
||||
import { pickFirstGenre } from '../../../utils/formatting/genres'
|
||||
import Animated, { Easing, FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import { useDiscoverArtists } from '../../../api/queries/suggestions'
|
||||
import AnimatedRow from '../../Global/helpers/animated-row'
|
||||
|
||||
export default function SuggestedArtists(): React.JSX.Element | null {
|
||||
export default function SuggestedArtists(): React.JSX.Element {
|
||||
const suggestedArtistsInfiniteQuery = useDiscoverArtists()
|
||||
|
||||
const navigation = useNavigation<NativeStackNavigationProp<DiscoverStackParamList>>()
|
||||
@@ -19,15 +19,7 @@ export default function SuggestedArtists(): React.JSX.Element | null {
|
||||
suggestedArtistsInfiniteQuery.data && suggestedArtistsInfiniteQuery.data.length > 0
|
||||
|
||||
return suggestedArtistsExist ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.easing(Easing.in(Easing.ease))}
|
||||
exiting={FadeOut.easing(Easing.out(Easing.ease))}
|
||||
layout={LinearTransition.springify()}
|
||||
testID='discover-suggested-artists'
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<AnimatedRow testID='discover-suggested-artists'>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
@@ -63,6 +55,8 @@ export default function SuggestedArtists(): React.JSX.Element | null {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
) : null
|
||||
</AnimatedRow>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
28
src/components/Global/helpers/animated-row.tsx
Normal file
28
src/components/Global/helpers/animated-row.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import Animated, {
|
||||
FadeIn,
|
||||
ReduceMotion,
|
||||
FadeOut,
|
||||
LinearTransition,
|
||||
Easing,
|
||||
} from 'react-native-reanimated'
|
||||
|
||||
interface AnimatedRowProps {
|
||||
children: React.ReactNode
|
||||
testID?: string
|
||||
}
|
||||
|
||||
export default function AnimatedRow({ children, testID }: AnimatedRowProps) {
|
||||
return (
|
||||
<Animated.View
|
||||
testID={testID}
|
||||
entering={FadeIn.easing(Easing.in(Easing.ease)).reduceMotion(ReduceMotion.System)}
|
||||
exiting={FadeOut.easing(Easing.out(Easing.ease)).reduceMotion(ReduceMotion.System)}
|
||||
layout={LinearTransition.springify().reduceMotion(ReduceMotion.System)}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
@@ -11,7 +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/formatting/genres'
|
||||
import Animated, { Easing, FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import AnimatedRow from '../../Global/helpers/animated-row'
|
||||
|
||||
export default function FrequentArtists(): React.JSX.Element {
|
||||
const navigation = useNavigation<NativeStackNavigationProp<HomeStackParamList>>()
|
||||
@@ -41,14 +41,7 @@ export default function FrequentArtists(): React.JSX.Element {
|
||||
)
|
||||
|
||||
return frequentArtistsInfiniteQuery.data ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.easing(Easing.in(Easing.ease))}
|
||||
exiting={FadeOut.easing(Easing.out(Easing.ease))}
|
||||
layout={LinearTransition.springify()}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<AnimatedRow testID='home-frequent-artists'>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
@@ -63,7 +56,7 @@ export default function FrequentArtists(): React.JSX.Element {
|
||||
data={frequentArtistsInfiniteQuery.data.slice(0, horizontalItems) ?? []}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
</Animated.View>
|
||||
</AnimatedRow>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ import HomeStackParamList from '../../../screens/Home/types'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { RootStackParamList } from '../../../screens/types'
|
||||
import { useFrequentlyPlayedTracks } from '../../../api/queries/frequents'
|
||||
import Animated, { Easing, FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import AnimatedRow from '../../Global/helpers/animated-row'
|
||||
|
||||
export default function FrequentlyPlayedTracks(): React.JSX.Element {
|
||||
const tracksInfiniteQuery = useFrequentlyPlayedTracks()
|
||||
@@ -23,14 +23,7 @@ export default function FrequentlyPlayedTracks(): React.JSX.Element {
|
||||
const { horizontalItems } = useDisplayContext()
|
||||
|
||||
return tracksInfiniteQuery.data ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.easing(Easing.in(Easing.ease))}
|
||||
exiting={FadeOut.easing(Easing.out(Easing.ease))}
|
||||
layout={LinearTransition.springify()}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<AnimatedRow testID='home-frequent-tracks'>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
@@ -74,7 +67,7 @@ export default function FrequentlyPlayedTracks(): React.JSX.Element {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
</AnimatedRow>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ import HomeStackParamList from '../../../screens/Home/types'
|
||||
import { useRecentArtists } from '../../../api/queries/recents'
|
||||
import { pickFirstGenre } from '../../../utils/formatting/genres'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'
|
||||
import Animated, { Easing, FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import AnimatedRow from '../../Global/helpers/animated-row'
|
||||
|
||||
export default function RecentArtists(): React.JSX.Element {
|
||||
const recentArtistsInfiniteQuery = useRecentArtists()
|
||||
@@ -47,14 +47,7 @@ export default function RecentArtists(): React.JSX.Element {
|
||||
)
|
||||
|
||||
return recentArtistsInfiniteQuery.data ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.easing(Easing.in(Easing.ease))}
|
||||
exiting={FadeOut.easing(Easing.out(Easing.ease))}
|
||||
layout={LinearTransition.springify()}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<AnimatedRow testID='home-recent-artists'>
|
||||
<XStack alignItems='center' onPress={handleHeaderPress}>
|
||||
<H5 marginLeft={'$2'}>Recent Artists</H5>
|
||||
<Icon name='arrow-right' />
|
||||
@@ -64,7 +57,7 @@ export default function RecentArtists(): React.JSX.Element {
|
||||
data={recentArtistsInfiniteQuery.data.slice(0, horizontalItems)}
|
||||
renderItem={renderItem}
|
||||
/>
|
||||
</Animated.View>
|
||||
</AnimatedRow>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
|
||||
@@ -11,8 +11,8 @@ import { useDisplayContext } from '../../../providers/Display/display-provider'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import HomeStackParamList from '../../../screens/Home/types'
|
||||
import { useRecentlyPlayedTracks } from '../../../api/queries/recents'
|
||||
import Animated, { Easing, FadeIn, FadeOut, LinearTransition } from 'react-native-reanimated'
|
||||
import { BaseItemDto, BaseItemKind } from '@jellyfin/sdk/lib/generated-client'
|
||||
import AnimatedRow from '../../Global/helpers/animated-row'
|
||||
|
||||
export default function RecentlyPlayed(): React.JSX.Element {
|
||||
const navigation = useNavigation<NativeStackNavigationProp<HomeStackParamList>>()
|
||||
@@ -43,14 +43,7 @@ export default function RecentlyPlayed(): React.JSX.Element {
|
||||
}
|
||||
|
||||
return tracksInfiniteQuery.data ? (
|
||||
<Animated.View
|
||||
entering={FadeIn.easing(Easing.in(Easing.ease))}
|
||||
exiting={FadeOut.easing(Easing.out(Easing.ease))}
|
||||
layout={LinearTransition.springify()}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<AnimatedRow testID='home-recently-played'>
|
||||
<XStack
|
||||
alignItems='center'
|
||||
onPress={() => {
|
||||
@@ -87,7 +80,7 @@ export default function RecentlyPlayed(): React.JSX.Element {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Animated.View>
|
||||
</AnimatedRow>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import Input from '../Global/helpers/input'
|
||||
import { H5, Text } from '../Global/helpers/text'
|
||||
import ItemRow from '../Global/components/item-row'
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||
import { QueryKeys } from '../../enums/query-keys'
|
||||
import { fetchSearchResults } from '../../api/queries/search'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { getToken, H3, Spinner, YStack } from 'tamagui'
|
||||
import Suggestions from './suggestions'
|
||||
import { isEmpty } from 'lodash'
|
||||
@@ -13,7 +10,6 @@ import HorizontalCardList from '../Global/components/horizontal-list'
|
||||
import ItemCard from '../Global/components/item-card'
|
||||
import SearchParamList from '../../screens/Search/types'
|
||||
import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry'
|
||||
import { getApi, getUser, useJellifyLibrary } from '../../stores'
|
||||
import { FlashList } from '@shopify/flash-list'
|
||||
import navigationRef from '../../../navigation'
|
||||
import { StackActions } from '@react-navigation/native'
|
||||
@@ -22,41 +18,35 @@ import Track from '../Global/components/Track'
|
||||
import { pickRandomItemFromArray } from '../../utils/parsing/random'
|
||||
import { SEARCH_PLACEHOLDERS } from '../../configs/placeholder.config'
|
||||
import { formatArtistName } from '../../utils/formatting/artist-names'
|
||||
import useSearchResults from '../../api/queries/search'
|
||||
|
||||
export default function Search({
|
||||
navigation,
|
||||
}: {
|
||||
navigation: NativeStackNavigationProp<SearchParamList, 'SearchScreen'>
|
||||
}): React.JSX.Element {
|
||||
const api = getApi()
|
||||
const user = getUser()
|
||||
const [library] = useJellifyLibrary()
|
||||
/**
|
||||
* Raw text input value from the user, updates immediately as they type
|
||||
*/
|
||||
const [inputValue, setInputValue] = useState<string | undefined>(undefined)
|
||||
|
||||
/**
|
||||
* Debounced search string that updates 500ms after the user stops typing, used to trigger the search query
|
||||
* which is keyed off of this value for caching.
|
||||
*/
|
||||
const [searchString, setSearchString] = useState<string | undefined>(undefined)
|
||||
|
||||
const {
|
||||
data: items,
|
||||
refetch,
|
||||
isFetching: fetchingResults,
|
||||
} = useQuery({
|
||||
queryKey: [QueryKeys.Search, library?.musicLibraryId, searchString],
|
||||
queryFn: () => fetchSearchResults(api, user, library?.musicLibraryId, searchString),
|
||||
})
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
setSearchString(inputValue || undefined)
|
||||
}, 500)
|
||||
return () => clearTimeout(timeout)
|
||||
}, [inputValue])
|
||||
|
||||
const search = () => {
|
||||
let timeout: ReturnType<typeof setTimeout>
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => {
|
||||
refetch()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
const { data: items, isFetching: fetchingResults } = useSearchResults(searchString)
|
||||
|
||||
const handleSearchStringUpdate = (value: string | undefined) => {
|
||||
setSearchString(value)
|
||||
search()
|
||||
setInputValue(value || undefined)
|
||||
}
|
||||
|
||||
const handleScrollBeginDrag = () => {
|
||||
@@ -90,7 +80,7 @@ export default function Search({
|
||||
<Input
|
||||
placeholder={placeholder}
|
||||
onChangeText={handleSearchStringUpdate}
|
||||
value={searchString}
|
||||
value={inputValue}
|
||||
testID='search-input'
|
||||
clearButtonMode='always'
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user