fix: refresh control with large header + refresh button

This commit is contained in:
Fredrik Burmester
2025-11-08 09:55:53 +01:00
parent f5b9e03dd9
commit 3e181eca72
2 changed files with 63 additions and 10 deletions

View File

@@ -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 && (
<>
<Chromecast.Chromecast background='transparent' />
<RefreshButton />
{user?.Policy?.IsAdministrator && <SessionsButton />}
<SettingsButton />
</>
@@ -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 (
<TouchableOpacity
onPress={handleRefresh}
className='mr-4'
disabled={isRefreshing}
>
{isRefreshing ? (
<ActivityIndicator size='small' color='white' />
) : (
<Ionicons name='refresh-outline' color='white' size={24} />
)}
</TouchableOpacity>
);
};
const SessionsButton = () => {
const router = useRouter();
const { sessions = [] } = useSessions({} as useSessionsProps);

View File

@@ -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={
<RefreshControl
refreshing={loading}
onRefresh={refetch}
tintColor='white' // For iOS
colors={["white"]} // For Android
progressViewOffset={showLargeHomeCarousel ? 200 : 0} // This offsets the refresh indicator to appear over the carousel
/>
showLargeHomeCarousel ? undefined : (
<RefreshControl
refreshing={loading}
onRefresh={refetch}
tintColor='white'
colors={["white"]}
progressViewOffset={100}
/>
)
}
style={{ marginTop: -headerOverlayOffset }}
contentContainerStyle={{ paddingTop: headerOverlayOffset }}