From ccb79257fdc8db2fc3762f1a2af280d310b7ed1a Mon Sep 17 00:00:00 2001 From: Damontecres Date: Tue, 27 Jan 2026 13:40:44 -0500 Subject: [PATCH] Add row for favorite items --- .../wholphin/data/model/HomeRowConfig.kt | 23 ++++- .../wholphin/services/HomeSettingsService.kt | 86 +++++++++++++++++-- .../damontecres/wholphin/ui/UiConstants.kt | 3 +- .../main/settings/HomeSettingsDestination.kt | 4 + .../main/settings/HomeSettingsFavoriteList.kt | 69 +++++++++++++++ .../main/settings/HomeSettingsLibraryList.kt | 72 +++++++++++++++- .../ui/main/settings/HomeSettingsPage.kt | 47 ++++++++-- .../ui/main/settings/HomeSettingsRowList.kt | 12 ++- .../ui/main/settings/HomeSettingsViewModel.kt | 42 ++++++++- 9 files changed, 334 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsFavoriteList.kt diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/HomeRowConfig.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/HomeRowConfig.kt index 46c3e664..ef0d77d4 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/model/HomeRowConfig.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/HomeRowConfig.kt @@ -10,6 +10,7 @@ import com.github.damontecres.wholphin.ui.data.SortAndDirection import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers +import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.serializer.UUIDSerializer import java.util.UUID @@ -86,13 +87,33 @@ sealed interface HomeRowConfig { val parentId: UUID, override val viewOptions: HomeRowViewOptions = HomeRowViewOptions( - heightDp = (Cards.HEIGHT_2X3_DP * .75f).toInt().let { it - it % 4 }, + heightDp = Cards.HEIGHT_EPISODE, aspectRatio = AspectRatio.WIDE, ), ) : HomeRowConfig { override fun updateViewOptions(viewOptions: HomeRowViewOptions): Genres = this.copy(viewOptions = viewOptions) } + /** + * Favorites for a specific type + */ + @Serializable + @SerialName("Favorite") + data class Favorite( + val kind: BaseItemKind, + override val viewOptions: HomeRowViewOptions = + if (kind == BaseItemKind.EPISODE) { + HomeRowViewOptions( + heightDp = Cards.HEIGHT_EPISODE, + aspectRatio = AspectRatio.WIDE, + ) + } else { + HomeRowViewOptions() + }, + ) : HomeRowConfig { + override fun updateViewOptions(viewOptions: HomeRowViewOptions): Favorite = this.copy(viewOptions = viewOptions) + } + /** * Fetch by parent ID such as a library, collection, or playlist with optional simple sorting */ diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt index 94766fb8..25ad8693 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt @@ -15,7 +15,9 @@ import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem import com.github.damontecres.wholphin.ui.toServerString import com.github.damontecres.wholphin.util.GetGenresRequestHandler import com.github.damontecres.wholphin.util.GetItemsRequestHandler +import com.github.damontecres.wholphin.util.GetPersonsHandler import com.github.damontecres.wholphin.util.HomeRowLoadingState +import com.github.damontecres.wholphin.util.HomeRowLoadingState.Success import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow @@ -31,12 +33,15 @@ import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi import org.jellyfin.sdk.api.client.extensions.userLibraryApi import org.jellyfin.sdk.model.UUID +import org.jellyfin.sdk.model.api.BaseItemKind +import org.jellyfin.sdk.model.api.ImageType import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.SortOrder import org.jellyfin.sdk.model.api.UserDto import org.jellyfin.sdk.model.api.request.GetGenresRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.api.request.GetLatestMediaRequest +import org.jellyfin.sdk.model.api.request.GetPersonsRequest import timber.log.Timber import java.io.File import javax.inject.Inject @@ -183,7 +188,19 @@ class HomeSettingsService suspend fun loadCurrentSettings(userId: UUID) { Timber.v("Getting setting for %s", userId) // User local then server/remote otherwise create a default - val settings = loadFromLocal(userId) ?: loadFromServer(userId) + val settings = + try { + loadFromLocal(userId) + } catch (ex: Exception) { + Timber.w(ex, "Error loading local settings") + // TODO show toast? + null + } ?: try { + loadFromServer(userId) + } catch (ex: Exception) { + Timber.w(ex, "Error loading remote settings") + null + } val resolvedSettings = if (settings != null) { Timber.v("Found settings") @@ -341,6 +358,11 @@ class HomeSettingsService config, ) } + + is HomeRowConfig.Favorite -> { + val name = context.getString(R.string.favorites) // TODO "Favorite " + HomeRowConfigDisplay(id, name, config) + } } /** @@ -358,7 +380,7 @@ class HomeSettingsService is HomeRowConfig.ContinueWatching -> { val resume = latestNextUpService.getResume(userDto.id, limit, true) - HomeRowLoadingState.Success( + Success( title = context.getString(R.string.continue_watching), items = resume, viewOptions = row.viewOptions, @@ -374,7 +396,7 @@ class HomeSettingsService false, ) - HomeRowLoadingState.Success( + Success( title = context.getString(R.string.next_up), items = nextUp, viewOptions = row.viewOptions, @@ -392,7 +414,7 @@ class HomeSettingsService false, ) - HomeRowLoadingState.Success( + Success( title = context.getString(R.string.continue_watching), items = latestNextUpService.buildCombined( @@ -438,7 +460,7 @@ class HomeSettingsService name?.let { context.getString(R.string.genres_in, it) } ?: context.getString(R.string.genres) - HomeRowLoadingState.Success( + Success( title, genres, viewOptions = row.viewOptions, @@ -468,7 +490,7 @@ class HomeSettingsService .content .map { BaseItem.Companion.from(it, api, true) } .let { - HomeRowLoadingState.Success( + Success( title, it, row.viewOptions, @@ -500,7 +522,7 @@ class HomeSettingsService .content.items .map { BaseItem.Companion.from(it, api, true) } .let { - HomeRowLoadingState.Success( + Success( title, it, row.viewOptions, @@ -528,7 +550,7 @@ class HomeSettingsService .content.items .map { BaseItem(it, true) } .let { - HomeRowLoadingState.Success( + Success( name ?: context.getString(R.string.collection), it, row.viewOptions, @@ -555,13 +577,59 @@ class HomeSettingsService .content.items .map { BaseItem(it, true) } .let { - HomeRowLoadingState.Success( + Success( row.name, it, row.viewOptions, ) } } + + is HomeRowConfig.Favorite -> { + if (row.kind == BaseItemKind.PERSON) { + val request = + GetPersonsRequest( + userId = userDto.id, + limit = limit, + fields = DefaultItemFields, + isFavorite = true, + enableImages = true, + enableImageTypes = listOf(ImageType.PRIMARY), + ) + GetPersonsHandler + .execute(api, request) + .content.items + .map { BaseItem(it, true) } + .let { + Success( + context.getString(R.string.favorites), // TODO + it, + row.viewOptions, + ) + } + } else { + val request = + GetItemsRequest( + userId = userDto.id, + recursive = true, + limit = limit, + fields = DefaultItemFields, + includeItemTypes = listOf(row.kind), + isFavorite = true, + ) + GetItemsRequestHandler + .execute(api, request) + .content.items + .map { BaseItem(it, false) } + .let { + Success( + context.getString(R.string.favorites), // TODO + it, + row.viewOptions, + ) + } + } + } } companion object { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/UiConstants.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/UiConstants.kt index 0ea92dcd..ce1a7352 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/UiConstants.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/UiConstants.kt @@ -75,7 +75,8 @@ val SlimItemFields = object Cards { const val HEIGHT_2X3_DP = 172 val height2x3 = HEIGHT_2X3_DP.dp - val heightEpisode = height2x3 * .75f + val HEIGHT_EPISODE = (HEIGHT_2X3_DP * .75f).toInt().let { it - it % 4 } + val heightEpisode = HEIGHT_EPISODE.dp val playedPercentHeight = 6.dp val serverUserCircle = height2x3 * .75f } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsDestination.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsDestination.kt index c08fe1f6..e3f4cb62 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsDestination.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsDestination.kt @@ -17,4 +17,8 @@ sealed interface HomeSettingsDestination : NavKey { data class RowSettings( val rowId: Int, ) : HomeSettingsDestination + + data object ChooseFavorite : HomeSettingsDestination + + data object ChooseDiscover : HomeSettingsDestination } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsFavoriteList.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsFavoriteList.kt new file mode 100644 index 00000000..6a0cfcce --- /dev/null +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsFavoriteList.kt @@ -0,0 +1,69 @@ +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.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 +import org.jellyfin.sdk.model.api.BaseItemKind + +@Composable +fun HomeSettingsFavoriteList( + onClick: (BaseItemKind) -> Unit, + modifier: Modifier = Modifier, + firstFocus: FocusRequester = remember { FocusRequester() }, +) { + LaunchedEffect(Unit) { firstFocus.tryRequestFocus() } + Column(modifier = modifier) { + Text( + text = "Add favorites row...", + ) + LazyColumn( + contentPadding = PaddingValues(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = + modifier + .fillMaxHeight() + .focusRestorer(firstFocus), + ) { + itemsIndexed(favoriteOptionsList) { index, type -> + ListItem( + selected = false, + headlineContent = { + Text( + text = stringResource(favoriteOptions[type]!!), + ) + }, + onClick = { onClick.invoke(type) }, + modifier = Modifier.ifElse(index == 0, Modifier.focusRequester(firstFocus)), + ) + } + } + } +} + +val favoriteOptions = + mapOf( + BaseItemKind.MOVIE to R.string.movies, + BaseItemKind.SERIES to R.string.tv_shows, + BaseItemKind.EPISODE to R.string.episodes, + BaseItemKind.VIDEO to R.string.videos, + BaseItemKind.PLAYLIST to R.string.playlists, + BaseItemKind.PERSON to R.string.people, + ) +val favoriteOptionsList = favoriteOptions.keys.toList() diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsLibraryList.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsLibraryList.kt index 998b634d..e8dd5c6c 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsLibraryList.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsLibraryList.kt @@ -5,6 +5,8 @@ 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.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.HorizontalDivider @@ -16,8 +18,10 @@ 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.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.tv.material3.ListItem +import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.ui.ifElse @@ -26,6 +30,7 @@ import com.github.damontecres.wholphin.ui.tryRequestFocus @Composable fun HomeSettingsLibraryList( libraries: List, + showDiscover: Boolean, onClick: (Library) -> Unit, onClickMeta: (MetaRowType) -> Unit, modifier: Modifier, @@ -44,7 +49,25 @@ fun HomeSettingsLibraryList( .fillMaxHeight() .focusRestorer(firstFocus), ) { - itemsIndexed(MetaRowType.entries) { index, type -> + item { + Text( + text = stringResource(R.string.continue_watching), + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface, + textAlign = TextAlign.Start, + modifier = + Modifier + .fillMaxWidth() + .padding(top = 8.dp, bottom = 4.dp), + ) + } + itemsIndexed( + listOf( + MetaRowType.CONTINUE_WATCHING, + MetaRowType.NEXT_UP, + MetaRowType.COMBINED_CONTINUE_WATCHING, + ), + ) { index, type -> ListItem( selected = false, headlineContent = { @@ -56,6 +79,16 @@ fun HomeSettingsLibraryList( } item { HorizontalDivider() + Text( + text = stringResource(R.string.library), + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface, + textAlign = TextAlign.Start, + modifier = + Modifier + .fillMaxWidth() + .padding(top = 8.dp, bottom = 4.dp), + ) } itemsIndexed(libraries) { index, library -> ListItem( @@ -67,6 +100,41 @@ fun HomeSettingsLibraryList( modifier = Modifier, // .ifElse(index == 0, Modifier.focusRequester(firstFocus)), ) } + item { + HorizontalDivider() + Text( + text = stringResource(R.string.more), + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface, + textAlign = TextAlign.Start, + modifier = + Modifier + .fillMaxWidth() + .padding(top = 8.dp, bottom = 4.dp), + ) + } + item { + ListItem( + selected = false, + headlineContent = { + Text(stringResource(MetaRowType.FAVORITES.stringId)) + }, + onClick = { onClickMeta.invoke(MetaRowType.FAVORITES) }, + modifier = Modifier, + ) + } + if (showDiscover) { + item { + ListItem( + selected = false, + headlineContent = { + Text(stringResource(MetaRowType.DISCOVER.stringId)) + }, + onClick = { onClickMeta.invoke(MetaRowType.DISCOVER) }, + modifier = Modifier, + ) + } + } } } } @@ -77,4 +145,6 @@ enum class MetaRowType( CONTINUE_WATCHING(R.string.continue_watching), NEXT_UP(R.string.next_up), COMBINED_CONTINUE_WATCHING(R.string.combine_continue_next), + FAVORITES(R.string.favorites), + DISCOVER(R.string.discover), } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsPage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsPage.kt index 289d1e85..ae605e9a 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsPage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsPage.kt @@ -22,6 +22,8 @@ import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.tv.material3.MaterialTheme import com.github.damontecres.wholphin.ui.main.HomePageContent +import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsDestination.ChooseRowType +import com.github.damontecres.wholphin.ui.main.settings.HomeSettingsDestination.RowSettings import com.github.damontecres.wholphin.util.ExceptionHandler import kotlinx.coroutines.launch import timber.log.Timber @@ -38,14 +40,15 @@ fun HomeSettingsPage( var destination by remember { mutableStateOf(HomeSettingsDestination.RowList) } val state by viewModel.state.collectAsState() + val discoverEnabled by viewModel.discoverEnabled.collectAsState(false) - BackHandler(destination is HomeSettingsDestination.ChooseRowType) { + BackHandler(destination is ChooseRowType) { destination = HomeSettingsDestination.ChooseLibrary } BackHandler(destination is HomeSettingsDestination.ChooseLibrary) { destination = HomeSettingsDestination.RowList } - BackHandler(destination is HomeSettingsDestination.RowSettings) { + BackHandler(destination is RowSettings) { destination = HomeSettingsDestination.RowList } Row( @@ -72,7 +75,7 @@ fun HomeSettingsPage( onClickMove = viewModel::moveRow, onClickDelete = viewModel::deleteRow, onClick = { index, row -> - destination = HomeSettingsDestination.RowSettings(row.id) + destination = RowSettings(row.id) scope.launch(ExceptionHandler()) { Timber.v("Scroll to $index") listState.scrollToItem(index) @@ -88,16 +91,32 @@ fun HomeSettingsPage( is HomeSettingsDestination.ChooseLibrary -> { HomeSettingsLibraryList( libraries = state.libraries, - onClick = { destination = HomeSettingsDestination.ChooseRowType(it) }, + showDiscover = discoverEnabled, + onClick = { destination = ChooseRowType(it) }, onClickMeta = { - viewModel.addRow(it) - destination = HomeSettingsDestination.RowList + when (it) { + MetaRowType.CONTINUE_WATCHING, + MetaRowType.NEXT_UP, + MetaRowType.COMBINED_CONTINUE_WATCHING, + -> { + viewModel.addRow(it) + destination = HomeSettingsDestination.RowList + } + + MetaRowType.FAVORITES -> { + destination = HomeSettingsDestination.ChooseFavorite + } + + MetaRowType.DISCOVER -> { + destination = HomeSettingsDestination.ChooseDiscover + } + } }, modifier = destModifier, ) } - is HomeSettingsDestination.ChooseRowType -> { + is ChooseRowType -> { HomeLibraryRowTypeList( library = dest.library, onClick = { @@ -108,7 +127,7 @@ fun HomeSettingsPage( ) } - is HomeSettingsDestination.RowSettings -> { + is RowSettings -> { val row = state.rows .first { it.id == dest.rowId } @@ -124,6 +143,18 @@ fun HomeSettingsPage( modifier = destModifier, ) } + + HomeSettingsDestination.ChooseDiscover -> { + TODO() + } + + HomeSettingsDestination.ChooseFavorite -> { + HomeSettingsFavoriteList( + onClick = { type -> + viewModel.addFavoriteRow(type) + }, + ) + } } } HomePageContent( diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsRowList.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsRowList.kt index c6761776..ff6ff4f7 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsRowList.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsRowList.kt @@ -23,9 +23,11 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusDirection import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRestorer +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp @@ -57,6 +59,7 @@ fun HomeSettingsRowList( modifier: Modifier, firstFocus: FocusRequester = remember { FocusRequester() }, ) { + val focusManager = LocalFocusManager.current LaunchedEffect(Unit) { firstFocus.tryRequestFocus() } Column(modifier = modifier) { LazyColumn( @@ -148,7 +151,14 @@ fun HomeSettingsRowList( moveDownAllowed = index != state.rows.lastIndex, deleteAllowed = state.rows.size > 1, onClickMove = { onClickMove.invoke(it, index) }, - onClickDelete = { onClickDelete.invoke(index) }, + onClickDelete = { + if (index != state.rows.lastIndex) { + focusManager.moveFocus(FocusDirection.Down) + } else { + focusManager.moveFocus(FocusDirection.Up) + } + onClickDelete.invoke(index) + }, onClick = { onClick.invoke(index, row) }, modifier = Modifier diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt index a5c1293d..1e89437a 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsViewModel.kt @@ -11,11 +11,15 @@ import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.HomePageSettings import com.github.damontecres.wholphin.data.model.HomeRowConfig +import com.github.damontecres.wholphin.data.model.HomeRowConfig.ContinueWatching +import com.github.damontecres.wholphin.data.model.HomeRowConfig.ContinueWatchingCombined +import com.github.damontecres.wholphin.data.model.HomeRowConfig.NextUp import com.github.damontecres.wholphin.data.model.HomeRowViewOptions import com.github.damontecres.wholphin.services.BackdropService import com.github.damontecres.wholphin.services.HomePageResolvedSettings import com.github.damontecres.wholphin.services.HomeRowConfigDisplay import com.github.damontecres.wholphin.services.HomeSettingsService +import com.github.damontecres.wholphin.services.SeerrServerRepository import com.github.damontecres.wholphin.services.UserPreferencesService import com.github.damontecres.wholphin.services.hilt.IoCoroutineScope import com.github.damontecres.wholphin.ui.launchIO @@ -30,6 +34,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.update +import org.jellyfin.sdk.model.api.BaseItemKind import org.jellyfin.sdk.model.api.CollectionType import timber.log.Timber import java.util.UUID @@ -45,11 +50,14 @@ class HomeSettingsViewModel private val userPreferencesService: UserPreferencesService, private val navDrawerItemRepository: NavDrawerItemRepository, private val backdropService: BackdropService, + private val seerrServerRepository: SeerrServerRepository, @param:IoCoroutineScope private val ioScope: CoroutineScope, ) : ViewModel() { private val _state = MutableStateFlow(HomePageSettingsState.EMPTY) val state: StateFlow = _state + val discoverEnabled = seerrServerRepository.active + init { addCloseable { saveToLocal() } viewModelScope.launchIO { @@ -164,7 +172,7 @@ class HomeSettingsViewModel HomeRowConfigDisplay( id = id, title = context.getString(R.string.continue_watching), - config = HomeRowConfig.ContinueWatching(), + config = ContinueWatching(), ) } @@ -172,7 +180,7 @@ class HomeSettingsViewModel HomeRowConfigDisplay( id = id, title = context.getString(R.string.continue_watching), - config = HomeRowConfig.NextUp(), + config = NextUp(), ) } @@ -180,9 +188,17 @@ class HomeSettingsViewModel HomeRowConfigDisplay( id = id, title = context.getString(R.string.combine_continue_next), - config = HomeRowConfig.ContinueWatchingCombined(), + config = ContinueWatchingCombined(), ) } + + MetaRowType.FAVORITES -> { + throw IllegalArgumentException("Should use addRow(BaseItemKind) instead") + } + + MetaRowType.DISCOVER -> { + TODO() + } } updateState { it.copy( @@ -246,6 +262,26 @@ class HomeSettingsViewModel } } + fun addFavoriteRow(type: BaseItemKind) { + viewModelScope.launchIO { + Timber.v("Adding favorite row for $type") + val id = state.value.rows.size + val newRow = + HomeRowConfigDisplay( + id = id, + title = context.getString(favoriteOptions[type]!!), + config = HomeRowConfig.Favorite(type), + ) + updateState { + it.copy( + loading = LoadingState.Loading, + rows = it.rows.toMutableList().apply { add(newRow) }, + ) + } + fetchRowData() + } + } + fun updateViewOptions( rowId: Int, viewOptions: HomeRowViewOptions,