mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-23 19:26:50 +00:00
Tighten TV home hero and bring-in-view offset
This commit is contained in:
@@ -43,7 +43,7 @@ fun TvHomeScreen(
|
||||
) {
|
||||
TvFocusedItemHero(
|
||||
item = focusedMediaUiModel.value,
|
||||
height = 250.dp
|
||||
height = 220.dp
|
||||
)
|
||||
TvHomeContent(
|
||||
libraries = libraries,
|
||||
|
||||
@@ -6,7 +6,7 @@ import androidx.compose.foundation.gestures.BringIntoViewSpec
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlin.math.abs
|
||||
|
||||
internal val TvHomeFocusedItemTopOffset = 56.dp
|
||||
internal val TvHomeFocusedItemTopOffset = 42.dp
|
||||
internal val TvHomeBringIntoViewTrailingSpace = 120.dp
|
||||
|
||||
private const val TvHomeRowPivotParentFraction = 0.3f
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package hu.bbara.purefin.ui.screen.home.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.LocalBringIntoViewSpec
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -11,9 +12,11 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.unit.dp
|
||||
import hu.bbara.purefin.core.ui.model.MediaUiModel
|
||||
@@ -37,67 +40,71 @@ fun TvHomeContent(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val scheme = MaterialTheme.colorScheme
|
||||
val topOffsetPx = with(LocalDensity.current) { TvHomeFocusedItemTopOffset.toPx() }
|
||||
val hasContinueWatching = continueWatching.isNotEmpty()
|
||||
val hasNextUp = nextUp.isNotEmpty()
|
||||
val hasVisibleContent = hasContinueWatching || hasNextUp
|
||||
val initialFocusRequester = remember { FocusRequester() }
|
||||
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(scheme.background)
|
||||
.testTag(TvHomeContentViewportTag),
|
||||
contentPadding = contentPadding
|
||||
CompositionLocalProvider(
|
||||
LocalBringIntoViewSpec provides tvHomeColumnBringIntoViewSpec(topOffsetPx)
|
||||
) {
|
||||
item(key = "tv-home-top-spacer") {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
if (hasContinueWatching) {
|
||||
item(key = "tv-home-continue-watching") {
|
||||
TvContinueWatchingSection(
|
||||
items = continueWatching,
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(scheme.background)
|
||||
.testTag(TvHomeContentViewportTag),
|
||||
contentPadding = contentPadding
|
||||
) {
|
||||
item(key = "tv-home-top-spacer") {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
if (hasContinueWatching) {
|
||||
item(key = "tv-home-continue-watching") {
|
||||
TvContinueWatchingSection(
|
||||
items = continueWatching,
|
||||
onFocusedItem = onMediaFocused,
|
||||
onMovieSelected = onMovieSelected,
|
||||
onEpisodeSelected = onEpisodeSelected,
|
||||
firstItemFocusRequester = initialFocusRequester,
|
||||
firstItemTestTag = TvHomeInitialFocusTag,
|
||||
rowTestTag = TvHomeContinueWatchingRowTag
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNextUp) {
|
||||
item(key = "tv-home-next-up") {
|
||||
TvNextUpSection(
|
||||
items = nextUp,
|
||||
onFocusedItem = onMediaFocused,
|
||||
onEpisodeSelected = onEpisodeSelected,
|
||||
firstItemFocusRequester = initialFocusRequester.takeIf { !hasContinueWatching },
|
||||
firstItemTestTag = TvHomeInitialFocusTag.takeIf { !hasContinueWatching },
|
||||
rowTestTag = TvHomeNextUpRowTag
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
itemsIndexed(
|
||||
items = libraries,
|
||||
key = { _, library -> library.id }
|
||||
) { _, library ->
|
||||
TvLibraryPosterSection(
|
||||
title = library.name,
|
||||
items = libraryContent[library.id].orEmpty(),
|
||||
onFocusedItem = onMediaFocused,
|
||||
onMovieSelected = onMovieSelected,
|
||||
onEpisodeSelected = onEpisodeSelected,
|
||||
firstItemFocusRequester = initialFocusRequester,
|
||||
firstItemTestTag = TvHomeInitialFocusTag,
|
||||
rowTestTag = TvHomeContinueWatchingRowTag
|
||||
onMovieSelected = onMovieSelected,
|
||||
onSeriesSelected = onSeriesSelected,
|
||||
onEpisodeSelected = onEpisodeSelected
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (hasNextUp) {
|
||||
item(key = "tv-home-next-up") {
|
||||
TvNextUpSection(
|
||||
items = nextUp,
|
||||
onFocusedItem = onMediaFocused,
|
||||
onEpisodeSelected = onEpisodeSelected,
|
||||
firstItemFocusRequester = initialFocusRequester.takeIf { !hasContinueWatching },
|
||||
firstItemTestTag = TvHomeInitialFocusTag.takeIf { !hasContinueWatching },
|
||||
rowTestTag = TvHomeNextUpRowTag
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
itemsIndexed(
|
||||
items = libraries,
|
||||
key = { _, library -> library.id }
|
||||
) { index, library ->
|
||||
TvLibraryPosterSection(
|
||||
title = library.name,
|
||||
items = libraryContent[library.id].orEmpty(),
|
||||
onFocusedItem = onMediaFocused,
|
||||
firstItemFocusRequester = initialFocusRequester,
|
||||
onMovieSelected = onMovieSelected,
|
||||
onSeriesSelected = onSeriesSelected,
|
||||
onEpisodeSelected = onEpisodeSelected
|
||||
)
|
||||
}
|
||||
|
||||
if (hasVisibleContent) {
|
||||
item(key = "tv-home-trailing-space") {
|
||||
Spacer(modifier = Modifier.height(TvHomeBringIntoViewTrailingSpace))
|
||||
if (hasVisibleContent) {
|
||||
item(key = "tv-home-trailing-space") {
|
||||
Spacer(modifier = Modifier.height(TvHomeBringIntoViewTrailingSpace))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package hu.bbara.purefin.ui.screen.home.components
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class TvHomeBringIntoViewSpecTest {
|
||||
|
||||
private val topOffsetPx = 56f
|
||||
private val spec = tvHomeColumnBringIntoViewSpec(topOffsetPx)
|
||||
|
||||
@Test
|
||||
fun returnsZero_whenFocusedItemAlreadyAtTopOffset() {
|
||||
assertEquals(
|
||||
0f,
|
||||
spec.calculateScrollDistance(
|
||||
offset = topOffsetPx,
|
||||
size = 52f,
|
||||
containerSize = 240f
|
||||
),
|
||||
0.0001f
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun scrollsDownToTopOffset_whenFocusedItemIsBelowTarget() {
|
||||
assertEquals(
|
||||
64f,
|
||||
spec.calculateScrollDistance(
|
||||
offset = 120f,
|
||||
size = 52f,
|
||||
containerSize = 240f
|
||||
),
|
||||
0.0001f
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun scrollsUpToTopOffset_whenFocusedItemIsAboveTarget() {
|
||||
assertEquals(
|
||||
-32f,
|
||||
spec.calculateScrollDistance(
|
||||
offset = 24f,
|
||||
size = 52f,
|
||||
containerSize = 240f
|
||||
),
|
||||
0.0001f
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user