mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
Fix TV detail top bar focus navigation
This commit is contained in:
@@ -2,15 +2,18 @@ package hu.bbara.purefin.app.content.episode
|
|||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import hu.bbara.purefin.common.ui.components.MediaDetailsTopBar
|
import hu.bbara.purefin.common.ui.components.MediaDetailsTopBar
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun EpisodeTopBar(
|
internal fun EpisodeTopBar(
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier,
|
||||||
|
downFocusRequester: FocusRequester? = null
|
||||||
) {
|
) {
|
||||||
MediaDetailsTopBar(
|
MediaDetailsTopBar(
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
modifier = modifier
|
modifier = modifier,
|
||||||
|
downFocusRequester = downFocusRequester
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
@@ -94,21 +95,21 @@ private fun EpisodeScreenInternal(
|
|||||||
playFocusRequester.requestFocus()
|
playFocusRequester.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyColumn(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(scheme.background)
|
.background(scheme.background)
|
||||||
|
) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
Box {
|
|
||||||
MediaHero(
|
MediaHero(
|
||||||
imageUrl = episode.heroImageUrl,
|
imageUrl = episode.heroImageUrl,
|
||||||
backgroundColor = scheme.background,
|
backgroundColor = scheme.background,
|
||||||
heightFraction = 0.30f,
|
heightFraction = 0.30f,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
EpisodeTopBar(onBack = onBack)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
Column(modifier = hPad) {
|
Column(modifier = hPad) {
|
||||||
@@ -188,4 +189,10 @@ private fun EpisodeScreenInternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EpisodeTopBar(
|
||||||
|
onBack = onBack,
|
||||||
|
downFocusRequester = playFocusRequester,
|
||||||
|
modifier = Modifier.align(Alignment.TopStart)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,18 @@ package hu.bbara.purefin.app.content.movie
|
|||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import hu.bbara.purefin.common.ui.components.MediaDetailsTopBar
|
import hu.bbara.purefin.common.ui.components.MediaDetailsTopBar
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun MovieTopBar(
|
internal fun MovieTopBar(
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier,
|
||||||
|
downFocusRequester: FocusRequester? = null
|
||||||
) {
|
) {
|
||||||
MediaDetailsTopBar(
|
MediaDetailsTopBar(
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
modifier = modifier
|
modifier = modifier,
|
||||||
|
downFocusRequester = downFocusRequester
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
@@ -76,21 +77,21 @@ private fun MovieScreenInternal(
|
|||||||
playFocusRequester.requestFocus()
|
playFocusRequester.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyColumn(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(scheme.background)
|
.background(scheme.background)
|
||||||
|
) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
Box {
|
|
||||||
MediaHero(
|
MediaHero(
|
||||||
imageUrl = movie.heroImageUrl,
|
imageUrl = movie.heroImageUrl,
|
||||||
backgroundColor = scheme.background,
|
backgroundColor = scheme.background,
|
||||||
heightFraction = 0.30f,
|
heightFraction = 0.30f,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
MovieTopBar(onBack = onBack)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
Column(modifier = hPad) {
|
Column(modifier = hPad) {
|
||||||
@@ -163,4 +164,10 @@ private fun MovieScreenInternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
MovieTopBar(
|
||||||
|
onBack = onBack,
|
||||||
|
downFocusRequester = playFocusRequester,
|
||||||
|
modifier = Modifier.align(Alignment.TopStart)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ 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.focusRequester
|
||||||
import androidx.compose.ui.focus.onFocusChanged
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
@@ -62,11 +64,13 @@ import hu.bbara.purefin.feature.shared.content.series.SeriesViewModel
|
|||||||
@Composable
|
@Composable
|
||||||
internal fun SeriesTopBar(
|
internal fun SeriesTopBar(
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier,
|
||||||
|
downFocusRequester: FocusRequester? = null
|
||||||
) {
|
) {
|
||||||
MediaDetailsTopBar(
|
MediaDetailsTopBar(
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
modifier = modifier
|
modifier = modifier,
|
||||||
|
downFocusRequester = downFocusRequester
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +92,7 @@ internal fun SeasonTabs(
|
|||||||
seasons: List<Season>,
|
seasons: List<Season>,
|
||||||
selectedSeason: Season?,
|
selectedSeason: Season?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
firstItemFocusRequester: FocusRequester? = null,
|
||||||
onSelect: (Season) -> Unit
|
onSelect: (Season) -> Unit
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
@@ -96,11 +101,16 @@ internal fun SeasonTabs(
|
|||||||
.horizontalScroll(rememberScrollState()),
|
.horizontalScroll(rememberScrollState()),
|
||||||
horizontalArrangement = Arrangement.spacedBy(20.dp)
|
horizontalArrangement = Arrangement.spacedBy(20.dp)
|
||||||
) {
|
) {
|
||||||
seasons.forEach { season ->
|
seasons.forEachIndexed { index, season ->
|
||||||
SeasonTab(
|
SeasonTab(
|
||||||
name = season.name,
|
name = season.name,
|
||||||
isSelected = season == selectedSeason,
|
isSelected = season == selectedSeason,
|
||||||
onSelect = { onSelect(season) }
|
onSelect = { onSelect(season) },
|
||||||
|
modifier = if (index == 0 && firstItemFocusRequester != null) {
|
||||||
|
Modifier.focusRequester(firstItemFocusRequester)
|
||||||
|
} else {
|
||||||
|
Modifier
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -71,22 +73,23 @@ private fun SeriesScreenInternal(
|
|||||||
return series.seasons.first()
|
return series.seasons.first()
|
||||||
}
|
}
|
||||||
val selectedSeason = remember { mutableStateOf<Season>(getDefaultSeason()) }
|
val selectedSeason = remember { mutableStateOf<Season>(getDefaultSeason()) }
|
||||||
|
val firstContentFocusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
LazyColumn(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(scheme.background)
|
.background(scheme.background)
|
||||||
|
) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
Box {
|
|
||||||
MediaHero(
|
MediaHero(
|
||||||
imageUrl = series.heroImageUrl,
|
imageUrl = series.heroImageUrl,
|
||||||
heightFraction = 0.30f,
|
heightFraction = 0.30f,
|
||||||
backgroundColor = scheme.background,
|
backgroundColor = scheme.background,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
SeriesTopBar(onBack = onBack)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
Column(modifier = hPad) {
|
Column(modifier = hPad) {
|
||||||
@@ -117,6 +120,7 @@ private fun SeriesScreenInternal(
|
|||||||
SeasonTabs(
|
SeasonTabs(
|
||||||
seasons = series.seasons,
|
seasons = series.seasons,
|
||||||
selectedSeason = selectedSeason.value,
|
selectedSeason = selectedSeason.value,
|
||||||
|
firstItemFocusRequester = firstContentFocusRequester,
|
||||||
onSelect = { selectedSeason.value = it },
|
onSelect = { selectedSeason.value = it },
|
||||||
modifier = hPad
|
modifier = hPad
|
||||||
)
|
)
|
||||||
@@ -144,4 +148,10 @@ private fun SeriesScreenInternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SeriesTopBar(
|
||||||
|
onBack = onBack,
|
||||||
|
downFocusRequester = firstContentFocusRequester,
|
||||||
|
modifier = Modifier.align(Alignment.TopStart)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import androidx.compose.material.icons.outlined.MoreVert
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusProperties
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -19,8 +21,15 @@ fun MediaDetailsTopBar(
|
|||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onCastClick: () -> Unit = {},
|
onCastClick: () -> Unit = {},
|
||||||
onMoreClick: () -> Unit = {}
|
onMoreClick: () -> Unit = {},
|
||||||
|
downFocusRequester: FocusRequester? = null
|
||||||
) {
|
) {
|
||||||
|
val downModifier = if (downFocusRequester != null) {
|
||||||
|
Modifier.focusProperties { down = downFocusRequester }
|
||||||
|
} else {
|
||||||
|
Modifier
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -32,11 +41,22 @@ fun MediaDetailsTopBar(
|
|||||||
GhostIconButton(
|
GhostIconButton(
|
||||||
icon = Icons.AutoMirrored.Outlined.ArrowBack,
|
icon = Icons.AutoMirrored.Outlined.ArrowBack,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
onClick = onBack
|
onClick = onBack,
|
||||||
|
modifier = downModifier
|
||||||
)
|
)
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||||
GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = onCastClick)
|
GhostIconButton(
|
||||||
GhostIconButton(icon = Icons.Outlined.MoreVert, contentDescription = "More", onClick = onMoreClick)
|
icon = Icons.Outlined.Cast,
|
||||||
|
contentDescription = "Cast",
|
||||||
|
onClick = onCastClick,
|
||||||
|
modifier = downModifier
|
||||||
|
)
|
||||||
|
GhostIconButton(
|
||||||
|
icon = Icons.Outlined.MoreVert,
|
||||||
|
contentDescription = "More",
|
||||||
|
onClick = onMoreClick,
|
||||||
|
modifier = downModifier
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user