mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Add some display option presets
This commit is contained in:
parent
561b12fe87
commit
f592f3081b
6 changed files with 348 additions and 1 deletions
|
|
@ -0,0 +1,206 @@
|
|||
package com.github.damontecres.wholphin.ui.main.settings
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
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.focus.focusRestorer
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
|
||||
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.tryRequestFocus
|
||||
import org.jellyfin.sdk.model.api.CollectionType
|
||||
|
||||
data class HomeRowPresets(
|
||||
val continueWatching: HomeRowViewOptions,
|
||||
val movieLibrary: HomeRowViewOptions,
|
||||
val tvLibrary: HomeRowViewOptions,
|
||||
val videoLibrary: HomeRowViewOptions,
|
||||
val photoLibrary: HomeRowViewOptions,
|
||||
val playlist: HomeRowViewOptions,
|
||||
val genreSize: Int,
|
||||
) {
|
||||
fun getByCollectionType(collectionType: CollectionType): HomeRowViewOptions =
|
||||
when (collectionType) {
|
||||
CollectionType.MOVIES -> movieLibrary
|
||||
|
||||
CollectionType.TVSHOWS -> tvLibrary
|
||||
|
||||
CollectionType.MUSICVIDEOS -> videoLibrary
|
||||
|
||||
CollectionType.TRAILERS -> videoLibrary
|
||||
|
||||
CollectionType.HOMEVIDEOS -> videoLibrary
|
||||
|
||||
CollectionType.BOXSETS -> movieLibrary
|
||||
|
||||
CollectionType.PHOTOS -> photoLibrary
|
||||
|
||||
CollectionType.UNKNOWN,
|
||||
CollectionType.MUSIC,
|
||||
CollectionType.BOOKS,
|
||||
CollectionType.LIVETV,
|
||||
CollectionType.PLAYLISTS,
|
||||
CollectionType.FOLDERS,
|
||||
-> HomeRowViewOptions()
|
||||
}
|
||||
|
||||
companion object {
|
||||
val WholphinDefault by lazy {
|
||||
HomeRowPresets(
|
||||
continueWatching = HomeRowViewOptions(),
|
||||
movieLibrary = HomeRowViewOptions(),
|
||||
tvLibrary = HomeRowViewOptions(),
|
||||
videoLibrary =
|
||||
HomeRowViewOptions(
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
),
|
||||
photoLibrary =
|
||||
HomeRowViewOptions(
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
contentScale = PrefContentScale.CROP,
|
||||
),
|
||||
playlist =
|
||||
HomeRowViewOptions(
|
||||
aspectRatio = AspectRatio.SQUARE,
|
||||
contentScale = PrefContentScale.FIT,
|
||||
),
|
||||
genreSize = Cards.HEIGHT_2X3_DP,
|
||||
)
|
||||
}
|
||||
|
||||
val WholphinCompact by lazy {
|
||||
val height = 148
|
||||
val epHeight = 100
|
||||
HomeRowPresets(
|
||||
continueWatching =
|
||||
HomeRowViewOptions(
|
||||
heightDp = height,
|
||||
),
|
||||
movieLibrary =
|
||||
HomeRowViewOptions(
|
||||
heightDp = height,
|
||||
),
|
||||
tvLibrary =
|
||||
HomeRowViewOptions(
|
||||
heightDp = height,
|
||||
),
|
||||
videoLibrary =
|
||||
HomeRowViewOptions(
|
||||
heightDp = epHeight,
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
),
|
||||
photoLibrary =
|
||||
HomeRowViewOptions(
|
||||
heightDp = epHeight,
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
contentScale = PrefContentScale.CROP,
|
||||
),
|
||||
playlist =
|
||||
HomeRowViewOptions(
|
||||
heightDp = epHeight,
|
||||
aspectRatio = AspectRatio.SQUARE,
|
||||
contentScale = PrefContentScale.FIT,
|
||||
),
|
||||
genreSize = epHeight,
|
||||
)
|
||||
}
|
||||
|
||||
val Thumbnails by lazy {
|
||||
val height = 148
|
||||
val epHeight = 100
|
||||
HomeRowPresets(
|
||||
continueWatching =
|
||||
HomeRowViewOptions(
|
||||
heightDp = epHeight,
|
||||
imageType = ViewOptionImageType.THUMB,
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
episodeImageType = ViewOptionImageType.THUMB,
|
||||
episodeAspectRatio = AspectRatio.WIDE,
|
||||
),
|
||||
movieLibrary =
|
||||
HomeRowViewOptions(
|
||||
heightDp = height,
|
||||
),
|
||||
tvLibrary =
|
||||
HomeRowViewOptions(
|
||||
heightDp = height,
|
||||
),
|
||||
videoLibrary =
|
||||
HomeRowViewOptions(
|
||||
heightDp = epHeight,
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
),
|
||||
photoLibrary =
|
||||
HomeRowViewOptions(
|
||||
heightDp = epHeight,
|
||||
aspectRatio = AspectRatio.WIDE,
|
||||
contentScale = PrefContentScale.CROP,
|
||||
),
|
||||
playlist =
|
||||
HomeRowViewOptions(
|
||||
heightDp = epHeight,
|
||||
aspectRatio = AspectRatio.SQUARE,
|
||||
contentScale = PrefContentScale.FIT,
|
||||
),
|
||||
genreSize = epHeight,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HomeRowPresetsContent(
|
||||
onApply: (HomeRowPresets) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val presets =
|
||||
remember {
|
||||
listOf(
|
||||
"Wholphin Default",
|
||||
"Wholphin Compact",
|
||||
"Thumbnails",
|
||||
)
|
||||
}
|
||||
val focusRequesters = remember { List(presets.size) { FocusRequester() } }
|
||||
LaunchedEffect(Unit) { focusRequesters[0].tryRequestFocus() }
|
||||
Column(modifier = modifier) {
|
||||
TitleText(stringResource(R.string.display_presets))
|
||||
LazyColumn(
|
||||
contentPadding = PaddingValues(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier =
|
||||
modifier
|
||||
.fillMaxHeight()
|
||||
.focusRestorer(focusRequesters[0]),
|
||||
) {
|
||||
itemsIndexed(presets) { index, title ->
|
||||
HomeSettingsListItem(
|
||||
selected = false,
|
||||
headlineText = title,
|
||||
onClick = {
|
||||
when (index) {
|
||||
0 -> onApply.invoke(HomeRowPresets.WholphinDefault)
|
||||
1 -> onApply.invoke(HomeRowPresets.WholphinCompact)
|
||||
2 -> onApply.invoke(HomeRowPresets.Thumbnails)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.focusRequester(focusRequesters[index]),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,4 +32,7 @@ sealed interface HomeSettingsDestination : NavKey {
|
|||
|
||||
@Serializable
|
||||
data object GlobalSettings : HomeSettingsDestination
|
||||
|
||||
@Serializable
|
||||
data object Presets : HomeSettingsDestination
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ fun HomeSettingsPage(
|
|||
state = state,
|
||||
onClickAdd = { backStack.add(HomeSettingsDestination.AddRow) },
|
||||
onClickSettings = { backStack.add(HomeSettingsDestination.GlobalSettings) },
|
||||
onClickPresets = { backStack.add(HomeSettingsDestination.Presets) },
|
||||
onClickMove = viewModel::moveRow,
|
||||
onClickDelete = viewModel::deleteRow,
|
||||
onClick = { index, row ->
|
||||
|
|
@ -241,6 +242,13 @@ fun HomeSettingsPage(
|
|||
modifier = destModifier,
|
||||
)
|
||||
}
|
||||
|
||||
HomeSettingsDestination.Presets -> {
|
||||
HomeRowPresetsContent(
|
||||
onApply = viewModel::applyPreset,
|
||||
modifier = destModifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ fun HomeSettingsRowList(
|
|||
onClick: (Int, HomeRowConfigDisplay) -> Unit,
|
||||
onClickAdd: () -> Unit,
|
||||
onClickSettings: () -> Unit,
|
||||
onClickPresets: () -> Unit,
|
||||
onClickMove: (MoveDirection, Int) -> Unit,
|
||||
onClickDelete: (Int) -> Unit,
|
||||
modifier: Modifier,
|
||||
|
|
@ -64,7 +65,7 @@ fun HomeSettingsRowList(
|
|||
val scope = rememberCoroutineScope()
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
val itemsBeforeRows = 3
|
||||
val itemsBeforeRows = 4
|
||||
val focusRequesters =
|
||||
remember(state.rows.size) { List(itemsBeforeRows + state.rows.size) { FocusRequester() } }
|
||||
|
||||
|
|
@ -117,6 +118,28 @@ fun HomeSettingsRowList(
|
|||
modifier = Modifier.focusRequester(focusRequesters[1]),
|
||||
)
|
||||
}
|
||||
item {
|
||||
HomeSettingsListItem(
|
||||
selected = false,
|
||||
headlineText = stringResource(R.string.display_presets),
|
||||
supportingContent = {
|
||||
Text(
|
||||
text = stringResource(R.string.display_presets_description),
|
||||
)
|
||||
},
|
||||
leadingContent = {
|
||||
Text(
|
||||
text = stringResource(R.string.fa_sliders),
|
||||
fontFamily = FontAwesome,
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
position = 2
|
||||
onClickPresets.invoke()
|
||||
},
|
||||
modifier = Modifier.focusRequester(focusRequesters[1]),
|
||||
)
|
||||
}
|
||||
item {
|
||||
TitleText(stringResource(R.string.home_rows))
|
||||
HorizontalDivider()
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ import kotlinx.coroutines.flow.update
|
|||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.jellyfin.sdk.api.client.ApiClient
|
||||
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.api.CollectionType
|
||||
import org.jellyfin.sdk.model.serializer.UUIDSerializer
|
||||
|
|
@ -62,6 +64,7 @@ class HomeSettingsViewModel
|
|||
@Inject
|
||||
constructor(
|
||||
@param:ApplicationContext private val context: Context,
|
||||
private val api: ApiClient,
|
||||
private val homeSettingsService: HomeSettingsService,
|
||||
private val serverRepository: ServerRepository,
|
||||
private val userPreferencesService: UserPreferencesService,
|
||||
|
|
@ -534,6 +537,108 @@ class HomeSettingsViewModel
|
|||
context.getString(R.string.settings_saved),
|
||||
Toast.LENGTH_SHORT,
|
||||
)
|
||||
|
||||
fun applyPreset(preset: HomeRowPresets) {
|
||||
_state.update { it.copy(loading = LoadingState.Loading) }
|
||||
viewModelScope.launchIO {
|
||||
val state = state.value
|
||||
|
||||
val typeCache = mutableMapOf<UUID, CollectionType?>()
|
||||
|
||||
suspend fun getCollectionType(itemId: UUID): CollectionType =
|
||||
typeCache.getOrPut(itemId) {
|
||||
state.libraries
|
||||
.firstOrNull { it.itemId == itemId }
|
||||
?.collectionType
|
||||
?: api.userLibraryApi
|
||||
.getItem(itemId)
|
||||
.content.collectionType ?: CollectionType.UNKNOWN
|
||||
} ?: CollectionType.UNKNOWN
|
||||
|
||||
val newRows =
|
||||
state.rows.map {
|
||||
val newConfig =
|
||||
when (it.config) {
|
||||
is ContinueWatching,
|
||||
is NextUp,
|
||||
is ContinueWatchingCombined,
|
||||
-> {
|
||||
it.config.updateViewOptions(preset.continueWatching)
|
||||
}
|
||||
|
||||
is HomeRowConfig.ByParent -> {
|
||||
val collectionType = getCollectionType(it.config.parentId)
|
||||
val viewOptions = preset.getByCollectionType(collectionType)
|
||||
it.config.updateViewOptions(viewOptions)
|
||||
}
|
||||
|
||||
is HomeRowConfig.Favorite -> {
|
||||
val viewOptions =
|
||||
when (it.config.kind) {
|
||||
BaseItemKind.MOVIE -> preset.movieLibrary
|
||||
BaseItemKind.SERIES -> preset.tvLibrary
|
||||
BaseItemKind.EPISODE -> preset.continueWatching
|
||||
BaseItemKind.VIDEO -> preset.videoLibrary
|
||||
BaseItemKind.PLAYLIST -> preset.playlist
|
||||
BaseItemKind.PERSON -> preset.movieLibrary
|
||||
else -> preset.movieLibrary
|
||||
}
|
||||
it.config.updateViewOptions(viewOptions)
|
||||
}
|
||||
|
||||
is Genres -> {
|
||||
it.config.updateViewOptions(it.config.viewOptions.copy(heightDp = preset.genreSize))
|
||||
}
|
||||
|
||||
is HomeRowConfig.GetItems -> {
|
||||
it.config
|
||||
}
|
||||
|
||||
is RecentlyAdded -> {
|
||||
val collectionType = getCollectionType(it.config.parentId)
|
||||
val viewOptions = preset.getByCollectionType(collectionType)
|
||||
it.config.updateViewOptions(viewOptions)
|
||||
}
|
||||
|
||||
is RecentlyReleased -> {
|
||||
val collectionType = getCollectionType(it.config.parentId)
|
||||
val viewOptions = preset.getByCollectionType(collectionType)
|
||||
it.config.updateViewOptions(viewOptions)
|
||||
}
|
||||
|
||||
is HomeRowConfig.Recordings -> {
|
||||
it.config.updateViewOptions(preset.tvLibrary)
|
||||
}
|
||||
|
||||
is Suggestions -> {
|
||||
val collectionType = getCollectionType(it.config.parentId)
|
||||
val viewOptions = preset.getByCollectionType(collectionType)
|
||||
it.config.updateViewOptions(viewOptions)
|
||||
}
|
||||
|
||||
is HomeRowConfig.TvPrograms -> {
|
||||
it.config.updateViewOptions(preset.tvLibrary)
|
||||
}
|
||||
}
|
||||
it.copy(config = newConfig)
|
||||
}
|
||||
|
||||
_state.update {
|
||||
it.copy(
|
||||
loading = LoadingState.Success,
|
||||
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(
|
||||
|
|
|
|||
|
|
@ -513,6 +513,8 @@
|
|||
<string name="decrease_all_cards_size">Decrease size for all cards</string>
|
||||
<string name="use_thumb_images">Use thumb images</string>
|
||||
<string name="settings_saved">Settings saved</string>
|
||||
<string name="display_presets">Display presets</string>
|
||||
<string name="display_presets_description">Built-in presets to quickly style all rows</string>
|
||||
|
||||
<string-array name="theme_song_volume">
|
||||
<item>Disabled</item>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue