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 cc60e436..7c1faf74 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 @@ -99,7 +99,7 @@ sealed class HomeRowConfig { val parentId: UUID, override val viewOptions: HomeRowViewOptions = HomeRowViewOptions( - heightDp = (Cards.HEIGHT_2X3_DP * .75f).toInt(), + heightDp = (Cards.HEIGHT_2X3_DP * .75f).toInt().let { it - it % 4 }, aspectRatio = AspectRatio.WIDE, ), ) : HomeRowConfig() { @@ -128,7 +128,7 @@ sealed class HomeRowConfig { @SerialName("GetItems") data class GetItems( override val id: Int, - val name: String?, + val name: String, val getItems: GetItemsRequest, override val viewOptions: HomeRowViewOptions, ) : HomeRowConfig() { @@ -142,8 +142,8 @@ data class HomeRowConfigDisplay( ) @Serializable -@SerialName("HomePageConfiguration") -data class HomePageConfiguration( +@SerialName("HomePageSettings") +data class HomePageSettings( val version: Int = 1, val rows: List, ) 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 new file mode 100644 index 00000000..31744dda --- /dev/null +++ b/app/src/main/java/com/github/damontecres/wholphin/services/HomeSettingsService.kt @@ -0,0 +1,102 @@ +package com.github.damontecres.wholphin.services + +import android.content.Context +import com.github.damontecres.wholphin.R +import com.github.damontecres.wholphin.data.ServerRepository +import com.github.damontecres.wholphin.data.model.HomePageSettings +import com.github.damontecres.wholphin.ui.toServerString +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.decodeFromStream +import kotlinx.serialization.json.encodeToStream +import org.jellyfin.sdk.api.client.ApiClient +import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi +import org.jellyfin.sdk.model.UUID +import java.io.File +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class HomeSettingsService + @Inject + constructor( + @param:ApplicationContext private val context: Context, + private val api: ApiClient, + private val serverRepository: ServerRepository, + ) { + val jsonParser = + Json { + isLenient = true + ignoreUnknownKeys = true + } + + suspend fun saveToServer( + settings: HomePageSettings, + displayPreferencesId: String = DISPLAY_PREF_ID, + ) { + serverRepository.currentUser.value?.let { user -> + val current = getDisplayPreferences(user.id, DISPLAY_PREF_ID) + val customPrefs = + current.customPrefs.toMutableMap().apply { + put(CUSTOM_PREF_ID, jsonParser.encodeToString(settings)) + } + api.displayPreferencesApi.updateDisplayPreferences( + displayPreferencesId = displayPreferencesId, + userId = user.id, + client = context.getString(R.string.app_name), + data = current.copy(customPrefs = customPrefs), + ) + } + } + + suspend fun loadFromServer(displayPreferencesId: String = DISPLAY_PREF_ID): HomePageSettings? = + serverRepository.currentUser.value?.let { user -> + val current = getDisplayPreferences(user.id, displayPreferencesId) + current.customPrefs[DISPLAY_PREF_ID]?.let { + Json.decodeFromString(it) + } + } + + private suspend fun getDisplayPreferences( + userId: UUID, + displayPreferencesId: String, + ) = api.displayPreferencesApi + .getDisplayPreferences( + userId = userId, + displayPreferencesId = displayPreferencesId, + client = context.getString(R.string.app_name), + ).content + + private fun filename(userId: UUID) = "${CUSTOM_PREF_ID}_${userId.toServerString()}.json" + + @OptIn(ExperimentalSerializationApi::class) + suspend fun saveToLocal(settings: HomePageSettings) { + serverRepository.currentUser.value?.let { user -> + val dir = File(context.filesDir, CUSTOM_PREF_ID) + dir.mkdirs() + File(dir, filename(user.id)).outputStream().use { + jsonParser.encodeToStream(settings, it) + } + } + } + + @OptIn(ExperimentalSerializationApi::class) + suspend fun loadFromLocal(): HomePageSettings? = + serverRepository.currentUser.value?.let { user -> + val dir = File(context.filesDir, CUSTOM_PREF_ID) + val file = File(dir, filename(user.id)) + if (file.exists()) { + file.inputStream().use { + jsonParser.decodeFromStream(it) + } + } else { + null + } + } + + companion object { + const val DISPLAY_PREF_ID = "default" + const val CUSTOM_PREF_ID = "home_settings" + } + } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt index dbcf8fb0..3bcea534 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/HomePage.kt @@ -195,6 +195,7 @@ fun HomePageContent( onFocusPosition: ((RowColumn) -> Unit)? = null, loadingState: LoadingState? = null, listState: LazyListState = rememberLazyListState(), + takeFocus: Boolean = true, ) { var position by rememberPosition() val focusedItem = @@ -204,22 +205,24 @@ fun HomePageContent( val rowFocusRequesters = remember(homeRows) { List(homeRows.size) { FocusRequester() } } var firstFocused by remember { mutableStateOf(false) } - LaunchedEffect(homeRows) { - if (!firstFocused) { - if (position.row >= 0) { - rowFocusRequesters[position.row].tryRequestFocus() - firstFocused = true - } else { - // Waiting for the first home row to load, then focus on it - homeRows - .indexOfFirst { it is HomeRowLoadingState.Success && it.items.isNotEmpty() } - .takeIf { it >= 0 } - ?.let { - rowFocusRequesters[it].tryRequestFocus() - firstFocused = true - delay(50) - listState.scrollToItem(it) - } + if (takeFocus) { + LaunchedEffect(homeRows) { + if (!firstFocused) { + if (position.row >= 0) { + rowFocusRequesters[position.row].tryRequestFocus() + firstFocused = true + } else { + // Waiting for the first home row to load, then focus on it + homeRows + .indexOfFirst { it is HomeRowLoadingState.Success && it.items.isNotEmpty() } + .takeIf { it >= 0 } + ?.let { + rowFocusRequesters[it].tryRequestFocus() + firstFocused = true + delay(50) + listState.scrollToItem(it) + } + } } } } @@ -421,19 +424,17 @@ fun HomePageHeader( item: BaseItem?, modifier: Modifier = Modifier, ) { - item?.let { - val isEpisode = item.type == BaseItemKind.EPISODE - val dto = item.data - HomePageHeader( - title = item.title, - subtitle = if (isEpisode) dto.name else null, - overview = dto.overview, - overviewTwoLines = isEpisode, - quickDetails = item.ui.quickDetails, - timeRemaining = item.timeRemainingOrRuntime, - modifier = modifier, - ) - } + val isEpisode = item?.type == BaseItemKind.EPISODE + val dto = item?.data + HomePageHeader( + title = item?.title, + subtitle = if (isEpisode) dto?.name else null, + overview = dto?.overview, + overviewTwoLines = isEpisode, + quickDetails = item?.ui?.quickDetails ?: AnnotatedString(""), + timeRemaining = item?.timeRemainingOrRuntime, + modifier = modifier, + ) } @Composable diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeRowSettings.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeRowSettings.kt index bf8e6676..5946fe4b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeRowSettings.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeRowSettings.kt @@ -4,17 +4,22 @@ import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Column import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items +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.unit.dp import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import androidx.tv.material3.surfaceColorAtElevation import com.github.damontecres.wholphin.data.model.HomeRowViewOptions import com.github.damontecres.wholphin.preferences.AppPreference +import com.github.damontecres.wholphin.ui.ifElse import com.github.damontecres.wholphin.ui.preferences.ComposablePreference +import com.github.damontecres.wholphin.ui.tryRequestFocus @Composable fun HomeRowSettings( @@ -25,6 +30,8 @@ fun HomeRowSettings( modifier: Modifier = Modifier, defaultViewOptions: HomeRowViewOptions = HomeRowViewOptions(), ) { + val firstFocus = remember { FocusRequester() } + LaunchedEffect(Unit) { firstFocus.tryRequestFocus() } Column(modifier = modifier) { Text( text = title, @@ -32,7 +39,7 @@ fun HomeRowSettings( color = MaterialTheme.colorScheme.onSurface, ) LazyColumn { - items(HomeRowViewOptions.OPTIONS) { pref -> + itemsIndexed(HomeRowViewOptions.OPTIONS) { index, pref -> pref as AppPreference val interactionSource = remember { MutableInteractionSource() } val value = pref.getter.invoke(viewOptions) @@ -51,7 +58,13 @@ fun HomeRowSettings( onApplyApplyAll.invoke() } }, - modifier = Modifier.background(MaterialTheme.colorScheme.surfaceColorAtElevation(5.dp)), + modifier = + Modifier + .background( + MaterialTheme.colorScheme.surfaceColorAtElevation( + 5.dp, + ), + ).ifElse(index == 0, Modifier.focusRequester(firstFocus)), ) } } 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 10398755..c08fe1f6 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 @@ -1,9 +1,11 @@ package com.github.damontecres.wholphin.ui.main.settings +import androidx.navigation3.runtime.NavKey + /** * Tracking the pages for selecting and configuring rows */ -sealed interface HomeSettingsDestination { +sealed interface HomeSettingsDestination : NavKey { data object RowList : HomeSettingsDestination data object ChooseLibrary : HomeSettingsDestination 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 7c226ba1..72cfa7a7 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 @@ -15,12 +15,16 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier 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.util.ExceptionHandler +import kotlinx.coroutines.launch +import timber.log.Timber val settingsWidth = 300.dp @@ -29,10 +33,12 @@ fun HomeSettingsPage( modifier: Modifier, viewModel: HomeSettingsViewModel = hiltViewModel(), ) { - val state by viewModel.state.collectAsState() + val scope = rememberCoroutineScope() val listState = rememberLazyListState() var destination by remember { mutableStateOf(HomeSettingsDestination.RowList) } + val state by viewModel.state.collectAsState() + BackHandler(destination is HomeSettingsDestination.ChooseRowType) { destination = HomeSettingsDestination.ChooseLibrary } @@ -62,10 +68,15 @@ fun HomeSettingsPage( HomeSettingsRowList( state = state, onClickAdd = { destination = HomeSettingsDestination.ChooseLibrary }, + onClickSaveLocal = { viewModel.saveToLocal() }, onClickMove = viewModel::moveRow, onClickDelete = viewModel::deleteRow, onClick = { index, row -> destination = HomeSettingsDestination.RowSettings(row.config.id) + scope.launch(ExceptionHandler()) { + Timber.v("Scroll to $index") + listState.scrollToItem(index) + } }, modifier = destModifier, ) @@ -121,6 +132,7 @@ fun HomeSettingsPage( showClock = false, onUpdateBackdrop = viewModel::updateBackdrop, listState = listState, + takeFocus = false, modifier = Modifier .fillMaxHeight() 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 49842fca..b1e72e92 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 @@ -13,8 +13,12 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Create import androidx.compose.material.icons.filled.Delete +import androidx.compose.material3.HorizontalDivider import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -33,7 +37,7 @@ import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.data.model.HomeRowConfigDisplay import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.components.Button -import com.github.damontecres.wholphin.ui.ifElse +import com.github.damontecres.wholphin.ui.tryRequestFocus enum class MoveDirection { UP, @@ -44,12 +48,14 @@ enum class MoveDirection { fun HomeSettingsRowList( state: HomePageSettingsState, onClick: (Int, HomeRowConfigDisplay) -> Unit, + onClickSaveLocal: () -> Unit, onClickAdd: () -> Unit, onClickMove: (MoveDirection, Int) -> Unit, onClickDelete: (Int) -> Unit, modifier: Modifier, firstFocus: FocusRequester = remember { FocusRequester() }, ) { + LaunchedEffect(Unit) { firstFocus.tryRequestFocus() } Column(modifier = modifier) { LazyColumn( verticalArrangement = Arrangement.spacedBy(8.dp), @@ -58,6 +64,45 @@ fun HomeSettingsRowList( .fillMaxHeight() .focusRestorer(firstFocus), ) { + item { + ListItem( + selected = false, + headlineContent = { + Text( + text = stringResource(R.string.add_row), + ) + }, + leadingContent = { + Icon( + imageVector = Icons.Default.Add, + contentDescription = null, + ) + }, + onClick = onClickAdd, + modifier = Modifier.focusRequester(firstFocus), + ) + } + item { + ListItem( + selected = false, + headlineContent = { + Text( + text = stringResource(R.string.save), + ) + }, + leadingContent = { + Icon( + imageVector = Icons.Default.Create, + contentDescription = null, + ) + }, + onClick = onClickSaveLocal, + modifier = Modifier, + ) + } + item { + HorizontalDivider() + } itemsIndexed(state.rows, key = { _, row -> row.config.id }) { index, row -> HomeRowConfigContent( config = row, @@ -69,20 +114,9 @@ fun HomeSettingsRowList( onClick = { onClick.invoke(index, row) }, modifier = Modifier - .fillMaxWidth() - .ifElse(index == 0, Modifier.focusRequester(firstFocus)), + .fillMaxWidth(), ) } - item { - Button( - onClick = onClickAdd, - modifier = Modifier.ifElse(state.rows.isEmpty(), Modifier.focusRequester(firstFocus)), - ) { - Text( - text = stringResource(R.string.add_row), - ) - } - } } } } 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 275fe202..623a18c1 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 @@ -1,6 +1,7 @@ package com.github.damontecres.wholphin.ui.main.settings import android.content.Context +import android.widget.Toast import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -8,11 +9,13 @@ import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.data.NavDrawerItemRepository 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.HomeRowConfigDisplay import com.github.damontecres.wholphin.data.model.HomeRowViewOptions import com.github.damontecres.wholphin.preferences.HomePagePreferences import com.github.damontecres.wholphin.services.BackdropService +import com.github.damontecres.wholphin.services.HomeSettingsService import com.github.damontecres.wholphin.services.ImageUrlService import com.github.damontecres.wholphin.services.LatestNextUpService import com.github.damontecres.wholphin.services.UserPreferencesService @@ -21,6 +24,7 @@ import com.github.damontecres.wholphin.ui.SlimItemFields import com.github.damontecres.wholphin.ui.components.getGenreImageMap import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem +import com.github.damontecres.wholphin.ui.showToast import com.github.damontecres.wholphin.util.GetGenresRequestHandler import com.github.damontecres.wholphin.util.GetItemsRequestHandler import com.github.damontecres.wholphin.util.HomeRowLoadingState @@ -40,6 +44,7 @@ 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.serializer.toUUID +import timber.log.Timber import java.util.UUID import javax.inject.Inject @@ -49,6 +54,7 @@ class HomeSettingsViewModel constructor( @param:ApplicationContext private val context: Context, private val api: ApiClient, + private val homeSettingsService: HomeSettingsService, private val serverRepository: ServerRepository, private val userPreferencesService: UserPreferencesService, private val navDrawerItemRepository: NavDrawerItemRepository, @@ -73,91 +79,176 @@ class HomeSettingsViewModel } _state.update { it.copy(libraries = libraries) } - // TODO get config + val localSettings = + try { + homeSettingsService.loadFromLocal() + } catch (ex: Exception) { + Timber.e(ex) + showToast(context, "Error loading settings: ${ex.localizedMessage}") + null + } + if (localSettings != null) { + val displays = localSettings.rows.map { convert(it) } + _state.update { + it.copy(rows = displays) + } + } else { - // Or create default - val prefs = userPreferencesService.getCurrent().appPreferences.homePagePreferences - val includedIds = - navDrawerItemRepository - .getFilteredNavDrawerItems(navDrawerItems) - .filter { it is ServerNavDrawerItem } - .mapIndexed { index, it -> - val id = (it as ServerNavDrawerItem).itemId - val name = libraries.firstOrNull { it.itemId == id }?.name - val title = - name?.let { context.getString(R.string.recently_added_in, it) } - ?: context.getString(R.string.recently_added) - HomeRowConfigDisplay( - title, - HomeRowConfig.RecentlyAdded( - index, - id, - HomeRowViewOptions(), + // Or create default + val prefs = + userPreferencesService.getCurrent().appPreferences.homePagePreferences + val includedIds = + navDrawerItemRepository + .getFilteredNavDrawerItems(navDrawerItems) + .filter { it is ServerNavDrawerItem } + .mapIndexed { index, it -> + val id = (it as ServerNavDrawerItem).itemId + val name = libraries.firstOrNull { it.itemId == id }?.name + val title = + name?.let { context.getString(R.string.recently_added_in, it) } + ?: context.getString(R.string.recently_added) + HomeRowConfigDisplay( + title, + HomeRowConfig.RecentlyAdded( + index, + id, + HomeRowViewOptions(), + ), + ) + } + val continueWatchingRows = + if (prefs.combineContinueNext) { + listOf( + HomeRowConfigDisplay( + context.getString(R.string.combine_continue_next), + HomeRowConfig.ContinueWatchingCombined( + includedIds.size + 1, + HomeRowViewOptions(), + ), + ), + ) + } else { + listOf( + HomeRowConfigDisplay( + context.getString(R.string.continue_watching), + HomeRowConfig.ContinueWatching( + includedIds.size + 1, + HomeRowViewOptions(), + ), + ), + HomeRowConfigDisplay( + context.getString(R.string.next_up), + HomeRowConfig.NextUp( + includedIds.size + 2, + HomeRowViewOptions(), + ), ), ) } - val continueWatchingRows = - if (prefs.combineContinueNext) { - listOf( - HomeRowConfigDisplay( - context.getString(R.string.combine_continue_next), - HomeRowConfig.ContinueWatchingCombined( - includedIds.size + 1, - HomeRowViewOptions(), + val rowConfig = + continueWatchingRows + includedIds + + // TODO remove after testing + listOf( + HomeRowConfigDisplay( + "Collection", + HomeRowConfig.ByParent( + id = 100, + parentId = "34ab6fd1f51c41bb014981f2e334f465".toUUID(), + recursive = true, + viewOptions = HomeRowViewOptions(), + ), ), - ), - ) - } else { - listOf( - HomeRowConfigDisplay( - context.getString(R.string.continue_watching), - HomeRowConfig.ContinueWatching( - includedIds.size + 1, - HomeRowViewOptions(), + HomeRowConfigDisplay( + "Playlist", + HomeRowConfig.ByParent( + id = 101, + parentId = "f94be36e9836127a0bccfc7843b19e5b".toUUID(), + recursive = true, + viewOptions = HomeRowViewOptions(), + ), ), - ), - HomeRowConfigDisplay( - context.getString(R.string.next_up), - HomeRowConfig.NextUp( - includedIds.size + 2, - HomeRowViewOptions(), - ), - ), - ) + ) + _state.update { + it.copy(rows = rowConfig) } - val rowConfig = - continueWatchingRows + includedIds + - // TODO remove after testing - listOf( - HomeRowConfigDisplay( - "Collection", - HomeRowConfig.ByParent( - id = 100, - parentId = "34ab6fd1f51c41bb014981f2e334f465".toUUID(), - recursive = true, - viewOptions = HomeRowViewOptions(), - ), - ), - HomeRowConfigDisplay( - "Playlist", - HomeRowConfig.ByParent( - id = 101, - parentId = "f94be36e9836127a0bccfc7843b19e5b".toUUID(), - recursive = true, - viewOptions = HomeRowViewOptions(), - ), - ), - ) - _state.update { - it.copy(rows = rowConfig) } -// val json = Json.encodeToString(rowConfig) -// Timber.v("json=$json") fetchRowData() } } + private suspend fun convert(config: HomeRowConfig): HomeRowConfigDisplay = + when (config) { + is HomeRowConfig.ByParent -> { + val name = + api.userLibraryApi + .getItem(itemId = config.parentId) + .content.name ?: "" + HomeRowConfigDisplay( + name, + config, + ) + } + + is HomeRowConfig.ContinueWatching -> { + HomeRowConfigDisplay( + context.getString(R.string.continue_watching), + config, + ) + } + + is HomeRowConfig.ContinueWatchingCombined -> { + HomeRowConfigDisplay( + context.getString(R.string.combine_continue_next), + config, + ) + } + + is HomeRowConfig.Genres -> { + val name = + api.userLibraryApi + .getItem(itemId = config.parentId) + .content.name ?: "" + HomeRowConfigDisplay( + context.getString(R.string.genres_in, name), + config, + ) + } + + is HomeRowConfig.GetItems -> { + HomeRowConfigDisplay(config.name, config) + } + + is HomeRowConfig.NextUp -> { + HomeRowConfigDisplay( + context.getString(R.string.next_up), + config, + ) + } + + is HomeRowConfig.RecentlyAdded -> { + val name = + api.userLibraryApi + .getItem(itemId = config.parentId) + .content.name ?: "" + HomeRowConfigDisplay( + context.getString(R.string.recently_added_in, name), + config, + ) + } + + is HomeRowConfig.RecentlyReleased -> { + val name = + api.userLibraryApi + .getItem(itemId = config.parentId) + .content.name ?: "" + HomeRowConfigDisplay( + context.getString(R.string.recently_released_in, name), + config, + ) + } + } + fun updateBackdrop(item: BaseItem) { viewModelScope.launchIO { backdropService.submit(item) @@ -615,6 +706,20 @@ class HomeSettingsViewModel ) } } + + fun saveToLocal() { + viewModelScope.launchIO { + val rows = state.value.rows.map { it.config } + val settings = HomePageSettings(rows = rows) + try { + homeSettingsService.saveToLocal(settings) + showToast(context, context.getString(R.string.save), Toast.LENGTH_SHORT) + } catch (ex: Exception) { + Timber.e(ex) + showToast(context, "Error saving: ${ex.localizedMessage}") + } + } + } } data class HomePageSettingsState(