Separate type for continue & next up

This commit is contained in:
Damontecres 2026-01-23 19:39:57 -05:00
parent 00f6de8ec4
commit a90e6bc7b0
No known key found for this signature in database
4 changed files with 159 additions and 48 deletions

View file

@ -27,7 +27,22 @@ sealed class HomeRowConfig {
@Serializable @Serializable
data class ContinueWatching( data class ContinueWatching(
override val id: UUID, override val id: UUID,
val combined: Boolean, override val viewOptions: HomeRowViewOptions,
) : HomeRowConfig() {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): HomeRowConfig = this.copy(viewOptions = viewOptions)
}
@Serializable
data class NextUp(
override val id: UUID,
override val viewOptions: HomeRowViewOptions,
) : HomeRowConfig() {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): HomeRowConfig = this.copy(viewOptions = viewOptions)
}
@Serializable
data class ContinueWatchingCombined(
override val id: UUID,
override val viewOptions: HomeRowViewOptions, override val viewOptions: HomeRowViewOptions,
) : HomeRowConfig() { ) : HomeRowConfig() {
override fun updateViewOptions(viewOptions: HomeRowViewOptions): HomeRowConfig = this.copy(viewOptions = viewOptions) override fun updateViewOptions(viewOptions: HomeRowViewOptions): HomeRowConfig = this.copy(viewOptions = viewOptions)

View file

@ -1,11 +1,13 @@
package com.github.damontecres.wholphin.ui.main.settings package com.github.damontecres.wholphin.ui.main.settings
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -13,9 +15,11 @@ 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
import androidx.compose.ui.focus.focusRestorer import androidx.compose.ui.focus.focusRestorer
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.tv.material3.ListItem import androidx.tv.material3.ListItem
import androidx.tv.material3.Text import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.ui.ifElse import com.github.damontecres.wholphin.ui.ifElse
import com.github.damontecres.wholphin.ui.tryRequestFocus import com.github.damontecres.wholphin.ui.tryRequestFocus
@ -23,6 +27,7 @@ import com.github.damontecres.wholphin.ui.tryRequestFocus
fun HomePageLibraryList( fun HomePageLibraryList(
libraries: List<Library>, libraries: List<Library>,
onClick: (Library) -> Unit, onClick: (Library) -> Unit,
onClickMeta: (MetaRowType) -> Unit,
modifier: Modifier, modifier: Modifier,
firstFocus: FocusRequester = remember { FocusRequester() }, firstFocus: FocusRequester = remember { FocusRequester() },
) { ) {
@ -39,6 +44,19 @@ fun HomePageLibraryList(
.fillMaxHeight() .fillMaxHeight()
.focusRestorer(firstFocus), .focusRestorer(firstFocus),
) { ) {
itemsIndexed(MetaRowType.entries) { index, type ->
ListItem(
selected = false,
headlineContent = {
Text(stringResource(type.stringId))
},
onClick = { onClickMeta.invoke(type) },
modifier = Modifier.ifElse(index == 0, Modifier.focusRequester(firstFocus)),
)
}
item {
HorizontalDivider()
}
itemsIndexed(libraries) { index, library -> itemsIndexed(libraries) { index, library ->
ListItem( ListItem(
selected = false, selected = false,
@ -46,9 +64,17 @@ fun HomePageLibraryList(
Text(library.name) Text(library.name)
}, },
onClick = { onClick.invoke(library) }, onClick = { onClick.invoke(library) },
modifier = Modifier.ifElse(index == 0, Modifier.focusRequester(firstFocus)), modifier = Modifier, // .ifElse(index == 0, Modifier.focusRequester(firstFocus)),
) )
} }
} }
} }
} }
enum class MetaRowType(
@param:StringRes val stringId: Int,
) {
CONTINUE_WATCHING(R.string.continue_watching),
NEXT_UP(R.string.next_up),
COMBINED_CONTINUE_WATCHING(R.string.combine_continue_next),
}

View file

