This commit is contained in:
Fredrik Burmester
2024-09-01 17:10:33 +02:00
parent ffea51ccb0
commit 3d73f604ac
5 changed files with 88 additions and 10 deletions

View File

@@ -1,8 +1,10 @@
import { ItemImage } from "@/components/common/ItemImage";
import { Text } from "@/components/common/Text"; import { Text } from "@/components/common/Text";
import { TouchableItemRouter } from "@/components/common/TouchableItemRouter"; import { TouchableItemRouter } from "@/components/common/TouchableItemRouter";
import { FilterButton } from "@/components/filters/FilterButton"; import { FilterButton } from "@/components/filters/FilterButton";
import { ResetFiltersButton } from "@/components/filters/ResetFiltersButton"; import { ResetFiltersButton } from "@/components/filters/ResetFiltersButton";
import { ItemCardText } from "@/components/ItemCardText"; import { ItemCardText } from "@/components/ItemCardText";
import { ItemPoster } from "@/components/posters/ItemPoster";
import MoviePoster from "@/components/posters/MoviePoster"; import MoviePoster from "@/components/posters/MoviePoster";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider"; import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import { import {
@@ -194,7 +196,8 @@ const page: React.FC = () => {
width: "89%", width: "89%",
}} }}
> >
<MoviePoster item={item} /> <ItemPoster item={item} />
{/* <MoviePoster item={item} /> */}
<ItemCardText item={item} /> <ItemCardText item={item} />
</View> </View>
</MemoizedTouchableItemRouter> </MemoizedTouchableItemRouter>

View File

@@ -46,6 +46,7 @@ import { FlashList } from "@shopify/flash-list";
import { Loader } from "@/components/Loader"; import { Loader } from "@/components/Loader";
import { useSafeAreaInsets } from "react-native-safe-area-context"; import { useSafeAreaInsets } from "react-native-safe-area-context";
import { orientationAtom } from "@/utils/atoms/orientation"; import { orientationAtom } from "@/utils/atoms/orientation";
import { ItemPoster } from "@/components/posters/ItemPoster";
const MemoizedTouchableItemRouter = React.memo(TouchableItemRouter); const MemoizedTouchableItemRouter = React.memo(TouchableItemRouter);
@@ -208,7 +209,8 @@ const Page = () => {
width: "89%", width: "89%",
}} }}
> >
<MoviePoster item={item} /> {/* <MoviePoster item={item} /> */}
<ItemPoster item={item} />
<ItemCardText item={item} /> <ItemCardText item={item} />
</View> </View>
</MemoizedTouchableItemRouter> </MemoizedTouchableItemRouter>

View File

@@ -1,20 +1,31 @@
import { useImageColors } from "@/hooks/useImageColors"; import { useImageColors } from "@/hooks/useImageColors";
import { apiAtom } from "@/providers/JellyfinProvider"; import { apiAtom } from "@/providers/JellyfinProvider";
import { Ionicons } from "@expo/vector-icons";
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models"; import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { Image, ImageProps, ImageSource } from "expo-image"; import { Image, ImageProps, ImageSource } from "expo-image";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useMemo } from "react"; import { useMemo } from "react";
import { View } from "react-native";
interface Props extends ImageProps { interface Props extends ImageProps {
item: BaseItemDto; item: BaseItemDto;
variant?: "Backdrop" | "Primary" | "Thumb" | "Logo"; variant?:
| "Primary"
| "Backdrop"
| "ParentBackdrop"
| "ParentLogo"
| "Logo"
| "AlbumPrimary"
| "SeriesPrimary"
| "Screenshot"
| "Thumb";
quality?: number; quality?: number;
width?: number; width?: number;
} }
export const ItemImage: React.FC<Props> = ({ export const ItemImage: React.FC<Props> = ({
item, item,
variant, variant = "Primary",
quality = 90, quality = 90,
width = 1000, width = 1000,
...props ...props
@@ -28,6 +39,8 @@ export const ItemImage: React.FC<Props> = ({
let blurhash: string | null | undefined; let blurhash: string | null | undefined;
let src: ImageSource | null = null; let src: ImageSource | null = null;
console.log("ImageItem ~ " + variant, item.Name, item.ImageTags);
switch (variant) { switch (variant) {
case "Backdrop": case "Backdrop":
if (item.Type === "Episode") { if (item.Type === "Episode") {
@@ -35,7 +48,7 @@ export const ItemImage: React.FC<Props> = ({
if (!tag) break; if (!tag) break;
blurhash = item.ImageBlurHashes?.Backdrop?.[tag]; blurhash = item.ImageBlurHashes?.Backdrop?.[tag];
src = { src = {
uri: `${api.basePath}/Items/${item.ParentBackdropItemId}/Images/Backdrop/0?quality=${quality}&tag=${tag}`, uri: `${api.basePath}/Items/${item.ParentBackdropItemId}/Images/Backdrop/0?quality=${quality}&tag=${tag}&width=${width}`,
blurhash, blurhash,
}; };
break; break;
@@ -45,7 +58,7 @@ export const ItemImage: React.FC<Props> = ({
if (!tag) break; if (!tag) break;
blurhash = item.ImageBlurHashes?.Backdrop?.[tag]; blurhash = item.ImageBlurHashes?.Backdrop?.[tag];
src = { src = {
uri: `${api.basePath}/Items/${item.Id}/Images/Backdrop/0?quality=${quality}&tag=${tag}`, uri: `${api.basePath}/Items/${item.Id}/Images/Backdrop/0?quality=${quality}&tag=${tag}&width=${width}`,
blurhash, blurhash,
}; };
break; break;
@@ -55,7 +68,7 @@ export const ItemImage: React.FC<Props> = ({
blurhash = item.ImageBlurHashes?.Primary?.[tag]; blurhash = item.ImageBlurHashes?.Primary?.[tag];
src = { src = {
uri: `${api.basePath}/Items/${item.Id}/Images/Primary?quality=${quality}&tag=${tag}`, uri: `${api.basePath}/Items/${item.Id}/Images/Primary?quality=${quality}&tag=${tag}&width=${width}`,
blurhash, blurhash,
}; };
break; break;
@@ -65,29 +78,42 @@ export const ItemImage: React.FC<Props> = ({
blurhash = item.ImageBlurHashes?.Thumb?.[tag]; blurhash = item.ImageBlurHashes?.Thumb?.[tag];
src = { src = {
uri: `${api.basePath}/Items/${item.Id}/Images/Backdrop?quality=${quality}&tag=${tag}`, uri: `${api.basePath}/Items/${item.Id}/Images/Backdrop?quality=${quality}&tag=${tag}&width=${width}`,
blurhash, blurhash,
}; };
break; break;
default: default:
tag = item.ImageTags?.["Primary"]; tag = item.ImageTags?.["Primary"];
src = { src = {
uri: `${api.basePath}/Items/${item.Id}/Images/Primary?quality=${quality}&tag=${tag}`, uri: `${api.basePath}/Items/${item.Id}/Images/Primary?quality=${quality}&tag=${tag}&width=${width}`,
}; };
break; break;
} }
console.log("src: ", src?.uri?.slice(0, 30));
return src; return src;
}, [item.ImageTags]); }, [item.ImageTags]);
useImageColors(source?.uri); useImageColors(source?.uri);
// return placeholder icon if no source
if (!source?.uri) return;
<View {...props}>
<Ionicons name="image-outline" size={24} color="white" />;
</View>;
return ( return (
<Image <Image
cachePolicy={"memory-disk"}
transition={300} transition={300}
placeholder={{ placeholder={{
blurhash: source?.blurhash, blurhash: source?.blurhash,
}} }}
style={{
width: "100%",
height: "100%",
}}
source={{ source={{
uri: source?.uri, uri: source?.uri,
}} }}

View File

@@ -55,7 +55,7 @@ export const TouchableItemRouter: React.FC<PropsWithChildren<Props>> = ({
} }
if (item.Type === "UserView") { if (item.Type === "UserView") {
Alert.alert("Not implemented"); router.push(`/(auth)/(tabs)/${from}/collections/${item.Id}`);
return; return;
} }

View File

@@ -0,0 +1,47 @@
import { View, ViewProps } from "react-native";
import { Text } from "@/components/common/Text";
import {
BaseItemDto,
BaseItemKind,
} from "@jellyfin/sdk/lib/generated-client/models";
import { ItemImage } from "../common/ItemImage";
import { WatchedIndicator } from "../WatchedIndicator";
import { useState } from "react";
interface Props extends ViewProps {
item: BaseItemDto;
showProgress?: boolean;
}
export const ItemPoster: React.FC<Props> = ({
item,
showProgress,
...props
}) => {
const [progress, setProgress] = useState(
item.UserData?.PlayedPercentage || 0
);
if (item.Type === "Movie" || item.Type === "Series" || item.Type === "BoxSet")
return (
<View className="relative rounded-lg overflow-hidden border border-neutral-900">
<ItemImage
style={{
aspectRatio: "10/15",
width: "100%",
}}
item={item}
/>
<WatchedIndicator item={item} />
{showProgress && progress > 0 && (
<View className="h-1 bg-red-600 w-full"></View>
)}
</View>
);
return (
<View className="rounded-lg w-full aspect-square overflow-hidden border border-neutral-900">
<ItemImage className="w-full aspect-square" item={item} />
</View>
);
};