import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, StyleSheet, FlatList, TouchableOpacity, ActivityIndicator, SafeAreaView, StatusBar, Dimensions, ScrollView, Platform, } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { NavigationProp } from '@react-navigation/native'; import { MaterialIcons } from '@expo/vector-icons'; import { colors } from '../styles'; import { catalogService, StreamingContent, CatalogContent } from '../services/catalogService'; import { Image } from 'expo-image'; import Animated, { FadeIn, FadeOut, SlideInRight, Layout } from 'react-native-reanimated'; import { LinearGradient } from 'expo-linear-gradient'; import { RootStackParamList } from '../navigation/AppNavigator'; import { logger } from '../utils/logger'; interface Category { id: string; name: string; type: 'movie' | 'series' | 'channel' | 'tv'; icon: keyof typeof MaterialIcons.glyphMap; } interface GenreCatalog { genre: string; items: StreamingContent[]; } const CATEGORIES: Category[] = [ { id: 'movie', name: 'Movies', type: 'movie', icon: 'local-movies' }, { id: 'series', name: 'TV Shows', type: 'series', icon: 'live-tv' } ]; // Common genres for movies and TV shows const COMMON_GENRES = [ 'All', 'Action', 'Adventure', 'Animation', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Family', 'Fantasy', 'History', 'Horror', 'Music', 'Mystery', 'Romance', 'Science Fiction', 'Thriller', 'War', 'Western' ]; const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0; const DiscoverScreen = () => { const navigation = useNavigation>(); const [selectedCategory, setSelectedCategory] = useState(CATEGORIES[0]); const [selectedGenre, setSelectedGenre] = useState('All'); const [catalogs, setCatalogs] = useState([]); const [allContent, setAllContent] = useState([]); const [loading, setLoading] = useState(true); const { width } = Dimensions.get('window'); const itemWidth = (width - 60) / 4; // 4 items per row with spacing const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: colors.darkBackground, }, header: { paddingHorizontal: 16, paddingVertical: 12, paddingTop: Platform.OS === 'android' ? ANDROID_STATUSBAR_HEIGHT + 12 : 4, borderBottomWidth: 1, borderBottomColor: 'rgba(255,255,255,0.1)', backgroundColor: colors.darkBackground, }, headerContent: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, headerTitle: { fontSize: 32, fontWeight: '800', letterSpacing: 0.5, color: colors.white, }, searchButton: { padding: 4, marginLeft: 16, }, categoryContainer: { paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: 'rgba(255,255,255,0.1)', }, categoriesContent: { flexDirection: 'row', justifyContent: 'center', paddingHorizontal: 12, gap: 12, }, categoryButton: { paddingHorizontal: 20, paddingVertical: 12, marginHorizontal: 4, borderRadius: 16, borderWidth: 1, borderColor: colors.lightGray, backgroundColor: 'transparent', flexDirection: 'row', alignItems: 'center', gap: 8, }, categoryIcon: { marginRight: 4, }, categoryText: { color: colors.mediumGray, fontWeight: '500', fontSize: 15, }, genreContainer: { paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: 'rgba(255,255,255,0.1)', }, genresScrollView: { paddingHorizontal: 16, }, genreButton: { paddingHorizontal: 16, paddingVertical: 8, marginRight: 8, borderRadius: 16, borderWidth: 1, borderColor: colors.lightGray, backgroundColor: 'transparent', }, genreText: { color: colors.mediumGray, fontWeight: '500', fontSize: 14, }, loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, catalogsContainer: { paddingVertical: 8, }, catalogContainer: { marginBottom: 24, }, catalogHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 16, marginBottom: 12, }, titleContainer: { flexDirection: 'column', }, catalogTitle: { fontSize: 18, fontWeight: '700', color: colors.white, marginBottom: 2, }, titleUnderline: { height: 2, width: 40, backgroundColor: colors.primary, borderRadius: 2, }, seeAllButton: { flexDirection: 'row', alignItems: 'center', gap: 4, }, seeAllText: { color: colors.primary, fontWeight: '600', fontSize: 14, }, contentItem: { width: itemWidth, marginHorizontal: 5, }, posterContainer: { borderRadius: 8, overflow: 'hidden', backgroundColor: colors.transparentLight, elevation: 4, shadowColor: colors.black, shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 4, }, poster: { aspectRatio: 2/3, width: '100%', }, posterGradient: { position: 'absolute', bottom: 0, left: 0, right: 0, padding: 8, justifyContent: 'flex-end', }, contentTitle: { fontSize: 12, fontWeight: '600', color: colors.white, marginBottom: 2, textShadowColor: 'rgba(0, 0, 0, 0.75)', textShadowOffset: { width: 0, height: 1 }, textShadowRadius: 2, }, contentYear: { fontSize: 10, color: colors.mediumGray, textShadowColor: 'rgba(0, 0, 0, 0.75)', textShadowOffset: { width: 0, height: 1 }, textShadowRadius: 2, }, emptyContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingTop: 100, }, emptyText: { color: colors.mediumGray, fontSize: 16, fontWeight: '500', }, }); useEffect(() => { loadContent(selectedCategory, selectedGenre); }, [selectedCategory, selectedGenre]); const loadContent = async (category: Category, genre: string) => { setLoading(true); try { // If genre is 'All', don't apply genre filter const genreFilter = genre === 'All' ? undefined : genre; const fetchedCatalogs = await catalogService.getCatalogByType(category.type, genreFilter); // Collect all content items const content: StreamingContent[] = []; fetchedCatalogs.forEach(catalog => { content.push(...catalog.items); }); setAllContent(content); if (genre === 'All') { // Group by genres when "All" is selected const genreCatalogs: GenreCatalog[] = []; // Get all genres from content const genresSet = new Set(); content.forEach(item => { if (item.genres && item.genres.length > 0) { item.genres.forEach(g => genresSet.add(g)); } }); // Create catalogs for each genre genresSet.forEach(g => { const genreItems = content.filter(item => item.genres && item.genres.includes(g) ); if (genreItems.length > 0) { genreCatalogs.push({ genre: g, items: genreItems }); } }); // Sort by number of items genreCatalogs.sort((a, b) => b.items.length - a.items.length); setCatalogs(genreCatalogs); } else { // When a specific genre is selected, show as a single catalog setCatalogs([{ genre, items: content }]); } } catch (error) { logger.error('Failed to load content:', error); setCatalogs([]); setAllContent([]); } finally { setLoading(false); } }; const handleCategoryPress = (category: Category) => { if (category.id !== selectedCategory.id) { setSelectedCategory(category); setSelectedGenre('All'); // Reset to All when changing category } }; const handleGenrePress = (genre: string) => { if (genre !== selectedGenre) { setSelectedGenre(genre); } }; const handleSearchPress = () => { // @ts-ignore - We'll fix navigation types later navigation.navigate('Search'); }; const renderCategory = ({ item }: { item: Category }) => { const isSelected = selectedCategory.id === item.id; return ( handleCategoryPress(item)} > {item.name} ); }; const renderGenre = useCallback((genre: string) => { const isSelected = selectedGenre === genre; return ( handleGenrePress(genre)} > {genre} ); }, [selectedGenre]); const renderContentItem = useCallback(({ item }: { item: StreamingContent }) => { return ( { navigation.navigate('Metadata', { id: item.id, type: item.type }); }} > {item.name} {item.year && ( {item.year} )} ); }, [navigation]); const renderCatalog = useCallback(({ item }: { item: GenreCatalog }) => { // Only display the first 4 items in the row const displayItems = item.items.slice(0, 4); return ( {item.genre} { // Navigate to catalog view with genre filter navigation.navigate('Catalog', { id: 'discover', type: selectedCategory.type, name: `${item.genre} ${selectedCategory.name}`, genreFilter: item.genre }); }} style={styles.seeAllButton} > See More item.id} horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ paddingHorizontal: 11 }} snapToInterval={itemWidth + 10} decelerationRate="fast" snapToAlignment="start" ItemSeparatorComponent={() => } /> ); }, [navigation, selectedCategory]); return ( Discover {CATEGORIES.map((category) => ( {renderCategory({ item: category })} ))} {COMMON_GENRES.map(genre => renderGenre(genre))} {loading ? ( ) : catalogs.length > 0 ? ( item.genre} contentContainerStyle={styles.catalogsContainer} showsVerticalScrollIndicator={false} initialNumToRender={3} maxToRenderPerBatch={3} /> ) : ( No content found for {selectedGenre !== 'All' ? selectedGenre : 'these filters'} )} ); }; export default DiscoverScreen;