update morelikethis sizing
This commit is contained in:
parent
175d47f71f
commit
68340eac9e
1 changed files with 61 additions and 44 deletions
|
|
@ -20,32 +20,13 @@ import CustomAlert from '../../components/CustomAlert';
|
||||||
|
|
||||||
const { width } = Dimensions.get('window');
|
const { width } = Dimensions.get('window');
|
||||||
|
|
||||||
// Dynamic poster calculation based on screen width for More Like This section
|
// Breakpoints for responsive sizing
|
||||||
const calculatePosterLayout = (screenWidth: number) => {
|
const BREAKPOINTS = {
|
||||||
const MIN_POSTER_WIDTH = 100; // Slightly smaller for more items in this section
|
phone: 0,
|
||||||
const MAX_POSTER_WIDTH = 130; // Maximum poster width
|
tablet: 768,
|
||||||
const HORIZONTAL_PADDING = 48; // Total horizontal padding/margins
|
largeTablet: 1024,
|
||||||
|
tv: 1440,
|
||||||
// Calculate how many posters can fit (aim for slightly more items than main sections)
|
} as const;
|
||||||
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 {
|
interface MoreLikeThisSectionProps {
|
||||||
recommendations: StreamingContent[];
|
recommendations: StreamingContent[];
|
||||||
|
|
@ -59,6 +40,48 @@ export const MoreLikeThisSection: React.FC<MoreLikeThisSectionProps> = ({
|
||||||
const { currentTheme } = useTheme();
|
const { currentTheme } = useTheme();
|
||||||
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
|
const navigation = useNavigation<NavigationProp<RootStackParamList>>();
|
||||||
|
|
||||||
|
// Determine device type
|
||||||
|
const deviceWidth = Dimensions.get('window').width;
|
||||||
|
const getDeviceType = React.useCallback(() => {
|
||||||
|
if (deviceWidth >= BREAKPOINTS.tv) return 'tv';
|
||||||
|
if (deviceWidth >= BREAKPOINTS.largeTablet) return 'largeTablet';
|
||||||
|
if (deviceWidth >= BREAKPOINTS.tablet) return 'tablet';
|
||||||
|
return 'phone';
|
||||||
|
}, [deviceWidth]);
|
||||||
|
const deviceType = getDeviceType();
|
||||||
|
const isTablet = deviceType === 'tablet';
|
||||||
|
const isLargeTablet = deviceType === 'largeTablet';
|
||||||
|
const isTV = deviceType === 'tv';
|
||||||
|
|
||||||
|
// Responsive spacing & sizes
|
||||||
|
const horizontalPadding = React.useMemo(() => {
|
||||||
|
switch (deviceType) {
|
||||||
|
case 'tv': return 32;
|
||||||
|
case 'largeTablet': return 28;
|
||||||
|
case 'tablet': return 24;
|
||||||
|
default: return 16;
|
||||||
|
}
|
||||||
|
}, [deviceType]);
|
||||||
|
|
||||||
|
const itemSpacing = React.useMemo(() => {
|
||||||
|
switch (deviceType) {
|
||||||
|
case 'tv': return 14;
|
||||||
|
case 'largeTablet': return 12;
|
||||||
|
case 'tablet': return 12;
|
||||||
|
default: return 12;
|
||||||
|
}
|
||||||
|
}, [deviceType]);
|
||||||
|
|
||||||
|
const posterWidth = React.useMemo(() => {
|
||||||
|
switch (deviceType) {
|
||||||
|
case 'tv': return 180;
|
||||||
|
case 'largeTablet': return 160;
|
||||||
|
case 'tablet': return 140;
|
||||||
|
default: return 120;
|
||||||
|
}
|
||||||
|
}, [deviceType]);
|
||||||
|
const posterHeight = React.useMemo(() => posterWidth * 1.5, [posterWidth]);
|
||||||
|
|
||||||
const [alertVisible, setAlertVisible] = React.useState(false);
|
const [alertVisible, setAlertVisible] = React.useState(false);
|
||||||
const [alertTitle, setAlertTitle] = React.useState('');
|
const [alertTitle, setAlertTitle] = React.useState('');
|
||||||
const [alertMessage, setAlertMessage] = React.useState('');
|
const [alertMessage, setAlertMessage] = React.useState('');
|
||||||
|
|
@ -94,15 +117,15 @@ export const MoreLikeThisSection: React.FC<MoreLikeThisSectionProps> = ({
|
||||||
|
|
||||||
const renderItem = ({ item }: { item: StreamingContent }) => (
|
const renderItem = ({ item }: { item: StreamingContent }) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.itemContainer}
|
style={[styles.itemContainer, { width: posterWidth, marginRight: itemSpacing }]}
|
||||||
onPress={() => handleItemPress(item)}
|
onPress={() => handleItemPress(item)}
|
||||||
>
|
>
|
||||||
<FastImage
|
<FastImage
|
||||||
source={{ uri: item.poster }}
|
source={{ uri: item.poster }}
|
||||||
style={[styles.poster, { backgroundColor: currentTheme.colors.elevation1 }]}
|
style={[styles.poster, { backgroundColor: currentTheme.colors.elevation1, width: posterWidth, height: posterHeight, borderRadius: isTV ? 12 : isLargeTablet ? 10 : isTablet ? 10 : 8 }]}
|
||||||
resizeMode={FastImage.resizeMode.cover}
|
resizeMode={FastImage.resizeMode.cover}
|
||||||
/>
|
/>
|
||||||
<Text style={[styles.title, { color: currentTheme.colors.mediumEmphasis }]} numberOfLines={2}>
|
<Text style={[styles.title, { color: currentTheme.colors.mediumEmphasis, fontSize: isTV ? 14 : isLargeTablet ? 13 : isTablet ? 13 : 13, lineHeight: isTV ? 20 : 18 }]} numberOfLines={2}>
|
||||||
{item.name}
|
{item.name}
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
@ -121,15 +144,15 @@ export const MoreLikeThisSection: React.FC<MoreLikeThisSectionProps> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={[styles.container, { paddingLeft: 0 }] }>
|
||||||
<Text style={[styles.sectionTitle, { color: currentTheme.colors.highEmphasis }]}>More Like This</Text>
|
<Text style={[styles.sectionTitle, { color: currentTheme.colors.highEmphasis, fontSize: isTV ? 24 : isLargeTablet ? 22 : isTablet ? 20 : 20, paddingHorizontal: horizontalPadding }]}>More Like This</Text>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={recommendations}
|
data={recommendations}
|
||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
keyExtractor={(item) => item.id}
|
keyExtractor={(item) => item.id}
|
||||||
horizontal
|
horizontal
|
||||||
showsHorizontalScrollIndicator={false}
|
showsHorizontalScrollIndicator={false}
|
||||||
contentContainerStyle={styles.listContentContainer}
|
contentContainerStyle={[styles.listContentContainer, { paddingHorizontal: horizontalPadding, paddingRight: horizontalPadding + itemSpacing }]}
|
||||||
/>
|
/>
|
||||||
<CustomAlert
|
<CustomAlert
|
||||||
visible={alertVisible}
|
visible={alertVisible}
|
||||||
|
|
@ -146,36 +169,30 @@ const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
marginTop: 16,
|
marginTop: 16,
|
||||||
marginBottom: 16,
|
marginBottom: 16,
|
||||||
paddingLeft: 0,
|
|
||||||
},
|
},
|
||||||
sectionTitle: {
|
sectionTitle: {
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: '800',
|
fontWeight: '800',
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
marginTop: 8,
|
marginTop: 8,
|
||||||
paddingHorizontal: 16,
|
|
||||||
},
|
},
|
||||||
listContentContainer: {
|
listContentContainer: {
|
||||||
paddingHorizontal: 16,
|
paddingRight: 32, // Will be overridden responsively
|
||||||
paddingRight: 32, // Ensure last item has padding
|
|
||||||
},
|
},
|
||||||
itemContainer: {
|
itemContainer: {
|
||||||
marginRight: 12,
|
marginRight: 12, // will be overridden responsively
|
||||||
width: POSTER_WIDTH,
|
|
||||||
},
|
},
|
||||||
poster: {
|
poster: {
|
||||||
width: POSTER_WIDTH,
|
borderRadius: 8, // overridden responsively
|
||||||
height: POSTER_HEIGHT,
|
|
||||||
borderRadius: 8,
|
|
||||||
marginBottom: 8,
|
marginBottom: 8,
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 13,
|
fontSize: 13, // overridden responsively
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
lineHeight: 18,
|
lineHeight: 18, // overridden responsively
|
||||||
},
|
},
|
||||||
loadingContainer: {
|
loadingContainer: {
|
||||||
height: POSTER_HEIGHT + 40, // Approximate height to prevent layout shifts
|
// Approximate height to prevent layout shifts; not used in responsive version
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue