diff --git a/src/components/home/CatalogSection.tsx b/src/components/home/CatalogSection.tsx index 8f4ed81..d4cdd9c 100644 --- a/src/components/home/CatalogSection.tsx +++ b/src/components/home/CatalogSection.tsx @@ -14,7 +14,32 @@ interface CatalogSectionProps { } const { width } = Dimensions.get('window'); -const POSTER_WIDTH = (width - 50) / 3; + +// Dynamic poster calculation based on screen width +const calculatePosterLayout = (screenWidth: number) => { + const MIN_POSTER_WIDTH = 110; // Minimum poster width for readability + const MAX_POSTER_WIDTH = 140; // Maximum poster width to prevent oversized posters + const HORIZONTAL_PADDING = 50; // Total horizontal padding/margins + + // Calculate how many posters can fit + const availableWidth = screenWidth - HORIZONTAL_PADDING; + const maxColumns = Math.floor(availableWidth / MIN_POSTER_WIDTH); + + // Limit to reasonable number of columns (3-6) + const numColumns = Math.min(Math.max(maxColumns, 3), 6); + + // Calculate actual poster width + const posterWidth = Math.min(availableWidth / numColumns, MAX_POSTER_WIDTH); + + return { + numColumns, + posterWidth, + spacing: 12 // Space between posters + }; +}; + +const posterLayout = calculatePosterLayout(width); +const POSTER_WIDTH = posterLayout.posterWidth; const CatalogSection = ({ catalog }: CatalogSectionProps) => { const navigation = useNavigation>(); diff --git a/src/components/home/ContentItem.tsx b/src/components/home/ContentItem.tsx index ac3b0db..f5061c5 100644 --- a/src/components/home/ContentItem.tsx +++ b/src/components/home/ContentItem.tsx @@ -12,7 +12,32 @@ interface ContentItemProps { } const { width } = Dimensions.get('window'); -const POSTER_WIDTH = (width - 50) / 3; + +// Dynamic poster calculation based on screen width +const calculatePosterLayout = (screenWidth: number) => { + const MIN_POSTER_WIDTH = 110; // Minimum poster width for readability + const MAX_POSTER_WIDTH = 140; // Maximum poster width to prevent oversized posters + const HORIZONTAL_PADDING = 50; // Total horizontal padding/margins + + // Calculate how many posters can fit + const availableWidth = screenWidth - HORIZONTAL_PADDING; + const maxColumns = Math.floor(availableWidth / MIN_POSTER_WIDTH); + + // Limit to reasonable number of columns (3-6) + const numColumns = Math.min(Math.max(maxColumns, 3), 6); + + // Calculate actual poster width + const posterWidth = Math.min(availableWidth / numColumns, MAX_POSTER_WIDTH); + + return { + numColumns, + posterWidth, + spacing: 12 // Space between posters + }; +}; + +const posterLayout = calculatePosterLayout(width); +const POSTER_WIDTH = posterLayout.posterWidth; const ContentItem = ({ item: initialItem, onPress }: ContentItemProps) => { const [menuVisible, setMenuVisible] = useState(false); diff --git a/src/components/home/ContinueWatchingSection.tsx b/src/components/home/ContinueWatchingSection.tsx index 5ef5002..17e64d2 100644 --- a/src/components/home/ContinueWatchingSection.tsx +++ b/src/components/home/ContinueWatchingSection.tsx @@ -33,8 +33,32 @@ interface ContinueWatchingRef { refresh: () => Promise; } +// Dynamic poster calculation based on screen width for Continue Watching section +const calculatePosterLayout = (screenWidth: number) => { + const MIN_POSTER_WIDTH = 120; // Slightly larger for continue watching items + const MAX_POSTER_WIDTH = 160; // Maximum poster width for this section + const HORIZONTAL_PADDING = 40; // Total horizontal padding/margins + + // Calculate how many posters can fit (fewer items for continue watching) + const availableWidth = screenWidth - HORIZONTAL_PADDING; + const maxColumns = Math.floor(availableWidth / MIN_POSTER_WIDTH); + + // Limit to reasonable number of columns (2-5 for continue watching) + const numColumns = Math.min(Math.max(maxColumns, 2), 5); + + // Calculate actual poster width + const posterWidth = Math.min(availableWidth / numColumns, MAX_POSTER_WIDTH); + + return { + numColumns, + posterWidth, + spacing: 12 // Space between posters + }; +}; + const { width } = Dimensions.get('window'); -const POSTER_WIDTH = (width - 40) / 2.7; +const posterLayout = calculatePosterLayout(width); +const POSTER_WIDTH = posterLayout.posterWidth; // Create a proper imperative handle with React.forwardRef and updated type const ContinueWatchingSection = React.forwardRef((props, ref) => { diff --git a/src/components/metadata/MoreLikeThisSection.tsx b/src/components/metadata/MoreLikeThisSection.tsx index f69cc69..f2df2e4 100644 --- a/src/components/metadata/MoreLikeThisSection.tsx +++ b/src/components/metadata/MoreLikeThisSection.tsx @@ -19,7 +19,32 @@ import { TMDBService } from '../../services/tmdbService'; import { catalogService } from '../../services/catalogService'; const { width } = Dimensions.get('window'); -const POSTER_WIDTH = (width - 48) / 3.5; // Adjust number for desired items visible + +// Dynamic poster calculation based on screen width for More Like This section +const calculatePosterLayout = (screenWidth: number) => { + const MIN_POSTER_WIDTH = 100; // Slightly smaller for more items in this section + const MAX_POSTER_WIDTH = 130; // Maximum poster width + const HORIZONTAL_PADDING = 48; // Total horizontal padding/margins + + // Calculate how many posters can fit (aim for slightly more items than main sections) + const availableWidth = screenWidth - HORIZONTAL_PADDING; + const maxColumns = Math.floor(availableWidth / MIN_POSTER_WIDTH); + + // Limit to reasonable number of columns (3-7 for this section) + const numColumns = Math.min(Math.max(maxColumns, 3), 7); + + // Calculate actual poster width + const posterWidth = Math.min(availableWidth / numColumns, MAX_POSTER_WIDTH); + + return { + numColumns, + posterWidth, + spacing: 12 // Space between posters + }; +}; + +const posterLayout = calculatePosterLayout(width); +const POSTER_WIDTH = posterLayout.posterWidth; const POSTER_HEIGHT = POSTER_WIDTH * 1.5; interface MoreLikeThisSectionProps { diff --git a/src/screens/CatalogScreen.tsx b/src/screens/CatalogScreen.tsx index 59d5c39..83de2ab 100644 --- a/src/screens/CatalogScreen.tsx +++ b/src/screens/CatalogScreen.tsx @@ -41,9 +41,35 @@ const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0; // Screen dimensions and grid layout const { width } = Dimensions.get('window'); -const NUM_COLUMNS = 3; + +// Dynamic column calculation based on screen width +const calculateCatalogLayout = (screenWidth: number) => { + const MIN_ITEM_WIDTH = 110; // Minimum item width for readability + const MAX_ITEM_WIDTH = 150; // Maximum item width + const HORIZONTAL_PADDING = SPACING.lg * 2; // Total horizontal padding + const ITEM_MARGIN_TOTAL = SPACING.sm * 2; // Total margin per item + + // Calculate how many columns can fit + const availableWidth = screenWidth - HORIZONTAL_PADDING; + const maxColumns = Math.floor(availableWidth / (MIN_ITEM_WIDTH + ITEM_MARGIN_TOTAL)); + + // Limit to reasonable number of columns (2-6) + const numColumns = Math.min(Math.max(maxColumns, 2), 6); + + // Calculate actual item width + const totalMargins = ITEM_MARGIN_TOTAL * numColumns; + const itemWidth = Math.min((availableWidth - totalMargins) / numColumns, MAX_ITEM_WIDTH); + + return { + numColumns, + itemWidth + }; +}; + +const catalogLayout = calculateCatalogLayout(width); +const NUM_COLUMNS = catalogLayout.numColumns; const ITEM_MARGIN = SPACING.sm; -const ITEM_WIDTH = (width - (SPACING.lg * 2) - (ITEM_MARGIN * 2 * NUM_COLUMNS)) / NUM_COLUMNS; +const ITEM_WIDTH = catalogLayout.itemWidth; // Create a styles creator function that accepts the theme colors const createStyles = (colors: any) => StyleSheet.create({ diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index f781b0d..8da022b 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -679,7 +679,32 @@ const HomeScreen = () => { }; const { width, height } = Dimensions.get('window'); -const POSTER_WIDTH = (width - 50) / 3; + +// Dynamic poster calculation based on screen width +const calculatePosterLayout = (screenWidth: number) => { + const MIN_POSTER_WIDTH = 110; // Minimum poster width for readability + const MAX_POSTER_WIDTH = 140; // Maximum poster width to prevent oversized posters + const HORIZONTAL_PADDING = 50; // Total horizontal padding/margins + + // Calculate how many posters can fit + const availableWidth = screenWidth - HORIZONTAL_PADDING; + const maxColumns = Math.floor(availableWidth / MIN_POSTER_WIDTH); + + // Limit to reasonable number of columns (3-6) + const numColumns = Math.min(Math.max(maxColumns, 3), 6); + + // Calculate actual poster width + const posterWidth = Math.min(availableWidth / numColumns, MAX_POSTER_WIDTH); + + return { + numColumns, + posterWidth, + spacing: 12 // Space between posters + }; +}; + +const posterLayout = calculatePosterLayout(width); +const POSTER_WIDTH = posterLayout.posterWidth; const styles = StyleSheet.create({ container: { diff --git a/src/styles/homeStyles.ts b/src/styles/homeStyles.ts index dff5863..c74c122 100644 --- a/src/styles/homeStyles.ts +++ b/src/styles/homeStyles.ts @@ -1,7 +1,32 @@ import { StyleSheet, Dimensions, Platform } from 'react-native'; const { width, height } = Dimensions.get('window'); -export const POSTER_WIDTH = (width - 50) / 3; + +// Dynamic poster calculation based on screen width +const calculatePosterLayout = (screenWidth: number) => { + const MIN_POSTER_WIDTH = 110; // Minimum poster width for readability + const MAX_POSTER_WIDTH = 140; // Maximum poster width to prevent oversized posters + const HORIZONTAL_PADDING = 50; // Total horizontal padding/margins + + // Calculate how many posters can fit + const availableWidth = screenWidth - HORIZONTAL_PADDING; + const maxColumns = Math.floor(availableWidth / MIN_POSTER_WIDTH); + + // Limit to reasonable number of columns (3-6) + const numColumns = Math.min(Math.max(maxColumns, 3), 6); + + // Calculate actual poster width + const posterWidth = Math.min(availableWidth / numColumns, MAX_POSTER_WIDTH); + + return { + numColumns, + posterWidth, + spacing: 12 // Space between posters + }; +}; + +const posterLayout = calculatePosterLayout(width); +export const POSTER_WIDTH = posterLayout.posterWidth; export const POSTER_HEIGHT = POSTER_WIDTH * 1.5; export const HORIZONTAL_PADDING = 16; diff --git a/src/utils/posterUtils.ts b/src/utils/posterUtils.ts new file mode 100644 index 0000000..4fa4c1d --- /dev/null +++ b/src/utils/posterUtils.ts @@ -0,0 +1,82 @@ +import { Dimensions } from 'react-native'; + +export interface PosterLayoutConfig { + minPosterWidth: number; + maxPosterWidth: number; + horizontalPadding: number; + minColumns: number; + maxColumns: number; + spacing: number; +} + +export interface PosterLayout { + numColumns: number; + posterWidth: number; + spacing: number; +} + +// Default configuration for main home sections +export const DEFAULT_POSTER_CONFIG: PosterLayoutConfig = { + minPosterWidth: 110, + maxPosterWidth: 140, + horizontalPadding: 50, + minColumns: 3, + maxColumns: 6, + spacing: 12 +}; + +// Configuration for More Like This section (smaller posters, more items) +export const MORE_LIKE_THIS_CONFIG: PosterLayoutConfig = { + minPosterWidth: 100, + maxPosterWidth: 130, + horizontalPadding: 48, + minColumns: 3, + maxColumns: 7, + spacing: 12 +}; + +// Configuration for Continue Watching section (larger posters, fewer items) +export const CONTINUE_WATCHING_CONFIG: PosterLayoutConfig = { + minPosterWidth: 120, + maxPosterWidth: 160, + horizontalPadding: 40, + minColumns: 2, + maxColumns: 5, + spacing: 12 +}; + +export const calculatePosterLayout = ( + screenWidth: number, + config: PosterLayoutConfig = DEFAULT_POSTER_CONFIG +): PosterLayout => { + const { + minPosterWidth, + maxPosterWidth, + horizontalPadding, + minColumns, + maxColumns, + spacing + } = config; + + // Calculate how many posters can fit + const availableWidth = screenWidth - horizontalPadding; + const maxColumnsBasedOnWidth = Math.floor(availableWidth / minPosterWidth); + + // Limit to reasonable number of columns + const numColumns = Math.min(Math.max(maxColumnsBasedOnWidth, minColumns), maxColumns); + + // Calculate actual poster width + const posterWidth = Math.min(availableWidth / numColumns, maxPosterWidth); + + return { + numColumns, + posterWidth, + spacing + }; +}; + +// Helper function to get current screen dimensions +export const getCurrentPosterLayout = (config?: PosterLayoutConfig): PosterLayout => { + const { width } = Dimensions.get('window'); + return calculatePosterLayout(width, config); +}; \ No newline at end of file