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 b6a784b0..6bf03b7e 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
@@ -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 =
diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsListItem.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsListItem.kt
new file mode 100644
index 00000000..c9ea14d6
--- /dev/null
+++ b/app/src/main/java/com/github/damontecres/wholphin/ui/main/settings/HomeSettingsListItem.kt
@@ -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,
+)
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 82ae6f9a..1076d727 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
@@ -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
+ },
+ )
+ }
}
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 41188e63..9d0cd9f1 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
@@ -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,
@@ -82,21 +84,57 @@ fun HomeSettingsRowList(
modifier = Modifier.focusRequester(firstFocus),
)
}
+ item {
+ Row {
+ HomeSettingsListItem(
+ selected = false,
+ headlineContent = {
+ Text(
+ text = "Increase card sizes",
+ )
+ },
+ leadingContent = {
+ Icon(
+ imageVector = Icons.Default.Edit,
+ contentDescription = null,
+ )
+ },
+ onClick = { onClickResize.invoke(1) },
+ modifier = Modifier.weight(1f),
+ )
+ HomeSettingsListItem(
+ selected = false,
+ headlineContent = {
+ Text(
+ text = "Decrease card sizes",
+ )
+ },
+ leadingContent = {
+ Icon(
+ imageVector = Icons.Default.Edit,
+ contentDescription = null,
+ )
+ },
+ onClick = { onClickResize.invoke(-1) },
+ modifier = Modifier.weight(1f),
+ )
+ }
+ }
item {
HomeSettingsListItem(
selected = false,
headlineContent = {
Text(
- text = "Increase card sizes",
+ text = stringResource(R.string.save_to_server),
)
},
leadingContent = {
- Icon(
- imageVector = Icons.Default.Edit,
- contentDescription = null,
+ Text(
+ text = stringResource(R.string.fa_cloud_arrow_up),
+ fontFamily = FontAwesome,
)
},
- onClick = { onClickResize.invoke(1) },
+ onClick = onClickSave,
modifier = Modifier,
)
}
@@ -105,38 +143,26 @@ fun HomeSettingsRowList(
selected = false,
headlineContent = {
Text(
- text = "Decrease card sizes",
+ text = stringResource(R.string.load_from_server),
)
},
leadingContent = {
- Icon(
- imageVector = Icons.Default.Edit,
- contentDescription = null,
- )
- },
- onClick = { onClickResize.invoke(-1) },
- modifier = Modifier,
- )
- }
- item {
- HomeSettingsListItem(
- selected = false,
- headlineContent = {
Text(
- text = stringResource(R.string.save),
+ text = stringResource(R.string.fa_cloud_arrow_down),
+ fontFamily = FontAwesome,
)
},
- leadingContent = {
- Icon(
- imageVector = Icons.Default.Create,
- contentDescription = null,
- )
- },
- 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,
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 ceba6b30..11962c18 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
@@ -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 {
diff --git a/app/src/main/res/values/fa_strings.xml b/app/src/main/res/values/fa_strings.xml
index ae2a4ae1..adf2c254 100644
--- a/app/src/main/res/values/fa_strings.xml
+++ b/app/src/main/res/values/fa_strings.xml
@@ -50,4 +50,6 @@
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 150d1213..b3050ad8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -468,6 +468,9 @@
Height
Apply to all rows
Customize home page
+ Home rows
+ Load from server
+ Save to server
- Disabled