optimzed perf

This commit is contained in:
tapframe 2025-10-17 22:09:42 +05:30
parent bf15c5fb45
commit 3effdee5c0

View file

@ -832,7 +832,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
const titleCardTranslateY = useSharedValue(0);
const genreOpacity = useSharedValue(1);
// Performance optimization: Cache theme colors
// Ultra-optimized theme colors with stable references
const themeColors = useMemo(() => ({
black: currentTheme.colors.black,
darkBackground: currentTheme.colors.darkBackground,
@ -840,6 +840,15 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
text: currentTheme.colors.text
}), [currentTheme.colors.black, currentTheme.colors.darkBackground, currentTheme.colors.highEmphasis, currentTheme.colors.text]);
// Pre-calculated style objects for better performance
const staticStyles = useMemo(() => ({
heroWrapper: styles.heroWrapper,
heroSection: styles.heroSection,
absoluteFill: styles.absoluteFill,
thumbnailContainer: styles.thumbnailContainer,
thumbnailImage: styles.thumbnailImage,
}), []);
// Handle trailer preload completion
const handleTrailerPreloaded = useCallback(() => {
setTrailerPreloaded(true);
@ -1153,34 +1162,30 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
opacity: watchProgressOpacity.value,
}), []);
// Enhanced backdrop with smooth loading animation and dynamic parallax effect
// Ultra-optimized backdrop with cached calculations and minimal worklet overhead
const backdropImageStyle = useAnimatedStyle(() => {
'worklet';
const scrollYValue = scrollY.value;
// Default zoom factor
const defaultZoom = 1.1; // 10% zoom by default
// Pre-calculated constants for better performance
const DEFAULT_ZOOM = 1.1;
const SCROLL_UP_MULTIPLIER = 0.002;
const SCROLL_DOWN_MULTIPLIER = 0.0001;
const MAX_SCALE = 1.4;
const PARALLAX_FACTOR = 0.3;
// Dynamic scale based on scroll direction and position
let scale = defaultZoom;
if (scrollYValue < 0) {
// Scrolling up - zoom in to fill blank area
scale = defaultZoom + Math.abs(scrollYValue) * 0.002; // More aggressive zoom when scrolling up
} else {
// Scrolling down - subtle scale effect
scale = defaultZoom + scrollYValue * 0.0001;
}
// Optimized scale calculation with minimal branching
const scrollUpScale = DEFAULT_ZOOM + Math.abs(scrollYValue) * SCROLL_UP_MULTIPLIER;
const scrollDownScale = DEFAULT_ZOOM + scrollYValue * SCROLL_DOWN_MULTIPLIER;
const scale = Math.min(scrollYValue < 0 ? scrollUpScale : scrollDownScale, MAX_SCALE);
// Cap the scale to prevent excessive zoom
scale = Math.min(scale, 1.4); // Allow up to 40% zoom (including default)
// Parallax effect - move image slower than scroll
const parallaxOffset = scrollYValue * 0.3; // 30% of scroll speed
// Single parallax calculation
const parallaxOffset = scrollYValue * PARALLAX_FACTOR;
return {
opacity: imageOpacity.value * imageLoadOpacity.value,
transform: [
{ scale: scale },
{ scale },
{ translateY: parallaxOffset }
],
};
@ -1209,29 +1214,29 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
opacity: genreOpacity.value
}), []);
// Trailer parallax effect - moves slower than scroll for depth with dynamic zoom
// Ultra-optimized trailer parallax with cached calculations
const trailerParallaxStyle = useAnimatedStyle(() => {
'worklet';
const scrollYValue = scrollY.value;
// Dynamic scale for trailer based on scroll direction
let scale = 1;
if (scrollYValue < 0) {
// Scrolling up - zoom in to fill blank area
scale = 1 + Math.abs(scrollYValue) * 0.0015; // Slightly less aggressive than background
} else {
// Scrolling down - subtle scale effect
scale = 1 + scrollYValue * 0.0001;
}
// Pre-calculated constants for better performance
const DEFAULT_ZOOM = 1.0;
const SCROLL_UP_MULTIPLIER = 0.0015;
const SCROLL_DOWN_MULTIPLIER = 0.0001;
const MAX_SCALE = 1.25;
const PARALLAX_FACTOR = 0.2;
// Cap the scale to prevent excessive zoom
scale = Math.min(scale, 1.25); // Allow up to 25% zoom for trailer
// Optimized scale calculation with minimal branching
const scrollUpScale = DEFAULT_ZOOM + Math.abs(scrollYValue) * SCROLL_UP_MULTIPLIER;
const scrollDownScale = DEFAULT_ZOOM + scrollYValue * SCROLL_DOWN_MULTIPLIER;
const scale = Math.min(scrollYValue < 0 ? scrollUpScale : scrollDownScale, MAX_SCALE);
const parallaxOffset = scrollYValue * 0.2; // 20% of scroll speed for trailer
// Single parallax calculation
const parallaxOffset = scrollYValue * PARALLAX_FACTOR;
return {
transform: [
{ scale: scale },
{ scale },
{ translateY: parallaxOffset }
],
};
@ -1384,27 +1389,31 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
}
}, [isFocused, setTrailerPlaying]);
// Pause/resume trailer based on scroll with hysteresis and guard
// Ultra-optimized scroll-based pause/resume with cached calculations
useDerivedValue(() => {
'worklet';
try {
if (!scrollGuardEnabledSV.value || isFocusedSV.value === 0) return;
const pauseThreshold = heroHeight.value * 0.7; // pause when beyond 70%
const resumeThreshold = heroHeight.value * 0.4; // resume when back within 40%
// Pre-calculate thresholds for better performance
const pauseThreshold = heroHeight.value * 0.7;
const resumeThreshold = heroHeight.value * 0.4;
const y = scrollY.value;
const isPlaying = isPlayingSV.value === 1;
const isPausedByScroll = pausedByScrollSV.value === 1;
if (y > pauseThreshold && isPlayingSV.value === 1 && pausedByScrollSV.value === 0) {
// Optimized pause/resume logic with minimal branching
if (y > pauseThreshold && isPlaying && !isPausedByScroll) {
pausedByScrollSV.value = 1;
runOnJS(setTrailerPlaying)(false);
isPlayingSV.value = 0;
} else if (y < resumeThreshold && pausedByScrollSV.value === 1) {
} else if (y < resumeThreshold && isPausedByScroll) {
pausedByScrollSV.value = 0;
runOnJS(setTrailerPlaying)(true);
isPlayingSV.value = 1;
}
} catch (e) {
// no-op
// Silent error handling for performance
}
});
@ -1456,21 +1465,21 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
return (
<View style={styles.heroWrapper}>
<Animated.View style={[styles.heroSection, heroAnimatedStyle]}>
<View style={staticStyles.heroWrapper}>
<Animated.View style={[staticStyles.heroSection, heroAnimatedStyle]}>
{/* Optimized Background */}
<View style={[styles.absoluteFill, { backgroundColor: themeColors.black }]} />
<View style={[staticStyles.absoluteFill, { backgroundColor: themeColors.black }]} />
{/* Shimmer loading effect removed */}
{/* Background thumbnail image - always rendered when available with parallax */}
{shouldLoadSecondaryData && imageSource && !loadingBanner && (
<Animated.View style={[styles.thumbnailContainer, {
<Animated.View style={[staticStyles.thumbnailContainer, {
opacity: thumbnailOpacity
}]}>
<Animated.Image
source={{ uri: imageSource }}
style={[styles.thumbnailImage, backdropImageStyle]}
style={[staticStyles.thumbnailImage, backdropImageStyle]}
resizeMode="cover"
onError={handleImageError}
onLoad={handleImageLoad}
@ -1480,13 +1489,13 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
{/* Hidden preload trailer player - loads in background */}
{shouldLoadSecondaryData && settings?.showTrailers && trailerUrl && !trailerLoading && !trailerError && !trailerPreloaded && (
<View style={[styles.absoluteFill, { opacity: 0, pointerEvents: 'none' }]}>
<View style={[staticStyles.absoluteFill, { opacity: 0, pointerEvents: 'none' }]}>
<TrailerPlayer
key={`preload-${trailerUrl}`}
trailerUrl={trailerUrl}
autoPlay={false}
muted={true}
style={styles.absoluteFill}
style={staticStyles.absoluteFill}
hideLoadingSpinner={true}
onLoad={handleTrailerPreloaded}
onError={handleTrailerError}
@ -1496,7 +1505,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
{/* Visible trailer player - rendered on top with fade transition and parallax */}
{shouldLoadSecondaryData && settings?.showTrailers && trailerUrl && !trailerLoading && !trailerError && trailerPreloaded && (
<Animated.View style={[styles.absoluteFill, {
<Animated.View style={[staticStyles.absoluteFill, {
opacity: trailerOpacity
}, trailerParallaxStyle]}>
<TrailerPlayer
@ -1505,7 +1514,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
trailerUrl={trailerUrl}
autoPlay={globalTrailerPlaying}
muted={trailerMuted}
style={styles.absoluteFill}
style={staticStyles.absoluteFill}
hideLoadingSpinner={true}
hideControls={true}
onFullscreenToggle={handleFullscreenToggle}