Refactor catalog loading logic in HomeScreen to ensure loading state is accurately represented. Update placeholder rendering with animations and improve layout for better user experience during content loading.

This commit is contained in:
tapframe 2025-07-05 20:39:52 +05:30
parent e2403ecd71
commit ab7134bd3a

View file

@ -236,28 +236,22 @@ const HomeScreen = () => {
// Start all catalog loading promises but don't wait for them // Start all catalog loading promises but don't wait for them
// They will update the state progressively as they complete // They will update the state progressively as they complete
Promise.allSettled(catalogPromises).then(() => { await Promise.allSettled(catalogPromises);
// Final cleanup: Filter out null values to get only successfully loaded catalogs
setCatalogs(prevCatalogs => prevCatalogs.filter(catalog => catalog !== null));
});
// Only set catalogsLoading to false after all promises have settled
setCatalogsLoading(false);
} catch (error) { } catch (error) {
console.error('[HomeScreen] Error in progressive catalog loading:', error); console.error('[HomeScreen] Error in progressive catalog loading:', error);
} finally {
setCatalogsLoading(false); setCatalogsLoading(false);
} }
}, []); }, []);
// Only count feature section as loading if it's enabled in settings // Only count feature section as loading if it's enabled in settings
// Render the screen immediately and let placeholders/skeletons handle progressive loading // For catalogs, we show them progressively, so loading should be false as soon as we have any content
const isLoading = useMemo(() => { const isLoading = useMemo(() =>
// Show a full-screen loader only if we literally have no data to display yet (showHeroSection ? featuredLoading : false) || (catalogsLoading && loadedCatalogCount === 0),
const noHeroSection = !showHeroSection; [showHeroSection, featuredLoading, catalogsLoading, loadedCatalogCount]
const noFeaturedData = !featuredContent && featuredLoading; );
const noCatalogsReady = catalogs.length === 0 && catalogsLoading;
return noHeroSection && noCatalogsReady && noFeaturedData;
}, [showHeroSection, featuredContent, featuredLoading, catalogsLoading, catalogs.length]);
// React to settings changes // React to settings changes
useEffect(() => { useEffect(() => {
@ -528,20 +522,25 @@ const HomeScreen = () => {
); );
case 'placeholder': case 'placeholder':
return ( return (
<View style={styles.catalogPlaceholder}> <Animated.View entering={FadeIn.duration(300)}>
<View style={styles.placeholderHeader}> <View style={styles.catalogPlaceholder}>
<View style={[styles.placeholderTitle, { backgroundColor: currentTheme.colors.elevation1 }]} /> <View style={styles.placeholderHeader}>
<ActivityIndicator size="small" color={currentTheme.colors.primary} /> <View style={[styles.placeholderTitle, { backgroundColor: currentTheme.colors.elevation1 }]} />
<ActivityIndicator size="small" color={currentTheme.colors.primary} />
</View>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.placeholderPosters}>
{[...Array(5)].map((_, posterIndex) => (
<View
key={posterIndex}
style={[styles.placeholderPoster, { backgroundColor: currentTheme.colors.elevation1 }]}
/>
))}
</ScrollView>
</View> </View>
<View style={styles.placeholderPosters}> </Animated.View>
{[...Array(4)].map((_, posterIndex) => (
<View
key={posterIndex}
style={[styles.placeholderPoster, { backgroundColor: currentTheme.colors.elevation1 }]}
/>
))}
</View>
</View>
); );
case 'welcome': case 'welcome':
return <FirstTimeWelcome />; return <FirstTimeWelcome />;
@ -559,11 +558,11 @@ const HomeScreen = () => {
const ListFooterComponent = useMemo(() => ( const ListFooterComponent = useMemo(() => (
<> <>
{catalogsLoading && catalogs.length < totalCatalogsRef.current && ( {catalogsLoading && loadedCatalogCount > 0 && loadedCatalogCount < totalCatalogsRef.current && (
<View style={styles.loadingMoreCatalogs}> <View style={styles.loadingMoreCatalogs}>
<ActivityIndicator size="small" color={currentTheme.colors.primary} /> <ActivityIndicator size="small" color={currentTheme.colors.primary} />
<Text style={[styles.loadingMoreText, { color: currentTheme.colors.textMuted }]}> <Text style={[styles.loadingMoreText, { color: currentTheme.colors.textMuted }]}>
Loading more content... ({loadedCatalogCount}/{totalCatalogsRef.current}) Loading catalogs... ({loadedCatalogCount}/{totalCatalogsRef.current})
</Text> </Text>
</View> </View>
)} )}
@ -609,8 +608,9 @@ const HomeScreen = () => {
initialNumToRender={5} initialNumToRender={5}
maxToRenderPerBatch={5} maxToRenderPerBatch={5}
windowSize={11} windowSize={11}
removeClippedSubviews={false} removeClippedSubviews={Platform.OS === 'android'}
onEndReachedThreshold={0.5} onEndReachedThreshold={0.5}
updateCellsBatchingPeriod={50}
maintainVisibleContentPosition={{ maintainVisibleContentPosition={{
minIndexForVisible: 0, minIndexForVisible: 0,
autoscrollToTopThreshold: 10 autoscrollToTopThreshold: 10
@ -697,6 +697,8 @@ const styles = StyleSheet.create<any>({
padding: 16, padding: 16,
marginHorizontal: 16, marginHorizontal: 16,
marginBottom: 16, marginBottom: 16,
backgroundColor: 'rgba(0,0,0,0.2)',
borderRadius: 8,
}, },
loadingMoreText: { loadingMoreText: {
marginLeft: 12, marginLeft: 12,
@ -719,12 +721,14 @@ const styles = StyleSheet.create<any>({
}, },
placeholderPosters: { placeholderPosters: {
flexDirection: 'row', flexDirection: 'row',
paddingVertical: 8,
gap: 8, gap: 8,
}, },
placeholderPoster: { placeholderPoster: {
width: POSTER_WIDTH, width: POSTER_WIDTH,
aspectRatio: 2/3, aspectRatio: 2/3,
borderRadius: 4, borderRadius: 4,
marginRight: 2,
}, },
emptyCatalog: { emptyCatalog: {
padding: 32, padding: 32,