mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-03-04 16:56:16 +00:00
141 lines
3.8 KiB
TypeScript
141 lines
3.8 KiB
TypeScript
import { Ionicons } from "@expo/vector-icons";
|
|
import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
|
import { BlurView } from "expo-blur";
|
|
import { Image } from "expo-image";
|
|
import { useAtomValue } from "jotai";
|
|
import React, { useMemo } from "react";
|
|
import { Dimensions, View } from "react-native";
|
|
import { Badge } from "@/components/Badge";
|
|
import { Text } from "@/components/common/Text";
|
|
import { GenreTags } from "@/components/GenreTags";
|
|
import { useScaledTVTypography } from "@/constants/TVTypography";
|
|
import { apiAtom } from "@/providers/JellyfinProvider";
|
|
import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById";
|
|
|
|
const { width: SCREEN_WIDTH } = Dimensions.get("window");
|
|
|
|
interface TVSeriesHeaderProps {
|
|
item: BaseItemDto;
|
|
}
|
|
|
|
export const TVSeriesHeader: React.FC<TVSeriesHeaderProps> = ({ item }) => {
|
|
const typography = useScaledTVTypography();
|
|
const api = useAtomValue(apiAtom);
|
|
|
|
const logoUrl = useMemo(() => {
|
|
if (!api || !item) return null;
|
|
return getLogoImageUrlById({ api, item });
|
|
}, [api, item]);
|
|
|
|
const yearString = useMemo(() => {
|
|
const startYear = item.StartDate
|
|
? new Date(item.StartDate).getFullYear()
|
|
: item.ProductionYear;
|
|
|
|
const endYear = item.EndDate ? new Date(item.EndDate).getFullYear() : null;
|
|
|
|
if (startYear && endYear) {
|
|
if (startYear === endYear) return String(startYear);
|
|
return `${startYear} - ${endYear}`;
|
|
}
|
|
if (startYear) return String(startYear);
|
|
return null;
|
|
}, [item.StartDate, item.EndDate, item.ProductionYear]);
|
|
|
|
return (
|
|
<View style={{ flex: 1, justifyContent: "center" }}>
|
|
{/* Logo or Title */}
|
|
{logoUrl ? (
|
|
<Image
|
|
source={{ uri: logoUrl }}
|
|
style={{
|
|
height: 100,
|
|
width: "80%",
|
|
marginBottom: 24,
|
|
}}
|
|
contentFit='contain'
|
|
contentPosition='left'
|
|
/>
|
|
) : (
|
|
<Text
|
|
style={{
|
|
fontSize: typography.display,
|
|
fontWeight: "bold",
|
|
color: "#FFFFFF",
|
|
marginBottom: 16,
|
|
}}
|
|
numberOfLines={2}
|
|
>
|
|
{item.Name}
|
|
</Text>
|
|
)}
|
|
|
|
{/* Metadata badges row */}
|
|
<View
|
|
style={{
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
flexWrap: "wrap",
|
|
gap: 12,
|
|
marginBottom: 20,
|
|
}}
|
|
>
|
|
{yearString && (
|
|
<Text style={{ color: "white", fontSize: typography.body }}>
|
|
{yearString}
|
|
</Text>
|
|
)}
|
|
{item.OfficialRating && (
|
|
<Badge text={item.OfficialRating} variant='gray' />
|
|
)}
|
|
{item.CommunityRating != null && (
|
|
<Badge
|
|
text={item.CommunityRating.toFixed(1)}
|
|
variant='gray'
|
|
iconLeft={<Ionicons name='star' size={16} color='gold' />}
|
|
/>
|
|
)}
|
|
</View>
|
|
|
|
{/* Genres */}
|
|
{item.Genres && item.Genres.length > 0 && (
|
|
<View style={{ marginBottom: 24 }}>
|
|
<GenreTags genres={item.Genres} />
|
|
</View>
|
|
)}
|
|
|
|
{/* Overview */}
|
|
{item.Overview && (
|
|
<BlurView
|
|
intensity={10}
|
|
tint='light'
|
|
style={{
|
|
borderRadius: 8,
|
|
overflow: "hidden",
|
|
maxWidth: SCREEN_WIDTH * 0.45,
|
|
alignSelf: "flex-start",
|
|
}}
|
|
>
|
|
<View
|
|
style={{
|
|
padding: 16,
|
|
backgroundColor: "rgba(0,0,0,0.3)",
|
|
}}
|
|
>
|
|
<Text
|
|
style={{
|
|
fontSize: typography.body,
|
|
color: "#E5E7EB",
|
|
lineHeight: 32,
|
|
}}
|
|
numberOfLines={4}
|
|
>
|
|
{item.Overview}
|
|
</Text>
|
|
</View>
|
|
</BlurView>
|
|
)}
|
|
</View>
|
|
);
|
|
};
|