mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
Fix TV home next up focus navigation
This commit is contained in:
@@ -20,6 +20,9 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusProperties
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.focus.onFocusChanged
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
@@ -41,6 +44,9 @@ import org.jellyfin.sdk.model.api.BaseItemKind
|
|||||||
fun PosterCard(
|
fun PosterCard(
|
||||||
item: PosterItem,
|
item: PosterItem,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
focusRequester: FocusRequester? = null,
|
||||||
|
upFocusRequester: FocusRequester? = null,
|
||||||
|
downFocusRequester: FocusRequester? = null,
|
||||||
onMovieSelected: (UUID) -> Unit,
|
onMovieSelected: (UUID) -> Unit,
|
||||||
onSeriesSelected: (UUID) -> Unit,
|
onSeriesSelected: (UUID) -> Unit,
|
||||||
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
||||||
@@ -70,8 +76,22 @@ fun PosterCard(
|
|||||||
.data(item.imageUrl)
|
.data(item.imageUrl)
|
||||||
.size(with(density) { posterWidth.roundToPx() }, with(density) { posterHeight.roundToPx() })
|
.size(with(density) { posterWidth.roundToPx() }, with(density) { posterHeight.roundToPx() })
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
val imageFocusModifier = Modifier
|
||||||
|
.then(if (focusRequester != null) Modifier.focusRequester(focusRequester) else Modifier)
|
||||||
|
.then(
|
||||||
|
if (upFocusRequester != null || downFocusRequester != null) {
|
||||||
|
Modifier.focusProperties {
|
||||||
|
upFocusRequester?.let { up = it }
|
||||||
|
downFocusRequester?.let { down = it }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Modifier
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.width(posterWidth)
|
.width(posterWidth)
|
||||||
.graphicsLayer { scaleX = scale; scaleY = scale }
|
.graphicsLayer { scaleX = scale; scaleY = scale }
|
||||||
) {
|
) {
|
||||||
@@ -79,7 +99,7 @@ fun PosterCard(
|
|||||||
PurefinAsyncImage(
|
PurefinAsyncImage(
|
||||||
model = imageRequest,
|
model = imageRequest,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier
|
modifier = imageFocusModifier
|
||||||
.aspectRatio(2f / 3f)
|
.aspectRatio(2f / 3f)
|
||||||
.clip(RoundedCornerShape(14.dp))
|
.clip(RoundedCornerShape(14.dp))
|
||||||
.border(
|
.border(
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import hu.bbara.purefin.feature.shared.home.ContinueWatchingItem
|
import hu.bbara.purefin.feature.shared.home.ContinueWatchingItem
|
||||||
import hu.bbara.purefin.feature.shared.home.LibraryItem
|
import hu.bbara.purefin.feature.shared.home.LibraryItem
|
||||||
@@ -27,6 +30,24 @@ fun TvHomeContent(
|
|||||||
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
val visibleLibraries = remember(libraries, libraryContent) {
|
||||||
|
libraries.filter { libraryContent[it.id]?.isEmpty() != true }
|
||||||
|
}
|
||||||
|
val continueWatchingFocusRequester = remember { FocusRequester() }
|
||||||
|
val nextUpFocusRequester = remember { FocusRequester() }
|
||||||
|
val libraryFocusRequesters = remember(visibleLibraries.map { it.id }) {
|
||||||
|
visibleLibraries.associate { it.id to FocusRequester() }
|
||||||
|
}
|
||||||
|
val firstSectionFocusRequester = when {
|
||||||
|
continueWatching.isNotEmpty() -> continueWatchingFocusRequester
|
||||||
|
nextUp.isNotEmpty() -> nextUpFocusRequester
|
||||||
|
else -> visibleLibraries.firstOrNull()?.let { libraryFocusRequesters[it.id] }
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(firstSectionFocusRequester) {
|
||||||
|
firstSectionFocusRequester?.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -38,6 +59,11 @@ fun TvHomeContent(
|
|||||||
item {
|
item {
|
||||||
TvContinueWatchingSection(
|
TvContinueWatchingSection(
|
||||||
items = continueWatching,
|
items = continueWatching,
|
||||||
|
firstItemFocusRequester = continueWatchingFocusRequester,
|
||||||
|
downFocusRequester = when {
|
||||||
|
nextUp.isNotEmpty() -> nextUpFocusRequester
|
||||||
|
else -> visibleLibraries.firstOrNull()?.let { libraryFocusRequesters[it.id] }
|
||||||
|
},
|
||||||
onMovieSelected = onMovieSelected,
|
onMovieSelected = onMovieSelected,
|
||||||
onEpisodeSelected = onEpisodeSelected
|
onEpisodeSelected = onEpisodeSelected
|
||||||
)
|
)
|
||||||
@@ -48,6 +74,9 @@ fun TvHomeContent(
|
|||||||
item {
|
item {
|
||||||
TvNextUpSection(
|
TvNextUpSection(
|
||||||
items = nextUp,
|
items = nextUp,
|
||||||
|
firstItemFocusRequester = nextUpFocusRequester,
|
||||||
|
upFocusRequester = continueWatching.takeIf { it.isNotEmpty() }?.let { continueWatchingFocusRequester },
|
||||||
|
downFocusRequester = visibleLibraries.firstOrNull()?.let { libraryFocusRequesters[it.id] },
|
||||||
onEpisodeSelected = onEpisodeSelected
|
onEpisodeSelected = onEpisodeSelected
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -55,13 +84,32 @@ fun TvHomeContent(
|
|||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
}
|
}
|
||||||
items(
|
items(
|
||||||
items = libraries.filter { libraryContent[it.id]?.isEmpty() != true },
|
items = visibleLibraries,
|
||||||
key = { it.id }
|
key = { it.id }
|
||||||
) { item ->
|
) { item ->
|
||||||
|
val libraryIndex = visibleLibraries.indexOfFirst { it.id == item.id }
|
||||||
|
val previousLibraryFocusRequester = visibleLibraries
|
||||||
|
.getOrNull(libraryIndex - 1)
|
||||||
|
?.let { libraryFocusRequesters[it.id] }
|
||||||
|
val nextLibraryFocusRequester = visibleLibraries
|
||||||
|
.getOrNull(libraryIndex + 1)
|
||||||
|
?.let { libraryFocusRequesters[it.id] }
|
||||||
|
|
||||||
TvLibraryPosterSection(
|
TvLibraryPosterSection(
|
||||||
title = item.name,
|
title = item.name,
|
||||||
items = libraryContent[item.id] ?: emptyList(),
|
items = libraryContent[item.id] ?: emptyList(),
|
||||||
action = "See All",
|
action = "See All",
|
||||||
|
firstItemFocusRequester = libraryFocusRequesters[item.id],
|
||||||
|
upFocusRequester = if (libraryIndex == 0) {
|
||||||
|
when {
|
||||||
|
nextUp.isNotEmpty() -> nextUpFocusRequester
|
||||||
|
continueWatching.isNotEmpty() -> continueWatchingFocusRequester
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
previousLibraryFocusRequester
|
||||||
|
},
|
||||||
|
downFocusRequester = nextLibraryFocusRequester,
|
||||||
onMovieSelected = onMovieSelected,
|
onMovieSelected = onMovieSelected,
|
||||||
onSeriesSelected = onSeriesSelected,
|
onSeriesSelected = onSeriesSelected,
|
||||||
onEpisodeSelected = onEpisodeSelected
|
onEpisodeSelected = onEpisodeSelected
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -31,6 +29,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusProperties
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.focus.onFocusChanged
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
@@ -55,16 +54,13 @@ import kotlin.math.nextUp
|
|||||||
@Composable
|
@Composable
|
||||||
fun TvContinueWatchingSection(
|
fun TvContinueWatchingSection(
|
||||||
items: List<ContinueWatchingItem>,
|
items: List<ContinueWatchingItem>,
|
||||||
|
firstItemFocusRequester: FocusRequester? = null,
|
||||||
|
upFocusRequester: FocusRequester? = null,
|
||||||
|
downFocusRequester: FocusRequester? = null,
|
||||||
onMovieSelected: (UUID) -> Unit,
|
onMovieSelected: (UUID) -> Unit,
|
||||||
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val firstItemFocusRequester = remember { FocusRequester() }
|
|
||||||
LaunchedEffect(items.isNotEmpty()) {
|
|
||||||
if (items.isNotEmpty()) {
|
|
||||||
firstItemFocusRequester.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (items.isEmpty()) return
|
if (items.isEmpty()) return
|
||||||
TvSectionHeader(
|
TvSectionHeader(
|
||||||
title = "Continue Watching",
|
title = "Continue Watching",
|
||||||
@@ -79,6 +75,10 @@ fun TvContinueWatchingSection(
|
|||||||
TvContinueWatchingCard(
|
TvContinueWatchingCard(
|
||||||
item = item,
|
item = item,
|
||||||
focusRequester = if (index == 0) firstItemFocusRequester else null,
|
focusRequester = if (index == 0) firstItemFocusRequester else null,
|
||||||
|
isFirstItem = index == 0,
|
||||||
|
isLastItem = index == items.lastIndex,
|
||||||
|
upFocusRequester = upFocusRequester,
|
||||||
|
downFocusRequester = downFocusRequester,
|
||||||
onMovieSelected = onMovieSelected,
|
onMovieSelected = onMovieSelected,
|
||||||
onEpisodeSelected = onEpisodeSelected
|
onEpisodeSelected = onEpisodeSelected
|
||||||
)
|
)
|
||||||
@@ -91,6 +91,10 @@ fun TvContinueWatchingCard(
|
|||||||
item: ContinueWatchingItem,
|
item: ContinueWatchingItem,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
focusRequester: FocusRequester? = null,
|
focusRequester: FocusRequester? = null,
|
||||||
|
isFirstItem: Boolean = false,
|
||||||
|
isLastItem: Boolean = false,
|
||||||
|
upFocusRequester: FocusRequester? = null,
|
||||||
|
downFocusRequester: FocusRequester? = null,
|
||||||
onMovieSelected: (UUID) -> Unit,
|
onMovieSelected: (UUID) -> Unit,
|
||||||
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -127,6 +131,32 @@ fun TvContinueWatchingCard(
|
|||||||
.size(with(density) { cardWidth.roundToPx() }, with(density) { cardHeight.roundToPx() })
|
.size(with(density) { cardWidth.roundToPx() }, with(density) { cardHeight.roundToPx() })
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
val imageFocusModifier = Modifier
|
||||||
|
.then(if (focusRequester != null) Modifier.focusRequester(focusRequester) else Modifier)
|
||||||
|
.then(
|
||||||
|
if (upFocusRequester != null || downFocusRequester != null) {
|
||||||
|
Modifier.focusProperties {
|
||||||
|
upFocusRequester?.let { up = it }
|
||||||
|
downFocusRequester?.let { down = it }
|
||||||
|
if (isFirstItem) {
|
||||||
|
left = FocusRequester.Cancel
|
||||||
|
}
|
||||||
|
if (isLastItem) {
|
||||||
|
right = FocusRequester.Cancel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Modifier.focusProperties {
|
||||||
|
if (isFirstItem) {
|
||||||
|
left = FocusRequester.Cancel
|
||||||
|
}
|
||||||
|
if (isLastItem) {
|
||||||
|
right = FocusRequester.Cancel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.width(cardWidth)
|
.width(cardWidth)
|
||||||
@@ -148,9 +178,8 @@ fun TvContinueWatchingCard(
|
|||||||
PurefinAsyncImage(
|
PurefinAsyncImage(
|
||||||
model = imageRequest,
|
model = imageRequest,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier
|
modifier = imageFocusModifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.then(if (focusRequester != null) Modifier.focusRequester(focusRequester) else Modifier)
|
|
||||||
.onFocusChanged { isFocused = it.isFocused }
|
.onFocusChanged { isFocused = it.isFocused }
|
||||||
.clickable {
|
.clickable {
|
||||||
openItem(item)
|
openItem(item)
|
||||||
@@ -188,6 +217,9 @@ fun TvContinueWatchingCard(
|
|||||||
@Composable
|
@Composable
|
||||||
fun TvNextUpSection(
|
fun TvNextUpSection(
|
||||||
items: List<NextUpItem>,
|
items: List<NextUpItem>,
|
||||||
|
firstItemFocusRequester: FocusRequester? = null,
|
||||||
|
upFocusRequester: FocusRequester? = null,
|
||||||
|
downFocusRequester: FocusRequester? = null,
|
||||||
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
@@ -201,10 +233,17 @@ fun TvNextUpSection(
|
|||||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
items(
|
itemsIndexed(
|
||||||
items = items, key = { it.id }) { item ->
|
items = items,
|
||||||
|
key = { _, item -> item.id }
|
||||||
|
) { index, item ->
|
||||||
TvNextUpCard(
|
TvNextUpCard(
|
||||||
item = item,
|
item = item,
|
||||||
|
focusRequester = if (index == 0) firstItemFocusRequester else null,
|
||||||
|
isFirstItem = index == 0,
|
||||||
|
isLastItem = index == items.lastIndex,
|
||||||
|
upFocusRequester = upFocusRequester,
|
||||||
|
downFocusRequester = downFocusRequester,
|
||||||
onEpisodeSelected = onEpisodeSelected
|
onEpisodeSelected = onEpisodeSelected
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -215,6 +254,11 @@ fun TvNextUpSection(
|
|||||||
fun TvNextUpCard(
|
fun TvNextUpCard(
|
||||||
item: NextUpItem,
|
item: NextUpItem,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
focusRequester: FocusRequester? = null,
|
||||||
|
isFirstItem: Boolean = false,
|
||||||
|
isLastItem: Boolean = false,
|
||||||
|
upFocusRequester: FocusRequester? = null,
|
||||||
|
downFocusRequester: FocusRequester? = null,
|
||||||
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
|
||||||
) {
|
) {
|
||||||
val scheme = MaterialTheme.colorScheme
|
val scheme = MaterialTheme.colorScheme
|
||||||
@@ -239,6 +283,32 @@ fun TvNextUpCard(
|
|||||||
.size(with(density) { cardWidth.roundToPx() }, with(density) { cardHeight.roundToPx() })
|
.size(with(density) { cardWidth.roundToPx() }, with(density) { cardHeight.roundToPx() })
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
val imageFocusModifier = Modifier
|
||||||
|
.then(if (focusRequester != null) Modifier.focusRequester(focusRequester) else Modifier)
|
||||||
|
.then(
|
||||||
|
if (upFocusRequester != null || downFocusRequester != null) {
|
||||||
|
Modifier.focusProperties {
|
||||||
|
upFocusRequester?.let { up = it }
|
||||||
|
downFocusRequester?.let { down = it }
|
||||||
|
if (isFirstItem) {
|
||||||
|
left = FocusRequester.Cancel
|
||||||
|
}
|
||||||
|
if (isLastItem) {
|
||||||
|
right = FocusRequester.Cancel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Modifier.focusProperties {
|
||||||
|
if (isFirstItem) {
|
||||||
|
left = FocusRequester.Cancel
|
||||||
|
}
|
||||||
|
if (isLastItem) {
|
||||||
|
right = FocusRequester.Cancel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.width(cardWidth)
|
.width(cardWidth)
|
||||||
@@ -260,7 +330,7 @@ fun TvNextUpCard(
|
|||||||
PurefinAsyncImage(
|
PurefinAsyncImage(
|
||||||
model = imageRequest,
|
model = imageRequest,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier
|
modifier = imageFocusModifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.onFocusChanged { isFocused = it.isFocused }
|
.onFocusChanged { isFocused = it.isFocused }
|
||||||
.clickable {
|
.clickable {
|
||||||
@@ -294,6 +364,9 @@ fun TvLibraryPosterSection(
|
|||||||
title: String,
|
title: String,
|
||||||
items: List<PosterItem>,
|
items: List<PosterItem>,
|
||||||
action: String?,
|
action: String?,
|
||||||
|
firstItemFocusRequester: FocusRequester? = null,
|
||||||
|
upFocusRequester: FocusRequester? = null,
|
||||||
|
downFocusRequester: FocusRequester? = null,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onMovieSelected: (UUID) -> Unit,
|
onMovieSelected: (UUID) -> Unit,
|
||||||
onSeriesSelected: (UUID) -> Unit,
|
onSeriesSelected: (UUID) -> Unit,
|
||||||
@@ -308,10 +381,15 @@ fun TvLibraryPosterSection(
|
|||||||
contentPadding = PaddingValues(horizontal = 16.dp),
|
contentPadding = PaddingValues(horizontal = 16.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
horizontalArrangement = Arrangement.spacedBy(16.dp)
|
||||||
) {
|
) {
|
||||||
items(
|
itemsIndexed(
|
||||||
items = items, key = { it.id }) { item ->
|
items = items,
|
||||||
|
key = { _, item -> item.id }
|
||||||
|
) { index, item ->
|
||||||
PosterCard(
|
PosterCard(
|
||||||
item = item,
|
item = item,
|
||||||
|
focusRequester = if (index == 0) firstItemFocusRequester else null,
|
||||||
|
upFocusRequester = upFocusRequester,
|
||||||
|
downFocusRequester = downFocusRequester,
|
||||||
onMovieSelected = onMovieSelected,
|
onMovieSelected = onMovieSelected,
|
||||||
onSeriesSelected = onSeriesSelected,
|
onSeriesSelected = onSeriesSelected,
|
||||||
onEpisodeSelected = onEpisodeSelected
|
onEpisodeSelected = onEpisodeSelected
|
||||||
|
|||||||
Reference in New Issue
Block a user