mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-07-13 16:02:55 +01:00
fix: navigatte to item
Some checks failed
🤖 Android APK Build (Phone + TV) / 🏗️ Build Android APK (phone) (push) Has been cancelled
🤖 Android APK Build (Phone + TV) / 🏗️ Build Android APK (tv) (push) Has been cancelled
🤖 iOS IPA Build (Phone + TV) / 🏗️ Build iOS IPA (phone) (push) Has been cancelled
🔒 Lockfile Consistency Check / 🔍 Check bun.lock and package.json consistency (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (actions) (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (javascript-typescript) (push) Has been cancelled
🏷️🔀Merge Conflict Labeler / 🏷️ Labeling Merge Conflicts (push) Has been cancelled
🚦 Security & Quality Gate / 🚑 Expo Doctor Check (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (check) (push) Has been cancelled
🚦 Security & Quality Gate / 📝 Validate PR Title (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Vulnerable Dependencies (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (format) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (lint) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (typecheck) (push) Has been cancelled
Some checks failed
🤖 Android APK Build (Phone + TV) / 🏗️ Build Android APK (phone) (push) Has been cancelled
🤖 Android APK Build (Phone + TV) / 🏗️ Build Android APK (tv) (push) Has been cancelled
🤖 iOS IPA Build (Phone + TV) / 🏗️ Build iOS IPA (phone) (push) Has been cancelled
🔒 Lockfile Consistency Check / 🔍 Check bun.lock and package.json consistency (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (actions) (push) Has been cancelled
🛡️ CodeQL Analysis / 🔎 Analyze with CodeQL (javascript-typescript) (push) Has been cancelled
🏷️🔀Merge Conflict Labeler / 🏷️ Labeling Merge Conflicts (push) Has been cancelled
🚦 Security & Quality Gate / 🚑 Expo Doctor Check (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (check) (push) Has been cancelled
🚦 Security & Quality Gate / 📝 Validate PR Title (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Vulnerable Dependencies (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (format) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (lint) (push) Has been cancelled
🚦 Security & Quality Gate / 🔍 Lint & Test (typecheck) (push) Has been cancelled
This commit is contained in:
@@ -7,9 +7,10 @@ import {
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { Image } from "expo-image";
|
import { Image } from "expo-image";
|
||||||
import { LinearGradient } from "expo-linear-gradient";
|
import { LinearGradient } from "expo-linear-gradient";
|
||||||
|
import { useRouter } from "expo-router";
|
||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { Dimensions, Pressable, View } from "react-native";
|
import { Dimensions, Pressable, TouchableOpacity, View } from "react-native";
|
||||||
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
||||||
import Animated, {
|
import Animated, {
|
||||||
Easing,
|
Easing,
|
||||||
@@ -25,6 +26,7 @@ import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
|
|||||||
import { useSettings } from "@/utils/atoms/settings";
|
import { useSettings } from "@/utils/atoms/settings";
|
||||||
import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById";
|
import { getLogoImageUrlById } from "@/utils/jellyfin/image/getLogoImageUrlById";
|
||||||
import { ItemImage } from "./common/ItemImage";
|
import { ItemImage } from "./common/ItemImage";
|
||||||
|
import { getItemNavigation } from "./common/TouchableItemRouter";
|
||||||
import type { SelectedOptions } from "./ItemContent";
|
import type { SelectedOptions } from "./ItemContent";
|
||||||
import { PlayButton } from "./PlayButton";
|
import { PlayButton } from "./PlayButton";
|
||||||
import { PlayedStatus } from "./PlayedStatus";
|
import { PlayedStatus } from "./PlayedStatus";
|
||||||
@@ -150,6 +152,7 @@ export const AppleTVCarousel: React.FC<AppleTVCarouselProps> = ({
|
|||||||
const api = useAtomValue(apiAtom);
|
const api = useAtomValue(apiAtom);
|
||||||
const user = useAtomValue(userAtom);
|
const user = useAtomValue(userAtom);
|
||||||
const { isConnected, serverConnected } = useNetworkStatus();
|
const { isConnected, serverConnected } = useNetworkStatus();
|
||||||
|
const router = useRouter();
|
||||||
const [currentIndex, setCurrentIndex] = useState(initialIndex);
|
const [currentIndex, setCurrentIndex] = useState(initialIndex);
|
||||||
const translateX = useSharedValue(-currentIndex * screenWidth);
|
const translateX = useSharedValue(-currentIndex * screenWidth);
|
||||||
|
|
||||||
@@ -301,6 +304,14 @@ export const AppleTVCarousel: React.FC<AppleTVCarouselProps> = ({
|
|||||||
[hasItems, items, onItemChange, translateX],
|
[hasItems, items, onItemChange, translateX],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const navigateToItem = useCallback(
|
||||||
|
(item: BaseItemDto) => {
|
||||||
|
const navigation = getItemNavigation(item, "(home)");
|
||||||
|
router.push(navigation as any);
|
||||||
|
},
|
||||||
|
[router],
|
||||||
|
);
|
||||||
|
|
||||||
const panGesture = Gesture.Pan()
|
const panGesture = Gesture.Pan()
|
||||||
.activeOffsetX([-PAN_ACTIVE_OFFSET, PAN_ACTIVE_OFFSET])
|
.activeOffsetX([-PAN_ACTIVE_OFFSET, PAN_ACTIVE_OFFSET])
|
||||||
.onUpdate((event) => {
|
.onUpdate((event) => {
|
||||||
@@ -591,7 +602,8 @@ export const AppleTVCarousel: React.FC<AppleTVCarouselProps> = ({
|
|||||||
|
|
||||||
{/* Logo Section */}
|
{/* Logo Section */}
|
||||||
{itemLogoUrl && (
|
{itemLogoUrl && (
|
||||||
<View
|
<TouchableOpacity
|
||||||
|
onPress={() => navigateToItem(item)}
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
bottom: LOGO_BOTTOM_POSITION,
|
bottom: LOGO_BOTTOM_POSITION,
|
||||||
@@ -611,7 +623,7 @@ export const AppleTVCarousel: React.FC<AppleTVCarouselProps> = ({
|
|||||||
}}
|
}}
|
||||||
contentFit='contain'
|
contentFit='contain'
|
||||||
/>
|
/>
|
||||||
</View>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Type and Genres Section */}
|
{/* Type and Genres Section */}
|
||||||
@@ -625,41 +637,56 @@ export const AppleTVCarousel: React.FC<AppleTVCarouselProps> = ({
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Animated.Text
|
<TouchableOpacity onPress={() => navigateToItem(item)}>
|
||||||
style={{
|
<Animated.Text
|
||||||
color: `rgba(255, 255, 255, ${TEXT_OPACITY})`,
|
style={{
|
||||||
fontSize: GENRES_FONT_SIZE,
|
color: `rgba(255, 255, 255, ${TEXT_OPACITY})`,
|
||||||
fontWeight: "500",
|
fontSize: GENRES_FONT_SIZE,
|
||||||
textAlign: "center",
|
fontWeight: "500",
|
||||||
textShadowColor: TEXT_SHADOW_COLOR,
|
textAlign: "center",
|
||||||
textShadowOffset: { width: 0, height: 1 },
|
textShadowColor: TEXT_SHADOW_COLOR,
|
||||||
textShadowRadius: TEXT_SHADOW_RADIUS,
|
textShadowOffset: { width: 0, height: 1 },
|
||||||
}}
|
textShadowRadius: TEXT_SHADOW_RADIUS,
|
||||||
>
|
}}
|
||||||
{(() => {
|
>
|
||||||
const typeLabel =
|
{(() => {
|
||||||
item.Type === "Series"
|
let typeLabel = "";
|
||||||
? "TV Show"
|
|
||||||
: item.Type === "Movie"
|
|
||||||
? "Movie"
|
|
||||||
: item.Type || "";
|
|
||||||
|
|
||||||
const genres =
|
if (item.Type === "Episode") {
|
||||||
item.Genres && item.Genres.length > 0
|
// For episodes, show season and episode number
|
||||||
? item.Genres.slice(0, MAX_GENRES_COUNT).join(" • ")
|
const season = item.ParentIndexNumber;
|
||||||
: "";
|
const episode = item.IndexNumber;
|
||||||
|
if (season && episode) {
|
||||||
|
typeLabel = `S${season} • E${episode}`;
|
||||||
|
} else {
|
||||||
|
typeLabel = "Episode";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
typeLabel =
|
||||||
|
item.Type === "Series"
|
||||||
|
? "TV Show"
|
||||||
|
: item.Type === "Movie"
|
||||||
|
? "Movie"
|
||||||
|
: item.Type || "";
|
||||||
|
}
|
||||||
|
|
||||||
if (typeLabel && genres) {
|
const genres =
|
||||||
return `${typeLabel} • ${genres}`;
|
item.Genres && item.Genres.length > 0
|
||||||
} else if (typeLabel) {
|
? item.Genres.slice(0, MAX_GENRES_COUNT).join(" • ")
|
||||||
return typeLabel;
|
: "";
|
||||||
} else if (genres) {
|
|
||||||
return genres;
|
if (typeLabel && genres) {
|
||||||
} else {
|
return `${typeLabel} • ${genres}`;
|
||||||
return "";
|
} else if (typeLabel) {
|
||||||
}
|
return typeLabel;
|
||||||
})()}
|
} else if (genres) {
|
||||||
</Animated.Text>
|
return genres;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
</Animated.Text>
|
||||||
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Controls Section */}
|
{/* Controls Section */}
|
||||||
|
|||||||
Reference in New Issue
Block a user