From 3e181eca726d98dcf0aa662db066534ad4807496 Mon Sep 17 00:00:00 2001 From: Fredrik Burmester Date: Sat, 8 Nov 2025 09:55:53 +0100 Subject: [PATCH] fix: refresh control with large header + refresh button --- app/(auth)/(tabs)/(home)/_layout.tsx | 37 ++++++++++++++++++++++++++-- components/settings/HomeIndex.tsx | 36 +++++++++++++++++++++------ 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/app/(auth)/(tabs)/(home)/_layout.tsx b/app/(auth)/(tabs)/(home)/_layout.tsx index 5e43476d..f5eb2c5e 100644 --- a/app/(auth)/(tabs)/(home)/_layout.tsx +++ b/app/(auth)/(tabs)/(home)/_layout.tsx @@ -1,8 +1,15 @@ import { Feather, Ionicons } from "@expo/vector-icons"; import { Stack, useRouter } from "expo-router"; +import { useState } from "react"; import { useTranslation } from "react-i18next"; -import { Platform, TouchableOpacity, View } from "react-native"; +import { + ActivityIndicator, + Platform, + TouchableOpacity, + View, +} from "react-native"; import { nestedTabPageScreenOptions } from "@/components/stacks/NestedTabPageStack"; +import { eventBus } from "@/utils/eventBus"; const Chromecast = Platform.isTV ? null : require("@/components/Chromecast"); @@ -30,7 +37,7 @@ export default function IndexLayout() { {!Platform.isTV && ( <> - + {user?.Policy?.IsAdministrator && } @@ -126,6 +133,32 @@ const SettingsButton = () => { ); }; +const RefreshButton = () => { + const [isRefreshing, setIsRefreshing] = useState(false); + + const handleRefresh = () => { + setIsRefreshing(true); + eventBus.emit("refreshHome"); + setTimeout(() => { + setIsRefreshing(false); + }, 2000); + }; + + return ( + + {isRefreshing ? ( + + ) : ( + + )} + + ); +}; + const SessionsButton = () => { const router = useRouter(); const { sessions = [] } = useSessions({} as useSessionsProps); diff --git a/components/settings/HomeIndex.tsx b/components/settings/HomeIndex.tsx index 8ac42dd4..6fd24395 100644 --- a/components/settings/HomeIndex.tsx +++ b/components/settings/HomeIndex.tsx @@ -12,7 +12,11 @@ import { getUserLibraryApi, getUserViewsApi, } from "@jellyfin/sdk/lib/utils/api"; -import { type QueryFunction, useQuery } from "@tanstack/react-query"; +import { + type QueryFunction, + useQuery, + useQueryClient, +} from "@tanstack/react-query"; import { useNavigation, useRouter, useSegments } from "expo-router"; import { useAtomValue } from "jotai"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -72,6 +76,7 @@ export const HomeIndex = () => { const [loading, setLoading] = useState(false); const { settings, refreshStreamyfinPluginSettings } = useSettings(); const showLargeHomeCarousel = settings.showLargeHomeCarousel ?? true; + const queryClient = useQueryClient(); const headerOverlayOffset = Platform.isTV ? 0 : showLargeHomeCarousel @@ -186,10 +191,21 @@ export const HomeIndex = () => { const refetch = async () => { setLoading(true); await refreshStreamyfinPluginSettings(); + await queryClient.clear(); await invalidateCache(); setLoading(false); }; + useEffect(() => { + const unsubscribe = eventBus.on("refreshHome", () => { + refetch(); + }); + + return () => { + unsubscribe(); + }; + }, [refetch]); + const createCollectionConfig = useCallback( ( title: string, @@ -472,14 +488,18 @@ export const HomeIndex = () => { nestedScrollEnabled contentInsetAdjustmentBehavior='never' scrollEventThrottle={16} + bounces={!showLargeHomeCarousel} + overScrollMode={showLargeHomeCarousel ? "never" : "auto"} refreshControl={ - + showLargeHomeCarousel ? undefined : ( + + ) } style={{ marginTop: -headerOverlayOffset }} contentContainerStyle={{ paddingTop: headerOverlayOffset }}