mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Save/load from server
This commit is contained in:
parent
e11b9ecc72
commit
f315531db7
7 changed files with 192 additions and 33 deletions
|
|
@ -399,7 +399,7 @@ class HomeSettingsService
|
|||
/**
|
||||
* Converts a [HomeRowConfig] into [HomeRowConfigDisplay] for UI purposes
|
||||
*/
|
||||
private suspend fun resolve(
|
||||
suspend fun resolve(
|
||||
id: Int,
|
||||
config: HomeRowConfig,
|
||||
): HomeRowConfigDisplay =
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
package com.github.damontecres.wholphin.ui.main.settings
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.NonRestartableComposable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.tv.material3.ListItem
|
||||
import androidx.tv.material3.ListItemBorder
|
||||
import androidx.tv.material3.ListItemColors
|
||||
import androidx.tv.material3.ListItemDefaults
|
||||
import androidx.tv.material3.ListItemGlow
|
||||
import androidx.tv.material3.ListItemScale
|
||||
import androidx.tv.material3.ListItemShape
|
||||
|
||||
@Composable
|
||||
@NonRestartableComposable
|
||||
fun HomeSettingsListItem(
|
||||
selected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
headlineContent: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
onLongClick: (() -> Unit)? = null,
|
||||
overlineContent: (@Composable () -> Unit)? = null,
|
||||
supportingContent: (@Composable () -> Unit)? = null,
|
||||
leadingContent: (@Composable BoxScope.() -> Unit)? = null,
|
||||
trailingContent: (@Composable () -> Unit)? = null,
|
||||
tonalElevation: Dp = 3.dp,
|
||||
shape: ListItemShape = ListItemDefaults.shape(),
|
||||
colors: ListItemColors = ListItemDefaults.colors(),
|
||||
scale: ListItemScale = ListItemDefaults.scale(),
|
||||
border: ListItemBorder = ListItemDefaults.border(),
|
||||
glow: ListItemGlow = ListItemDefaults.glow(),
|
||||
interactionSource: MutableInteractionSource? = null,
|
||||
) = ListItem(
|
||||
selected = selected,
|
||||
onClick = onClick,
|
||||
headlineContent = headlineContent,
|
||||
modifier = modifier,
|
||||
enabled = enabled,
|
||||
onLongClick = onLongClick,
|
||||
overlineContent = overlineContent,
|
||||
supportingContent = supportingContent,
|
||||
leadingContent = leadingContent,
|
||||
trailingContent = trailingContent,
|
||||
tonalElevation = tonalElevation,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
scale = scale,
|
||||
border = border,
|
||||
glow = glow,
|
||||
interactionSource = interactionSource,
|
||||
)
|
||||
|
|
@ -12,8 +12,12 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
|||
import androidx.compose.runtime.Composable
|
||||
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.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
|
||||
|
|
@ -23,6 +27,8 @@ import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
|
|||
import androidx.navigation3.ui.NavDisplay
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.surfaceColorAtElevation
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.ui.components.ConfirmDialog
|
||||
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
|
||||
|
|
@ -41,6 +47,7 @@ fun HomeSettingsPage(
|
|||
val scope = rememberCoroutineScope()
|
||||
val listState = rememberLazyListState()
|
||||
val backStack = rememberNavBackStack(HomeSettingsDestination.RowList)
|
||||
var showConfirmDialog by remember { mutableStateOf<(() -> Unit)?>(null) }
|
||||
|
||||
val state by viewModel.state.collectAsState()
|
||||
val discoverEnabled by viewModel.discoverEnabled.collectAsState(false)
|
||||
|
|
@ -86,7 +93,16 @@ fun HomeSettingsPage(
|
|||
HomeSettingsRowList(
|
||||
state = state,
|
||||
onClickAdd = { backStack.add(HomeSettingsDestination.AddRow) },
|
||||
onClickSaveLocal = { viewModel.saveToLocal() },
|
||||
onClickSave = {
|
||||
showConfirmDialog = {
|
||||
viewModel.saveToRemote()
|
||||
}
|
||||
},
|
||||
onClickLoad = {
|
||||
showConfirmDialog = {
|
||||
viewModel.loadFromRemote()
|
||||
}
|
||||
},
|
||||
onClickMove = viewModel::moveRow,
|
||||
onClickDelete = viewModel::deleteRow,
|
||||
onClick = { index, row ->
|
||||
|
|
@ -189,4 +205,15 @@ fun HomeSettingsPage(
|
|||
.weight(1f),
|
||||
)
|
||||
}
|
||||
showConfirmDialog?.let { onConfirm ->
|
||||
ConfirmDialog(
|
||||
title = stringResource(R.string.confirm),
|
||||
body = "Overwrite?",
|
||||
onCancel = { showConfirmDialog = null },
|
||||
onConfirm = {
|
||||
onConfirm.invoke()
|
||||
showConfirmDialog = null
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
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.material.icons.filled.Edit
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
|
|
@ -27,9 +26,11 @@ 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.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.tv.material3.Icon
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.services.HomeRowConfigDisplay
|
||||
|
|
@ -47,7 +48,8 @@ fun HomeSettingsRowList(
|
|||
state: HomePageSettingsState,
|
||||
onClick: (Int, HomeRowConfigDisplay) -> Unit,
|
||||
onClickResize: (Int) -> Unit,
|
||||
onClickSaveLocal: () -> Unit,
|
||||
onClickSave: () -> Unit,
|
||||
onClickLoad: () -> Unit,
|
||||
onClickAdd: () -> Unit,
|
||||
onClickMove: (MoveDirection, Int) -> Unit,
|
||||
onClickDelete: (Int) -> Unit,
|
||||
|
|
@ -83,6 +85,7 @@ fun HomeSettingsRowList(
|
|||
)
|
||||
}
|
||||
item {
|
||||
Row {
|
||||
HomeSettingsListItem(
|
||||
selected = false,
|
||||
headlineContent = {
|
||||
|
|
@ -97,10 +100,8 @@ fun HomeSettingsRowList(
|
|||
)
|
||||
},
|
||||
onClick = { onClickResize.invoke(1) },
|
||||
modifier = Modifier,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
item {
|
||||
HomeSettingsListItem(
|
||||
selected = false,
|
||||
headlineContent = {
|
||||
|
|
@ -115,6 +116,25 @@ fun HomeSettingsRowList(
|
|||
)
|
||||
},
|
||||
onClick = { onClickResize.invoke(-1) },
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
HomeSettingsListItem(
|
||||
selected = false,
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(R.string.save_to_server),
|
||||
)
|
||||
},
|
||||
leadingContent = {
|
||||
Text(
|
||||
text = stringResource(R.string.fa_cloud_arrow_up),
|
||||
fontFamily = FontAwesome,
|
||||
)
|
||||
},
|
||||
onClick = onClickSave,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
|
@ -123,20 +143,26 @@ fun HomeSettingsRowList(
|
|||
selected = false,
|
||||
headlineContent = {
|
||||
Text(
|
||||
text = stringResource(R.string.save),
|
||||
text = stringResource(R.string.load_from_server),
|
||||
)
|
||||
},
|
||||
leadingContent = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Create,
|
||||
contentDescription = null,
|
||||
Text(
|
||||
text = stringResource(R.string.fa_cloud_arrow_down),
|
||||
fontFamily = FontAwesome,
|
||||
)
|
||||
},
|
||||
onClick = onClickSaveLocal,
|
||||
onClick = onClickLoad,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
item {
|
||||
Text(
|
||||
text = stringResource(R.string.home_rows),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
HorizontalDivider()
|
||||
}
|
||||
itemsIndexed(state.rows, key = { _, row -> row.id }) { index, row ->
|
||||
|
|
@ -192,8 +218,7 @@ fun HomeRowConfigContent(
|
|||
Text(
|
||||
text = config.title,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier =
|
||||
Modifier,
|
||||
modifier = Modifier,
|
||||
)
|
||||
},
|
||||
onClick = onClick,
|
||||
|
|
|
|||
|
|
@ -339,6 +339,52 @@ class HomeSettingsViewModel
|
|||
}
|
||||
}
|
||||
|
||||
fun saveToRemote() {
|
||||
viewModelScope.launchIO {
|
||||
serverRepository.currentUser.value?.let { user ->
|
||||
Timber.d("Saving home settings to remote")
|
||||
val rows = state.value.rows.map { it.config }
|
||||
val settings = HomePageSettings(rows = rows)
|
||||
try {
|
||||
Timber.d("saveToRemote")
|
||||
homeSettingsService.saveToServer(user.id, settings)
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex)
|
||||
showToast(context, "Error saving: ${ex.localizedMessage}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loadFromRemote() {
|
||||
viewModelScope.launchIO {
|
||||
serverRepository.currentUser.value?.let { user ->
|
||||
Timber.d("Loading home settings from remote")
|
||||
try {
|
||||
_state.update { it.copy(loading = LoadingState.Loading) }
|
||||
val result = homeSettingsService.loadFromServer(user.id)
|
||||
if (result != null) {
|
||||
Timber.v("Got remote settings")
|
||||
val newRows =
|
||||
result.rows.mapIndexed { index, config ->
|
||||
homeSettingsService.resolve(index, config)
|
||||
}
|
||||
_state.update {
|
||||
it.copy(rows = newRows)
|
||||
}
|
||||
} else {
|
||||
Timber.v("No remote settings")
|
||||
showToast(context, "No server-side settings found")
|
||||
}
|
||||
fetchRowData()
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex)
|
||||
showToast(context, "Error: ${ex.localizedMessage}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun saveToLocal() {
|
||||
// This uses injected ioScope so that it will still run when the page is closing
|
||||
ioScope.launchIO {
|
||||
|
|
|
|||
|
|
@ -50,4 +50,6 @@
|
|||
<string name="fa_clock" translatable="false"></string>
|
||||
<string name="fa_bell" translatable="false"></string>
|
||||
<string name="fa_check" translatable="false"></string>
|
||||
<string name="fa_cloud_arrow_up" translatable="false"></string>
|
||||
<string name="fa_cloud_arrow_down" translatable="false"></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -468,6 +468,9 @@
|
|||
<string name="height">Height</string>
|
||||
<string name="apply_all_rows">Apply to all rows</string>
|
||||
<string name="customize_home">Customize home page</string>
|
||||
<string name="home_rows">Home rows</string>
|
||||
<string name="load_from_server">Load from server</string>
|
||||
<string name="save_to_server">Save to server</string>
|
||||
|
||||
<string-array name="theme_song_volume">
|
||||
<item>Disabled</item>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue