From 2303c329405642e0ca1c6cbb91fa7c845085f400 Mon Sep 17 00:00:00 2001 From: tapframe Date: Fri, 17 Oct 2025 20:32:46 +0530 Subject: [PATCH] ui changes --- src/components/metadata/TrailerModal.tsx | 175 ++++--- src/components/metadata/TrailersSection.tsx | 501 +++++++++++++++----- 2 files changed, 493 insertions(+), 183 deletions(-) diff --git a/src/components/metadata/TrailerModal.tsx b/src/components/metadata/TrailerModal.tsx index c23f6a407..46a07562d 100644 --- a/src/components/metadata/TrailerModal.tsx +++ b/src/components/metadata/TrailerModal.tsx @@ -19,6 +19,24 @@ import TrailerPlayer from '../video/TrailerPlayer'; const { width, height } = Dimensions.get('window'); const isTablet = width >= 768; +// Helper function to format trailer type +const formatTrailerType = (type: string): string => { + switch (type) { + case 'Trailer': + return 'Official Trailer'; + case 'Teaser': + return 'Teaser'; + case 'Clip': + return 'Clip'; + case 'Featurette': + return 'Featurette'; + case 'Behind the Scenes': + return 'Behind the Scenes'; + default: + return type; + } +}; + interface TrailerVideo { id: string; key: string; @@ -136,42 +154,43 @@ const TrailerModal: React.FC = memo(({ maxHeight: modalHeight, backgroundColor: currentTheme.colors.background }]}> - {/* Header */} + {/* Enhanced Header */} - - - - {trailer.name} - + + + + + + + {trailer.name} + + + + {formatTrailerType(trailer.type)} • {new Date(trailer.published_at).getFullYear()} + + + - {/* Trailer Info */} - - - {trailer.type} • {new Date(trailer.published_at).getFullYear()} - {trailer.official && ' • Official'} - - - {/* Player Container */} {loading && ( @@ -223,11 +242,23 @@ const TrailerModal: React.FC = memo(({ )} - {/* Footer */} + {/* Enhanced Footer */} - - {contentTitle} - + + + + {contentTitle} + + + + + {trailer.size}p HD + + @@ -238,50 +269,70 @@ const TrailerModal: React.FC = memo(({ const styles = StyleSheet.create({ overlay: { flex: 1, - backgroundColor: 'rgba(0,0,0,0.9)', + backgroundColor: 'rgba(0,0,0,0.92)', justifyContent: 'center', alignItems: 'center', }, modal: { - borderRadius: 16, + borderRadius: 20, overflow: 'hidden', - elevation: 10, + elevation: 12, shadowColor: '#000', - shadowOffset: { width: 0, height: 4 }, - shadowOpacity: 0.3, - shadowRadius: 8, + shadowOffset: { width: 0, height: 6 }, + shadowOpacity: 0.4, + shadowRadius: 12, + borderWidth: 1, + borderColor: 'rgba(255,255,255,0.1)', }, + + // Enhanced Header Styles header: { flexDirection: 'row', - alignItems: 'center', + alignItems: 'flex-start', justifyContent: 'space-between', paddingHorizontal: 20, - paddingVertical: 16, + paddingVertical: 18, borderBottomWidth: 1, - borderBottomColor: 'rgba(255,255,255,0.1)', + borderBottomColor: 'rgba(255,255,255,0.08)', }, - titleContainer: { + headerLeft: { flexDirection: 'row', - alignItems: 'center', flex: 1, - gap: 8, + gap: 12, + }, + headerIconContainer: { + width: 36, + height: 36, + borderRadius: 10, + alignItems: 'center', + justifyContent: 'center', + }, + headerTextContainer: { + flex: 1, + gap: 4, }, title: { fontSize: 16, - fontWeight: '600', - flex: 1, + fontWeight: '700', + lineHeight: 20, + color: '#fff', }, - closeButton: { - padding: 4, - marginLeft: 8, - }, - infoContainer: { - paddingHorizontal: 20, - paddingVertical: 8, + headerMeta: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, }, meta: { fontSize: 12, - opacity: 0.8, + opacity: 0.7, + fontWeight: '500', + }, + closeButton: { + width: 32, + height: 32, + borderRadius: 16, + alignItems: 'center', + justifyContent: 'center', }, playerContainer: { aspectRatio: 16 / 9, @@ -336,16 +387,34 @@ const styles = StyleSheet.create({ player: { flex: 1, }, + // Enhanced Footer Styles footer: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', paddingHorizontal: 20, - paddingVertical: 12, + paddingVertical: 16, borderTopWidth: 1, - borderTopColor: 'rgba(255,255,255,0.1)', + borderTopColor: 'rgba(255,255,255,0.08)', + }, + footerContent: { + flexDirection: 'row', + alignItems: 'center', + flex: 1, + gap: 6, }, footerText: { - fontSize: 12, + fontSize: 13, + fontWeight: '500', + opacity: 0.8, + }, + footerMeta: { + alignItems: 'flex-end', + }, + footerMetaText: { + fontSize: 11, opacity: 0.6, - textAlign: 'center', + fontWeight: '500', }, }); diff --git a/src/components/metadata/TrailersSection.tsx b/src/components/metadata/TrailersSection.tsx index 935db6146..316301e19 100644 --- a/src/components/metadata/TrailersSection.tsx +++ b/src/components/metadata/TrailersSection.tsx @@ -8,6 +8,8 @@ import { Dimensions, Alert, Platform, + ScrollView, + Modal, } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; import FastImage from '@d11/react-native-fast-image'; @@ -53,6 +55,8 @@ const TrailersSection: React.FC = memo(({ const [error, setError] = useState(null); const [selectedTrailer, setSelectedTrailer] = useState(null); const [modalVisible, setModalVisible] = useState(false); + const [selectedCategory, setSelectedCategory] = useState('Trailer'); + const [dropdownVisible, setDropdownVisible] = useState(false); // Fetch trailers from TMDB useEffect(() => { @@ -104,9 +108,16 @@ const TrailersSection: React.FC = memo(({ if (totalVideos === 0) { logger.info('TrailersSection', `No videos found for TMDB ID ${tmdbId} - this is normal`); setTrailers({}); // No trailers available + setSelectedCategory(''); // No category selected } else { logger.info('TrailersSection', `Categorized ${totalVideos} videos into ${Object.keys(categorized).length} categories`); setTrailers(categorized); + + // Auto-select the first available category, preferring "Trailer" + const availableCategories = Object.keys(categorized); + const preferredCategory = availableCategories.includes('Trailer') ? 'Trailer' : + availableCategories.includes('Teaser') ? 'Teaser' : availableCategories[0]; + setSelectedCategory(preferredCategory); } } catch (err) { const errorMessage = err instanceof Error ? err.message : 'Failed to load trailers'; @@ -156,6 +167,17 @@ const TrailersSection: React.FC = memo(({ setSelectedTrailer(null); }; + // Handle category selection + const handleCategorySelect = (category: string) => { + setSelectedCategory(category); + setDropdownVisible(false); + }; + + // Toggle dropdown + const toggleDropdown = () => { + setDropdownVisible(!dropdownVisible); + }; + // Get thumbnail URL for YouTube video const getYouTubeThumbnail = (videoId: string, quality: 'default' | 'hq' | 'maxres' = 'hq') => { const qualities = { @@ -272,73 +294,161 @@ const TrailersSection: React.FC = memo(({ return ( + {/* Enhanced Header with Category Selector */} - - Trailers + Trailers & Videos - - {trailerCategories.map(category => ( - - + {/* Category Selector - Right Aligned */} + {trailerCategories.length > 0 && selectedCategory && ( + + + {formatTrailerType(selectedCategory)} + - - {formatTrailerType(category)} - - - {trailers[category].length} - + + )} + + + {/* Category Dropdown Modal */} + setDropdownVisible(false)} + > + setDropdownVisible(false)} + > + + {trailerCategories.map(category => ( + handleCategorySelect(category)} + activeOpacity={0.7} + > + + + + + + {formatTrailerType(category)} + + + {trailers[category].length} + + + {selectedCategory === category && ( + + )} + + ))} + + - - {trailers[category].map(trailer => { - - return ( - handleTrailerPress(trailer)} - activeOpacity={0.8} - > - + {/* Selected Category Trailers */} + {selectedCategory && trailers[selectedCategory] && ( + + {/* Trailers Horizontal Scroll */} + + {trailers[selectedCategory].map((trailer, index) => ( + handleTrailerPress(trailer)} + activeOpacity={0.9} + > + {/* Thumbnail with Gradient Overlay */} + - - - - - + {/* Subtle Gradient Overlay */} + + {/* Quality Badge */} + + {trailer.size}p - - - {trailer.name} - - - {new Date(trailer.published_at).getFullYear()} - {trailer.official && ' • Official'} - - - - ); - })} - + {/* Trailer Info */} + + + {trailer.name} + + + {new Date(trailer.published_at).getFullYear()} + + + + ))} + {/* Scroll Indicator - shows when there are more items to scroll */} + {trailers[selectedCategory].length > (isTablet ? 4 : 3) && ( + + + + )} + - ))} + )} {/* Trailer Modal */}