mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Basic save/load locally
This commit is contained in:
parent
84dc56289c
commit
ee8a4ac0ac
8 changed files with 392 additions and 123 deletions
|
|
@ -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<HomeRowConfig>,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<HomePageSettings>(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<HomePageSettings>(it)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DISPLAY_PREF_ID = "default"
|
||||
const val CUSTOM_PREF_ID = "home_settings"
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<HomeRowViewOptions, Any>
|
||||
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)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>(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()
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue