feat(tv): fix home page loading skeletons and initialize auth/network status synchronously

This commit is contained in:
Fredrik Burmester
2026-05-27 10:40:48 +02:00
parent 05d9b8f32c
commit 82eaf62354
8 changed files with 265 additions and 45 deletions

View File

@@ -37,7 +37,11 @@ import useRouter from "@/hooks/useAppRouter";
import { useNetworkStatus } from "@/hooks/useNetworkStatus";
import { useInvalidatePlaybackProgressCache } from "@/hooks/useRevalidatePlaybackProgressCache";
import { useTVItemActionModal } from "@/hooks/useTVItemActionModal";
import { apiAtom, userAtom } from "@/providers/JellyfinProvider";
import {
apiAtom,
cacheVersionAtom,
userAtom,
} from "@/providers/JellyfinProvider";
import { useSettings } from "@/utils/atoms/settings";
import { getBackdropUrl } from "@/utils/jellyfin/image/getBackdropUrl";
import { scaleSize } from "@/utils/scaleSize";
@@ -69,6 +73,7 @@ export const Home = () => {
const { t } = useTranslation();
const api = useAtomValue(apiAtom);
const user = useAtomValue(userAtom);
const cacheVersion = useAtomValue(cacheVersionAtom);
const insets = useSafeAreaInsets();
const { settings } = useSettings();
const scrollRef = useRef<ScrollView>(null);
@@ -669,7 +674,7 @@ export const Home = () => {
);
return (
<View style={{ flex: 1, backgroundColor: "#000000" }}>
<View key={cacheVersion} style={{ flex: 1, backgroundColor: "#000000" }}>
{/* Dynamic backdrop with crossfade - only shown when hero is disabled */}
{!showHero && settings.showHomeBackdrop && (
<View

View File

@@ -27,7 +27,7 @@ import { SortByOption, SortOrderOption } from "@/utils/atoms/filters";
import { scaleSize } from "@/utils/scaleSize";
// Extra padding to accommodate scale animation (1.05x) and glow shadow
const SCALE_PADDING = scaleSize(20);
const _SCALE_PADDING = scaleSize(20);
interface Props extends ViewProps {
title?: string | null;
@@ -276,8 +276,9 @@ export const InfiniteScrollingCollectionList: React.FC<Props> = ({
style={{
flexDirection: "row",
gap: ITEM_GAP,
paddingHorizontal: SCALE_PADDING,
paddingVertical: SCALE_PADDING,
paddingLeft: sizes.padding.horizontal,
paddingRight: sizes.padding.horizontal,
paddingVertical: sizes.gaps.small,
}}
>
{[1, 2, 3, 4, 5].map((i) => (
@@ -287,12 +288,13 @@ export const InfiniteScrollingCollectionList: React.FC<Props> = ({
backgroundColor: "#262626",
width: itemWidth,
aspectRatio: orientation === "horizontal" ? 16 / 9 : 10 / 15,
borderRadius: scaleSize(12),
marginBottom: scaleSize(8),
borderRadius: scaleSize(24),
}}
/>
<View
style={{
marginTop: scaleSize(12),
paddingHorizontal: scaleSize(4),
borderRadius: 6,
overflow: "hidden",
marginBottom: 4,

View File

@@ -158,7 +158,8 @@ const WatchlistSection: React.FC<WatchlistSectionProps> = ({
style={{
flexDirection: "row",
gap: ITEM_GAP,
paddingHorizontal: SCALE_PADDING,
paddingLeft: sizes.padding.horizontal,
paddingRight: sizes.padding.horizontal,
paddingVertical: SCALE_PADDING,
}}
>
@@ -169,10 +170,31 @@ const WatchlistSection: React.FC<WatchlistSectionProps> = ({
backgroundColor: "#262626",
width: posterSizes.poster,
aspectRatio: 10 / 15,
borderRadius: scaleSize(12),
marginBottom: scaleSize(8),
borderRadius: scaleSize(24),
}}
/>
<View
style={{
marginTop: scaleSize(12),
paddingHorizontal: scaleSize(4),
borderRadius: 6,
overflow: "hidden",
marginBottom: 4,
alignSelf: "flex-start",
}}
>
<Text
style={{
color: "#262626",
backgroundColor: "#262626",
borderRadius: 6,
fontSize: typography.callout,
}}
numberOfLines={1}
>
Placeholder text here
</Text>
</View>
</View>
))}
</View>
@@ -217,6 +239,7 @@ export const StreamystatsPromotedWatchlists: React.FC<
const api = useAtomValue(apiAtom);
const user = useAtomValue(userAtom);
const { settings } = useSettings();
const typography = useScaledTVTypography();
const streamyStatsEnabled = useMemo(() => {
return Boolean(settings?.streamyStatsServerUrl);
@@ -291,15 +314,16 @@ export const StreamystatsPromotedWatchlists: React.FC<
width: scaleSize(128),
backgroundColor: "#262626",
borderRadius: scaleSize(4),
marginLeft: SCALE_PADDING,
marginBottom: scaleSize(16),
marginLeft: sizes.padding.horizontal,
marginBottom: scaleSize(20),
}}
/>
<View
style={{
flexDirection: "row",
gap: ITEM_GAP,
paddingHorizontal: SCALE_PADDING,
paddingLeft: sizes.padding.horizontal,
paddingRight: sizes.padding.horizontal,
paddingVertical: SCALE_PADDING,
}}
>
@@ -310,10 +334,31 @@ export const StreamystatsPromotedWatchlists: React.FC<
backgroundColor: "#262626",
width: posterSizes.poster,
aspectRatio: 10 / 15,
borderRadius: scaleSize(12),
marginBottom: scaleSize(8),
borderRadius: scaleSize(24),
}}
/>
<View
style={{
marginTop: scaleSize(12),
paddingHorizontal: scaleSize(4),
borderRadius: 6,
overflow: "hidden",
marginBottom: 4,
alignSelf: "flex-start",
}}
>
<Text
style={{
color: "#262626",
backgroundColor: "#262626",
borderRadius: 6,
fontSize: typography.callout,
}}
numberOfLines={1}
>
Placeholder text here
</Text>
</View>
</View>
))}
</View>

View File

@@ -210,7 +210,8 @@ export const StreamystatsRecommendations: React.FC<Props> = ({
style={{
flexDirection: "row",
gap: sizes.gaps.item,
paddingHorizontal: sizes.padding.scale,
paddingLeft: sizes.padding.horizontal,
paddingRight: sizes.padding.horizontal,
paddingVertical: sizes.padding.scale,
}}
>
@@ -221,10 +222,31 @@ export const StreamystatsRecommendations: React.FC<Props> = ({
backgroundColor: "#262626",
width: sizes.posters.poster,
aspectRatio: 10 / 15,
borderRadius: scaleSize(12),
marginBottom: scaleSize(8),
borderRadius: scaleSize(24),
}}
/>
<View
style={{
marginTop: scaleSize(12),
paddingHorizontal: scaleSize(4),
borderRadius: 6,
overflow: "hidden",
marginBottom: 4,
alignSelf: "flex-start",
}}
>
<Text
style={{
color: "#262626",
backgroundColor: "#262626",
borderRadius: 6,
fontSize: typography.callout,
}}
numberOfLines={1}
>
Placeholder text here
</Text>
</View>
</View>
))}
</View>