mirror of
https://github.com/Jellify-Music/App.git
synced 2026-04-21 17:18:23 -05:00
Merge pull request #134 from anultravioletaurora/59-improve-onboarding-experience
Memory Spillage Fixes (Again)
This commit is contained in:
@@ -9,7 +9,6 @@ import jellifyConfig from './tamagui.config';
|
||||
import { clientPersister } from './constants/storage';
|
||||
import { queryClient } from './constants/query-client';
|
||||
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
||||
import { createWorkletRuntime } from 'react-native-reanimated';
|
||||
|
||||
// export const backgroundRuntime = createWorkletRuntime('background');
|
||||
|
||||
|
||||
@@ -13,6 +13,4 @@ export const useApi = (serverUrl?: string, username?: string, password?: string,
|
||||
|
||||
return createApi(serverUrl, username, password, accessToken)
|
||||
},
|
||||
gcTime: 1000,
|
||||
refetchInterval: false
|
||||
})
|
||||
@@ -1,30 +0,0 @@
|
||||
import { QueryKeys } from "../../enums/query-keys";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { fetchMusicLibraries, fetchPlaylistLibrary, fetchUserViews } from "./functions/libraries";
|
||||
|
||||
/**
|
||||
* @deprecated use {@link useUserViews} instead as that will respect user permissions
|
||||
* @returns
|
||||
*/
|
||||
export const useMusicLibraries = () => useQuery({
|
||||
queryKey: [QueryKeys.Libraries],
|
||||
queryFn: () => fetchMusicLibraries()
|
||||
});
|
||||
|
||||
/**
|
||||
* @deprecated use {@link useUserViews} instead as that will respect user permissions
|
||||
* @returns
|
||||
*/
|
||||
export const usePlaylistLibrary = () => useQuery({
|
||||
queryKey: [QueryKeys.Playlist],
|
||||
queryFn: () => fetchPlaylistLibrary()
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
export const useUserViews = () => useQuery({
|
||||
queryKey: [QueryKeys.UserViews],
|
||||
queryFn: () => fetchUserViews()
|
||||
});
|
||||
@@ -1,7 +1,6 @@
|
||||
import { StackParamList } from "../types";
|
||||
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
|
||||
import { HomeAlbumProps } from "../types";
|
||||
import { YStack, XStack, Separator } from "tamagui";
|
||||
import { BaseItemDto, ItemSortBy } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { ItemSortBy } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { H3, H5, Text } from "../Global/helpers/text";
|
||||
import { FlatList } from "react-native";
|
||||
import { RunTimeTicks } from "../Global/helpers/time-codes";
|
||||
@@ -14,16 +13,15 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { QueryKeys } from "../../enums/query-keys";
|
||||
import { getItemsApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import Client from "../../api/client";
|
||||
import { useMemo } from "react";
|
||||
|
||||
interface AlbumProps {
|
||||
album: BaseItemDto,
|
||||
navigation: NativeStackNavigationProp<StackParamList>;
|
||||
}
|
||||
|
||||
export default function Album({
|
||||
album,
|
||||
navigation
|
||||
}: AlbumProps): React.JSX.Element {
|
||||
export function AlbumScreen({
|
||||
route,
|
||||
navigation
|
||||
} : HomeAlbumProps): React.JSX.Element {
|
||||
|
||||
const { album } = route.params;
|
||||
|
||||
navigation.setOptions({
|
||||
headerRight: () => {
|
||||
@@ -60,24 +58,31 @@ export default function Album({
|
||||
<FlatList
|
||||
contentInsetAdjustmentBehavior="automatic"
|
||||
data={tracks}
|
||||
keyExtractor={(item) => item.Id!}
|
||||
numColumns={1}
|
||||
ItemSeparatorComponent={() => <Separator />}
|
||||
ListHeaderComponent={() => (
|
||||
<YStack
|
||||
alignItems="center"
|
||||
alignContent="center"
|
||||
marginTop={"$4"}
|
||||
minHeight={width / 1.1}
|
||||
>
|
||||
<BlurhashedImage
|
||||
item={album}
|
||||
width={width / 1.1}
|
||||
height={width / 1.1}
|
||||
/>
|
||||
ListHeaderComponent={(
|
||||
useMemo(() => {
|
||||
return (
|
||||
<YStack
|
||||
alignItems="center"
|
||||
alignContent="center"
|
||||
marginTop={"$4"}
|
||||
minHeight={width / 1.1}
|
||||
>
|
||||
<BlurhashedImage
|
||||
item={album}
|
||||
width={width / 1.1}
|
||||
height={width / 1.1}
|
||||
/>
|
||||
|
||||
<H5>{ album.Name ?? "Untitled Album" }</H5>
|
||||
<Text>{ album.ProductionYear?.toString() ?? "" }</Text>
|
||||
</YStack>
|
||||
<H5>{ album.Name ?? "Untitled Album" }</H5>
|
||||
<Text>{ album.ProductionYear?.toString() ?? "" }</Text>
|
||||
</YStack>
|
||||
)
|
||||
}, [
|
||||
album
|
||||
])
|
||||
|
||||
)}
|
||||
renderItem={({ item: track, index }) => {
|
||||
@@ -88,11 +93,12 @@ export default function Album({
|
||||
tracklist={tracks!}
|
||||
index={index}
|
||||
navigation={navigation}
|
||||
queue={album}
|
||||
/>
|
||||
)
|
||||
|
||||
}}
|
||||
ListFooterComponent={() => (
|
||||
ListFooterComponent={(
|
||||
<YStack justifyContent="flex-start">
|
||||
<XStack flex={1} marginTop={"$3"} justifyContent="flex-end">
|
||||
<Text
|
||||
@@ -108,6 +114,7 @@ export default function Album({
|
||||
<H3>Album Artists</H3>
|
||||
<FlatList
|
||||
horizontal
|
||||
keyExtractor={(item) => item.Id!}
|
||||
data={album.ArtistItems}
|
||||
renderItem={({ index, item: artist }) => {
|
||||
return (
|
||||
@@ -132,6 +139,5 @@ export default function Album({
|
||||
// overflow: 'hidden' // Prevent unnecessary memory usage
|
||||
// }}
|
||||
/>
|
||||
|
||||
)
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { RouteProp } from "@react-navigation/native";
|
||||
import Album from "../component";
|
||||
import { StackParamList } from "../../types";
|
||||
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
|
||||
|
||||
|
||||
export function AlbumScreen({ route, navigation } : { route: RouteProp<StackParamList, "Album">, navigation: NativeStackNavigationProp<StackParamList> }): React.JSX.Element {
|
||||
return (
|
||||
<Album
|
||||
album={route.params.album }
|
||||
navigation={navigation}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -26,13 +26,14 @@ export default function BlurhashedImage({
|
||||
const { data: image, isSuccess } = useQuery({
|
||||
queryKey: [
|
||||
QueryKeys.ItemImage,
|
||||
item.Id!,
|
||||
item.AlbumId ? item.AlbumId : item.Id!,
|
||||
type ?? ImageType.Primary,
|
||||
Math.ceil(width / 100) * 100, // Images are fetched at a higher, generic resolution
|
||||
Math.ceil(height ?? width / 100) * 100 // So these keys need to match
|
||||
],
|
||||
queryFn: () => fetchItemImage(item.Id!, type ?? ImageType.Primary, width, height ?? width),
|
||||
staleTime: (1000 * 60 * 60) // 1 hour,
|
||||
queryFn: () => fetchItemImage(item.AlbumId ? item.AlbumId : item.Id!, type ?? ImageType.Primary, width, height ?? width),
|
||||
staleTime: (1000 * 60 * 60) * 24, // 1 day, images probably don't refresh that often
|
||||
gcTime: (1000 * 1 * 1) * 1 // 1 second, these are stored on disk anyways so refetching is cheap
|
||||
});;
|
||||
|
||||
const blurhash = !isEmpty(item.ImageBlurHashes)
|
||||
|
||||
@@ -52,7 +52,7 @@ export default function Item({
|
||||
usePlayNewQueue.mutate({
|
||||
track: item,
|
||||
tracklist: [item],
|
||||
queueName,
|
||||
queue: "Search",
|
||||
queuingType: QueuingType.FromSelection
|
||||
})
|
||||
break;
|
||||
|
||||
@@ -17,7 +17,7 @@ interface TrackProps {
|
||||
navigation: NativeStackNavigationProp<StackParamList>;
|
||||
tracklist?: BaseItemDto[] | undefined;
|
||||
index?: number | undefined;
|
||||
queue?: Queue;
|
||||
queue: Queue;
|
||||
showArtwork?: boolean | undefined;
|
||||
onPress?: () => void | undefined;
|
||||
onLongPress?: () => void | undefined;
|
||||
@@ -64,7 +64,7 @@ export default function Track({
|
||||
track,
|
||||
index,
|
||||
tracklist: tracklist ?? playQueue.map((track) => track.item),
|
||||
queue: queue ? queue : "Queue",
|
||||
queue,
|
||||
queuingType: QueuingType.FromSelection
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { NativeStackNavigationProp } from "@react-navigation/native-stack";
|
||||
import { trigger } from "react-native-haptic-feedback";
|
||||
import { QueuingType } from "../../../enums/queuing-type";
|
||||
import Icon from "../../../components/Global/helpers/icon";
|
||||
import { FlatList } from "react-native";
|
||||
|
||||
export default function RecentlyPlayed({
|
||||
navigation
|
||||
@@ -42,11 +43,10 @@ export default function RecentlyPlayed({
|
||||
</YStack>
|
||||
)}
|
||||
</XStack>
|
||||
<ScrollView
|
||||
<FlatList
|
||||
horizontal
|
||||
removeClippedSubviews // Save memory usage
|
||||
>
|
||||
{ recentTracks && recentTracks.map((recentlyPlayedTrack, index) => {
|
||||
data={recentTracks}
|
||||
renderItem={({ index, item: recentlyPlayedTrack }) => {
|
||||
return (
|
||||
<ItemCard
|
||||
caption={recentlyPlayedTrack.Name}
|
||||
@@ -58,7 +58,7 @@ export default function RecentlyPlayed({
|
||||
usePlayNewQueue.mutate({
|
||||
track: recentlyPlayedTrack,
|
||||
index: index,
|
||||
tracklist: recentTracks,
|
||||
tracklist: recentTracks ?? [recentlyPlayedTrack],
|
||||
queue: "Recently Played",
|
||||
queuingType: QueuingType.FromSelection
|
||||
});
|
||||
@@ -72,8 +72,11 @@ export default function RecentlyPlayed({
|
||||
}}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</ScrollView>
|
||||
}}
|
||||
style={{
|
||||
overflow: 'hidden'
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { HomeProvider } from "./provider";
|
||||
import { createNativeStackNavigator } from "@react-navigation/native-stack";
|
||||
import { StackParamList } from "../types";
|
||||
import { ArtistScreen } from "../Artist/screens";
|
||||
import { AlbumScreen } from "../Album/screens";
|
||||
import { AlbumScreen } from "../Album";
|
||||
import { PlaylistScreen } from "../Playlist/screens";
|
||||
import { ProvidedHome } from "./component";
|
||||
import DetailsScreen from "../ItemDetail/screen";
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function TrackOptions({
|
||||
<YStack width={width}>
|
||||
|
||||
<XStack justifyContent="space-evenly">
|
||||
{ albumFetchSuccess ? (
|
||||
{ albumFetchSuccess && album ? (
|
||||
<IconButton
|
||||
name="music-box"
|
||||
title="Go to Album"
|
||||
@@ -83,9 +83,21 @@ export default function TrackOptions({
|
||||
navigation.goBack();
|
||||
|
||||
navigation.goBack();
|
||||
navigation.navigate("Album", {
|
||||
album
|
||||
});
|
||||
|
||||
if (isNested)
|
||||
navigation.navigate('Tabs', {
|
||||
screen: 'Home',
|
||||
params: {
|
||||
screen: 'Album',
|
||||
params: {
|
||||
album
|
||||
}
|
||||
}
|
||||
});
|
||||
else
|
||||
navigation.navigate('Album', {
|
||||
album
|
||||
});
|
||||
}}
|
||||
size={width / 6}
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { StackParamList } from "../types";
|
||||
import Library from "./component";
|
||||
import { ArtistScreen } from "../Artist/screens";
|
||||
import { AlbumScreen } from "../Album/screens";
|
||||
import { AlbumScreen } from "../Album";
|
||||
import { PlaylistScreen } from "../Playlist/screens";
|
||||
import ArtistsScreen from "../Artists/screen";
|
||||
import AlbumsScreen from "../Albums/screen";
|
||||
|
||||
@@ -4,11 +4,13 @@ import { useAuthenticationContext } from "../provider";
|
||||
import { H1, H2, Label, Text } from "../../Global/helpers/text";
|
||||
import Button from "../../Global/helpers/button";
|
||||
import _ from "lodash";
|
||||
import { useUserViews } from "../../../api/queries/libraries";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import Client from "../../../api/client";
|
||||
import { useJellifyContext } from "../../provider";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { QueryKeys } from "../../../enums/query-keys";
|
||||
import { fetchUserViews } from "../../../api/queries/functions/libraries";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
export default function ServerLibrary(): React.JSX.Element {
|
||||
|
||||
@@ -19,7 +21,10 @@ export default function ServerLibrary(): React.JSX.Element {
|
||||
const [libraryId, setLibraryId] = useState<string | undefined>(undefined);
|
||||
const [playlistLibrary, setPlaylistLibrary] = useState<BaseItemDto | undefined>(undefined);
|
||||
|
||||
const { data : libraries, isError, isPending, isSuccess, refetch } = useUserViews();
|
||||
const { data : libraries, isError, isPending, isSuccess, refetch } = useQuery({
|
||||
queryKey: [QueryKeys.UserViews],
|
||||
queryFn: () => fetchUserViews()
|
||||
});;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isPending && isSuccess)
|
||||
|
||||
@@ -12,7 +12,7 @@ import { FadeIn, FadeOut, ReduceMotion, SequencedTransition } from "react-native
|
||||
export default function Queue({ navigation }: { navigation: NativeStackNavigationProp<StackParamList>}): React.JSX.Element {
|
||||
|
||||
const { width } = useSafeAreaFrame();
|
||||
const { playQueue: queue, useClearQueue, useRemoveFromQueue, useReorderQueue, useSkip, nowPlaying } = usePlayerContext();
|
||||
const { playQueue, queue, useClearQueue, useRemoveFromQueue, useReorderQueue, useSkip, nowPlaying } = usePlayerContext();
|
||||
|
||||
navigation.setOptions({
|
||||
headerRight: () => {
|
||||
@@ -24,12 +24,12 @@ export default function Queue({ navigation }: { navigation: NativeStackNavigatio
|
||||
}
|
||||
})
|
||||
|
||||
const scrollIndex = queue.findIndex(queueItem => queueItem.item.Id! === nowPlaying!.item.Id!)
|
||||
const scrollIndex = playQueue.findIndex(queueItem => queueItem.item.Id! === nowPlaying!.item.Id!)
|
||||
|
||||
return (
|
||||
<DraggableFlatList
|
||||
contentInsetAdjustmentBehavior="automatic"
|
||||
data={queue}
|
||||
data={playQueue}
|
||||
dragHitSlop={{ left: -50 }} // https://github.com/computerjazz/react-native-draggable-flatlist/issues/336
|
||||
extraData={nowPlaying}
|
||||
// enableLayoutAnimationExperimental
|
||||
@@ -54,6 +54,7 @@ export default function Queue({ navigation }: { navigation: NativeStackNavigatio
|
||||
|
||||
return (
|
||||
<Track
|
||||
queue={queue}
|
||||
navigation={navigation}
|
||||
track={queueItem.item}
|
||||
index={getIndex()}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { StackParamList } from "../types";
|
||||
import PlayerScreen from "./screens";
|
||||
import Queue from "./screens/queue";
|
||||
import DetailsScreen from "../ItemDetail/screen";
|
||||
import { AlbumScreen } from "../Album/screens";
|
||||
import { AlbumScreen } from "../Album";
|
||||
|
||||
export const PlayerStack = createNativeStackNavigator<StackParamList>();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createNativeStackNavigator } from "@react-navigation/native-stack"
|
||||
import SearchScreen from "./screen";
|
||||
import { StackParamList } from "../types";
|
||||
import { ArtistScreen } from "../Artist/screens";
|
||||
import { AlbumScreen } from "../Album/screens";
|
||||
import { AlbumScreen } from "../Album";
|
||||
import { PlaylistScreen } from "../Playlist/screens";
|
||||
import DetailsScreen from "../ItemDetail/screen";
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function Tracks({ navigation }: { navigation: NativeStackNavigati
|
||||
showArtwork
|
||||
track={track}
|
||||
tracklist={tracks?.slice(index, index + 50) ?? []}
|
||||
queue="Queue"
|
||||
queue="Favorite Tracks"
|
||||
/>
|
||||
|
||||
)
|
||||
|
||||
+40
-1
@@ -12,14 +12,53 @@ import { PortalProvider } from "@tamagui/portal";
|
||||
import { JellifyProvider, useJellifyContext } from "./provider";
|
||||
import { ToastProvider, ToastViewport } from "@tamagui/toast";
|
||||
import SafeToastViewport from "./Global/components/toast-area-view-port";
|
||||
import { QueryKeys } from "../enums/query-keys";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import TrackPlayer, { IOSCategory, IOSCategoryOptions } from "react-native-track-player";
|
||||
import { CAPABILITIES } from "../player/constants";
|
||||
|
||||
export default function Jellify(): React.JSX.Element {
|
||||
|
||||
const { isSuccess: isPlayerReady } = useQuery({
|
||||
queryKey: [QueryKeys.Player],
|
||||
queryFn: async () => {
|
||||
await TrackPlayer.setupPlayer({
|
||||
autoHandleInterruptions: true,
|
||||
maxCacheSize: 1000 * 100, // 100MB, TODO make this adjustable
|
||||
iosCategory: IOSCategory.Playback,
|
||||
iosCategoryOptions: [
|
||||
IOSCategoryOptions.AllowAirPlay,
|
||||
IOSCategoryOptions.AllowBluetooth,
|
||||
]
|
||||
});
|
||||
|
||||
return await TrackPlayer.updateOptions({
|
||||
progressUpdateEventInterval: 1,
|
||||
capabilities: CAPABILITIES,
|
||||
notificationCapabilities: CAPABILITIES,
|
||||
compactCapabilities: CAPABILITIES,
|
||||
// ratingType: RatingType.Heart,
|
||||
// likeOptions: {
|
||||
// isActive: false,
|
||||
// title: "Favorite"
|
||||
// },
|
||||
// dislikeOptions: {
|
||||
// isActive: true,
|
||||
// title: "Unfavorite"
|
||||
// }
|
||||
});
|
||||
},
|
||||
retry: 0,
|
||||
// staleTime: 1000 * 60 * 60 * 24 * 7 // 7 days
|
||||
});
|
||||
|
||||
return (
|
||||
<PortalProvider shouldAddRootHost>
|
||||
<ToastProvider burntOptions={{ from: 'top'}}>
|
||||
<JellifyProvider>
|
||||
<App />
|
||||
{ isPlayerReady && (
|
||||
<App />
|
||||
)}
|
||||
</JellifyProvider>
|
||||
</ToastProvider>
|
||||
</PortalProvider>
|
||||
|
||||
@@ -32,7 +32,6 @@ export function Tabs() : React.JSX.Element {
|
||||
<>
|
||||
<Separator />
|
||||
<Miniplayer navigation={props.navigation} />
|
||||
<Separator />
|
||||
</>
|
||||
)}
|
||||
<BottomTabBar {...props} />
|
||||
|
||||
+14
-19
@@ -1,26 +1,21 @@
|
||||
import { MMKV } from "react-native-mmkv";
|
||||
import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";
|
||||
import { persistQueryClient } from "@tanstack/react-query-persist-client";
|
||||
import { queryClient } from "./query-client";
|
||||
|
||||
export const storage = new MMKV();
|
||||
|
||||
const clientStorage = {
|
||||
setItem: (key: string, value: string | number | boolean | Uint8Array) => {
|
||||
storage.set(key, value);
|
||||
},
|
||||
getItem: (key: string) => {
|
||||
const value = storage.getString(key);
|
||||
return value === undefined ? null : value;
|
||||
},
|
||||
removeItem: (key: string) => {
|
||||
storage.delete(key);
|
||||
},
|
||||
};
|
||||
setItem: (key: string, value: string | number | boolean | Uint8Array) => {
|
||||
storage.set(key, value);
|
||||
},
|
||||
getItem: (key: string) => {
|
||||
const value = storage.getString(key);
|
||||
return value === undefined ? null : value;
|
||||
},
|
||||
removeItem: (key: string) => {
|
||||
storage.delete(key);
|
||||
},
|
||||
};
|
||||
|
||||
export const clientPersister = createSyncStoragePersister({ storage: clientStorage });
|
||||
|
||||
persistQueryClient({
|
||||
queryClient,
|
||||
persister: clientPersister
|
||||
});
|
||||
export const clientPersister = createSyncStoragePersister({
|
||||
storage: clientStorage,
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Capability } from "react-native-track-player";
|
||||
|
||||
export const CAPABILITIES: Capability[] = [
|
||||
Capability.Pause,
|
||||
Capability.Play,
|
||||
Capability.PlayFromId,
|
||||
Capability.SeekTo,
|
||||
// Capability.JumpForward,
|
||||
// Capability.JumpBackward,
|
||||
Capability.SkipToNext,
|
||||
Capability.SkipToPrevious,
|
||||
// Capability.Like,
|
||||
// Capability.Dislike
|
||||
]
|
||||
+2
-46
@@ -1,49 +1,5 @@
|
||||
import { QueryKeys } from "../../enums/query-keys"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import TrackPlayer, { Capability, IOSCategory, IOSCategoryOptions, RatingType } from "react-native-track-player"
|
||||
|
||||
const CAPABILITIES: Capability[] = [
|
||||
Capability.Pause,
|
||||
Capability.Play,
|
||||
Capability.PlayFromId,
|
||||
Capability.SeekTo,
|
||||
// Capability.JumpForward,
|
||||
// Capability.JumpBackward,
|
||||
Capability.SkipToNext,
|
||||
Capability.SkipToPrevious,
|
||||
// Capability.Like,
|
||||
// Capability.Dislike
|
||||
]
|
||||
|
||||
export const useSetupPlayer = () => useQuery({
|
||||
queryKey: [QueryKeys.Player],
|
||||
queryFn: async () => {
|
||||
await TrackPlayer.setupPlayer({
|
||||
autoHandleInterruptions: true,
|
||||
maxCacheSize: 1000 * 100, // 100MB, TODO make this adjustable
|
||||
iosCategory: IOSCategory.Playback,
|
||||
iosCategoryOptions: [
|
||||
IOSCategoryOptions.AllowAirPlay,
|
||||
IOSCategoryOptions.AllowBluetooth,
|
||||
]
|
||||
})
|
||||
return await TrackPlayer.updateOptions({
|
||||
progressUpdateEventInterval: 1,
|
||||
capabilities: CAPABILITIES,
|
||||
notificationCapabilities: CAPABILITIES,
|
||||
compactCapabilities: CAPABILITIES,
|
||||
// ratingType: RatingType.Heart,
|
||||
// likeOptions: {
|
||||
// isActive: false,
|
||||
// title: "Favorite"
|
||||
// },
|
||||
// dislikeOptions: {
|
||||
// isActive: true,
|
||||
// title: "Unfavorite"
|
||||
// }
|
||||
});
|
||||
}
|
||||
});
|
||||
import TrackPlayer, { RatingType } from "react-native-track-player"
|
||||
import { CAPABILITIES } from "../constants";
|
||||
|
||||
export const useUpdateOptions = async (isFavorite: boolean) => {
|
||||
return await TrackPlayer.updateOptions({
|
||||
|
||||
+8
-14
@@ -3,13 +3,13 @@ import { JellifyTrack } from "../types/JellifyTrack";
|
||||
import { storage } from "../constants/storage";
|
||||
import { MMKVStorageKeys } from "../enums/mmkv-storage-keys";
|
||||
import { findPlayNextIndexStart, findPlayQueueIndexStart } from "./helpers/index";
|
||||
import TrackPlayer, { Event, Progress, State, usePlaybackState, useProgress, useTrackPlayerEvents } from "react-native-track-player";
|
||||
import TrackPlayer, { Event, IOSCategory, IOSCategoryOptions, Progress, State, usePlaybackState, useProgress, useTrackPlayerEvents } from "react-native-track-player";
|
||||
import { isEqual, isUndefined } from "lodash";
|
||||
import { getPlaystateApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import { handlePlaybackProgressUpdated, handlePlaybackState } from "./handlers";
|
||||
import { useSetupPlayer, useUpdateOptions } from "../player/hooks";
|
||||
import { useUpdateOptions } from "../player/hooks";
|
||||
import { UPDATE_INTERVAL } from "./config";
|
||||
import { useMutation, UseMutationResult } from "@tanstack/react-query";
|
||||
import { useMutation, UseMutationResult, useQuery } from "@tanstack/react-query";
|
||||
import { mapDtoToTrack } from "../helpers/mappings";
|
||||
import { QueuingType } from "../enums/queuing-type";
|
||||
import { trigger } from "react-native-haptic-feedback";
|
||||
@@ -21,6 +21,8 @@ import { Section } from "../components/Player/types";
|
||||
import { Queue } from "./types/queue-item";
|
||||
import { markItemPlayed } from "../api/mutations/functions/item";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { QueryKeys } from "../enums/query-keys";
|
||||
import { CAPABILITIES } from "./constants";
|
||||
|
||||
interface PlayerContext {
|
||||
initialized: boolean;
|
||||
@@ -234,7 +236,7 @@ const PlayerContextInitializer = () => {
|
||||
//#endregion
|
||||
|
||||
//#region RNTP Setup
|
||||
const isPlayerReady = useSetupPlayer().isSuccess;
|
||||
|
||||
const { state: playbackState } = usePlaybackState();
|
||||
const progress = useProgress(UPDATE_INTERVAL);
|
||||
|
||||
@@ -298,21 +300,13 @@ const PlayerContextInitializer = () => {
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isPlayerReady)
|
||||
console.debug("Player is ready")
|
||||
else
|
||||
console.warn("Player could not be setup")
|
||||
}, [
|
||||
isPlayerReady
|
||||
])
|
||||
//#endregion RNTP Setup
|
||||
|
||||
//#region useEffects
|
||||
useEffect(() => {
|
||||
storage.set(MMKVStorageKeys.Queue, JSON.stringify(playQueue))
|
||||
storage.set(MMKVStorageKeys.Queue, JSON.stringify(queue))
|
||||
}, [
|
||||
playQueue
|
||||
queue
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
|
||||
export type Queue = BaseItemDto | "Recently Played" | "Queue";
|
||||
export type Queue = BaseItemDto | "Recently Played" | "Search" | "Favorite Tracks";
|
||||
Reference in New Issue
Block a user