Better support for using thumbnails

This commit is contained in:
Damontecres 2026-02-01 17:33:46 -05:00
parent f786ec647e
commit 9a86e854e9
No known key found for this signature in database
8 changed files with 174 additions and 56 deletions

View file

@ -199,4 +199,7 @@ data class HomeRowViewOptions(
val imageType: ViewOptionImageType = ViewOptionImageType.PRIMARY,
val showTitles: Boolean = false,
val useSeries: Boolean = true,
val episodeContentScale: PrefContentScale = PrefContentScale.FIT,
val episodeAspectRatio: AspectRatio = AspectRatio.TALL,
val episodeImageType: ViewOptionImageType = ViewOptionImageType.PRIMARY,
)

View file

@ -976,8 +976,6 @@ val basicPreferences =
),
)
val uiPreferences = listOf<PreferenceGroup>()
private val ExoPlayerSettings =
listOf(
AppPreference.FfmpegPreference,

View file

@ -371,12 +371,36 @@ fun HomePageContent(
}
else -> {
val imageType =
remember(item, viewOptions) {
if (item?.type == BaseItemKind.EPISODE) {
viewOptions.episodeImageType.imageType
} else {
viewOptions.imageType.imageType
}
}
val ratio =
remember(item, viewOptions) {
if (item?.type == BaseItemKind.EPISODE) {
viewOptions.episodeAspectRatio.ratio
} else {
viewOptions.aspectRatio.ratio
}
}
val scale =
remember(item, viewOptions) {
if (item?.type == BaseItemKind.EPISODE) {
viewOptions.episodeContentScale.scale
} else {
viewOptions.contentScale.scale
}
}
BannerCard(
name = item?.data?.seriesName ?: item?.name,
item = item,
aspectRatio = viewOptions.aspectRatio.ratio,
imageType = viewOptions.imageType.imageType,
imageContentScale = viewOptions.contentScale.scale,
aspectRatio = ratio,
imageType = imageType,
imageContentScale = scale,
cornerText = item?.ui?.episdodeUnplayedCornerText,
played = item?.data?.userData?.played ?: false,
favorite = item?.favorite ?: false,

View file

@ -11,6 +11,7 @@ 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.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.surfaceColorAtElevation
@ -25,54 +26,60 @@ 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.preferences.ComposablePreference
import com.github.damontecres.wholphin.ui.preferences.PreferenceGroup
import com.github.damontecres.wholphin.ui.tryRequestFocus
@Composable
fun HomeRowSettings(
title: String,
preferenceOptions: List<PreferenceGroup<HomeRowViewOptions>>,
viewOptions: HomeRowViewOptions,
onViewOptionsChange: (HomeRowViewOptions) -> Unit,
onApplyApplyAll: () -> Unit,
userGenreSettings: Boolean,
modifier: Modifier = Modifier,
defaultViewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) {
val options = if (userGenreSettings) Options.GENRE_OPTIONS else Options.OPTIONS
val firstFocus = remember { FocusRequester() }
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
Column(modifier = modifier) {
TitleText(title)
LazyColumn {
itemsIndexed(options) { index, pref ->
pref as AppPreference<HomeRowViewOptions, Any>
val interactionSource = remember { MutableInteractionSource() }
val value = pref.getter.invoke(viewOptions)
ComposablePreference(
preference = pref,
value = value,
onNavigate = {},
onValueChange = { newValue ->
onViewOptionsChange.invoke(pref.setter(viewOptions, newValue))
},
interactionSource = interactionSource,
onClickPreference = { pref ->
if (pref == Options.ViewOptionsReset) {
onViewOptionsChange.invoke(defaultViewOptions)
} else if (pref == Options.ViewOptionsApplyAll) {
onApplyApplyAll.invoke()
}
},
modifier =
Modifier
.background(
MaterialTheme.colorScheme.surfaceColorAtElevation(
5.dp,
),
).ifElse(index == 0, Modifier.focusRequester(firstFocus)),
)
preferenceOptions.forEachIndexed { groupIndex, prefGroup ->
if (preferenceOptions.size > 1) {
item {
TitleText(stringResource(prefGroup.title))
}
}
itemsIndexed(prefGroup.preferences) { index, pref ->
pref as AppPreference<HomeRowViewOptions, Any>
val interactionSource = remember { MutableInteractionSource() }
val value = pref.getter.invoke(viewOptions)
ComposablePreference(
preference = pref,
value = value,
onNavigate = {},
onValueChange = { newValue ->
onViewOptionsChange.invoke(pref.setter(viewOptions, newValue))
},
interactionSource = interactionSource,
onClickPreference = { pref ->
if (pref == Options.ViewOptionsReset) {
onViewOptionsChange.invoke(defaultViewOptions)
} else if (pref == Options.ViewOptionsApplyAll) {
onApplyApplyAll.invoke()
}
},
modifier =
Modifier
.background(
MaterialTheme.colorScheme.surfaceColorAtElevation(
5.dp,
),
).ifElse(index == 0, Modifier.focusRequester(firstFocus)),
)
}
}
}
}
@ -157,33 +164,111 @@ internal object Options {
)
val ViewOptionsApplyAll =
AppClickablePreference<ViewOptions>(
AppClickablePreference<HomeRowViewOptions>(
title = R.string.apply_all_rows,
)
val ViewOptionsReset =
AppClickablePreference<ViewOptions>(
AppClickablePreference<HomeRowViewOptions>(
title = R.string.reset,
)
val ViewOptionsEpisodeContentScale =
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(episodeContentScale = value) },
indexToValue = { PrefContentScale.forNumber(it) },
valueToIndex = { it.number },
)
val ViewOptionsEpisodeAspectRatio =
AppChoicePreference<HomeRowViewOptions, AspectRatio>(
title = R.string.aspect_ratio,
defaultValue = AspectRatio.TALL,
displayValues = R.array.aspect_ratios,
getter = { it.aspectRatio },
setter = { viewOptions, value -> viewOptions.copy(episodeAspectRatio = value) },
indexToValue = { AspectRatio.entries[it] },
valueToIndex = { it.ordinal },
)
val ViewOptionsEpisodeImageType =
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(episodeImageType = value, episodeAspectRatio = aspectRatio)
},
indexToValue = { ViewOptionImageType.entries[it] },
valueToIndex = { it.ordinal },
)
val OPTIONS =
listOf(
ViewOptionsImageType,
ViewOptionsAspectRatio,
// TODO
PreferenceGroup(
title = R.string.general,
preferences =
listOf(
ViewOptionsImageType,
ViewOptionsAspectRatio,
// TODO
// ViewOptionsShowTitles,
ViewOptionsUseSeries,
ViewOptionsCardHeight,
ViewOptionsSpacing,
ViewOptionsContentScale,
ViewOptionsUseSeries,
ViewOptionsCardHeight,
ViewOptionsSpacing,
ViewOptionsContentScale,
// ViewOptionsApplyAll,
ViewOptionsReset,
ViewOptionsReset,
),
),
)
val OPTIONS_EPISODES =
listOf(
PreferenceGroup(
title = R.string.general,
preferences =
listOf(
ViewOptionsCardHeight,
ViewOptionsSpacing,
ViewOptionsImageType,
ViewOptionsAspectRatio,
ViewOptionsUseSeries,
ViewOptionsContentScale,
ViewOptionsReset,
),
),
PreferenceGroup(
title = R.string.for_episodes,
preferences =
listOf(
ViewOptionsEpisodeImageType,
ViewOptionsEpisodeContentScale,
ViewOptionsEpisodeAspectRatio,
),
),
)
val GENRE_OPTIONS =
listOf(
ViewOptionsCardHeight,
ViewOptionsSpacing,
ViewOptionsReset,
PreferenceGroup(
title = R.string.general,
preferences =
listOf(
ViewOptionsCardHeight,
ViewOptionsSpacing,
ViewOptionsReset,
),
),
)
}

View file

@ -151,8 +151,21 @@ fun HomeSettingsPage(
val row =
state.rows
.first { it.id == dest.rowId }
val preferenceOptions =
remember(row.config) {
when (row.config) {
is HomeRowConfig.ContinueWatching,
is HomeRowConfig.ContinueWatchingCombined,
-> Options.OPTIONS_EPISODES
is HomeRowConfig.Genres -> Options.GENRE_OPTIONS
else -> Options.OPTIONS
}
}
HomeRowSettings(
title = row.title,
preferenceOptions = preferenceOptions,
viewOptions = row.config.viewOptions,
onViewOptionsChange = {
viewModel.updateViewOptions(dest.rowId, it)
@ -160,7 +173,6 @@ fun HomeSettingsPage(
onApplyApplyAll = {
viewModel.updateViewOptionsForAll(row.config.viewOptions)
},
userGenreSettings = row.config is HomeRowConfig.Genres,
modifier = destModifier,
)
}

View file

@ -8,9 +8,9 @@ import kotlinx.serialization.Serializable
/**
* A group of preferences
*/
data class PreferenceGroup(
data class PreferenceGroup<T>(
@param:StringRes val title: Int,
val preferences: List<AppPreference<AppPreferences, out Any?>>,
val preferences: List<AppPreference<T, out Any?>>,
val conditionalPreferences: List<ConditionalPreferences> = listOf(),
)
@ -34,7 +34,6 @@ sealed interface PreferenceValidation {
enum class PreferenceScreenOption {
BASIC,
ADVANCED,
USER_INTERFACE,
SUBTITLES,
EXO_PLAYER,
MPV,

View file

@ -50,7 +50,6 @@ import com.github.damontecres.wholphin.preferences.MpvPreferences
import com.github.damontecres.wholphin.preferences.PlayerBackend
import com.github.damontecres.wholphin.preferences.advancedPreferences
import com.github.damontecres.wholphin.preferences.basicPreferences
import com.github.damontecres.wholphin.preferences.uiPreferences
import com.github.damontecres.wholphin.preferences.updatePlaybackPreferences
import com.github.damontecres.wholphin.services.UpdateChecker
import com.github.damontecres.wholphin.ui.components.ConfirmDialog
@ -125,7 +124,6 @@ fun PreferencesContent(
when (preferenceScreenOption) {
PreferenceScreenOption.BASIC -> basicPreferences
PreferenceScreenOption.ADVANCED -> advancedPreferences
PreferenceScreenOption.USER_INTERFACE -> uiPreferences
PreferenceScreenOption.SUBTITLES -> SubtitleSettings.preferences
PreferenceScreenOption.EXO_PLAYER -> ExoPlayerPreferences
PreferenceScreenOption.MPV -> MpvPreferences
@ -134,7 +132,6 @@ fun PreferencesContent(
when (preferenceScreenOption) {
PreferenceScreenOption.BASIC -> R.string.settings
PreferenceScreenOption.ADVANCED -> R.string.advanced_settings
PreferenceScreenOption.USER_INTERFACE -> R.string.ui_interface
PreferenceScreenOption.SUBTITLES -> R.string.subtitle_style
PreferenceScreenOption.EXO_PLAYER -> R.string.exoplayer_options
PreferenceScreenOption.MPV -> R.string.mpv_options
@ -526,7 +523,6 @@ fun PreferencesPage(
when (preferenceScreenOption) {
PreferenceScreenOption.BASIC,
PreferenceScreenOption.ADVANCED,
PreferenceScreenOption.USER_INTERFACE,
PreferenceScreenOption.EXO_PLAYER,
PreferenceScreenOption.MPV,
-> {

View file

@ -476,6 +476,7 @@
<string name="add_row_for">Add row for %1$s</string>
<string name="overwrite_server_settings">Overwrite settings on server?</string>
<string name="overwrite_local_settings">Overwrite local settings?</string>
<string name="for_episodes">For episodes</string>
<string-array name="theme_song_volume">
<item>Disabled</item>