From e529ab388b6152497e2a42b8d25d50007e3468fc Mon Sep 17 00:00:00 2001 From: tapframe Date: Mon, 30 Jun 2025 14:29:16 +0530 Subject: [PATCH] Remove Discover-related components and constants to streamline the application structure. This includes the deletion of CatalogSection, CatalogsList, CategorySelector, GenreSelector, ContentItem, and the DiscoverScreen, along with associated constants. The AppNavigator has been updated to reflect these changes, removing references to the Discover screen and adjusting navigation parameters accordingly. --- src/components/discover/CatalogSection.tsx | 134 ------------ src/components/discover/CatalogsList.tsx | 44 ---- src/components/discover/CategorySelector.tsx | 95 --------- src/components/discover/ContentItem.tsx | 96 --------- src/components/discover/GenreSelector.tsx | 88 -------- src/components/home/CatalogSection.tsx | 2 +- src/components/home/FeaturedContent.tsx | 2 +- src/components/home/ThisWeekSection.tsx | 4 +- src/constants/discover.ts | 42 ---- src/navigation/AppNavigator.tsx | 34 ++- src/screens/DiscoverScreen.tsx | 205 ------------------- src/screens/HomeScreen.tsx | 9 +- src/styles/screens/discoverStyles.ts | 69 ------- 13 files changed, 24 insertions(+), 800 deletions(-) delete mode 100644 src/components/discover/CatalogSection.tsx delete mode 100644 src/components/discover/CatalogsList.tsx delete mode 100644 src/components/discover/CategorySelector.tsx delete mode 100644 src/components/discover/ContentItem.tsx delete mode 100644 src/components/discover/GenreSelector.tsx delete mode 100644 src/constants/discover.ts delete mode 100644 src/screens/DiscoverScreen.tsx delete mode 100644 src/styles/screens/discoverStyles.ts diff --git a/src/components/discover/CatalogSection.tsx b/src/components/discover/CatalogSection.tsx deleted file mode 100644 index 72cb381e..00000000 --- a/src/components/discover/CatalogSection.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import React, { useCallback, useMemo } from 'react'; -import { View, Text, TouchableOpacity, StyleSheet, FlatList, Dimensions } from 'react-native'; -import { MaterialIcons } from '@expo/vector-icons'; -import { useNavigation } from '@react-navigation/native'; -import { NavigationProp } from '@react-navigation/native'; -import { useTheme } from '../../contexts/ThemeContext'; -import { GenreCatalog, Category } from '../../constants/discover'; -import { StreamingContent } from '../../services/catalogService'; -import { RootStackParamList } from '../../navigation/AppNavigator'; -import ContentItem from './ContentItem'; - -interface CatalogSectionProps { - catalog: GenreCatalog; - selectedCategory: Category; -} - -const CatalogSection = ({ catalog, selectedCategory }: CatalogSectionProps) => { - const navigation = useNavigation>(); - const { currentTheme } = useTheme(); - const { width } = Dimensions.get('window'); - const itemWidth = (width - 48) / 2.2; // 2 items per row with spacing - - // Only display first 3 items in each section - const displayItems = useMemo(() => - catalog.items.slice(0, 3), - [catalog.items] - ); - - const handleContentPress = useCallback((item: StreamingContent) => { - navigation.navigate('Metadata', { id: item.id, type: item.type }); - }, [navigation]); - - const handleSeeMorePress = useCallback(() => { - navigation.navigate('Catalog', { - id: catalog.genre, - type: selectedCategory.type, - name: `${catalog.genre} ${selectedCategory.name}`, - genreFilter: catalog.genre - }); - }, [navigation, selectedCategory, catalog.genre]); - - const renderItem = useCallback(({ item }: { item: StreamingContent }) => ( - handleContentPress(item)} - width={itemWidth} - /> - ), [handleContentPress, itemWidth]); - - const keyExtractor = useCallback((item: StreamingContent) => item.id, []); - - const ItemSeparator = useCallback(() => ( - - ), []); - - return ( - - - - - {catalog.genre} - - - - - View All - - - - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - marginBottom: 32, - }, - header: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - paddingHorizontal: 20, - marginBottom: 16, - }, - titleContainer: { - flexDirection: 'column', - }, - titleBar: { - width: 32, - height: 3, - marginTop: 6, - borderRadius: 2, - }, - title: { - fontSize: 20, - fontWeight: '700', - }, - seeAllButton: { - flexDirection: 'row', - alignItems: 'center', - paddingVertical: 8, - paddingHorizontal: 10, - borderRadius: 20, - marginRight: -10, - }, - seeAllText: { - fontSize: 14, - fontWeight: '600', - marginRight: 4, - }, -}); - -export default React.memo(CatalogSection); \ No newline at end of file diff --git a/src/components/discover/CatalogsList.tsx b/src/components/discover/CatalogsList.tsx deleted file mode 100644 index 6a8bcdfa..00000000 --- a/src/components/discover/CatalogsList.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React, { useCallback } from 'react'; -import { FlatList, StyleSheet, Platform } from 'react-native'; -import { GenreCatalog, Category } from '../../constants/discover'; -import CatalogSection from './CatalogSection'; - -interface CatalogsListProps { - catalogs: GenreCatalog[]; - selectedCategory: Category; -} - -const CatalogsList = ({ catalogs, selectedCategory }: CatalogsListProps) => { - const renderCatalogItem = useCallback(({ item }: { item: GenreCatalog }) => ( - - ), [selectedCategory]); - - // Memoize list key extractor - const catalogKeyExtractor = useCallback((item: GenreCatalog) => item.genre, []); - - return ( - - ); -}; - -const styles = StyleSheet.create({ - container: { - paddingVertical: 8, - paddingBottom: 90, - }, -}); - -export default React.memo(CatalogsList); \ No newline at end of file diff --git a/src/components/discover/CategorySelector.tsx b/src/components/discover/CategorySelector.tsx deleted file mode 100644 index c090e8a7..00000000 --- a/src/components/discover/CategorySelector.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import React, { useCallback } from 'react'; -import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; -import { MaterialIcons } from '@expo/vector-icons'; -import { useTheme } from '../../contexts/ThemeContext'; -import { Category } from '../../constants/discover'; - -interface CategorySelectorProps { - categories: Category[]; - selectedCategory: Category; - onSelectCategory: (category: Category) => void; -} - -const CategorySelector = ({ - categories, - selectedCategory, - onSelectCategory -}: CategorySelectorProps) => { - const { currentTheme } = useTheme(); - - const renderCategoryButton = useCallback((category: Category) => { - const isSelected = selectedCategory.id === category.id; - - return ( - onSelectCategory(category)} - activeOpacity={0.7} - > - - - {category.name} - - - ); - }, [selectedCategory, onSelectCategory, currentTheme]); - - return ( - - - {categories.map(renderCategoryButton)} - - - ); -}; - -const styles = StyleSheet.create({ - container: { - paddingVertical: 20, - borderBottomWidth: 1, - borderBottomColor: 'rgba(255,255,255,0.05)', - }, - content: { - flexDirection: 'row', - justifyContent: 'center', - paddingHorizontal: 20, - gap: 16, - }, - categoryButton: { - paddingHorizontal: 20, - paddingVertical: 14, - borderRadius: 24, - backgroundColor: 'rgba(255,255,255,0.05)', - flexDirection: 'row', - alignItems: 'center', - gap: 10, - flex: 1, - maxWidth: 160, - justifyContent: 'center', - shadowColor: '#000', - shadowOffset: { width: 0, height: 4 }, - shadowOpacity: 0.15, - shadowRadius: 8, - elevation: 4, - }, - categoryText: { - color: '#9e9e9e', // Default medium gray - fontWeight: '600', - fontSize: 16, - }, -}); - -export default React.memo(CategorySelector); \ No newline at end of file diff --git a/src/components/discover/ContentItem.tsx b/src/components/discover/ContentItem.tsx deleted file mode 100644 index 1f7e85d2..00000000 --- a/src/components/discover/ContentItem.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react'; -import { View, Text, TouchableOpacity, StyleSheet, Dimensions } from 'react-native'; -import { Image } from 'expo-image'; -import { LinearGradient } from 'expo-linear-gradient'; -import { useTheme } from '../../contexts/ThemeContext'; -import { StreamingContent } from '../../services/catalogService'; - -interface ContentItemProps { - item: StreamingContent; - onPress: () => void; - width?: number; -} - -const ContentItem = ({ item, onPress, width }: ContentItemProps) => { - const { width: screenWidth } = Dimensions.get('window'); - const { currentTheme } = useTheme(); - const itemWidth = width || (screenWidth - 48) / 2.2; // Default to 2 items per row with spacing - - return ( - - - - - - {item.name} - - {item.year && ( - {item.year} - )} - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - marginHorizontal: 0, - }, - posterContainer: { - borderRadius: 8, - overflow: 'hidden', - backgroundColor: 'rgba(255,255,255,0.03)', - elevation: 5, - shadowOffset: { width: 0, height: 4 }, - shadowOpacity: 0.2, - shadowRadius: 8, - }, - poster: { - aspectRatio: 2/3, - width: '100%', - }, - gradient: { - position: 'absolute', - bottom: 0, - left: 0, - right: 0, - padding: 16, - justifyContent: 'flex-end', - height: '45%', - }, - title: { - fontSize: 15, - fontWeight: '700', - marginBottom: 4, - textShadowColor: 'rgba(0, 0, 0, 0.75)', - textShadowOffset: { width: 0, height: 1 }, - textShadowRadius: 2, - letterSpacing: 0.3, - }, - year: { - fontSize: 12, - color: 'rgba(255,255,255,0.7)', - textShadowColor: 'rgba(0, 0, 0, 0.75)', - textShadowOffset: { width: 0, height: 1 }, - textShadowRadius: 2, - }, -}); - -export default React.memo(ContentItem); \ No newline at end of file diff --git a/src/components/discover/GenreSelector.tsx b/src/components/discover/GenreSelector.tsx deleted file mode 100644 index 7cc4df08..00000000 --- a/src/components/discover/GenreSelector.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React, { useCallback } from 'react'; -import { View, Text, TouchableOpacity, StyleSheet, ScrollView } from 'react-native'; -import { useTheme } from '../../contexts/ThemeContext'; - -interface GenreSelectorProps { - genres: string[]; - selectedGenre: string; - onSelectGenre: (genre: string) => void; -} - -const GenreSelector = ({ - genres, - selectedGenre, - onSelectGenre -}: GenreSelectorProps) => { - const { currentTheme } = useTheme(); - - const renderGenreButton = useCallback((genre: string) => { - const isSelected = selectedGenre === genre; - - return ( - onSelectGenre(genre)} - activeOpacity={0.7} - > - - {genre} - - - ); - }, [selectedGenre, onSelectGenre, currentTheme]); - - return ( - - - {genres.map(renderGenreButton)} - - - ); -}; - -const styles = StyleSheet.create({ - container: { - paddingTop: 20, - paddingBottom: 12, - zIndex: 10, - }, - scrollViewContent: { - paddingHorizontal: 20, - paddingBottom: 8, - }, - genreButton: { - paddingHorizontal: 18, - paddingVertical: 10, - marginRight: 12, - borderRadius: 20, - backgroundColor: 'rgba(255,255,255,0.05)', - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 4, - elevation: 2, - overflow: 'hidden', - }, - genreText: { - color: '#9e9e9e', // Default medium gray - fontWeight: '500', - fontSize: 14, - }, -}); - -export default React.memo(GenreSelector); \ No newline at end of file diff --git a/src/components/home/CatalogSection.tsx b/src/components/home/CatalogSection.tsx index a0860b80..9365880c 100644 --- a/src/components/home/CatalogSection.tsx +++ b/src/components/home/CatalogSection.tsx @@ -176,4 +176,4 @@ const styles = StyleSheet.create({ }, }); -export default CatalogSection; \ No newline at end of file +export default React.memo(CatalogSection); \ No newline at end of file diff --git a/src/components/home/FeaturedContent.tsx b/src/components/home/FeaturedContent.tsx index 46ee9390..b8ac3b57 100644 --- a/src/components/home/FeaturedContent.tsx +++ b/src/components/home/FeaturedContent.tsx @@ -764,4 +764,4 @@ const styles = StyleSheet.create({ }, }); -export default FeaturedContent; \ No newline at end of file +export default React.memo(FeaturedContent); \ No newline at end of file diff --git a/src/components/home/ThisWeekSection.tsx b/src/components/home/ThisWeekSection.tsx index fbba9d72..aa78aa43 100644 --- a/src/components/home/ThisWeekSection.tsx +++ b/src/components/home/ThisWeekSection.tsx @@ -41,7 +41,7 @@ interface ThisWeekEpisode { season_poster_path: string | null; } -export const ThisWeekSection = () => { +export const ThisWeekSection = React.memo(() => { const navigation = useNavigation>(); const { libraryItems, loading: libraryLoading } = useLibrary(); const [episodes, setEpisodes] = useState([]); @@ -287,7 +287,7 @@ export const ThisWeekSection = () => { /> ); -}; +}); const styles = StyleSheet.create({ container: { diff --git a/src/constants/discover.ts b/src/constants/discover.ts deleted file mode 100644 index 1af9de27..00000000 --- a/src/constants/discover.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { MaterialIcons } from '@expo/vector-icons'; -import { StreamingContent } from '../services/catalogService'; - -export interface Category { - id: string; - name: string; - type: 'movie' | 'series' | 'channel' | 'tv'; - icon: keyof typeof MaterialIcons.glyphMap; -} - -export interface GenreCatalog { - genre: string; - items: StreamingContent[]; -} - -export 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 -export const COMMON_GENRES = [ - 'All', - 'Action', - 'Adventure', - 'Animation', - 'Comedy', - 'Crime', - 'Documentary', - 'Drama', - 'Family', - 'Fantasy', - 'History', - 'Horror', - 'Music', - 'Mystery', - 'Romance', - 'Science Fiction', - 'Thriller', - 'War', - 'Western' -]; \ No newline at end of file diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx index d09acb9f..3c8723c0 100644 --- a/src/navigation/AppNavigator.tsx +++ b/src/navigation/AppNavigator.tsx @@ -17,7 +17,6 @@ import { useTheme } from '../contexts/ThemeContext'; // Import screens with their proper types import HomeScreen from '../screens/HomeScreen'; -import DiscoverScreen from '../screens/DiscoverScreen'; import LibraryScreen from '../screens/LibraryScreen'; import SettingsScreen from '../screens/SettingsScreen'; import MetadataScreen from '../screens/MetadataScreen'; @@ -46,7 +45,6 @@ export type RootStackParamList = { Onboarding: undefined; MainTabs: undefined; Home: undefined; - Discover: undefined; Library: undefined; Settings: undefined; Search: undefined; @@ -110,8 +108,8 @@ export type RootStackNavigationProp = NativeStackNavigationProp { case 'Home': iconName = 'home'; break; - case 'Discover': - iconName = 'compass'; - break; case 'Library': iconName = 'play-box-multiple'; break; + case 'Search': + iconName = 'feature-search'; + break; case 'Settings': iconName = 'cog'; break; @@ -546,12 +544,12 @@ const MainTabs = () => { case 'Home': iconName = 'home'; break; - case 'Discover': - iconName = 'compass'; - break; case 'Library': iconName = 'play-box-multiple'; break; + case 'Search': + iconName = 'feature-search'; + break; case 'Settings': iconName = 'cog'; break; @@ -634,14 +632,6 @@ const MainTabs = () => { tabBarLabel: 'Home', }} /> - { headerShown: false }} /> + { - const navigation = useNavigation>(); - const [selectedCategory, setSelectedCategory] = useState(CATEGORIES[0]); - const [selectedGenre, setSelectedGenre] = useState('All'); - const [catalogs, setCatalogs] = useState([]); - const [loading, setLoading] = useState(true); - const styles = useDiscoverStyles(); - const insets = useSafeAreaInsets(); - const { currentTheme } = useTheme(); - - // Force consistent status bar settings - useEffect(() => { - const applyStatusBarConfig = () => { - StatusBar.setBarStyle('light-content'); - if (Platform.OS === 'android') { - StatusBar.setTranslucent(true); - StatusBar.setBackgroundColor('transparent'); - } - }; - - applyStatusBarConfig(); - - // Re-apply on focus - const unsubscribe = navigation.addListener('focus', applyStatusBarConfig); - return unsubscribe; - }, [navigation]); - - // Load content when category or genre changes - 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); - }); - - 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([]); - } finally { - setLoading(false); - } - }; - - const handleCategoryPress = useCallback((category: Category) => { - if (category.id !== selectedCategory.id) { - setSelectedCategory(category); - setSelectedGenre('All'); // Reset to All when changing category - } - }, [selectedCategory]); - - const handleGenrePress = useCallback((genre: string) => { - if (genre !== selectedGenre) { - setSelectedGenre(genre); - } - }, [selectedGenre]); - - const handleSearchPress = useCallback(() => { - navigation.navigate('Search'); - }, [navigation]); - - const headerBaseHeight = Platform.OS === 'android' ? 80 : 60; - const topSpacing = Platform.OS === 'android' ? (StatusBar.currentHeight || 0) : insets.top; - const headerHeight = headerBaseHeight + topSpacing; - - const renderEmptyState = () => ( - - - No content found for {selectedGenre !== 'All' ? selectedGenre : 'these filters'} - - - ); - - return ( - - {/* Fixed position header background */} - - - - {/* Header Section */} - - - Discover - - - - - - - {/* Content Container */} - - {/* Categories Section */} - - - {/* Genres Section */} - - - {/* Content Section */} - {loading ? ( - - - - ) : catalogs.length > 0 ? ( - - ) : renderEmptyState()} - - - - ); -}; - -export default React.memo(DiscoverScreen); \ No newline at end of file diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 68fbfa54..00011891 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -602,11 +602,10 @@ const HomeScreen = () => { ]} showsVerticalScrollIndicator={false} ListFooterComponent={ListFooterComponent} - initialNumToRender={3} - maxToRenderPerBatch={2} - windowSize={5} - removeClippedSubviews={Platform.OS === 'android'} - updateCellsBatchingPeriod={50} + initialNumToRender={5} + maxToRenderPerBatch={5} + windowSize={11} + removeClippedSubviews={false} onEndReachedThreshold={0.5} maintainVisibleContentPosition={{ minIndexForVisible: 0, diff --git a/src/styles/screens/discoverStyles.ts b/src/styles/screens/discoverStyles.ts deleted file mode 100644 index 0e00c21d..00000000 --- a/src/styles/screens/discoverStyles.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { StyleSheet, Dimensions } from 'react-native'; -import { useTheme } from '../../contexts/ThemeContext'; - -const useDiscoverStyles = () => { - const { width } = Dimensions.get('window'); - const { currentTheme } = useTheme(); - - return StyleSheet.create({ - container: { - flex: 1, - backgroundColor: currentTheme.colors.darkBackground, - }, - headerBackground: { - position: 'absolute', - top: 0, - left: 0, - right: 0, - backgroundColor: currentTheme.colors.darkBackground, - zIndex: 1, - }, - contentContainer: { - flex: 1, - backgroundColor: currentTheme.colors.darkBackground, - }, - header: { - paddingHorizontal: 20, - justifyContent: 'flex-end', - paddingBottom: 8, - backgroundColor: 'transparent', - zIndex: 2, - }, - headerContent: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - }, - headerTitle: { - fontSize: 32, - fontWeight: '800', - color: currentTheme.colors.white, - letterSpacing: 0.3, - }, - searchButton: { - padding: 10, - borderRadius: 24, - backgroundColor: 'rgba(255,255,255,0.08)', - }, - loadingContainer: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - emptyContainer: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - paddingTop: 80, - paddingBottom: 90, - }, - emptyText: { - color: currentTheme.colors.mediumGray, - fontSize: 16, - textAlign: 'center', - paddingHorizontal: 32, - }, - }); -}; - -export default useDiscoverStyles; \ No newline at end of file