diff --git a/api/queries/functions/images.ts b/api/queries/functions/images.ts index e036deff..7991ff74 100644 --- a/api/queries/functions/images.ts +++ b/api/queries/functions/images.ts @@ -3,6 +3,7 @@ import { ImageFormat, ImageType } from "@jellyfin/sdk/lib/generated-client/model import { getImageApi } from "@jellyfin/sdk/lib/utils/api" import _ from "lodash" import { queryConfig } from "../query.config" +import Client from "@/api/client" @@ -26,35 +27,18 @@ export function fetchImage(api: Api, itemId: string, imageType?: ImageType) : Pr }); } - -export function fetchArtistImage(api: Api, artistId: string, imageType?: ImageType) : Promise { - return new Promise(async (resolve, reject) => { - let response = await getImageApi(api).getArtistImage({ - name: "", - imageIndex: 1, - imageType: imageType ? imageType : ImageType.Primary - }) - - console.log(response.data) - - if (_.isEmpty(response.data)) - reject(new Error("No image for artist")) - - resolve(convertFileToBase64(response.data)); - }); -} - -export function fetchItemImage(api: Api, itemId: string, imageType?: ImageType, width?: number) { +export function fetchItemImage(itemId: string, imageType?: ImageType, width?: number) { - return getImageApi(api).getItemImage({ - itemId, - imageType: imageType ? imageType : ImageType.Primary, - format: ImageFormat.Jpg - }) - .then((response) => { - console.log(convertFileToBase64(response.data)) - return convertFileToBase64(response.data); - }) + return getImageApi(Client.api!) + .getItemImage({ + itemId, + imageType: imageType ? imageType : ImageType.Primary, + format: ImageFormat.Jpg + }) + .then((response) => { + console.log(convertFileToBase64(response.data)) + return convertFileToBase64(response.data); + }); } function base64toJpeg(encode: string) : string { diff --git a/api/queries/image.ts b/api/queries/image.ts index 6ef05d09..4db62e82 100644 --- a/api/queries/image.ts +++ b/api/queries/image.ts @@ -1,20 +1,9 @@ import { useQuery } from "@tanstack/react-query"; import { QueryKeys } from "../../enums/query-keys"; -import { Api } from "@jellyfin/sdk"; -import { fetchArtistImage, fetchImage, fetchItemImage } from "./functions/images"; +import { fetchItemImage } from "./functions/images"; import { ImageType } from "@jellyfin/sdk/lib/generated-client/models"; -export const useImage = (api: Api, itemId: string, imageType?: ImageType) => useQuery({ - queryKey: [QueryKeys.ItemImage, api, itemId, imageType], - queryFn: ({ queryKey }) => fetchImage(queryKey[1] as Api, queryKey[2] as string, queryKey[3] as ImageType | undefined) -}); - -export const useArtistImage = (api: Api, artistName: string, imageType?: ImageType) => useQuery({ - queryKey: [QueryKeys.ArtistImage, api, artistName, imageType], - queryFn: ({ queryKey }) => fetchArtistImage(queryKey[1] as Api, queryKey[2] as string, queryKey[3] as ImageType | undefined) -}) - -export const useItemImage = (api: Api, itemId: string, imageType?: ImageType, width?: number) => useQuery({ - queryKey: [QueryKeys.ItemImage, api, itemId, imageType, width], - queryFn: ({ queryKey }) => fetchItemImage(queryKey[1] as Api, queryKey[2] as string, queryKey[3] as ImageType | undefined, queryKey[4] as number | undefined) +export const useItemImage = (itemId: string, imageType?: ImageType, width?: number) => useQuery({ + queryKey: [QueryKeys.ItemImage, itemId, imageType, width], + queryFn: () => fetchItemImage(itemId, imageType, width) }); \ No newline at end of file diff --git a/components/Favorites/component.tsx b/components/Favorites/component.tsx index e69c56ea..c0cc55a3 100644 --- a/components/Favorites/component.tsx +++ b/components/Favorites/component.tsx @@ -96,7 +96,7 @@ export default function Library(): React.JSX.Element { name="Details" component={DetailsScreen} options={{ - headerTitle: "", + headerShown: false, presentation: "modal" }} /> diff --git a/components/Global/helpers/blurhash-loading.tsx b/components/Global/helpers/blurhash-loading.tsx deleted file mode 100644 index 9ab5353b..00000000 --- a/components/Global/helpers/blurhash-loading.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import Client from "../../../api/client"; -import { useItemImage } from "../../../api/queries/image"; -import { Blurhash } from "react-native-blurhash"; -import { Image, View } from "tamagui"; - -interface BlurhashLoadingProps { - itemId: string; - blurhash: string; - size: number -} - -export default function BlurhashLoading(props: BlurhashLoadingProps) : React.JSX.Element { - - const { data: image, isSuccess } = useItemImage(Client.api!, props.itemId); - - return ( - - - { isSuccess ? ( - - ) : ( - - ) - } - - ) -} \ No newline at end of file diff --git a/components/Global/helpers/blurhashed-image.tsx b/components/Global/helpers/blurhashed-image.tsx new file mode 100644 index 00000000..65a0538a --- /dev/null +++ b/components/Global/helpers/blurhashed-image.tsx @@ -0,0 +1,38 @@ +import { BaseItemDto, ImageType } from "@jellyfin/sdk/lib/generated-client/models"; +import { useItemImage } from "../../../api/queries/image"; +import { Blurhash } from "react-native-blurhash"; +import { Image, View } from "tamagui"; +import { isEmpty } from "lodash"; + +interface BlurhashLoadingProps { + item: BaseItemDto; + size: number +} + +export default function BlurhashedImage({ item, size, type }: { item: BaseItemDto, size: number, type?: ImageType }) : React.JSX.Element { + + const { data: image, isSuccess } = useItemImage(item.Id!, type); + + const blurhash = !isEmpty(item.ImageBlurHashes) + && !isEmpty(item.ImageBlurHashes.Primary) + ? Object.values(item.ImageBlurHashes.Primary)[0] + : undefined; + + return ( + + + { isSuccess ? ( + + ) : blurhash && ( + + ) + } + + ) +} \ No newline at end of file diff --git a/components/Home/component.tsx b/components/Home/component.tsx index 33147b16..a7f48c5c 100644 --- a/components/Home/component.tsx +++ b/components/Home/component.tsx @@ -69,7 +69,7 @@ export default function Home(): React.JSX.Element { name="Details" component={DetailsScreen} options={{ - headerTitle: "", + headerShown: false, presentation: "modal" }} /> diff --git a/components/ItemDetail/component.tsx b/components/ItemDetail/component.tsx index c7ef0c15..9b9a36f8 100644 --- a/components/ItemDetail/component.tsx +++ b/components/ItemDetail/component.tsx @@ -1,9 +1,12 @@ import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; import { NativeStackNavigationProp } from "@react-navigation/native-stack"; -import { SafeAreaView } from "react-native-safe-area-context"; +import { SafeAreaView, useSafeAreaFrame } from "react-native-safe-area-context"; import { StackParamList } from "../types"; import TrackOptions from "./helpers/TrackOptions"; -import { View } from "tamagui"; +import { View, XStack, YStack } from "tamagui"; +import BlurhashedImage from "../Global/helpers/blurhashed-image"; +import { Text } from "../Global/helpers/text"; +import { Colors } from "@/enums/colors"; export default function ItemDetail({ item, @@ -15,6 +18,8 @@ export default function ItemDetail({ let options: React.JSX.Element | undefined = undefined; + const { width } = useSafeAreaFrame(); + switch (item.Type) { case "Audio": { options = TrackOptions({ item, navigation }); @@ -43,7 +48,39 @@ export default function ItemDetail({ return ( - + + + + + + { item.Name ?? "Untitled Track" } + + + { + if (item.ArtistItems) { + navigation.navigate("Artist", { + artist: item.ArtistItems[0] + }); + } + }}> + { item.Artists?.join(", ") ?? "Unknown Artist"} + + + + { item.Album ?? "" } + + + + { options ?? } ) diff --git a/components/ItemDetail/helpers/TrackOptions.tsx b/components/ItemDetail/helpers/TrackOptions.tsx index 42fcfe11..3c22740b 100644 --- a/components/ItemDetail/helpers/TrackOptions.tsx +++ b/components/ItemDetail/helpers/TrackOptions.tsx @@ -1,4 +1,4 @@ -import { StackParamList } from "../../components/types"; +import { StackParamList } from "../../../components/types"; import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { View } from "tamagui"; diff --git a/components/Player/component.tsx b/components/Player/stack.tsx similarity index 97% rename from components/Player/component.tsx rename to components/Player/stack.tsx index d6c5909c..05ced874 100644 --- a/components/Player/component.tsx +++ b/components/Player/stack.tsx @@ -35,7 +35,7 @@ export default function Player({ navigation }: { navigation: NativeStackNavigati name="Details" component={DetailsScreen} options={{ - headerTitle: "" + headerShown: false }} /> diff --git a/components/Settings/screens/account-details.tsx b/components/Settings/screens/account-details.tsx new file mode 100644 index 00000000..12940e7a --- /dev/null +++ b/components/Settings/screens/account-details.tsx @@ -0,0 +1,13 @@ +import { StackParamList } from "@/components/types"; +import { NativeStackNavigationProp } from "@react-navigation/native-stack"; + +export default function AccountDetails({ + navigation +} : { + navigation: NativeStackNavigationProp + }) : React.JSX.Element { + + return ( + + ) + } \ No newline at end of file diff --git a/components/Settings/screens/root.tsx b/components/Settings/screens/root.tsx index 05461b83..ee5d1f0b 100644 --- a/components/Settings/screens/root.tsx +++ b/components/Settings/screens/root.tsx @@ -1,17 +1,41 @@ import React from "react"; import { SafeAreaView } from "react-native"; -import { ScrollView, Separator } from "tamagui"; +import { ListItem, ScrollView, Separator, YGroup } from "tamagui"; import AccountDetails from "../helpers/account-details"; import SignOut from "../helpers/sign-out"; import ServerDetails from "../helpers/server-details"; import LibraryDetails from "../helpers/library-details"; +import { NativeStackNavigationProp } from "@react-navigation/native-stack"; +import { StackParamList } from "@/components/types"; + +export default function Root({ + navigation +}: { + navigation: NativeStackNavigationProp +}) : React.JSX.Element { -export default function Root() : React.JSX.Element { return ( - - + + + { + navigation.push("AccountDetails") + }} + /> + + + diff --git a/components/Settings/component.tsx b/components/Settings/stack.tsx similarity index 63% rename from components/Settings/component.tsx rename to components/Settings/stack.tsx index b823bd9a..f8038b0d 100644 --- a/components/Settings/component.tsx +++ b/components/Settings/stack.tsx @@ -1,6 +1,7 @@ import React from "react"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import Root from "./screens/root"; +import AccountDetails from "./screens/account-details"; export const SettingsStack = createNativeStackNavigator(); @@ -18,6 +19,17 @@ export default function Settings(): React.JSX.Element { } }} /> + + ) } \ No newline at end of file diff --git a/components/navigation.tsx b/components/navigation.tsx index 02797277..8de6733a 100644 --- a/components/navigation.tsx +++ b/components/navigation.tsx @@ -1,5 +1,5 @@ import { createNativeStackNavigator } from "@react-navigation/native-stack"; -import Player from "./Player/component"; +import Player from "./Player/stack"; import { Tabs } from "./tabs"; import { StackParamList } from "./types"; diff --git a/components/tabs.tsx b/components/tabs.tsx index 25a9c109..c0736334 100644 --- a/components/tabs.tsx +++ b/components/tabs.tsx @@ -6,7 +6,7 @@ import { useColorScheme } from "react-native"; import { Colors } from "../enums/colors"; import Search from "./Search/component"; import Favorites from "./Favorites/component"; -import Settings from "./Settings/component"; +import Settings from "./Settings/stack"; import { Discover } from "./Discover/component"; import { Miniplayer } from "./Player/mini-player"; import { Separator } from "tamagui"; diff --git a/components/types.tsx b/components/types.tsx index 8a75975b..749143f6 100644 --- a/components/types.tsx +++ b/components/types.tsx @@ -4,18 +4,26 @@ import { NativeStackScreenProps } from "@react-navigation/native-stack"; export type StackParamList = { Home: undefined; + Discover: undefined; - Favorites: undefined, - Artists: undefined, - Albums: undefined, - Tracks: undefined, - Genres: undefined, - Playlists: undefined, - Search: undefined, - Settings: undefined, - Tabs: undefined, - Player: undefined, - Queue: undefined, + + Favorites: undefined; + Artists: undefined; + Albums: undefined; + Tracks: undefined; + Genres: undefined; + Playlists: undefined; + + Search: undefined; + + Settings: undefined; + AccountDetails: undefined; + + Tabs: undefined; + + Player: undefined; + Queue: undefined; + Artist: { artist: BaseItemDto }; @@ -56,4 +64,6 @@ export type TracksProps = NativeStackScreenProps; export type GenresProps = NativeStackScreenProps; -export type DetailsProps = NativeStackScreenProps; \ No newline at end of file +export type DetailsProps = NativeStackScreenProps; + +export type AccountDetailsProps = NativeStackScreenProps; \ No newline at end of file