mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 08:01:20 +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
|
@Serializable
|
||||||
data object GlobalSettings : HomeSettingsDestination
|
data object GlobalSettings : HomeSettingsDestination
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data object Presets : HomeSettingsDestination
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ fun HomeSettingsPage(
|
||||||
state = state,
|
state = state,
|
||||||
onClickAdd = { backStack.add(HomeSettingsDestination.AddRow) },
|
onClickAdd = { backStack.add(HomeSettingsDestination.AddRow) },
|
||||||
onClickSettings = { backStack.add(HomeSettingsDestination.GlobalSettings) },
|
onClickSettings = { backStack.add(HomeSettingsDestination.GlobalSettings) },
|
||||||
|
onClickPresets = { backStack.add(HomeSettingsDestination.Presets) },
|
||||||
onClickMove = viewModel::moveRow,
|
onClickMove = viewModel::moveRow,
|
||||||
onClickDelete = viewModel::deleteRow,
|
onClickDelete = viewModel::deleteRow,
|
||||||
onClick = { index, row ->
|
onClick = { index, row ->
|
||||||
|
|
@ -241,6 +242,13 @@ fun HomeSettingsPage(
|
||||||
modifier = destModifier,
|
modifier = destModifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HomeSettingsDestination.Presets -> {
|
||||||
|
HomeRowPresetsContent(
|
||||||
|
onApply = viewModel::applyPreset,
|
||||||
|
modifier = destModifier,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ fun HomeSettingsRowList(
|
||||||
onClick: (Int, HomeRowConfigDisplay) -> Unit,
|
onClick: (Int, HomeRowConfigDisplay) -> Unit,
|
||||||
onClickAdd: () -> Unit,
|
onClickAdd: () -> Unit,
|
||||||
onClickSettings: () -> Unit,
|
onClickSettings: () -> Unit,
|
||||||
|
onClickPresets: () -> Unit,
|
||||||
onClickMove: (MoveDirection, Int) -> Unit,
|
onClickMove: (MoveDirection, Int) -> Unit,
|
||||||
onClickDelete: (Int) -> Unit,
|
onClickDelete: (Int) -> Unit,
|
||||||
modifier: Modifier,
|
modifier: Modifier,
|
||||||
|
|
@ -64,7 +65,7 @@ fun HomeSettingsRowList(
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
val itemsBeforeRows = 3
|
val itemsBeforeRows = 4
|
||||||
val focusRequesters =
|
val focusRequesters =
|
||||||
remember(state.rows.size) { List(itemsBeforeRows + state.rows.size) { FocusRequester() } }
|
remember(state.rows.size) { List(itemsBeforeRows + state.rows.size) { FocusRequester() } }
|
||||||
|
|
||||||
|
|
@ -117,6 +118,28 @@ fun HomeSettingsRowList(
|
||||||
modifier = Modifier.focusRequester(focusRequesters[1]),
|
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 {
|
item {
|
||||||
TitleText(stringResource(R.string.home_rows))
|
TitleText(stringResource(R.string.home_rows))
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.sync.Semaphore
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
import kotlinx.coroutines.sync.withPermit
|
import kotlinx.coroutines.sync.withPermit
|
||||||
import kotlinx.serialization.Serializable
|
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.BaseItemKind
|
||||||
import org.jellyfin.sdk.model.api.CollectionType
|
import org.jellyfin.sdk.model.api.CollectionType
|
||||||
import org.jellyfin.sdk.model.serializer.UUIDSerializer
|
import org.jellyfin.sdk.model.serializer.UUIDSerializer
|
||||||
|
|
@ -62,6 +64,7 @@ class HomeSettingsViewModel
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
@param:ApplicationContext private val context: Context,
|
@param:ApplicationContext private val context: Context,
|
||||||
|
private val api: ApiClient,
|
||||||
private val homeSettingsService: HomeSettingsService,
|
private val homeSettingsService: HomeSettingsService,
|
||||||
private val serverRepository: ServerRepository,
|
private val serverRepository: ServerRepository,
|
||||||
private val userPreferencesService: UserPreferencesService,
|
private val userPreferencesService: UserPreferencesService,
|
||||||
|
|
@ -534,6 +537,108 @@ class HomeSettingsViewModel
|
||||||
context.getString(R.string.settings_saved),
|
context.getString(R.string.settings_saved),
|
||||||
Toast.LENGTH_SHORT,
|
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(
|
data class HomePageSettingsState(
|
||||||
|
|
|
||||||
|
|
@ -513,6 +513,8 @@
|
||||||
<string name="decrease_all_cards_size">Decrease size for all cards</string>
|
<string name="decrease_all_cards_size">Decrease size for all cards</string>
|
||||||
<string name="use_thumb_images">Use thumb images</string>
|
<string name="use_thumb_images">Use thumb images</string>
|
||||||
<string name="settings_saved">Settings saved</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">
|
<string-array name="theme_song_volume">
|
||||||
<item>Disabled</item>
|
<item>Disabled</item>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue