mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-05 17:59:06 +00:00
Enhance ContinueWatchingSection with background refresh and loading state management
This update improves the ContinueWatchingSection component by implementing a background refresh mechanism and managing loading states more effectively. The loadContinueWatching function now prevents concurrent refreshes and allows for manual refreshes with a loading indicator. Additionally, the debounce time for background refreshes has been slightly increased, enhancing performance and user experience.
This commit is contained in:
parent
314ece1238
commit
e2db895d66
2 changed files with 24 additions and 16 deletions
|
|
@ -77,10 +77,20 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
||||||
const appState = useRef(AppState.currentState);
|
const appState = useRef(AppState.currentState);
|
||||||
const refreshTimerRef = useRef<NodeJS.Timeout | null>(null);
|
const refreshTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
|
// Use a state to track if a background refresh is in progress
|
||||||
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||||
|
|
||||||
// Modified loadContinueWatching to be more efficient
|
// Modified loadContinueWatching to be more efficient
|
||||||
const loadContinueWatching = useCallback(async () => {
|
const loadContinueWatching = useCallback(async (isBackgroundRefresh = false) => {
|
||||||
try {
|
// Prevent multiple concurrent refreshes
|
||||||
|
if (isRefreshing) return;
|
||||||
|
|
||||||
|
if (!isBackgroundRefresh) {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
}
|
||||||
|
setIsRefreshing(true);
|
||||||
|
|
||||||
|
try {
|
||||||
const allProgress = await storageService.getAllWatchProgress();
|
const allProgress = await storageService.getAllWatchProgress();
|
||||||
|
|
||||||
if (Object.keys(allProgress).length === 0) {
|
if (Object.keys(allProgress).length === 0) {
|
||||||
|
|
@ -193,8 +203,9 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
||||||
logger.error('Failed to load continue watching items:', error);
|
logger.error('Failed to load continue watching items:', error);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
setIsRefreshing(false);
|
||||||
}
|
}
|
||||||
}, []);
|
}, [isRefreshing]);
|
||||||
|
|
||||||
// Function to handle app state changes
|
// Function to handle app state changes
|
||||||
const handleAppStateChange = useCallback((nextAppState: AppStateStatus) => {
|
const handleAppStateChange = useCallback((nextAppState: AppStateStatus) => {
|
||||||
|
|
@ -202,8 +213,8 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
||||||
appState.current.match(/inactive|background/) &&
|
appState.current.match(/inactive|background/) &&
|
||||||
nextAppState === 'active'
|
nextAppState === 'active'
|
||||||
) {
|
) {
|
||||||
// App has come to the foreground - refresh data
|
// App has come to the foreground - trigger a background refresh
|
||||||
loadContinueWatching();
|
loadContinueWatching(true);
|
||||||
}
|
}
|
||||||
appState.current = nextAppState;
|
appState.current = nextAppState;
|
||||||
}, [loadContinueWatching]);
|
}, [loadContinueWatching]);
|
||||||
|
|
@ -220,8 +231,9 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
||||||
clearTimeout(refreshTimerRef.current);
|
clearTimeout(refreshTimerRef.current);
|
||||||
}
|
}
|
||||||
refreshTimerRef.current = setTimeout(() => {
|
refreshTimerRef.current = setTimeout(() => {
|
||||||
loadContinueWatching();
|
// Trigger a background refresh
|
||||||
}, 300);
|
loadContinueWatching(true);
|
||||||
|
}, 500); // Increased debounce time slightly
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to set up a custom event listener or use a timer as fallback
|
// Try to set up a custom event listener or use a timer as fallback
|
||||||
|
|
@ -236,7 +248,7 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// Fallback: poll for updates every 30 seconds
|
// Fallback: poll for updates every 30 seconds
|
||||||
const intervalId = setInterval(loadContinueWatching, 30000);
|
const intervalId = setInterval(() => loadContinueWatching(true), 30000);
|
||||||
return () => {
|
return () => {
|
||||||
subscription.remove();
|
subscription.remove();
|
||||||
clearInterval(intervalId);
|
clearInterval(intervalId);
|
||||||
|
|
@ -252,13 +264,12 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
||||||
loadContinueWatching();
|
loadContinueWatching();
|
||||||
}, [loadContinueWatching]);
|
}, [loadContinueWatching]);
|
||||||
|
|
||||||
// Properly expose the refresh method
|
// Expose the refresh function via the ref
|
||||||
React.useImperativeHandle(ref, () => ({
|
React.useImperativeHandle(ref, () => ({
|
||||||
refresh: async () => {
|
refresh: async () => {
|
||||||
await loadContinueWatching();
|
// Allow manual refresh to show loading indicator
|
||||||
// Return whether there are items to help parent determine visibility
|
await loadContinueWatching(false);
|
||||||
const hasItems = continueWatchingItems.length > 0;
|
return true;
|
||||||
return hasItems;
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import {
|
||||||
import { Image } from 'expo-image';
|
import { Image } from 'expo-image';
|
||||||
import Animated, {
|
import Animated, {
|
||||||
FadeIn,
|
FadeIn,
|
||||||
Layout,
|
|
||||||
} from 'react-native-reanimated';
|
} from 'react-native-reanimated';
|
||||||
import { useTheme } from '../../contexts/ThemeContext';
|
import { useTheme } from '../../contexts/ThemeContext';
|
||||||
|
|
||||||
|
|
@ -43,7 +42,6 @@ export const CastSection: React.FC<CastSectionProps> = ({
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={styles.castSection}
|
style={styles.castSection}
|
||||||
entering={FadeIn.duration(300).delay(150)}
|
entering={FadeIn.duration(300).delay(150)}
|
||||||
layout={Layout}
|
|
||||||
>
|
>
|
||||||
<View style={styles.sectionHeader}>
|
<View style={styles.sectionHeader}>
|
||||||
<Text style={[styles.sectionTitle, { color: currentTheme.colors.highEmphasis }]}>Cast</Text>
|
<Text style={[styles.sectionTitle, { color: currentTheme.colors.highEmphasis }]}>Cast</Text>
|
||||||
|
|
@ -57,7 +55,6 @@ export const CastSection: React.FC<CastSectionProps> = ({
|
||||||
renderItem={({ item, index }) => (
|
renderItem={({ item, index }) => (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
entering={FadeIn.duration(300).delay(50 + index * 30)}
|
entering={FadeIn.duration(300).delay(50 + index * 30)}
|
||||||
layout={Layout}
|
|
||||||
>
|
>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.castCard}
|
style={styles.castCard}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue