From 92704f09987b12461f9b6aad32212975c50fafca Mon Sep 17 00:00:00 2001 From: tapframe Date: Tue, 27 May 2025 22:19:08 +0530 Subject: [PATCH] Enhance StreamsScreen animations and layout for improved user experience This update introduces staggered animations for stream cards and provider filters, enhancing the visual appeal during loading states. The layout has been refined to ensure a smoother transition and better organization of stream details and actions. Additionally, the use of Animated.View components improves performance and responsiveness, contributing to a more engaging user interface. --- src/screens/StreamsScreen.tsx | 221 ++++++++++++++++++---------------- 1 file changed, 120 insertions(+), 101 deletions(-) diff --git a/src/screens/StreamsScreen.tsx b/src/screens/StreamsScreen.tsx index eddfc1b8..ac5ef769 100644 --- a/src/screens/StreamsScreen.tsx +++ b/src/screens/StreamsScreen.tsx @@ -42,7 +42,8 @@ import Animated, { Extrapolate, runOnJS, cancelAnimation, - SharedValue + SharedValue, + Layout } from 'react-native-reanimated'; import { logger } from '../utils/logger'; @@ -76,78 +77,86 @@ const StreamCard = ({ stream, onPress, index, isLoading, statusMessage, theme }: const displayTitle = isHDRezka ? `HDRezka ${stream.title}` : (stream.name || stream.title || 'Unnamed Stream'); const displayAddonName = isHDRezka ? '' : (stream.title || ''); + // Animation delay based on index - stagger effect + const enterDelay = 100 + (index * 50); + return ( - - - - - - {displayTitle} - - {displayAddonName && displayAddonName !== displayTitle && ( - - {displayAddonName} + + + + + + {displayTitle} + {displayAddonName && displayAddonName !== displayTitle && ( + + {displayAddonName} + + )} + + + {/* Show loading indicator if stream is loading */} + {isLoading && ( + + + + {statusMessage || "Loading..."} + + )} - {/* Show loading indicator if stream is loading */} - {isLoading && ( - - - - {statusMessage || "Loading..."} - - - )} + + {quality && quality >= "720" && ( + + )} + + {isDolby && ( + + )} + + {size && ( + + {size} + + )} + + {isDebrid && ( + + DEBRID + + )} + + {/* Special badge for HDRezka streams */} + {isHDRezka && ( + + HDREZKA + + )} + - - {quality && quality >= "720" && ( - - )} - - {isDolby && ( - - )} - - {size && ( - - {size} - - )} - - {isDebrid && ( - - DEBRID - - )} - - {/* Special badge for HDRezka streams */} - {isHDRezka && ( - - HDREZKA - - )} + + - - - - - - + + ); }; @@ -174,44 +183,53 @@ const ProviderFilter = memo(({ }) => { const styles = React.useMemo(() => createStyles(theme.colors), [theme.colors]); - const renderItem = useCallback(({ item }: { item: { id: string; name: string } }) => ( - onSelect(item.id)} + const renderItem = useCallback(({ item, index }: { item: { id: string; name: string }; index: number }) => ( + - - {item.name} - - + onSelect(item.id)} + > + + {item.name} + + + ), [selectedProvider, onSelect, styles]); return ( - item.id} - horizontal - showsHorizontalScrollIndicator={false} - style={styles.filterScroll} - bounces={true} - overScrollMode="never" - decelerationRate="fast" - initialNumToRender={5} - maxToRenderPerBatch={3} - windowSize={3} - getItemLayout={(data, index) => ({ - length: 100, // Approximate width of each item - offset: 100 * index, - index, - })} - /> + + item.id} + horizontal + showsHorizontalScrollIndicator={false} + style={styles.filterScroll} + bounces={true} + overScrollMode="never" + decelerationRate="fast" + initialNumToRender={5} + maxToRenderPerBatch={3} + windowSize={3} + getItemLayout={(data, index) => ({ + length: 100, // Approximate width of each item + offset: 100 * index, + index, + })} + /> + ); }); @@ -807,13 +825,14 @@ export const StreamsScreen = () => { ); }, [handleStreamPress, loadingProviders, providerStatus, currentTheme]); - const renderSectionHeader = useCallback(({ section }: { section: { title: string } }) => ( + const renderSectionHeader = useCallback(({ section }: { section: { title: string; addonId: string } }) => ( {section.title} - ), []); + ), [styles.streamGroupTitle]); return (