From 4a6f349cdba81e5515873b22224e316603095932 Mon Sep 17 00:00:00 2001 From: tapframe Date: Sat, 21 Jun 2025 18:36:20 +0530 Subject: [PATCH] Refactor animation durations across multiple components for improved performance and consistency This update modifies the animation durations in various components, including CatalogSection, ContinueWatchingSection, FeaturedContent, and ThisWeekSection, reducing the fade-in durations to enhance the user experience. Additionally, adjustments were made to the CastSection, MetadataDetails, and SeriesContent components to streamline animations. The changes aim to create a more cohesive and responsive interface throughout the application. --- src/components/home/CatalogSection.tsx | 2 +- .../home/ContinueWatchingSection.tsx | 2 +- src/components/home/FeaturedContent.tsx | 2 +- src/components/home/ThisWeekSection.tsx | 4 +- src/components/metadata/CastSection.tsx | 6 +- src/components/metadata/MetadataDetails.tsx | 4 +- src/components/metadata/SeriesContent.tsx | 10 +- .../player/modals/AudioTrackModal.tsx | 14 +- src/components/player/modals/SourcesModal.tsx | 22 ++- .../player/modals/SubtitleModals.tsx | 46 +++--- src/hooks/useMetadataAnimations.ts | 135 ++++++++++++------ src/screens/HomeScreen.tsx | 2 +- src/screens/SearchScreen.tsx | 5 +- src/screens/ShowRatingsScreen.tsx | 4 +- src/screens/StreamsScreen.tsx | 10 +- 15 files changed, 153 insertions(+), 115 deletions(-) diff --git a/src/components/home/CatalogSection.tsx b/src/components/home/CatalogSection.tsx index 0f13a2d1..1f96b6fd 100644 --- a/src/components/home/CatalogSection.tsx +++ b/src/components/home/CatalogSection.tsx @@ -76,7 +76,7 @@ const CatalogSection = ({ catalog }: CatalogSectionProps) => { return ( diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index e995586b..f3aef200 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -272,7 +272,7 @@ const ContinueWatchingSection = React.forwardRef((props, re } return ( - + Continue Watching diff --git a/src/components/home/FeaturedContent.tsx b/src/components/home/FeaturedContent.tsx index f35fd66c..3fa762f5 100644 --- a/src/components/home/FeaturedContent.tsx +++ b/src/components/home/FeaturedContent.tsx @@ -382,7 +382,7 @@ const FeaturedContent = ({ featuredContent, isSaved, handleSaveToLibrary }: Feat return ( { return ( { }; return ( - + This Week diff --git a/src/components/metadata/CastSection.tsx b/src/components/metadata/CastSection.tsx index f904eb72..07605cce 100644 --- a/src/components/metadata/CastSection.tsx +++ b/src/components/metadata/CastSection.tsx @@ -42,7 +42,7 @@ export const CastSection: React.FC = ({ return ( @@ -56,7 +56,7 @@ export const CastSection: React.FC = ({ keyExtractor={(item) => item.id.toString()} renderItem={({ item, index }) => ( = ({ transition={200} /> ) : ( - + {item.name.split(' ').reduce((prev: string, current: string) => prev + current[0], '').substring(0, 2)} diff --git a/src/components/metadata/MetadataDetails.tsx b/src/components/metadata/MetadataDetails.tsx index 1011359c..fdc4b43a 100644 --- a/src/components/metadata/MetadataDetails.tsx +++ b/src/components/metadata/MetadataDetails.tsx @@ -60,7 +60,7 @@ const MetadataDetails: React.FC = ({ {/* Creator/Director Info */} {metadata.directors && metadata.directors.length > 0 && ( @@ -81,7 +81,7 @@ const MetadataDetails: React.FC = ({ {metadata.description && ( setIsFullDescriptionOpen(!isFullDescriptionOpen)} diff --git a/src/components/metadata/SeriesContent.tsx b/src/components/metadata/SeriesContent.tsx index 5f5feb51..3bc6734c 100644 --- a/src/components/metadata/SeriesContent.tsx +++ b/src/components/metadata/SeriesContent.tsx @@ -535,13 +535,13 @@ export const SeriesContent: React.FC = ({ return ( {renderSeasonSelector()} {episodes.length} {episodes.length === 1 ? 'Episode' : 'Episodes'} @@ -562,7 +562,7 @@ export const SeriesContent: React.FC = ({ {currentSeasonEpisodes.map((episode, index) => ( = ({ {currentSeasonEpisodes.map((episode, index) => ( {renderVerticalEpisodeCard(episode)} @@ -596,7 +596,7 @@ export const SeriesContent: React.FC = ({ currentSeasonEpisodes.map((episode, index) => ( {renderVerticalEpisodeCard(episode)} diff --git a/src/components/player/modals/AudioTrackModal.tsx b/src/components/player/modals/AudioTrackModal.tsx index 63805e1c..c2363563 100644 --- a/src/components/player/modals/AudioTrackModal.tsx +++ b/src/components/player/modals/AudioTrackModal.tsx @@ -19,8 +19,6 @@ import Animated, { withDelay, withSequence, runOnJS, - BounceIn, - ZoomIn } from 'react-native-reanimated'; import { LinearGradient } from 'expo-linear-gradient'; import { styles } from '../utils/playerStyles'; @@ -227,7 +225,7 @@ export const AudioTrackModal: React.FC = ({ - + = ({ {vlcAudioTracks.length > 0 ? vlcAudioTracks.map((track, index) => ( = ({ {selectedAudioTrack === track.id && ( = ({ : 'rgba(255, 255, 255, 0.1)', }}> {selectedAudioTrack === track.id ? ( - + ) : ( @@ -400,7 +398,7 @@ export const AudioTrackModal: React.FC = ({ )) : ( { return ( ( = ({ }} > = ({ - + = ({ {sortedProviders.map(([providerId, { streams, addonName }], providerIndex) => ( 0 ? 32 : 0, width: '100%', @@ -426,8 +424,8 @@ const SourcesModal: React.FC = ({ return ( = ({ {isSelected && ( = ({ shadowRadius: 4, }}> {isSelected ? ( - + ) : ( diff --git a/src/components/player/modals/SubtitleModals.tsx b/src/components/player/modals/SubtitleModals.tsx index cf5e247c..264c0096 100644 --- a/src/components/player/modals/SubtitleModals.tsx +++ b/src/components/player/modals/SubtitleModals.tsx @@ -19,8 +19,6 @@ import Animated, { withDelay, withSequence, runOnJS, - BounceIn, - ZoomIn } from 'react-native-reanimated'; import { LinearGradient } from 'expo-linear-gradient'; import { styles } from '../utils/playerStyles'; @@ -281,7 +279,7 @@ export const SubtitleModals: React.FC = ({ - + = ({ {/* External Subtitles Section */} = ({ {/* Custom subtitles option */} {customSubtitles.length > 0 && ( = ({ {useCustomSubtitles && ( = ({ : 'rgba(255, 255, 255, 0.1)', }}> {useCustomSubtitles ? ( - + ) : ( @@ -500,8 +498,8 @@ export const SubtitleModals: React.FC = ({ {/* Search for external subtitles */} = ({ {/* Subtitle Size Controls */} {useCustomSubtitles && ( = ({ = ({ {vlcTextTracks.length > 0 ? vlcTextTracks.map((track, index) => ( = ({ {(selectedTextTrack === track.id && !useCustomSubtitles) && ( = ({ : 'rgba(255, 255, 255, 0.1)', }}> {(selectedTextTrack === track.id && !useCustomSubtitles) ? ( - + ) : ( @@ -824,7 +823,8 @@ export const SubtitleModals: React.FC = ({ )) : ( = ({ - + = ({ {availableSubtitles.length > 0 ? availableSubtitles.map((subtitle, index) => ( = ({ )) : ( { - // Batch all entrance animations to run simultaneously + // Batch all entrance animations to run simultaneously with safety const enterAnimations = () => { 'worklet'; - // Start with slightly reduced values and animate to full visibility - screenOpacity.value = withTiming(1, { - duration: 250, - easing: easings.fast - }); - - heroOpacity.value = withTiming(1, { - duration: 300, - easing: easings.fast - }); - - heroScale.value = withSpring(1, ultraFastSpring); - - uiElementsOpacity.value = withTiming(1, { - duration: 400, - easing: easings.natural - }); - - uiElementsTranslateY.value = withSpring(0, fastSpring); - - contentOpacity.value = withTiming(1, { - duration: 350, - easing: easings.fast - }); + try { + // Start with slightly reduced values and animate to full visibility + screenOpacity.value = withTiming(1, { + duration: 250, + easing: easings.fast + }); + + heroOpacity.value = withTiming(1, { + duration: 300, + easing: easings.fast + }); + + heroScale.value = withSpring(1, ultraFastSpring); + + uiElementsOpacity.value = withTiming(1, { + duration: 400, + easing: easings.natural + }); + + uiElementsTranslateY.value = withSpring(0, fastSpring); + + contentOpacity.value = withTiming(1, { + duration: 350, + easing: easings.fast + }); + } catch (error) { + // Silently handle any animation errors + console.warn('Animation error in enterAnimations:', error); + } }; - // Use runOnUI for better performance - runOnUI(enterAnimations)(); + // Use runOnUI for better performance with error handling + try { + runOnUI(enterAnimations)(); + } catch (error) { + console.warn('Failed to run enter animations:', error); + } }, []); - // Optimized watch progress animation + // Optimized watch progress animation with safety useEffect(() => { const hasProgress = watchProgress && watchProgress.duration > 0; const updateProgress = () => { 'worklet'; - progressOpacity.value = withTiming(hasProgress ? 1 : 0, { - duration: hasProgress ? 200 : 150, - easing: easings.fast - }); + + try { + progressOpacity.value = withTiming(hasProgress ? 1 : 0, { + duration: hasProgress ? 200 : 150, + easing: easings.fast + }); + } catch (error) { + console.warn('Animation error in updateProgress:', error); + } }; - runOnUI(updateProgress)(); + try { + runOnUI(updateProgress)(); + } catch (error) { + console.warn('Failed to run progress animation:', error); + } }, [watchProgress]); - // Ultra-optimized scroll handler with minimal calculations + // Cleanup function to cancel animations + useEffect(() => { + return () => { + try { + cancelAnimation(screenOpacity); + cancelAnimation(contentOpacity); + cancelAnimation(heroOpacity); + cancelAnimation(heroScale); + cancelAnimation(uiElementsOpacity); + cancelAnimation(uiElementsTranslateY); + cancelAnimation(progressOpacity); + cancelAnimation(scrollY); + cancelAnimation(headerProgress); + cancelAnimation(staticHeaderElementsY); + } catch (error) { + console.warn('Error canceling animations:', error); + } + }; + }, []); + + // Ultra-optimized scroll handler with minimal calculations and safety const scrollHandler = useAnimatedScrollHandler({ onScroll: (event) => { 'worklet'; - const rawScrollY = event.contentOffset.y; - scrollY.value = rawScrollY; + try { + const rawScrollY = event.contentOffset.y; + scrollY.value = rawScrollY; - // Single calculation for header threshold - const threshold = height * 0.4 - safeAreaTop; - const progress = rawScrollY > threshold ? 1 : 0; - - // Use single progress value for all header animations - if (headerProgress.value !== progress) { - headerProgress.value = withTiming(progress, { - duration: progress ? 200 : 150, - easing: easings.ultraFast - }); + // Single calculation for header threshold + const threshold = height * 0.4 - safeAreaTop; + const progress = rawScrollY > threshold ? 1 : 0; + + // Use single progress value for all header animations + if (headerProgress.value !== progress) { + headerProgress.value = withTiming(progress, { + duration: progress ? 200 : 150, + easing: easings.ultraFast + }); + } + } catch (error) { + console.warn('Animation error in scroll handler:', error); } }, }); diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 75ed40af..355e6a62 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -463,7 +463,7 @@ const HomeScreen = () => { /> ); case 'thisWeek': - return ; + return ; case 'continueWatching': return ; case 'catalog': diff --git a/src/screens/SearchScreen.tsx b/src/screens/SearchScreen.tsx index 7ba205bd..df2027d3 100644 --- a/src/screens/SearchScreen.tsx +++ b/src/screens/SearchScreen.tsx @@ -35,7 +35,6 @@ import Animated, { interpolate, withSpring, withDelay, - ZoomIn } from 'react-native-reanimated'; import { RootStackParamList } from '../navigation/AppNavigator'; import { logger } from '../utils/logger'; @@ -445,7 +444,7 @@ const SearchScreen = () => { onPress={() => { navigation.navigate('Metadata', { id: item.id, type: item.type }); }} - entering={FadeIn.duration(500).delay(index * 100)} + entering={FadeIn.duration(300).delay(index * 50)} activeOpacity={0.7} > { {seriesResults.length > 0 && ( TV Shows ({seriesResults.length}) diff --git a/src/screens/ShowRatingsScreen.tsx b/src/screens/ShowRatingsScreen.tsx index 390ed0fb..462751d5 100644 --- a/src/screens/ShowRatingsScreen.tsx +++ b/src/screens/ShowRatingsScreen.tsx @@ -481,7 +481,7 @@ const ShowRatingsScreen = ({ route }: Props) => { S{season.season_number} @@ -507,7 +507,7 @@ const ShowRatingsScreen = ({ route }: Props) => { {season.episodes[episodeIndex] && ( { return ( @@ -1196,11 +1196,11 @@ export const StreamsScreen = () => { {type === 'series' && currentEpisode && (