mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-19 15:52:03 +00:00
bug fix
This commit is contained in:
parent
65845c6e10
commit
400a4313d9
1 changed files with 40 additions and 8 deletions
|
|
@ -9,7 +9,7 @@ import {
|
||||||
InteractionManager,
|
InteractionManager,
|
||||||
AppState,
|
AppState,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { useFocusEffect } from '@react-navigation/native';
|
import { useFocusEffect, useIsFocused } from '@react-navigation/native';
|
||||||
|
|
||||||
import { MaterialIcons } from '@expo/vector-icons';
|
import { MaterialIcons } from '@expo/vector-icons';
|
||||||
import { LinearGradient } from 'expo-linear-gradient';
|
import { LinearGradient } from 'expo-linear-gradient';
|
||||||
|
|
@ -701,6 +701,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
const { isAuthenticated: isTraktAuthenticated } = useTraktContext();
|
const { isAuthenticated: isTraktAuthenticated } = useTraktContext();
|
||||||
const { settings, updateSetting } = useSettings();
|
const { settings, updateSetting } = useSettings();
|
||||||
const { isTrailerPlaying: globalTrailerPlaying, setTrailerPlaying } = useTrailer();
|
const { isTrailerPlaying: globalTrailerPlaying, setTrailerPlaying } = useTrailer();
|
||||||
|
const isFocused = useIsFocused();
|
||||||
|
|
||||||
// Performance optimization: Refs for avoiding re-renders
|
// Performance optimization: Refs for avoiding re-renders
|
||||||
const interactionComplete = useRef(false);
|
const interactionComplete = useRef(false);
|
||||||
|
|
@ -727,6 +728,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
const pausedByScrollSV = useSharedValue(0);
|
const pausedByScrollSV = useSharedValue(0);
|
||||||
const scrollGuardEnabledSV = useSharedValue(0);
|
const scrollGuardEnabledSV = useSharedValue(0);
|
||||||
const isPlayingSV = useSharedValue(0);
|
const isPlayingSV = useSharedValue(0);
|
||||||
|
const isFocusedSV = useSharedValue(0);
|
||||||
// Guards to avoid repeated auto-starts
|
// Guards to avoid repeated auto-starts
|
||||||
const startedOnFocusRef = useRef(false);
|
const startedOnFocusRef = useRef(false);
|
||||||
const startedOnReadyRef = useRef(false);
|
const startedOnReadyRef = useRef(false);
|
||||||
|
|
@ -752,6 +754,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
|
|
||||||
// Handle smooth transition when trailer is ready to play
|
// Handle smooth transition when trailer is ready to play
|
||||||
const handleTrailerReady = useCallback(() => {
|
const handleTrailerReady = useCallback(() => {
|
||||||
|
if (!isFocused) return;
|
||||||
if (!trailerPreloaded) {
|
if (!trailerPreloaded) {
|
||||||
setTrailerPreloaded(true);
|
setTrailerPreloaded(true);
|
||||||
}
|
}
|
||||||
|
|
@ -763,17 +766,17 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
// Enable scroll guard after a brief delay to avoid immediate pause on entry
|
// Enable scroll guard after a brief delay to avoid immediate pause on entry
|
||||||
scrollGuardEnabledSV.value = 0;
|
scrollGuardEnabledSV.value = 0;
|
||||||
setTimeout(() => { scrollGuardEnabledSV.value = 1; }, 1000);
|
setTimeout(() => { scrollGuardEnabledSV.value = 1; }, 1000);
|
||||||
}, [thumbnailOpacity, trailerOpacity, trailerPreloaded]);
|
}, [thumbnailOpacity, trailerOpacity, trailerPreloaded, isFocused]);
|
||||||
|
|
||||||
// Auto-start trailer when ready on initial entry if enabled
|
// Auto-start trailer when ready on initial entry if enabled
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (trailerReady && settings?.showTrailers && !globalTrailerPlaying && !startedOnReadyRef.current) {
|
if (trailerReady && settings?.showTrailers && isFocused && !globalTrailerPlaying && !startedOnReadyRef.current) {
|
||||||
startedOnReadyRef.current = true;
|
startedOnReadyRef.current = true;
|
||||||
logger.info('HeroSection', 'Trailer ready - auto-starting playback');
|
logger.info('HeroSection', 'Trailer ready - auto-starting playback');
|
||||||
setTrailerPlaying(true);
|
setTrailerPlaying(true);
|
||||||
isPlayingSV.value = 1;
|
isPlayingSV.value = 1;
|
||||||
}
|
}
|
||||||
}, [trailerReady, settings?.showTrailers, globalTrailerPlaying, setTrailerPlaying]);
|
}, [trailerReady, settings?.showTrailers, isFocused, globalTrailerPlaying, setTrailerPlaying]);
|
||||||
|
|
||||||
// Handle fullscreen toggle
|
// Handle fullscreen toggle
|
||||||
const handleFullscreenToggle = useCallback(async () => {
|
const handleFullscreenToggle = useCallback(async () => {
|
||||||
|
|
@ -820,8 +823,10 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
|
|
||||||
// Fetch trailer URL when component mounts (only if trailers are enabled)
|
// Fetch trailer URL when component mounts (only if trailers are enabled)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
let alive = true as boolean;
|
||||||
|
let timerId: any = null;
|
||||||
const fetchTrailer = async () => {
|
const fetchTrailer = async () => {
|
||||||
if (!metadata?.name || !metadata?.year || !settings?.showTrailers) return;
|
if (!metadata?.name || !metadata?.year || !settings?.showTrailers || !isFocused) return;
|
||||||
|
|
||||||
setTrailerLoading(true);
|
setTrailerLoading(true);
|
||||||
setTrailerError(false);
|
setTrailerError(false);
|
||||||
|
|
@ -851,7 +856,10 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
};
|
};
|
||||||
|
|
||||||
// Delay trailer fetch to prevent blocking UI
|
// Delay trailer fetch to prevent blocking UI
|
||||||
setTimeout(fetchWithDelay, 100);
|
timerId = setTimeout(() => {
|
||||||
|
if (!alive) return;
|
||||||
|
fetchWithDelay();
|
||||||
|
}, 100);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('HeroSection', 'Error in trailer fetch setup:', error);
|
logger.error('HeroSection', 'Error in trailer fetch setup:', error);
|
||||||
setTrailerError(true);
|
setTrailerError(true);
|
||||||
|
|
@ -860,7 +868,11 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchTrailer();
|
fetchTrailer();
|
||||||
}, [metadata?.name, metadata?.year, settings?.showTrailers]);
|
return () => {
|
||||||
|
alive = false;
|
||||||
|
try { if (timerId) clearTimeout(timerId); } catch (_e) {}
|
||||||
|
};
|
||||||
|
}, [metadata?.name, metadata?.year, settings?.showTrailers, isFocused]);
|
||||||
|
|
||||||
// Optimized shimmer animation for loading state
|
// Optimized shimmer animation for loading state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -1084,11 +1096,31 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
|
||||||
isPlayingSV.value = globalTrailerPlaying ? 1 : 0;
|
isPlayingSV.value = globalTrailerPlaying ? 1 : 0;
|
||||||
}, [globalTrailerPlaying]);
|
}, [globalTrailerPlaying]);
|
||||||
|
|
||||||
|
// Mirror focus state to shared value for worklets and enforce pause when unfocused
|
||||||
|
useEffect(() => {
|
||||||
|
isFocusedSV.value = isFocused ? 1 : 0;
|
||||||
|
if (!isFocused) {
|
||||||
|
// Ensure trailer is not playing when screen loses focus
|
||||||
|
setTrailerPlaying(false);
|
||||||
|
isPlayingSV.value = 0;
|
||||||
|
startedOnFocusRef.current = false;
|
||||||
|
startedOnReadyRef.current = false;
|
||||||
|
// Also reset trailer state to prevent background start
|
||||||
|
try {
|
||||||
|
setTrailerReady(false);
|
||||||
|
setTrailerPreloaded(false);
|
||||||
|
setTrailerUrl(null);
|
||||||
|
trailerOpacity.value = 0;
|
||||||
|
thumbnailOpacity.value = 1;
|
||||||
|
} catch (_e) {}
|
||||||
|
}
|
||||||
|
}, [isFocused, setTrailerPlaying]);
|
||||||
|
|
||||||
// Pause/resume trailer based on scroll with hysteresis and guard
|
// Pause/resume trailer based on scroll with hysteresis and guard
|
||||||
useDerivedValue(() => {
|
useDerivedValue(() => {
|
||||||
'worklet';
|
'worklet';
|
||||||
try {
|
try {
|
||||||
if (!scrollGuardEnabledSV.value) return;
|
if (!scrollGuardEnabledSV.value || isFocusedSV.value === 0) return;
|
||||||
const pauseThreshold = heroHeight.value * 0.7; // pause when beyond 70%
|
const pauseThreshold = heroHeight.value * 0.7; // pause when beyond 70%
|
||||||
const resumeThreshold = heroHeight.value * 0.4; // resume when back within 40%
|
const resumeThreshold = heroHeight.value * 0.4; // resume when back within 40%
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue