some UI changes to metadat overlay on videoplayers

This commit is contained in:
tapframe 2025-08-17 18:57:06 +05:30
parent 9ae1a32989
commit 3886f615c9
4 changed files with 189 additions and 125 deletions

View file

@ -1,5 +1,5 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState, useCallback } from 'react';
import { Platform } from 'react-native'; import { Platform, Animated, TouchableWithoutFeedback, View } from 'react-native';
import Video, { VideoRef, SelectedTrack, BufferingStrategyType, ResizeMode } from 'react-native-video'; import Video, { VideoRef, SelectedTrack, BufferingStrategyType, ResizeMode } from 'react-native-video';
interface VideoPlayerProps { interface VideoPlayerProps {

@ -1 +1 @@
Subproject commit c176aabb4edd73a709ebdc097688e780b65b651a Subproject commit 6591e3bc12a64a191367829d3fa5eb3783085c95

View file

@ -1372,6 +1372,40 @@ const AndroidVideoPlayer: React.FC = () => {
} }
}, [nextEpisode, id, isLoadingNextEpisode, navigation, metadata, imdbId, backdrop]); }, [nextEpisode, id, isLoadingNextEpisode, navigation, metadata, imdbId, backdrop]);
// Function to hide pause overlay and show controls
const hidePauseOverlay = useCallback(() => {
if (showPauseOverlay) {
Animated.parallel([
Animated.timing(pauseOverlayOpacity, {
toValue: 0,
duration: 220,
useNativeDriver: true,
}),
Animated.timing(pauseOverlayTranslateY, {
toValue: 8,
duration: 220,
useNativeDriver: true,
})
]).start(() => setShowPauseOverlay(false));
// Show controls when overlay is touched
if (!showControls) {
setShowControls(true);
Animated.timing(fadeAnim, {
toValue: 1,
duration: 300,
useNativeDriver: true,
}).start();
// Auto-hide controls after 5 seconds
if (controlsTimeout.current) {
clearTimeout(controlsTimeout.current);
}
controlsTimeout.current = setTimeout(hideControls, 5000);
}
}
}, [showPauseOverlay, pauseOverlayOpacity, pauseOverlayTranslateY, showControls, fadeAnim, controlsTimeout, hideControls]);
// Handle paused overlay after 5 seconds of being paused // Handle paused overlay after 5 seconds of being paused
useEffect(() => { useEffect(() => {
if (paused) { if (paused) {
@ -1400,20 +1434,7 @@ const AndroidVideoPlayer: React.FC = () => {
clearTimeout(pauseOverlayTimerRef.current); clearTimeout(pauseOverlayTimerRef.current);
pauseOverlayTimerRef.current = null; pauseOverlayTimerRef.current = null;
} }
if (showPauseOverlay) { hidePauseOverlay();
Animated.parallel([
Animated.timing(pauseOverlayOpacity, {
toValue: 0,
duration: 220,
useNativeDriver: true,
}),
Animated.timing(pauseOverlayTranslateY, {
toValue: 8,
duration: 220,
useNativeDriver: true,
})
]).start(() => setShowPauseOverlay(false));
}
} }
return () => { return () => {
if (pauseOverlayTimerRef.current) { if (pauseOverlayTimerRef.current) {
@ -1421,7 +1442,7 @@ const AndroidVideoPlayer: React.FC = () => {
pauseOverlayTimerRef.current = null; pauseOverlayTimerRef.current = null;
} }
}; };
}, [paused]); }, [paused, hidePauseOverlay]);
// Handle next episode button visibility based on current time and next episode availability // Handle next episode button visibility based on current time and next episode availability
useEffect(() => { useEffect(() => {
@ -1924,65 +1945,76 @@ const AndroidVideoPlayer: React.FC = () => {
/> />
{showPauseOverlay && ( {showPauseOverlay && (
<Animated.View <TouchableOpacity
pointerEvents="none" activeOpacity={1}
onPress={hidePauseOverlay}
style={{ style={{
position: 'absolute', position: 'absolute',
top: 0, top: 0,
left: 0, left: 0,
right: 0, right: 0,
bottom: 0, bottom: 0,
opacity: pauseOverlayOpacity,
}} }}
> >
{/* Strong horizontal fade from left side */} <Animated.View
<View style={{ position: 'absolute', top: 0, left: 0, bottom: 0, width: screenDimensions.width * 0.7 }}> style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
opacity: pauseOverlayOpacity,
}}
>
{/* Strong horizontal fade from left side */}
<View style={{ position: 'absolute', top: 0, left: 0, bottom: 0, width: screenDimensions.width * 0.7 }}>
<LinearGradient
start={{ x: 0, y: 0.5 }}
end={{ x: 1, y: 0.5 }}
colors={[ 'rgba(0,0,0,0.85)', 'rgba(0,0,0,0.0)' ]}
locations={[0, 1]}
style={StyleSheet.absoluteFill}
/>
</View>
<LinearGradient <LinearGradient
start={{ x: 0, y: 0.5 }} colors={[
end={{ x: 1, y: 0.5 }} 'rgba(0,0,0,0.6)',
colors={[ 'rgba(0,0,0,0.85)', 'rgba(0,0,0,0.0)' ]} 'rgba(0,0,0,0.4)',
locations={[0, 1]} 'rgba(0,0,0,0.2)',
'rgba(0,0,0,0.0)'
]}
locations={[0, 0.3, 0.6, 1]}
style={StyleSheet.absoluteFill} style={StyleSheet.absoluteFill}
/> />
</View> <Animated.View style={{
<LinearGradient position: 'absolute',
colors={[ left: 24 + insets.left,
'rgba(0,0,0,0.6)', right: 24 + insets.right,
'rgba(0,0,0,0.4)', bottom: 110 + insets.bottom,
'rgba(0,0,0,0.2)', transform: [{ translateY: pauseOverlayTranslateY }]
'rgba(0,0,0,0.0)' }}>
]} <Text style={{ color: '#B8B8B8', fontSize: 18, marginBottom: 8 }}>You're watching</Text>
locations={[0, 0.3, 0.6, 1]} <Text style={{ color: '#FFFFFF', fontSize: 48, fontWeight: '800', marginBottom: 10 }} numberOfLines={1}>
style={StyleSheet.absoluteFill} {title}
/>
<Animated.View style={{
position: 'absolute',
left: 24 + insets.left,
right: 24 + insets.right,
bottom: 110 + insets.bottom,
transform: [{ translateY: pauseOverlayTranslateY }]
}}>
<Text style={{ color: '#B8B8B8', fontSize: 18, marginBottom: 8 }}>You're watching</Text>
<Text style={{ color: '#FFFFFF', fontSize: 48, fontWeight: '800', marginBottom: 10 }} numberOfLines={1}>
{title}
</Text>
{!!year && (
<Text style={{ color: '#CCCCCC', fontSize: 18, marginBottom: 8 }} numberOfLines={1}>
{`${year}${type === 'series' && season && episode ? ` • S${season}E${episode}` : ''}`}
</Text> </Text>
)} {!!year && (
{!!episodeTitle && ( <Text style={{ color: '#CCCCCC', fontSize: 18, marginBottom: 8 }} numberOfLines={1}>
<Text style={{ color: '#FFFFFF', fontSize: 20, fontWeight: '600', marginBottom: 8 }} numberOfLines={1}> {`${year}${type === 'series' && season && episode ? ` • S${season}E${episode}` : ''}`}
{episodeTitle} </Text>
</Text> )}
)} {!!episodeTitle && (
{(currentEpisodeDescription || metadata?.description) && ( <Text style={{ color: '#FFFFFF', fontSize: 20, fontWeight: '600', marginBottom: 8 }} numberOfLines={1}>
<Text style={{ color: '#D6D6D6', fontSize: 18, lineHeight: 24 }} numberOfLines={3}> {episodeTitle}
{(type as any) === 'series' ? (currentEpisodeDescription || metadata?.description || '') : (metadata?.description || '')} </Text>
</Text> )}
)} {(currentEpisodeDescription || metadata?.description) && (
<Text style={{ color: '#D6D6D6', fontSize: 18, lineHeight: 24 }} numberOfLines={3}>
{(type as any) === 'series' ? (currentEpisodeDescription || metadata?.description || '') : (metadata?.description || '')}
</Text>
)}
</Animated.View>
</Animated.View> </Animated.View>
</Animated.View> </TouchableOpacity>
)} )}
{/* Next Episode Button */} {/* Next Episode Button */}

View file

@ -1272,6 +1272,40 @@ const VideoPlayer: React.FC = () => {
} }
}, [nextEpisode, id, isLoadingNextEpisode, navigation, metadata, imdbId, backdrop]); }, [nextEpisode, id, isLoadingNextEpisode, navigation, metadata, imdbId, backdrop]);
// Function to hide pause overlay and show controls
const hidePauseOverlay = useCallback(() => {
if (showPauseOverlay) {
Animated.parallel([
Animated.timing(pauseOverlayOpacity, {
toValue: 0,
duration: 220,
useNativeDriver: true,
}),
Animated.timing(pauseOverlayTranslateY, {
toValue: 8,
duration: 220,
useNativeDriver: true,
})
]).start(() => setShowPauseOverlay(false));
// Show controls when overlay is touched
if (!showControls) {
setShowControls(true);
Animated.timing(fadeAnim, {
toValue: 1,
duration: 300,
useNativeDriver: true,
}).start();
// Auto-hide controls after 5 seconds
if (controlsTimeout.current) {
clearTimeout(controlsTimeout.current);
}
controlsTimeout.current = setTimeout(hideControls, 5000);
}
}
}, [showPauseOverlay, pauseOverlayOpacity, pauseOverlayTranslateY, showControls, fadeAnim, controlsTimeout, hideControls]);
// Handle paused overlay after 5 seconds of being paused // Handle paused overlay after 5 seconds of being paused
useEffect(() => { useEffect(() => {
if (paused) { if (paused) {
@ -1300,20 +1334,7 @@ const VideoPlayer: React.FC = () => {
clearTimeout(pauseOverlayTimerRef.current); clearTimeout(pauseOverlayTimerRef.current);
pauseOverlayTimerRef.current = null; pauseOverlayTimerRef.current = null;
} }
if (showPauseOverlay) { hidePauseOverlay();
Animated.parallel([
Animated.timing(pauseOverlayOpacity, {
toValue: 0,
duration: 220,
useNativeDriver: true,
}),
Animated.timing(pauseOverlayTranslateY, {
toValue: 8,
duration: 220,
useNativeDriver: true,
})
]).start(() => setShowPauseOverlay(false));
}
} }
return () => { return () => {
if (pauseOverlayTimerRef.current) { if (pauseOverlayTimerRef.current) {
@ -1321,7 +1342,7 @@ const VideoPlayer: React.FC = () => {
pauseOverlayTimerRef.current = null; pauseOverlayTimerRef.current = null;
} }
}; };
}, [paused]); }, [paused, hidePauseOverlay]);
// Handle next episode button visibility based on current time and next episode availability // Handle next episode button visibility based on current time and next episode availability
useEffect(() => { useEffect(() => {
@ -1827,65 +1848,76 @@ const VideoPlayer: React.FC = () => {
/> />
{showPauseOverlay && ( {showPauseOverlay && (
<Animated.View <TouchableOpacity
pointerEvents="none" activeOpacity={1}
onPress={hidePauseOverlay}
style={{ style={{
position: 'absolute', position: 'absolute',
top: 0, top: 0,
left: 0, left: 0,
right: 0, right: 0,
bottom: 0, bottom: 0,
opacity: pauseOverlayOpacity,
}} }}
> >
{/* Strong horizontal fade from left side */} <Animated.View
<View style={{ position: 'absolute', top: 0, left: 0, bottom: 0, width: screenDimensions.width * 0.7 }}> style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
opacity: pauseOverlayOpacity,
}}
>
{/* Strong horizontal fade from left side */}
<View style={{ position: 'absolute', top: 0, left: 0, bottom: 0, width: screenDimensions.width * 0.7 }}>
<LinearGradient
start={{ x: 0, y: 0.5 }}
end={{ x: 1, y: 0.5 }}
colors={[ 'rgba(0,0,0,0.85)', 'rgba(0,0,0,0.0)' ]}
locations={[0, 1]}
style={StyleSheet.absoluteFill}
/>
</View>
<LinearGradient <LinearGradient
start={{ x: 0, y: 0.5 }} colors={[
end={{ x: 1, y: 0.5 }} 'rgba(0,0,0,0.6)',
colors={[ 'rgba(0,0,0,0.85)', 'rgba(0,0,0,0.0)' ]} 'rgba(0,0,0,0.4)',
locations={[0, 1]} 'rgba(0,0,0,0.2)',
'rgba(0,0,0,0.0)'
]}
locations={[0, 0.3, 0.6, 1]}
style={StyleSheet.absoluteFill} style={StyleSheet.absoluteFill}
/> />
</View> <Animated.View style={{
<LinearGradient position: 'absolute',
colors={[ left: 24 + insets.left,
'rgba(0,0,0,0.6)', right: 24 + insets.right,
'rgba(0,0,0,0.4)', bottom: 110 + insets.bottom,
'rgba(0,0,0,0.2)', transform: [{ translateY: pauseOverlayTranslateY }]
'rgba(0,0,0,0.0)' }}>
]} <Text style={{ color: '#B8B8B8', fontSize: 18, marginBottom: 8 }}>You're watching</Text>
locations={[0, 0.3, 0.6, 1]} <Text style={{ color: '#FFFFFF', fontSize: 48, fontWeight: '800', marginBottom: 10 }} numberOfLines={1}>
style={StyleSheet.absoluteFill} {title}
/>
<Animated.View style={{
position: 'absolute',
left: 24 + insets.left,
right: 24 + insets.right,
bottom: 110 + insets.bottom,
transform: [{ translateY: pauseOverlayTranslateY }]
}}>
<Text style={{ color: '#B8B8B8', fontSize: 18, marginBottom: 8 }}>You're watching</Text>
<Text style={{ color: '#FFFFFF', fontSize: 48, fontWeight: '800', marginBottom: 10 }} numberOfLines={1}>
{title}
</Text>
{!!year && (
<Text style={{ color: '#CCCCCC', fontSize: 18, marginBottom: 8 }} numberOfLines={1}>
{`${year}${type === 'series' && season && episode ? ` • S${season}E${episode}` : ''}`}
</Text> </Text>
)} {!!year && (
{!!episodeTitle && ( <Text style={{ color: '#CCCCCC', fontSize: 18, marginBottom: 8 }} numberOfLines={1}>
<Text style={{ color: '#FFFFFF', fontSize: 20, fontWeight: '600', marginBottom: 8 }} numberOfLines={1}> {`${year}${type === 'series' && season && episode ? ` • S${season}E${episode}` : ''}`}
{episodeTitle} </Text>
</Text> )}
)} {!!episodeTitle && (
{(currentEpisodeDescription || metadata?.description) && ( <Text style={{ color: '#FFFFFF', fontSize: 20, fontWeight: '600', marginBottom: 8 }} numberOfLines={1}>
<Text style={{ color: '#D6D6D6', fontSize: 18, lineHeight: 24 }} numberOfLines={3}> {episodeTitle}
{type === 'series' ? (currentEpisodeDescription || metadata?.description || '') : (metadata?.description || '')} </Text>
</Text> )}
)} {(currentEpisodeDescription || metadata?.description) && (
<Text style={{ color: '#D6D6D6', fontSize: 18, lineHeight: 24 }} numberOfLines={3}>
{type === 'series' ? (currentEpisodeDescription || metadata?.description || '') : (metadata?.description || '')}
</Text>
)}
</Animated.View>
</Animated.View> </Animated.View>
</Animated.View> </TouchableOpacity>
)} )}
{/* Next Episode Button */} {/* Next Episode Button */}