fix(native): make person filmography grid responsive to screen width

Replace the hardcoded 2-column filmography grid with a responsive layout that uses 2, 3, or 4 columns based on screen width (600px and 900px breakpoints). Switch from per-item fixed widths to horizontal gutter padding so columns are evenly distributed across all screen sizes.
This commit is contained in:
2026-03-16 11:07:49 -04:00
parent 3e9d7efd94
commit 1c3c74fb0a
+19 -6
View File
@@ -33,6 +33,7 @@ import { addRecentlyViewed } from "@/lib/recently-viewed";
const FILMOGRAPHY_GAP = 12; const FILMOGRAPHY_GAP = 12;
const FILMOGRAPHY_PADDING = 16; const FILMOGRAPHY_PADDING = 16;
const FILMOGRAPHY_GUTTER = FILMOGRAPHY_GAP / 2;
function calculateAge(birthday: string, deathday?: string | null): number { function calculateAge(birthday: string, deathday?: string | null): number {
const birth = new Date(birthday); const birth = new Date(birthday);
@@ -60,8 +61,14 @@ export default function PersonDetailScreen() {
const { back } = useRouter(); const { back } = useRouter();
const { width: screenWidth } = useWindowDimensions(); const { width: screenWidth } = useWindowDimensions();
const useAutomaticInsets = process.env.EXPO_OS === "ios"; const useAutomaticInsets = process.env.EXPO_OS === "ios";
const columnWidth = const filmographyColumns =
(screenWidth - FILMOGRAPHY_PADDING * 2 - FILMOGRAPHY_GAP) / 2; screenWidth >= 900 ? 4 : screenWidth >= 600 ? 3 : 2;
const columnWidth = Math.floor(
(screenWidth -
FILMOGRAPHY_PADDING * 2 -
FILMOGRAPHY_GAP * (filmographyColumns - 1)) /
filmographyColumns,
);
const mutedForeground = useCSSVariable("--color-muted-foreground") as string; const mutedForeground = useCSSVariable("--color-muted-foreground") as string;
const primaryColor = useCSSVariable("--color-primary") as string; const primaryColor = useCSSVariable("--color-primary") as string;
@@ -117,7 +124,12 @@ export default function PersonDetailScreen() {
const renderFilmographyItem = useCallback( const renderFilmographyItem = useCallback(
({ item: credit }: { item: (typeof filmography)[number] }) => ( ({ item: credit }: { item: (typeof filmography)[number] }) => (
<View style={{ width: columnWidth, paddingBottom: FILMOGRAPHY_GAP }}> <View
style={{
paddingBottom: FILMOGRAPHY_GAP,
paddingHorizontal: FILMOGRAPHY_GUTTER,
}}
>
<PosterCard <PosterCard
id={credit.titleId} id={credit.titleId}
tmdbId={credit.tmdbId} tmdbId={credit.tmdbId}
@@ -128,7 +140,7 @@ export default function PersonDetailScreen() {
releaseDate={credit.releaseDate ?? credit.firstAirDate} releaseDate={credit.releaseDate ?? credit.firstAirDate}
voteAverage={credit.voteAverage} voteAverage={credit.voteAverage}
userStatus={userStatuses[credit.titleId] ?? null} userStatus={userStatuses[credit.titleId] ?? null}
width={undefined} width={columnWidth}
onPress={handlePress} onPress={handlePress}
onQuickAdd={handleQuickAdd} onQuickAdd={handleQuickAdd}
isAdding={addingKey === `${credit.tmdbId}-${credit.type}`} isAdding={addingKey === `${credit.tmdbId}-${credit.type}`}
@@ -360,13 +372,14 @@ export default function PersonDetailScreen() {
data={filmography} data={filmography}
keyExtractor={(item) => item.titleId} keyExtractor={(item) => item.titleId}
renderItem={renderFilmographyItem} renderItem={renderFilmographyItem}
numColumns={2} numColumns={filmographyColumns}
showsVerticalScrollIndicator={false}
contentInsetAdjustmentBehavior={ contentInsetAdjustmentBehavior={
useAutomaticInsets ? "automatic" : "never" useAutomaticInsets ? "automatic" : "never"
} }
contentContainerStyle={{ contentContainerStyle={{
paddingBottom: useAutomaticInsets ? 32 : insets.bottom + 32, paddingBottom: useAutomaticInsets ? 32 : insets.bottom + 32,
paddingHorizontal: FILMOGRAPHY_PADDING, paddingHorizontal: FILMOGRAPHY_PADDING - FILMOGRAPHY_GUTTER,
}} }}
ListHeaderComponent={listHeader} ListHeaderComponent={listHeader}
onEndReached={() => { onEndReached={() => {