mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-03-06 09:46:17 +00:00
wip
This commit is contained in:
4
app.json
4
app.json
@@ -36,6 +36,10 @@
|
||||
"icon": "./assets/images/icon-ios-liquid-glass.icon",
|
||||
"appleTeamId": "MWD5K362T8"
|
||||
},
|
||||
"tvos": {
|
||||
"icon": "./assets/images/icon.png",
|
||||
"bundleIdentifier": "com.fredrikburmester.streamyfin"
|
||||
},
|
||||
"android": {
|
||||
"jsEngine": "hermes",
|
||||
"versionCode": 92,
|
||||
|
||||
@@ -9,8 +9,8 @@ export const ItemContentSkeletonTV: React.FC = () => {
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
paddingTop: 140,
|
||||
paddingHorizontal: 80,
|
||||
paddingTop: 180,
|
||||
paddingHorizontal: 160,
|
||||
}}
|
||||
>
|
||||
{/* Left side - Poster placeholder */}
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
useInfiniteQuery,
|
||||
} from "@tanstack/react-query";
|
||||
import { useSegments } from "expo-router";
|
||||
import { useCallback, useEffect, useMemo, useRef } from "react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
ActivityIndicator,
|
||||
@@ -95,6 +95,27 @@ export const InfiniteScrollingCollectionList: React.FC<Props> = ({
|
||||
const segments = useSegments();
|
||||
const from = (segments as string[])[2] || "(home)";
|
||||
|
||||
// Track focus within section and scroll back to start when leaving
|
||||
const flatListRef = useRef<FlatList<BaseItemDto>>(null);
|
||||
const [focusedCount, setFocusedCount] = useState(0);
|
||||
const prevFocusedCount = useRef(0);
|
||||
|
||||
// When section loses all focus, scroll back to start
|
||||
useEffect(() => {
|
||||
if (prevFocusedCount.current > 0 && focusedCount === 0) {
|
||||
flatListRef.current?.scrollToOffset({ offset: 0, animated: true });
|
||||
}
|
||||
prevFocusedCount.current = focusedCount;
|
||||
}, [focusedCount]);
|
||||
|
||||
const handleItemFocus = useCallback(() => {
|
||||
setFocusedCount((c) => c + 1);
|
||||
}, []);
|
||||
|
||||
const handleItemBlur = useCallback(() => {
|
||||
setFocusedCount((c) => Math.max(0, c - 1));
|
||||
}, []);
|
||||
|
||||
const {
|
||||
data,
|
||||
isLoading,
|
||||
@@ -229,6 +250,8 @@ export const InfiniteScrollingCollectionList: React.FC<Props> = ({
|
||||
<TVFocusablePoster
|
||||
onPress={() => handleItemPress(item)}
|
||||
hasTVPreferredFocus={isFirstItem}
|
||||
onFocus={handleItemFocus}
|
||||
onBlur={handleItemBlur}
|
||||
>
|
||||
{renderPoster()}
|
||||
</TVFocusablePoster>
|
||||
@@ -236,7 +259,14 @@ export const InfiniteScrollingCollectionList: React.FC<Props> = ({
|
||||
</View>
|
||||
);
|
||||
},
|
||||
[orientation, isFirstSection, itemWidth, handleItemPress],
|
||||
[
|
||||
orientation,
|
||||
isFirstSection,
|
||||
itemWidth,
|
||||
handleItemPress,
|
||||
handleItemFocus,
|
||||
handleItemBlur,
|
||||
],
|
||||
);
|
||||
|
||||
if (hideIfEmpty === true && allItems.length === 0 && !isLoading) return null;
|
||||
@@ -310,6 +340,7 @@ export const InfiniteScrollingCollectionList: React.FC<Props> = ({
|
||||
</View>
|
||||
) : (
|
||||
<FlatList
|
||||
ref={flatListRef}
|
||||
horizontal
|
||||
data={allItems}
|
||||
keyExtractor={(item) => item.Id!}
|
||||
|
||||
@@ -8,6 +8,8 @@ interface TVFocusablePosterProps {
|
||||
glowColor?: "white" | "purple";
|
||||
scaleAmount?: number;
|
||||
style?: ViewStyle;
|
||||
onFocus?: () => void;
|
||||
onBlur?: () => void;
|
||||
}
|
||||
|
||||
export const TVFocusablePoster: React.FC<TVFocusablePosterProps> = ({
|
||||
@@ -17,6 +19,8 @@ export const TVFocusablePoster: React.FC<TVFocusablePosterProps> = ({
|
||||
glowColor = "white",
|
||||
scaleAmount = 1.05,
|
||||
style,
|
||||
onFocus: onFocusProp,
|
||||
onBlur: onBlurProp,
|
||||
}) => {
|
||||
const [focused, setFocused] = useState(false);
|
||||
const scale = useRef(new Animated.Value(1)).current;
|
||||
@@ -37,10 +41,12 @@ export const TVFocusablePoster: React.FC<TVFocusablePosterProps> = ({
|
||||
onFocus={() => {
|
||||
setFocused(true);
|
||||
animateTo(scaleAmount);
|
||||
onFocusProp?.();
|
||||
}}
|
||||
onBlur={() => {
|
||||
setFocused(false);
|
||||
animateTo(1);
|
||||
onBlurProp?.();
|
||||
}}
|
||||
hasTVPreferredFocus={hasTVPreferredFocus}
|
||||
>
|
||||
|
||||
17
eas.json
17
eas.json
@@ -43,6 +43,13 @@
|
||||
"EXPO_PUBLIC_WRITE_DEBUG": "1"
|
||||
}
|
||||
},
|
||||
"preview_tv": {
|
||||
"distribution": "internal",
|
||||
"env": {
|
||||
"EXPO_TV": "1",
|
||||
"EXPO_PUBLIC_WRITE_DEBUG": "1"
|
||||
}
|
||||
},
|
||||
"production": {
|
||||
"environment": "production",
|
||||
"channel": "0.52.0",
|
||||
@@ -68,9 +75,17 @@
|
||||
"env": {
|
||||
"EXPO_TV": "1"
|
||||
}
|
||||
},
|
||||
"production_tv": {
|
||||
"environment": "production",
|
||||
"channel": "0.52.0",
|
||||
"env": {
|
||||
"EXPO_TV": "1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"submit": {
|
||||
"production": {}
|
||||
"production": {},
|
||||
"production_tv": {}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user