Handle adding rows & back handling

This commit is contained in:
Damontecres 2026-01-23 12:06:07 -05:00
parent 6d53869180
commit 5dcdde36c3
No known key found for this signature in database
7 changed files with 270 additions and 39 deletions

View file

@ -13,29 +13,33 @@ import java.util.UUID
@Serializable
sealed class HomeRowConfig {
abstract val id: UUID
abstract val viewOptions: HomeRowViewOptions
@Serializable
data class ContinueWatching(
override val id: UUID,
val combined: Boolean,
override val viewOptions: HomeRowViewOptions,
) : HomeRowConfig()
@Serializable
data class RecentlyAdded(
override val id: UUID,
val parentId: UUID,
override val viewOptions: HomeRowViewOptions,
) : HomeRowConfig()
@Serializable
data class RecentlyReleased(
override val id: UUID,
val parentId: UUID,
override val viewOptions: HomeRowViewOptions,
) : HomeRowConfig()
@Serializable
data class Genres(
val genreId: UUID,
override val id: UUID,
val parentId: UUID,
override val viewOptions: HomeRowViewOptions,
) : HomeRowConfig()

View file

@ -0,0 +1,54 @@
package com.github.damontecres.wholphin.ui.main.settings
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusRestorer
import androidx.compose.ui.unit.dp
import androidx.tv.material3.ListItem
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.ui.ifElse
import com.github.damontecres.wholphin.ui.tryRequestFocus
@Composable
fun HomePageLibraryList(
libraries: List<Library>,
onClick: (Library) -> Unit,
modifier: Modifier,
firstFocus: FocusRequester = remember { FocusRequester() },
) {
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
Column(modifier = modifier) {
Text(
text = "Add row for...",
)
LazyColumn(
contentPadding = PaddingValues(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier =
modifier
.fillMaxHeight()
.focusRestorer(firstFocus),
) {
itemsIndexed(libraries) { index, library ->
ListItem(
selected = false,
headlineContent = {
Text(library.name)
},
onClick = { onClick.invoke(library) },
modifier = Modifier.ifElse(index == 0, Modifier.focusRequester(firstFocus)),
)
}
}
}
}

View file

@ -0,0 +1,71 @@
package com.github.damontecres.wholphin.ui.main.settings
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusRestorer
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.tv.material3.ListItem
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.ui.ifElse
import com.github.damontecres.wholphin.ui.tryRequestFocus
@Composable
fun HomePageLibraryRowTypeList(
library: Library,
onClick: (LibraryRowType) -> Unit,
modifier: Modifier,
firstFocus: FocusRequester = remember { FocusRequester() },
) {
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
Column(modifier = modifier) {
Text(
text = "Add row for ${library.name}",
)
LazyColumn(
contentPadding = PaddingValues(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier =
modifier
.fillMaxHeight()
.focusRestorer(firstFocus),
) {
itemsIndexed(LibraryRowType.entries) { index, rowType ->
ListItem(
selected = false,
headlineContent = {
Text(
text = stringResource(rowType.stringId),
)
},
onClick = { onClick.invoke(rowType) },
modifier =
Modifier
.fillMaxWidth()
.ifElse(index == 0, Modifier.focusRequester(firstFocus)),
)
}
}
}
}
enum class LibraryRowType(
@param:StringRes val stringId: Int,
) {
RECENTLY_ADDED(R.string.recently_added),
RECENTLY_RELEASED(R.string.recently_released),
GENRES(R.string.genres),
}

View file

@ -4,7 +4,6 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
@ -31,6 +30,7 @@ import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import androidx.tv.material3.surfaceColorAtElevation
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.model.HomeRowConfig
import com.github.damontecres.wholphin.data.model.HomeRowConfigDisplay
import com.github.damontecres.wholphin.ui.FontAwesome
import com.github.damontecres.wholphin.ui.components.Button
@ -52,18 +52,18 @@ fun HomePageRowList(
) {
Column(modifier = modifier) {
LazyColumn(
contentPadding = PaddingValues(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier =
modifier
.fillMaxHeight()
.focusRestorer(firstFocus),
) {
itemsIndexed(state.rows) { index, row ->
itemsIndexed(state.rows, key = { _, row -> row.config.id }) { index, row ->
HomeRowConfigContent(
config = row,
moveUpAllowed = index > 0,
moveDownAllowed = index != state.rows.lastIndex,
deleteAllowed = row.config !is HomeRowConfig.ContinueWatching,
onClickMove = { onClickMove.invoke(it, index) },
onClickDelete = { onClickDelete.invoke(index) },
modifier =
@ -91,6 +91,7 @@ fun HomeRowConfigContent(
config: HomeRowConfigDisplay,
moveUpAllowed: Boolean,
moveDownAllowed: Boolean,
deleteAllowed: Boolean,
onClickMove: (MoveDirection) -> Unit,
onClickDelete: () -> Unit,
modifier: Modifier,
@ -108,14 +109,17 @@ fun HomeRowConfigContent(
.background(
color = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp),
shape = RoundedCornerShape(8.dp),
).padding(8.dp),
),
) {
Text(
text = config.title,
color = MaterialTheme.colorScheme.onSurface,
style = MaterialTheme.typography.titleMedium,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f),
modifier =
Modifier
.weight(1f)
.padding(start = 4.dp),
)
Row(
horizontalArrangement = Arrangement.spacedBy(4.dp),
@ -141,7 +145,7 @@ fun HomeRowConfigContent(
}
Button(
onClick = onClickDelete,
enabled = true,
enabled = deleteAllowed,
) {
Icon(
imageVector = Icons.Default.Delete,

View file

@ -1,15 +1,18 @@
package com.github.damontecres.wholphin.ui.main.settings
import android.content.Context
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -96,7 +99,11 @@ class HomePageSettingsViewModel
?: context.getString(R.string.recently_added)
HomeRowConfigDisplay(
title,
HomeRowConfig.RecentlyAdded(id, HomeRowViewOptions()),
HomeRowConfig.RecentlyAdded(
UUID.randomUUID(),
id,
HomeRowViewOptions(),
),
)
}
val rowConfig =
@ -104,6 +111,7 @@ class HomePageSettingsViewModel
HomeRowConfigDisplay(
context.getString(R.string.continue_watching),
HomeRowConfig.ContinueWatching(
UUID.randomUUID(),
prefs.combineContinueNext,
HomeRowViewOptions(),
),
@ -274,6 +282,66 @@ class HomePageSettingsViewModel
)
}
}
fun addRow(
library: Library,
rowType: LibraryRowType,
) {
viewModelScope.launchIO {
val newRow =
when (rowType) {
LibraryRowType.RECENTLY_ADDED -> {
val title =
library.name.let { context.getString(R.string.recently_added_in, it) }
HomeRowConfigDisplay(
title,
HomeRowConfig.RecentlyAdded(
UUID.randomUUID(),
library.itemId,
HomeRowViewOptions(),
),
)
}
LibraryRowType.RECENTLY_RELEASED -> {
val title =
library.name.let {
context.getString(
R.string.recently_released_in,
it,
)
}
HomeRowConfigDisplay(
title,
HomeRowConfig.RecentlyReleased(
UUID.randomUUID(),
library.itemId,
HomeRowViewOptions(),
),
)
}
LibraryRowType.GENRES -> {
val title = library.name.let { context.getString(R.string.genres_in, it) }
HomeRowConfigDisplay(
title,
HomeRowConfig.Genres(
UUID.randomUUID(),
library.itemId,
HomeRowViewOptions(),
),
)
}
}
_state.update {
it.copy(
loading = LoadingState.Loading,
rows = it.rows.toMutableList().apply { add(newRow) },
)
}
fetchRowData()
}
}
}
data class HomePageSettingsState(
@ -293,6 +361,7 @@ data class HomePageSettingsState(
}
}
@Immutable
data class Library(
val itemId: UUID,
val name: String,
@ -309,10 +378,66 @@ fun HomePageSettings(
val state by viewModel.state.collectAsState()
val listState = rememberLazyListState()
var destination by remember { mutableStateOf<HomePageSettingsDestination>(HomePageSettingsDestination.RowList) }
BackHandler(destination is HomePageSettingsDestination.ChooseRowType) {
destination = HomePageSettingsDestination.ChooseLibrary
}
BackHandler(destination is HomePageSettingsDestination.ChooseLibrary) {
destination = HomePageSettingsDestination.RowList
}
BackHandler(destination is HomePageSettingsDestination.RowSettings) {
destination = HomePageSettingsDestination.RowList
}
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier,
) {
Box(
modifier =
Modifier
.width(settingsWidth)
.fillMaxHeight()
.background(color = MaterialTheme.colorScheme.surface),
) {
val destModifier =
Modifier
.fillMaxSize()
.padding(4.dp)
when (val dest = destination) {
HomePageSettingsDestination.RowList -> {
HomePageRowList(
state = state,
onClickAdd = { destination = HomePageSettingsDestination.ChooseLibrary },
onClickMove = viewModel::moveRow,
onClickDelete = viewModel::deleteRow,
modifier = destModifier,
)
}
is HomePageSettingsDestination.ChooseLibrary -> {
HomePageLibraryList(
libraries = state.libraries,
onClick = { destination = HomePageSettingsDestination.ChooseRowType(it) },
modifier = destModifier,
)
}
is HomePageSettingsDestination.ChooseRowType -> {
HomePageLibraryRowTypeList(
library = dest.library,
onClick = {
viewModel.addRow(dest.library, it)
destination = HomePageSettingsDestination.RowList
},
modifier = destModifier,
)
}
is HomePageSettingsDestination.RowSettings -> {
TODO()
}
}
}
HomePageContent(
loadingState = state.loading,
homeRows = state.rowData,
@ -322,38 +447,10 @@ fun HomePageSettings(
showClock = false,
onUpdateBackdrop = viewModel::updateBackdrop,
listState = listState,
modifier = Modifier.fillMaxHeight().weight(1f),
)
Box(
modifier =
Modifier
.width(settingsWidth)
.fillMaxHeight()
.background(color = MaterialTheme.colorScheme.surface),
) {
when (destination) {
HomePageSettingsDestination.RowList -> {
HomePageRowList(
state = state,
onClickAdd = { destination = HomePageSettingsDestination.ChooseLibrary },
onClickMove = viewModel::moveRow,
onClickDelete = viewModel::deleteRow,
modifier = Modifier.fillMaxSize(),
)
}
is HomePageSettingsDestination.ChooseLibrary -> {
TODO()
}
is HomePageSettingsDestination.ChooseRow -> {
TODO()
}
is HomePageSettingsDestination.RowSettings -> {
TODO()
}
}
}
.weight(1f),
)
}
}

View file

@ -7,7 +7,7 @@ sealed interface HomePageSettingsDestination {
data object ChooseLibrary : HomePageSettingsDestination
data class ChooseRow(
data class ChooseRowType(
val library: Library,
) : HomePageSettingsDestination

View file

@ -464,6 +464,7 @@
<string name="upgrade_mpv_toast">MPV is now the default player except for HDR.\nYou can change this in settings.</string>
<string name="add_row">Add row</string>
<string name="genres_in">Genres in %1$s</string>
<string name="recently_released_in">Recently released in %1$s</string>
<string-array name="theme_song_volume">
<item>Disabled</item>