From ccb78141336de1a3333d6677fdb475f9fe84dd63 Mon Sep 17 00:00:00 2001 From: Robbie <205481179+tormox@users.noreply.github.com> Date: Tue, 25 Aug 2026 09:42:04 +0100 Subject: [PATCH 1/2] [verified] fix(mobile): compact details backdrop in phone landscape In landscape, the media detail page backdrop was forced to at least 400dp by coerceAtLeast, which exceeded the entire screen height on phones. Use 35% of screen height (capped at 200dp) in landscape, keeping the existing 53%/400dp floor for portrait. Apply the same fix to the SkeletonLoader placeholder. --- .../kotlin/com/arflix/tv/ui/components/SkeletonLoader.kt | 7 ++++++- .../com/arflix/tv/ui/screens/details/DetailsScreen.kt | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/arflix/tv/ui/components/SkeletonLoader.kt b/app/src/main/kotlin/com/arflix/tv/ui/components/SkeletonLoader.kt index 2958969a0..e7726a64c 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/components/SkeletonLoader.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/components/SkeletonLoader.kt @@ -333,7 +333,12 @@ fun SkeletonDetailsPage( if (isMobile) { val configuration = LocalConfiguration.current val screenHeightDp = configuration.screenHeightDp.dp - val backdropHeight = (screenHeightDp * 0.53f).coerceAtLeast(400.dp) + val isLandscape = configuration.screenWidthDp > configuration.screenHeightDp + val backdropHeight = if (isLandscape) { + (screenHeightDp * 0.35f).coerceIn(120.dp, 200.dp) + } else { + (screenHeightDp * 0.53f).coerceAtLeast(400.dp) + } Column( modifier = modifier diff --git a/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt b/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt index 3a7ede60c..06fa14594 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt @@ -1297,7 +1297,12 @@ private fun DetailsContent( if (isMobile) { val configuration = LocalConfiguration.current val screenHeightDp = configuration.screenHeightDp.dp - val backdropHeight = (screenHeightDp * 0.53f).coerceAtLeast(400.dp) + val isLandscape = configuration.screenWidthDp > configuration.screenHeightDp + val backdropHeight = if (isLandscape) { + (screenHeightDp * 0.35f).coerceIn(120.dp, 200.dp) + } else { + (screenHeightDp * 0.53f).coerceAtLeast(400.dp) + } val mobileScrollState = rememberScrollState() val density = LocalDensity.current var stickyThreshold by remember { mutableStateOf(-1f) } From 53b2476c12aab61514ca7a5ae800b862f083e710 Mon Sep 17 00:00:00 2001 From: Arvin Date: Tue, 25 Aug 2026 15:37:11 +0200 Subject: [PATCH 2/2] [verified] fix(mobile): keep compact details overlay readable --- .../ui/components/DetailsResponsiveLayout.kt | 14 +++++ .../arflix/tv/ui/components/SkeletonLoader.kt | 13 ++--- .../tv/ui/screens/details/DetailsScreen.kt | 14 ++--- .../components/DetailsResponsiveLayoutTest.kt | 58 +++++++++++++++++++ 4 files changed, 85 insertions(+), 14 deletions(-) create mode 100644 app/src/main/kotlin/com/arflix/tv/ui/components/DetailsResponsiveLayout.kt create mode 100644 app/src/test/kotlin/com/arflix/tv/ui/components/DetailsResponsiveLayoutTest.kt diff --git a/app/src/main/kotlin/com/arflix/tv/ui/components/DetailsResponsiveLayout.kt b/app/src/main/kotlin/com/arflix/tv/ui/components/DetailsResponsiveLayout.kt new file mode 100644 index 000000000..b8284b77d --- /dev/null +++ b/app/src/main/kotlin/com/arflix/tv/ui/components/DetailsResponsiveLayout.kt @@ -0,0 +1,14 @@ +package com.arflix.tv.ui.components + +internal fun resolveDetailsBackdropHeightDp( + screenWidthDp: Int, + screenHeightDp: Int, + isPhone: Boolean, +): Float { + val isPhoneLandscape = isPhone && screenWidthDp > screenHeightDp + return if (isPhoneLandscape) { + (screenHeightDp * 0.55f).coerceIn(190f, 220f) + } else { + (screenHeightDp * 0.53f).coerceAtLeast(400f) + } +} diff --git a/app/src/main/kotlin/com/arflix/tv/ui/components/SkeletonLoader.kt b/app/src/main/kotlin/com/arflix/tv/ui/components/SkeletonLoader.kt index e7726a64c..7bf532445 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/components/SkeletonLoader.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/components/SkeletonLoader.kt @@ -33,6 +33,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.sp +import com.arflix.tv.util.DeviceType import com.arflix.tv.util.LocalDeviceType import androidx.tv.foundation.lazy.list.TvLazyRow @@ -332,13 +333,11 @@ fun SkeletonDetailsPage( ) { if (isMobile) { val configuration = LocalConfiguration.current - val screenHeightDp = configuration.screenHeightDp.dp - val isLandscape = configuration.screenWidthDp > configuration.screenHeightDp - val backdropHeight = if (isLandscape) { - (screenHeightDp * 0.35f).coerceIn(120.dp, 200.dp) - } else { - (screenHeightDp * 0.53f).coerceAtLeast(400.dp) - } + val backdropHeight = resolveDetailsBackdropHeightDp( + screenWidthDp = configuration.screenWidthDp, + screenHeightDp = configuration.screenHeightDp, + isPhone = LocalDeviceType.current == DeviceType.PHONE, + ).dp Column( modifier = modifier diff --git a/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt b/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt index 06fa14594..2452ec7b4 100644 --- a/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt +++ b/app/src/main/kotlin/com/arflix/tv/ui/screens/details/DetailsScreen.kt @@ -148,6 +148,7 @@ import com.arflix.tv.ui.components.CardLayoutMode import com.arflix.tv.ui.components.MediaCard import com.arflix.tv.ui.components.PersonModal import com.arflix.tv.ui.components.PosterCard +import com.arflix.tv.ui.components.resolveDetailsBackdropHeightDp import com.arflix.tv.ui.components.rememberCatalogueRowLayoutMode import com.arflix.tv.ui.components.SidebarItem import com.arflix.tv.ui.components.SkeletonDetailsPage @@ -178,6 +179,7 @@ import com.arflix.tv.ui.theme.Pink import com.arflix.tv.ui.theme.Purple import com.arflix.tv.ui.theme.TextPrimary import com.arflix.tv.ui.theme.TextSecondary +import com.arflix.tv.util.DeviceType import com.arflix.tv.util.LocalDeviceType import com.arflix.tv.util.formatGenreName import com.arflix.tv.util.isInCinema @@ -1296,13 +1298,11 @@ private fun DetailsContent( // ===================== MOBILE LAYOUT ===================== if (isMobile) { val configuration = LocalConfiguration.current - val screenHeightDp = configuration.screenHeightDp.dp - val isLandscape = configuration.screenWidthDp > configuration.screenHeightDp - val backdropHeight = if (isLandscape) { - (screenHeightDp * 0.35f).coerceIn(120.dp, 200.dp) - } else { - (screenHeightDp * 0.53f).coerceAtLeast(400.dp) - } + val backdropHeight = resolveDetailsBackdropHeightDp( + screenWidthDp = configuration.screenWidthDp, + screenHeightDp = configuration.screenHeightDp, + isPhone = LocalDeviceType.current == DeviceType.PHONE, + ).dp val mobileScrollState = rememberScrollState() val density = LocalDensity.current var stickyThreshold by remember { mutableStateOf(-1f) } diff --git a/app/src/test/kotlin/com/arflix/tv/ui/components/DetailsResponsiveLayoutTest.kt b/app/src/test/kotlin/com/arflix/tv/ui/components/DetailsResponsiveLayoutTest.kt new file mode 100644 index 000000000..39d09c617 --- /dev/null +++ b/app/src/test/kotlin/com/arflix/tv/ui/components/DetailsResponsiveLayoutTest.kt @@ -0,0 +1,58 @@ +package com.arflix.tv.ui.components + +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class DetailsResponsiveLayoutTest { + + @Test + fun phoneLandscapeUsesCompactHeightThatStillFitsOverlay() { + assertThat( + resolveDetailsBackdropHeightDp( + screenWidthDp = 640, + screenHeightDp = 360, + isPhone = true, + ) + ).isWithin(0.01f).of(198f) + } + + @Test + fun phoneLandscapeHeightIsClampedToSafeRange() { + assertThat( + resolveDetailsBackdropHeightDp( + screenWidthDp = 480, + screenHeightDp = 320, + isPhone = true, + ) + ).isEqualTo(190f) + assertThat( + resolveDetailsBackdropHeightDp( + screenWidthDp = 1280, + screenHeightDp = 720, + isPhone = true, + ) + ).isEqualTo(220f) + } + + @Test + fun phonePortraitKeepsExistingBackdropRule() { + assertThat( + resolveDetailsBackdropHeightDp( + screenWidthDp = 411, + screenHeightDp = 891, + isPhone = true, + ) + ).isWithin(0.01f).of(472.23f) + } + + @Test + fun landscapeTabletKeepsExistingBackdropRule() { + assertThat( + resolveDetailsBackdropHeightDp( + screenWidthDp = 1280, + screenHeightDp = 800, + isPhone = false, + ) + ).isWithin(0.01f).of(424f) + } +}