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