@ -30,7 +30,6 @@ import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text import androidx.tv.material3.Text
import androidx.tv.material3.surfaceColorAtElevation import androidx.tv.material3.surfaceColorAtElevation
import com.github.damontecres.wholphin.R 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.data.model.HomeRowConfigDisplay
import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.FontAwesome
import com.github.damontecres.wholphin.ui.components.Button import com.github.damontecres.wholphin.ui.components.Button
@ -64,7 +63,7 @@ fun HomePageRowList(
config = row, config = row,
moveUpAllowed = index > 0, moveUpAllowed = index > 0,
moveDownAllowed = index != state.rows.lastIndex, moveDownAllowed = index != state.rows.lastIndex,
deleteAllowed = row.config !is HomeRowConfig.ContinueWatching, deleteAllowed = true,
onClickMove = { onClickMove.invoke(it, index) }, onClickMove = { onClickMove.invoke(it, index) },
onClickDelete = { onClickDelete.invoke(index) }, onClickDelete = { onClickDelete.invoke(index) },
onClick = { onClick.invoke(index, row) }, onClick = { onClick.invoke(index, row) },

View file

@ -111,17 +111,36 @@ class HomePageSettingsViewModel
), ),
) )
} }
val rowConfig = val continueWatchingRows =
listOf( if (prefs.combineContinueNext) {
HomeRowConfigDisplay( listOf(
context.getString(R.string.continue_watching), HomeRowConfigDisplay(
HomeRowConfig.ContinueWatching( context.getString(R.string.combine_continue_next),
UUID.randomUUID(), HomeRowConfig.ContinueWatchingCombined(
prefs.combineContinueNext, UUID.randomUUID(),
HomeRowViewOptions(), HomeRowViewOptions(),
),
), ),
), )
) + includedIds } else {
listOf(
HomeRowConfigDisplay(
context.getString(R.string.continue_watching),
HomeRowConfig.ContinueWatching(
UUID.randomUUID(),
HomeRowViewOptions(),
),
),
HomeRowConfigDisplay(
context.getString(R.string.next_up),
HomeRowConfig.NextUp(
UUID.randomUUID(),
HomeRowViewOptions(),
),
),
)
}
val rowConfig = continueWatchingRows + includedIds
_state.update { _state.update {
it.copy(rows = rowConfig) it.copy(rows = rowConfig)
} }
@ -148,6 +167,16 @@ class HomePageSettingsViewModel
when (row) { when (row) {
is HomeRowConfig.ContinueWatching -> { is HomeRowConfig.ContinueWatching -> {
val resume = latestNextUpService.getResume(userDto.id, limit, true) val resume = latestNextUpService.getResume(userDto.id, limit, true)
listOf(
HomeRowLoadingState.Success(
title = context.getString(R.string.continue_watching),
items = resume,
viewOptions = row.viewOptions,
),
)
}
is HomeRowConfig.NextUp -> {
val nextUp = val nextUp =
latestNextUpService.getNextUp( latestNextUpService.getNextUp(
userDto.id, userDto.id,
@ -155,40 +184,37 @@ class HomePageSettingsViewModel
prefs.enableRewatchingNextUp, prefs.enableRewatchingNextUp,
false, false,
) )
val watching = listOf(
buildList { HomeRowLoadingState.Success(
if (row.combined) { title = context.getString(R.string.next_up),
val items = items = nextUp,
latestNextUpService.buildCombined(resume, nextUp) viewOptions = row.viewOptions,
add( ),
HomeRowLoadingState.Success( )
title = context.getString(R.string.continue_watching), }
items = items,
viewOptions = row.viewOptions, is HomeRowConfig.ContinueWatchingCombined -> {
), val resume =
) latestNextUpService.getResume(userDto.id, limit, true)
} else { val nextUp =
if (resume.isNotEmpty()) { latestNextUpService.getNextUp(
add( userDto.id,
HomeRowLoadingState.Success( limit,
title = context.getString(R.string.continue_watching), prefs.enableRewatchingNextUp,
items = resume, false,
viewOptions = row.viewOptions, )
),
) listOf(
} HomeRowLoadingState.Success(
if (nextUp.isNotEmpty()) { title = context.getString(R.string.continue_watching),
add( items =
HomeRowLoadingState.Success( latestNextUpService.buildCombined(
title = context.getString(R.string.next_up), resume,
items = nextUp, nextUp,
viewOptions = row.viewOptions, ),
), viewOptions = row.viewOptions,
) ),
} )
}
}
watching
} }
is HomeRowConfig.Genres -> { is HomeRowConfig.Genres -> {
@ -321,6 +347,50 @@ class HomePageSettingsViewModel
} }
} }
fun addRow(type: MetaRowType) {
viewModelScope.launchIO {
val newRow =
when (type) {
MetaRowType.CONTINUE_WATCHING -> {
HomeRowConfigDisplay(
context.getString(R.string.continue_watching),
HomeRowConfig.ContinueWatching(
UUID.randomUUID(),
HomeRowViewOptions(),
),
)
}
MetaRowType.NEXT_UP -> {
HomeRowConfigDisplay(
context.getString(R.string.continue_watching),
HomeRowConfig.NextUp(
UUID.randomUUID(),
HomeRowViewOptions(),
),
)
}
MetaRowType.COMBINED_CONTINUE_WATCHING -> {
HomeRowConfigDisplay(
context.getString(R.string.combine_continue_next),
HomeRowConfig.ContinueWatchingCombined(
UUID.randomUUID(),
HomeRowViewOptions(),
),
)
}
}
_state.update {
it.copy(
loading = LoadingState.Loading,
rows = it.rows.toMutableList().apply { add(newRow) },
)
}
fetchRowData()
}
}
fun addRow( fun addRow(
library: Library, library: Library,
rowType: LibraryRowType, rowType: LibraryRowType,
@ -510,6 +580,7 @@ fun HomePageSettings(
HomePageLibraryList( HomePageLibraryList(
libraries = state.libraries, libraries = state.libraries,
onClick = { destination = HomePageSettingsDestination.ChooseRowType(it) }, onClick = { destination = HomePageSettingsDestination.ChooseRowType(it) },
onClickMeta = { viewModel.addRow(it) },
modifier = destModifier, modifier = destModifier,
) )
} }