improved trailer playback logic

This commit is contained in:
tapframe 2025-08-31 16:01:38 +05:30
parent 6f24275ff0
commit 220fc6aa21
4 changed files with 85 additions and 9 deletions

View file

@ -8,6 +8,7 @@ import {
Platform,
InteractionManager,
} from 'react-native';
import { MaterialIcons } from '@expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
import { Image } from 'expo-image';
@ -709,6 +710,7 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
const [isTrailerPlaying, setIsTrailerPlaying] = useState(false);
const [trailerReady, setTrailerReady] = useState(false);
const [trailerPreloaded, setTrailerPreloaded] = useState(false);
const trailerVideoRef = useRef<any>(null);
const imageOpacity = useSharedValue(1);
const imageLoadOpacity = useSharedValue(0);
const shimmerOpacity = useSharedValue(0.3);
@ -747,6 +749,18 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
trailerOpacity.value = withTiming(1, { duration: 500 });
}, [thumbnailOpacity, trailerOpacity, trailerPreloaded]);
// Handle fullscreen toggle
const handleFullscreenToggle = useCallback(async () => {
try {
if (trailerVideoRef.current) {
// Use the native fullscreen player
await trailerVideoRef.current.presentFullscreenPlayer();
}
} catch (error) {
logger.error('HeroSection', 'Error toggling fullscreen:', error);
}
}, []);
// Handle trailer error - fade back to thumbnail
const handleTrailerError = useCallback(() => {
setTrailerError(true);
@ -973,6 +987,8 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
imageLoadOpacity.value = 0;
shimmerOpacity.value = 0.3;
interactionComplete.current = false;
// Cleanup on unmount
};
}, []);
@ -990,6 +1006,8 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
}
});
return (
<Animated.View style={[styles.heroSection, heroAnimatedStyle]}>
{/* Optimized Background */}
@ -1045,11 +1063,13 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
opacity: trailerOpacity
}]}>
<TrailerPlayer
ref={trailerVideoRef}
trailerUrl={trailerUrl}
autoPlay={true}
muted={trailerMuted}
style={styles.absoluteFill}
hideLoadingSpinner={true}
onFullscreenToggle={handleFullscreenToggle}
onLoad={handleTrailerReady}
onError={handleTrailerError}
onPlaybackStatusUpdate={(status) => {
@ -1061,15 +1081,35 @@ const HeroSection: React.FC<HeroSectionProps> = memo(({
</Animated.View>
)}
{/* Unmute button for trailer */}
{/* Trailer control buttons (unmute and fullscreen) */}
{settings?.showTrailers && trailerReady && trailerUrl && (
<Animated.View style={{
position: 'absolute',
top: Platform.OS === 'android' ? 40 : 50,
right: width >= 768 ? 32 : 16,
zIndex: 10,
opacity: trailerOpacity
opacity: trailerOpacity,
flexDirection: 'row',
gap: 8,
}}>
{/* Fullscreen button */}
<TouchableOpacity
onPress={handleFullscreenToggle}
activeOpacity={0.7}
style={{
padding: 8,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderRadius: 20,
}}
>
<MaterialIcons
name="fullscreen"
size={24}
color="white"
/>
</TouchableOpacity>
{/* Unmute button */}
<TouchableOpacity
onPress={() => {
setTrailerMuted(!trailerMuted);
@ -1207,6 +1247,7 @@ const styles = StyleSheet.create({
backgroundColor: '#000',
overflow: 'hidden',
},
absoluteFill: {
position: 'absolute',
top: 0,

View file

@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import {
View,
Text,
@ -12,6 +12,7 @@ import Animated, {
FadeIn,
} from 'react-native-reanimated';
import { useTheme } from '../../contexts/ThemeContext';
import { isMDBListEnabled } from '../../screens/MDBListSettingsScreen';
// MetadataSourceSelector removed
interface MetadataDetailsProps {
@ -34,6 +35,20 @@ const MetadataDetails: React.FC<MetadataDetailsProps> = ({
}) => {
const { currentTheme } = useTheme();
const [isFullDescriptionOpen, setIsFullDescriptionOpen] = useState(false);
const [isMDBEnabled, setIsMDBEnabled] = useState(false);
useEffect(() => {
const checkMDBListEnabled = async () => {
try {
const enabled = await isMDBListEnabled();
setIsMDBEnabled(enabled);
} catch (error) {
setIsMDBEnabled(false); // Default to disabled if there's an error
}
};
checkMDBListEnabled();
}, []);
return (
<>
@ -60,7 +75,7 @@ const MetadataDetails: React.FC<MetadataDetailsProps> = ({
{metadata.certification && (
<Text style={[styles.metaText, { color: currentTheme.colors.text }]}>{metadata.certification}</Text>
)}
{metadata.imdbRating && (
{metadata.imdbRating && !isMDBEnabled && (
<View style={styles.ratingContainer}>
<Image
source={{ uri: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/69/IMDB_Logo_2016.svg/575px-IMDB_Logo_2016.svg.png' }}

View file

@ -34,9 +34,10 @@ interface TrailerPlayerProps {
onPlaybackStatusUpdate?: (status: { isLoaded: boolean; didJustFinish: boolean }) => void;
style?: any;
hideLoadingSpinner?: boolean;
onFullscreenToggle?: () => void;
}
const TrailerPlayer: React.FC<TrailerPlayerProps> = memo(({
const TrailerPlayer = React.forwardRef<any, TrailerPlayerProps>(({
trailerUrl,
autoPlay = true,
muted = true,
@ -47,7 +48,8 @@ const TrailerPlayer: React.FC<TrailerPlayerProps> = memo(({
onPlaybackStatusUpdate,
style,
hideLoadingSpinner = false,
}) => {
onFullscreenToggle,
}, ref) => {
const { currentTheme } = useTheme();
const videoRef = useRef<VideoRef>(null);
@ -171,6 +173,15 @@ const TrailerPlayer: React.FC<TrailerPlayerProps> = memo(({
};
}, []);
// Forward the ref to the video element
React.useImperativeHandle(ref, () => ({
presentFullscreenPlayer: () => {
if (videoRef.current) {
return videoRef.current.presentFullscreenPlayer();
}
}
}));
// Animated styles
const controlsAnimatedStyle = useAnimatedStyle(() => ({
opacity: controlsOpacity.value,
@ -287,6 +298,16 @@ const TrailerPlayer: React.FC<TrailerPlayerProps> = memo(({
color="white"
/>
</TouchableOpacity>
{onFullscreenToggle && (
<TouchableOpacity style={styles.controlButton} onPress={onFullscreenToggle}>
<MaterialIcons
name="fullscreen"
size={isTablet ? 32 : 24}
color="white"
/>
</TouchableOpacity>
)}
</View>
</View>
</LinearGradient>
@ -296,6 +317,8 @@ const TrailerPlayer: React.FC<TrailerPlayerProps> = memo(({
);
});
const styles = StyleSheet.create({
container: {
flex: 1,

View file

@ -735,7 +735,6 @@ const LibraryScreen = () => {
numColumns={numColumns}
contentContainerStyle={styles.listContainer}
showsVerticalScrollIndicator={false}
columnWrapperStyle={styles.columnWrapper}
onEndReachedThreshold={0.7}
onEndReached={() => {}}
/>
@ -776,7 +775,6 @@ const LibraryScreen = () => {
renderItem={({ item }) => renderTraktItem({ item })}
keyExtractor={(item) => `${item.type}-${item.id}`}
numColumns={numColumns}
columnWrapperStyle={styles.row}
style={styles.traktContainer}
contentContainerStyle={{ paddingBottom: insets.bottom + 80 }}
showsVerticalScrollIndicator={false}
@ -874,7 +872,6 @@ const LibraryScreen = () => {
numColumns={numColumns}
contentContainerStyle={styles.listContainer}
showsVerticalScrollIndicator={false}
columnWrapperStyle={styles.columnWrapper}
onEndReachedThreshold={0.7}
onEndReached={() => {}}
/>