mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-21 00:32:04 +00:00
Stability improvement on catalogsection
This commit is contained in:
parent
f86e6256a7
commit
ebb7d4cec6
2 changed files with 8 additions and 25 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useCallback, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useMemo, useRef } from 'react';
|
||||||
import { View, Text, StyleSheet, TouchableOpacity, Platform, Dimensions } from 'react-native';
|
import { View, Text, StyleSheet, TouchableOpacity, Platform, Dimensions } from 'react-native';
|
||||||
import { FlashList } from '@shopify/flash-list';
|
import { FlashList } from '@shopify/flash-list';
|
||||||
import { NavigationProp, useNavigation } from '@react-navigation/native';
|
import { NavigationProp, useNavigation } from '@react-navigation/native';
|
||||||
|
|
@ -56,32 +56,19 @@ const POSTER_WIDTH = posterLayout.posterWidth;
|
||||||
const CatalogSection = ({ catalog }: CatalogSectionProps) => {
|
const CatalogSection = ({ catalog }: CatalogSectionProps) => {
|
||||||
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
|
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
|
||||||
const { currentTheme } = useTheme();
|
const { currentTheme } = useTheme();
|
||||||
// Simplified visibility tracking - just load all images immediately for better performance
|
|
||||||
const [hasLoaded, setHasLoaded] = useState(false);
|
|
||||||
|
|
||||||
// Load all images after a short delay to prevent blocking initial render
|
|
||||||
React.useEffect(() => {
|
|
||||||
const timer = setTimeout(() => {
|
|
||||||
setHasLoaded(true);
|
|
||||||
}, 100);
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleContentPress = useCallback((id: string, type: string) => {
|
const handleContentPress = useCallback((id: string, type: string) => {
|
||||||
navigation.navigate('Metadata', { id, type, addonId: catalog.addon });
|
navigation.navigate('Metadata', { id, type, addonId: catalog.addon });
|
||||||
}, [navigation, catalog.addon]);
|
}, [navigation, catalog.addon]);
|
||||||
|
|
||||||
const renderContentItem = useCallback(({ item, index }: { item: StreamingContent, index: number }) => {
|
const renderContentItem = useCallback(({ item }: { item: StreamingContent, index: number }) => {
|
||||||
// Load images immediately for better scrolling performance
|
|
||||||
return (
|
return (
|
||||||
<ContentItem
|
<ContentItem
|
||||||
item={item}
|
item={item}
|
||||||
onPress={handleContentPress}
|
onPress={handleContentPress}
|
||||||
shouldLoadImage={hasLoaded}
|
|
||||||
deferMs={index * 10} // Small stagger to prevent blocking
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}, [handleContentPress, hasLoaded]);
|
}, [handleContentPress]);
|
||||||
|
|
||||||
// Memoize the ItemSeparatorComponent to prevent re-creation
|
// Memoize the ItemSeparatorComponent to prevent re-creation
|
||||||
const ItemSeparator = useCallback(() => <View style={{ width: 8 }} />, []);
|
const ItemSeparator = useCallback(() => <View style={{ width: 8 }} />, []);
|
||||||
|
|
|
||||||
|
|
@ -152,15 +152,10 @@ const ContentItem = ({ item, onPress, shouldLoadImage: shouldLoadImageProp, defe
|
||||||
return item.poster;
|
return item.poster;
|
||||||
}, [item.poster, retryCount, item.id]);
|
}, [item.poster, retryCount, item.id]);
|
||||||
|
|
||||||
// Smoothly fade in content when settings are ready
|
// Avoid strong fade animations that can appear as flicker on mount/scroll
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isLoaded) {
|
if (isLoaded) {
|
||||||
fadeInOpacity.setValue(0);
|
fadeInOpacity.setValue(1);
|
||||||
Animated.timing(fadeInOpacity, {
|
|
||||||
toValue: 1,
|
|
||||||
duration: 180,
|
|
||||||
useNativeDriver: true,
|
|
||||||
}).start();
|
|
||||||
}
|
}
|
||||||
}, [isLoaded, fadeInOpacity]);
|
}, [isLoaded, fadeInOpacity]);
|
||||||
|
|
||||||
|
|
@ -196,14 +191,14 @@ const ContentItem = ({ item, onPress, shouldLoadImage: shouldLoadImageProp, defe
|
||||||
delayLongPress={300}
|
delayLongPress={300}
|
||||||
>
|
>
|
||||||
<View ref={itemRef} style={[styles.contentItemContainer, { borderRadius: posterRadius }] }>
|
<View ref={itemRef} style={[styles.contentItemContainer, { borderRadius: posterRadius }] }>
|
||||||
{/* Always load image for horizontal scrolling to prevent blank posters */}
|
{/* Image with lightweight placeholder to reduce flicker */}
|
||||||
{item.poster ? (
|
{item.poster ? (
|
||||||
<ExpoImage
|
<ExpoImage
|
||||||
source={{ uri: optimizedPosterUrl }}
|
source={{ uri: optimizedPosterUrl }}
|
||||||
style={[styles.poster, { backgroundColor: currentTheme.colors.elevation1, borderRadius: posterRadius }]}
|
style={[styles.poster, { backgroundColor: currentTheme.colors.elevation1, borderRadius: posterRadius }]}
|
||||||
contentFit="cover"
|
contentFit="cover"
|
||||||
cachePolicy={Platform.OS === 'android' ? 'disk' : 'memory-disk'}
|
cachePolicy={Platform.OS === 'android' ? 'disk' : 'memory-disk'}
|
||||||
transition={100} // Faster transition for scrolling
|
transition={0}
|
||||||
allowDownscaling
|
allowDownscaling
|
||||||
priority="normal" // Normal priority for horizontal scrolling
|
priority="normal" // Normal priority for horizontal scrolling
|
||||||
onLoad={() => {
|
onLoad={() => {
|
||||||
|
|
@ -222,6 +217,7 @@ const ContentItem = ({ item, onPress, shouldLoadImage: shouldLoadImageProp, defe
|
||||||
setImageLoaded(false);
|
setImageLoaded(false);
|
||||||
}}
|
}}
|
||||||
recyclingKey={item.id} // Add recycling key for better performance
|
recyclingKey={item.id} // Add recycling key for better performance
|
||||||
|
placeholder={PLACEHOLDER_BLURHASH}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
// Show placeholder for items without posters
|
// Show placeholder for items without posters
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue