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 2958969a0..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,8 +333,11 @@ fun SkeletonDetailsPage( ) { if (isMobile) { val configuration = LocalConfiguration.current - val screenHeightDp = configuration.screenHeightDp.dp - val backdropHeight = (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 3a7ede60c..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,8 +1298,11 @@ private fun DetailsContent( // ===================== MOBILE LAYOUT ===================== if (isMobile) { val configuration = LocalConfiguration.current - val screenHeightDp = configuration.screenHeightDp.dp - val backdropHeight = (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) + } +}