mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 08:01:20 +02:00
UI controls
This commit is contained in:
parent
15ce562957
commit
efb87bd692
7 changed files with 186 additions and 126 deletions
|
|
@ -265,7 +265,9 @@ class MainActivity : AppCompatActivity() {
|
||||||
server = current.server,
|
server = current.server,
|
||||||
startDestination =
|
startDestination =
|
||||||
requestedDestination
|
requestedDestination
|
||||||
?: Destination.Home(),
|
// TODO undo after testing
|
||||||
|
// ?: Destination.Home(),
|
||||||
|
?: Destination.HomeSettings,
|
||||||
navigationManager = navigationManager,
|
navigationManager = navigationManager,
|
||||||
preferences = preferences,
|
preferences = preferences,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,10 @@
|
||||||
|
|
||||||
package com.github.damontecres.wholphin.data.model
|
package com.github.damontecres.wholphin.data.model
|
||||||
|
|
||||||
import com.github.damontecres.wholphin.R
|
|
||||||
import com.github.damontecres.wholphin.preferences.AppChoicePreference
|
|
||||||
import com.github.damontecres.wholphin.preferences.AppClickablePreference
|
|
||||||
import com.github.damontecres.wholphin.preferences.AppSliderPreference
|
|
||||||
import com.github.damontecres.wholphin.preferences.AppSwitchPreference
|
|
||||||
import com.github.damontecres.wholphin.preferences.PrefContentScale
|
import com.github.damontecres.wholphin.preferences.PrefContentScale
|
||||||
import com.github.damontecres.wholphin.ui.AspectRatio
|
import com.github.damontecres.wholphin.ui.AspectRatio
|
||||||
import com.github.damontecres.wholphin.ui.Cards
|
import com.github.damontecres.wholphin.ui.Cards
|
||||||
import com.github.damontecres.wholphin.ui.components.ViewOptionImageType
|
import com.github.damontecres.wholphin.ui.components.ViewOptionImageType
|
||||||
import com.github.damontecres.wholphin.ui.components.ViewOptions
|
|
||||||
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
@ -160,109 +154,6 @@ data class HomeRowViewOptions(
|
||||||
val contentScale: PrefContentScale = PrefContentScale.FIT,
|
val contentScale: PrefContentScale = PrefContentScale.FIT,
|
||||||
val aspectRatio: AspectRatio = AspectRatio.TALL,
|
val aspectRatio: AspectRatio = AspectRatio.TALL,
|
||||||
val imageType: ViewOptionImageType = ViewOptionImageType.PRIMARY,
|
val imageType: ViewOptionImageType = ViewOptionImageType.PRIMARY,
|
||||||
val showTitles: Boolean = true,
|
val showTitles: Boolean = false,
|
||||||
val useSeries: Boolean = true,
|
val useSeries: Boolean = true,
|
||||||
) {
|
)
|
||||||
companion object {
|
|
||||||
val ViewOptionsColumns =
|
|
||||||
AppSliderPreference<HomeRowViewOptions>(
|
|
||||||
title = R.string.height,
|
|
||||||
defaultValue = Cards.HEIGHT_2X3_DP.toLong(),
|
|
||||||
min = 64L,
|
|
||||||
max = Cards.HEIGHT_2X3_DP + 64L,
|
|
||||||
interval = 4,
|
|
||||||
getter = { it.heightDp.toLong() },
|
|
||||||
setter = { prefs, value -> prefs.copy(heightDp = value.toInt()) },
|
|
||||||
)
|
|
||||||
val ViewOptionsSpacing =
|
|
||||||
AppSliderPreference<HomeRowViewOptions>(
|
|
||||||
title = R.string.spacing,
|
|
||||||
defaultValue = 16,
|
|
||||||
min = 0,
|
|
||||||
max = 32,
|
|
||||||
interval = 2,
|
|
||||||
getter = { it.spacing.toLong() },
|
|
||||||
setter = { prefs, value -> prefs.copy(spacing = value.toInt()) },
|
|
||||||
)
|
|
||||||
|
|
||||||
val ViewOptionsContentScale =
|
|
||||||
AppChoicePreference<HomeRowViewOptions, PrefContentScale>(
|
|
||||||
title = R.string.global_content_scale,
|
|
||||||
defaultValue = PrefContentScale.FIT,
|
|
||||||
displayValues = R.array.content_scale,
|
|
||||||
getter = { it.contentScale },
|
|
||||||
setter = { viewOptions, value -> viewOptions.copy(contentScale = value) },
|
|
||||||
indexToValue = { PrefContentScale.forNumber(it) },
|
|
||||||
valueToIndex = { it.number },
|
|
||||||
)
|
|
||||||
|
|
||||||
val ViewOptionsAspectRatio =
|
|
||||||
AppChoicePreference<HomeRowViewOptions, AspectRatio>(
|
|
||||||
title = R.string.aspect_ratio,
|
|
||||||
defaultValue = AspectRatio.TALL,
|
|
||||||
displayValues = R.array.aspect_ratios,
|
|
||||||
getter = { it.aspectRatio },
|
|
||||||
setter = { viewOptions, value -> viewOptions.copy(aspectRatio = value) },
|
|
||||||
indexToValue = { AspectRatio.entries[it] },
|
|
||||||
valueToIndex = { it.ordinal },
|
|
||||||
)
|
|
||||||
|
|
||||||
val ViewOptionsShowTitles =
|
|
||||||
AppSwitchPreference<HomeRowViewOptions>(
|
|
||||||
title = R.string.show_titles,
|
|
||||||
defaultValue = true,
|
|
||||||
getter = { it.showTitles },
|
|
||||||
setter = { vo, value -> vo.copy(showTitles = value) },
|
|
||||||
)
|
|
||||||
|
|
||||||
val ViewOptionsUseSeries =
|
|
||||||
AppSwitchPreference<HomeRowViewOptions>(
|
|
||||||
title = R.string.go_to_series, // TODO
|
|
||||||
defaultValue = true,
|
|
||||||
getter = { it.useSeries },
|
|
||||||
setter = { vo, value -> vo.copy(useSeries = value) },
|
|
||||||
)
|
|
||||||
|
|
||||||
val ViewOptionsImageType =
|
|
||||||
AppChoicePreference<HomeRowViewOptions, ViewOptionImageType>(
|
|
||||||
title = R.string.image_type,
|
|
||||||
defaultValue = ViewOptionImageType.PRIMARY,
|
|
||||||
displayValues = R.array.image_types,
|
|
||||||
getter = { it.imageType },
|
|
||||||
setter = { viewOptions, value ->
|
|
||||||
val aspectRatio =
|
|
||||||
when (value) {
|
|
||||||
ViewOptionImageType.PRIMARY -> AspectRatio.TALL
|
|
||||||
ViewOptionImageType.THUMB -> AspectRatio.WIDE
|
|
||||||
}
|
|
||||||
viewOptions.copy(imageType = value, aspectRatio = aspectRatio)
|
|
||||||
},
|
|
||||||
indexToValue = { ViewOptionImageType.entries[it] },
|
|
||||||
valueToIndex = { it.ordinal },
|
|
||||||
)
|
|
||||||
|
|
||||||
val ViewOptionsApplyAll =
|
|
||||||
AppClickablePreference<ViewOptions>(
|
|
||||||
title = R.string.apply_all_rows,
|
|
||||||
)
|
|
||||||
|
|
||||||
val ViewOptionsReset =
|
|
||||||
AppClickablePreference<ViewOptions>(
|
|
||||||
title = R.string.reset,
|
|
||||||
)
|
|
||||||
|
|
||||||
val OPTIONS =
|
|
||||||
listOf(
|
|
||||||
ViewOptionsImageType,
|
|
||||||
ViewOptionsAspectRatio,
|
|
||||||
// TODO
|
|
||||||
// ViewOptionsShowTitles,
|
|
||||||
// ViewOptionsUseSeries,
|
|
||||||
ViewOptionsColumns,
|
|
||||||
ViewOptionsSpacing,
|
|
||||||
ViewOptionsContentScale,
|
|
||||||
ViewOptionsApplyAll,
|
|
||||||
ViewOptionsReset,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -550,22 +550,13 @@ class HomeSettingsService
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val name =
|
|
||||||
if (row.name == null && request.parentId != null) {
|
|
||||||
// If a name was not provided, use the parent's name if available
|
|
||||||
api.userLibraryApi
|
|
||||||
.getItem(itemId = request.parentId!!)
|
|
||||||
.content.name
|
|
||||||
} else {
|
|
||||||
row.name
|
|
||||||
}
|
|
||||||
GetItemsRequestHandler
|
GetItemsRequestHandler
|
||||||
.execute(api, request)
|
.execute(api, request)
|
||||||
.content.items
|
.content.items
|
||||||
.map { BaseItem.Companion.from(it, api, true) }
|
.map { BaseItem(it, true) }
|
||||||
.let {
|
.let {
|
||||||
HomeRowLoadingState.Success(
|
HomeRowLoadingState.Success(
|
||||||
name ?: context.getString(R.string.collection),
|
row.name,
|
||||||
it,
|
it,
|
||||||
row.viewOptions,
|
row.viewOptions,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,18 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.tv.material3.MaterialTheme
|
import androidx.tv.material3.MaterialTheme
|
||||||
import androidx.tv.material3.Text
|
import androidx.tv.material3.Text
|
||||||
import androidx.tv.material3.surfaceColorAtElevation
|
import androidx.tv.material3.surfaceColorAtElevation
|
||||||
|
import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
||||||
|
import com.github.damontecres.wholphin.preferences.AppChoicePreference
|
||||||
|
import com.github.damontecres.wholphin.preferences.AppClickablePreference
|
||||||
import com.github.damontecres.wholphin.preferences.AppPreference
|
import com.github.damontecres.wholphin.preferences.AppPreference
|
||||||
|
import com.github.damontecres.wholphin.preferences.AppSliderPreference
|
||||||
|
import com.github.damontecres.wholphin.preferences.AppSwitchPreference
|
||||||
|
import com.github.damontecres.wholphin.preferences.PrefContentScale
|
||||||
|
import com.github.damontecres.wholphin.ui.AspectRatio
|
||||||
|
import com.github.damontecres.wholphin.ui.Cards
|
||||||
|
import com.github.damontecres.wholphin.ui.components.ViewOptionImageType
|
||||||
|
import com.github.damontecres.wholphin.ui.components.ViewOptions
|
||||||
import com.github.damontecres.wholphin.ui.ifElse
|
import com.github.damontecres.wholphin.ui.ifElse
|
||||||
import com.github.damontecres.wholphin.ui.preferences.ComposablePreference
|
import com.github.damontecres.wholphin.ui.preferences.ComposablePreference
|
||||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||||
|
|
@ -39,7 +49,7 @@ fun HomeRowSettings(
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
)
|
)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
itemsIndexed(HomeRowViewOptions.OPTIONS) { index, pref ->
|
itemsIndexed(Options.OPTIONS) { index, pref ->
|
||||||
pref as AppPreference<HomeRowViewOptions, Any>
|
pref as AppPreference<HomeRowViewOptions, Any>
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
val value = pref.getter.invoke(viewOptions)
|
val value = pref.getter.invoke(viewOptions)
|
||||||
|
|
@ -52,9 +62,9 @@ fun HomeRowSettings(
|
||||||
},
|
},
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
onClickPreference = { pref ->
|
onClickPreference = { pref ->
|
||||||
if (pref == HomeRowViewOptions.ViewOptionsReset) {
|
if (pref == Options.ViewOptionsReset) {
|
||||||
onViewOptionsChange.invoke(defaultViewOptions)
|
onViewOptionsChange.invoke(defaultViewOptions)
|
||||||
} else if (pref == HomeRowViewOptions.ViewOptionsApplyAll) {
|
} else if (pref == Options.ViewOptionsApplyAll) {
|
||||||
onApplyApplyAll.invoke()
|
onApplyApplyAll.invoke()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -70,3 +80,106 @@ fun HomeRowSettings(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal object Options {
|
||||||
|
val ViewOptionsColumns =
|
||||||
|
AppSliderPreference<HomeRowViewOptions>(
|
||||||
|
title = R.string.height,
|
||||||
|
defaultValue = Cards.HEIGHT_2X3_DP.toLong(),
|
||||||
|
min = 64L,
|
||||||
|
max = Cards.HEIGHT_2X3_DP + 64L,
|
||||||
|
interval = 4,
|
||||||
|
getter = { it.heightDp.toLong() },
|
||||||
|
setter = { prefs, value -> prefs.copy(heightDp = value.toInt()) },
|
||||||
|
)
|
||||||
|
val ViewOptionsSpacing =
|
||||||
|
AppSliderPreference<HomeRowViewOptions>(
|
||||||
|
title = R.string.spacing,
|
||||||
|
defaultValue = 16,
|
||||||
|
min = 0,
|
||||||
|
max = 32,
|
||||||
|
interval = 2,
|
||||||
|
getter = { it.spacing.toLong() },
|
||||||
|
setter = { prefs, value -> prefs.copy(spacing = value.toInt()) },
|
||||||
|
)
|
||||||
|
|
||||||
|
val ViewOptionsContentScale =
|
||||||
|
AppChoicePreference<HomeRowViewOptions, PrefContentScale>(
|
||||||
|
title = R.string.global_content_scale,
|
||||||
|
defaultValue = PrefContentScale.FIT,
|
||||||
|
displayValues = R.array.content_scale,
|
||||||
|
getter = { it.contentScale },
|
||||||
|
setter = { viewOptions, value -> viewOptions.copy(contentScale = value) },
|
||||||
|
indexToValue = { PrefContentScale.forNumber(it) },
|
||||||
|
valueToIndex = { it.number },
|
||||||
|
)
|
||||||
|
|
||||||
|
val ViewOptionsAspectRatio =
|
||||||
|
AppChoicePreference<HomeRowViewOptions, AspectRatio>(
|
||||||
|
title = R.string.aspect_ratio,
|
||||||
|
defaultValue = AspectRatio.TALL,
|
||||||
|
displayValues = R.array.aspect_ratios,
|
||||||
|
getter = { it.aspectRatio },
|
||||||
|
setter = { viewOptions, value -> viewOptions.copy(aspectRatio = value) },
|
||||||
|
indexToValue = { AspectRatio.entries[it] },
|
||||||
|
valueToIndex = { it.ordinal },
|
||||||
|
)
|
||||||
|
|
||||||
|
val ViewOptionsShowTitles =
|
||||||
|
AppSwitchPreference<HomeRowViewOptions>(
|
||||||
|
title = R.string.show_titles,
|
||||||
|
defaultValue = true,
|
||||||
|
getter = { it.showTitles },
|
||||||
|
setter = { vo, value -> vo.copy(showTitles = value) },
|
||||||
|
)
|
||||||
|
|
||||||
|
val ViewOptionsUseSeries =
|
||||||
|
AppSwitchPreference<HomeRowViewOptions>(
|
||||||
|
title = R.string.go_to_series, // TODO
|
||||||
|
defaultValue = true,
|
||||||
|
getter = { it.useSeries },
|
||||||
|
setter = { vo, value -> vo.copy(useSeries = value) },
|
||||||
|
)
|
||||||
|
|
||||||
|
val ViewOptionsImageType =
|
||||||
|
AppChoicePreference<HomeRowViewOptions, ViewOptionImageType>(
|
||||||
|
title = R.string.image_type,
|
||||||
|
defaultValue = ViewOptionImageType.PRIMARY,
|
||||||
|
displayValues = R.array.image_types,
|
||||||
|
getter = { it.imageType },
|
||||||
|
setter = { viewOptions, value ->
|
||||||
|
val aspectRatio =
|
||||||
|
when (value) {
|
||||||
|
ViewOptionImageType.PRIMARY -> AspectRatio.TALL
|
||||||
|
ViewOptionImageType.THUMB -> AspectRatio.WIDE
|
||||||
|
}
|
||||||
|
viewOptions.copy(imageType = value, aspectRatio = aspectRatio)
|
||||||
|
},
|
||||||
|
indexToValue = { ViewOptionImageType.entries[it] },
|
||||||
|
valueToIndex = { it.ordinal },
|
||||||
|
)
|
||||||
|
|
||||||
|
val ViewOptionsApplyAll =
|
||||||
|
AppClickablePreference<ViewOptions>(
|
||||||
|
title = R.string.apply_all_rows,
|
||||||
|
)
|
||||||
|
|
||||||
|
val ViewOptionsReset =
|
||||||
|
AppClickablePreference<ViewOptions>(
|
||||||
|
title = R.string.reset,
|
||||||
|
)
|
||||||
|
|
||||||
|
val OPTIONS =
|
||||||
|
listOf(
|
||||||
|
ViewOptionsImageType,
|
||||||
|
ViewOptionsAspectRatio,
|
||||||
|
// TODO
|
||||||
|
// ViewOptionsShowTitles,
|
||||||
|
// ViewOptionsUseSeries,
|
||||||
|
ViewOptionsColumns,
|
||||||
|
ViewOptionsSpacing,
|
||||||
|
ViewOptionsContentScale,
|
||||||
|
ViewOptionsApplyAll,
|
||||||
|
ViewOptionsReset,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,9 @@ fun HomeSettingsPage(
|
||||||
listState.scrollToItem(index)
|
listState.scrollToItem(index)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onClickResize = {
|
||||||
|
viewModel.resizeCards(it)
|
||||||
|
},
|
||||||
modifier = destModifier,
|
modifier = destModifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.Create
|
import androidx.compose.material.icons.filled.Create
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
import androidx.compose.material.icons.filled.Edit
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
|
@ -48,6 +49,7 @@ enum class MoveDirection {
|
||||||
fun HomeSettingsRowList(
|
fun HomeSettingsRowList(
|
||||||
state: HomePageSettingsState,
|
state: HomePageSettingsState,
|
||||||
onClick: (Int, HomeRowConfigDisplay) -> Unit,
|
onClick: (Int, HomeRowConfigDisplay) -> Unit,
|
||||||
|
onClickResize: (Int) -> Unit,
|
||||||
onClickSaveLocal: () -> Unit,
|
onClickSaveLocal: () -> Unit,
|
||||||
onClickAdd: () -> Unit,
|
onClickAdd: () -> Unit,
|
||||||
onClickMove: (MoveDirection, Int) -> Unit,
|
onClickMove: (MoveDirection, Int) -> Unit,
|
||||||
|
|
@ -82,6 +84,42 @@ fun HomeSettingsRowList(
|
||||||
modifier = Modifier.focusRequester(firstFocus),
|
modifier = Modifier.focusRequester(firstFocus),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
item {
|
||||||
|
ListItem(
|
||||||
|
selected = false,
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = "Increase card sizes",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Edit,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick = { onClickResize.invoke(1) },
|
||||||
|
modifier = Modifier,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
ListItem(
|
||||||
|
selected = false,
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = "Decrease card sizes",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Edit,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClick = { onClickResize.invoke(-1) },
|
||||||
|
modifier = Modifier,
|
||||||
|
)
|
||||||
|
}
|
||||||
item {
|
item {
|
||||||
ListItem(
|
ListItem(
|
||||||
selected = false,
|
selected = false,
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,28 @@ class HomeSettingsViewModel
|
||||||
}
|
}
|
||||||
homeSettingsService.currentSettings.update { HomePageResolvedSettings(state.value.rows) }
|
homeSettingsService.currentSettings.update { HomePageResolvedSettings(state.value.rows) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun resizeCards(relative: Int) {
|
||||||
|
updateState {
|
||||||
|
val newRows =
|
||||||
|
it.rows.toMutableList().map { row ->
|
||||||
|
val vo = row.config.viewOptions
|
||||||
|
val newVo = vo.copy(heightDp = vo.heightDp + (4 * relative))
|
||||||
|
row.copy(config = row.config.updateViewOptions(newVo))
|
||||||
|
}
|
||||||
|
it.copy(
|
||||||
|
rows = newRows,
|
||||||
|
rowData =
|
||||||
|
it.rowData.toMutableList().mapIndexed { index, row ->
|
||||||
|
if (row is HomeRowLoadingState.Success) {
|
||||||
|
row.copy(viewOptions = newRows[index].config.viewOptions)
|
||||||
|
} else {
|
||||||
|
row
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class HomePageSettingsState(
|
data class HomePageSettingsState(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue