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 imageType: ViewOptionImageType = ViewOptionImageType.PRIMARY,
val showTitles: Boolean = false, val showTitles: Boolean = false,
val useSeries: Boolean = true, 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 = private val ExoPlayerSettings =
listOf( listOf(
AppPreference.FfmpegPreference, AppPreference.FfmpegPreference,

View file

@ -371,12 +371,36 @@ fun HomePageContent(
} }
else -> { 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( BannerCard(
name = item?.data?.seriesName ?: item?.name, name = item?.data?.seriesName ?: item?.name,
item = item, item = item,
aspectRatio = viewOptions.aspectRatio.ratio, aspectRatio = ratio,
imageType = viewOptions.imageType.imageType, imageType = imageType,
imageContentScale = viewOptions.contentScale.scale, imageContentScale = scale,
cornerText = item?.ui?.episdodeUnplayedCornerText, cornerText = item?.ui?.episdodeUnplayedCornerText,
played = item?.data?.userData?.played ?: false, played = item?.data?.userData?.played ?: false,
favorite = item?.favorite ?: 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.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
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.compose.ui.unit.dp
import androidx.tv.material3.MaterialTheme import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.surfaceColorAtElevation 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.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.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.preferences.PreferenceGroup
import com.github.damontecres.wholphin.ui.tryRequestFocus import com.github.damontecres.wholphin.ui.tryRequestFocus
@Composable @Composable
fun HomeRowSettings( fun HomeRowSettings(
title: String, title: String,
preferenceOptions: List<PreferenceGroup<HomeRowViewOptions>>,
viewOptions: HomeRowViewOptions, viewOptions: HomeRowViewOptions,
onViewOptionsChange: (HomeRowViewOptions) -> Unit, onViewOptionsChange: (HomeRowViewOptions) -> Unit,
onApplyApplyAll: () -> Unit, onApplyApplyAll: () -> Unit,
userGenreSettings: Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
defaultViewOptions: HomeRowViewOptions = HomeRowViewOptions(), defaultViewOptions: HomeRowViewOptions = HomeRowViewOptions(),
) { ) {
val options = if (userGenreSettings) Options.GENRE_OPTIONS else Options.OPTIONS
val firstFocus = remember { FocusRequester() } val firstFocus = remember { FocusRequester() }
LaunchedEffect(Unit) { firstFocus.tryRequestFocus() } LaunchedEffect(Unit) { firstFocus.tryRequestFocus() }
Column(modifier = modifier) { Column(modifier = modifier) {
TitleText(title) TitleText(title)
LazyColumn { LazyColumn {
itemsIndexed(options) { index, pref -> preferenceOptions.forEachIndexed { groupIndex, prefGroup ->
pref as AppPreference<HomeRowViewOptions, Any> if (preferenceOptions.size > 1) {
val interactionSource = remember { MutableInteractionSource() } item {
val value = pref.getter.invoke(viewOptions) TitleText(stringResource(prefGroup.title))
ComposablePreference( }
preference = pref, }
value = value, itemsIndexed(prefGroup.preferences) { index, pref ->
onNavigate = {}, pref as AppPreference<HomeRowViewOptions, Any>
onValueChange = { newValue -> val interactionSource = remember { MutableInteractionSource() }
onViewOptionsChange.invoke(pref.setter(viewOptions, newValue)) val value = pref.getter.invoke(viewOptions)
}, ComposablePreference(
interactionSource = interactionSource, preference = pref,
onClickPreference = { pref -> value = value,
if (pref == Options.ViewOptionsReset) { onNavigate = {},
onViewOptionsChange.invoke(defaultViewOptions) onValueChange = { newValue ->
} else if (pref == Options.ViewOptionsApplyAll) { onViewOptionsChange.invoke(pref.setter(viewOptions, newValue))
onApplyApplyAll.invoke() },
} interactionSource = interactionSource,
}, onClickPreference = { pref ->
modifier = if (pref == Options.ViewOptionsReset) {
Modifier onViewOptionsChange.invoke(defaultViewOptions)
.background( } else if (pref == Options.ViewOptionsApplyAll) {
MaterialTheme.colorScheme.surfaceColorAtElevation( onApplyApplyAll.invoke()
5.dp, }
), },
).ifElse(index == 0, Modifier.focusRequester(firstFocus)), modifier =
) Modifier
.background(
MaterialTheme.colorScheme.surfaceColorAtElevation(
5.dp,
),
).ifElse(index == 0, Modifier.focusRequester(firstFocus)),
)
}
} }
} }
} }
@ -157,33 +164,111 @@ internal object Options {
) )
val ViewOptionsApplyAll = val ViewOptionsApplyAll =
AppClickablePreference<ViewOptions>( AppClickablePreference<HomeRowViewOptions>(
title = R.string.apply_all_rows, title = R.string.apply_all_rows,
) )
val ViewOptionsReset = val ViewOptionsReset =
AppClickablePreference<ViewOptions>( AppClickablePreference<HomeRowViewOptions>(
title = R.string.reset, 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 = val OPTIONS =
listOf( listOf(
ViewOptionsImageType, PreferenceGroup(
ViewOptionsAspectRatio, title = R.string.general,
// TODO preferences =
listOf(
ViewOptionsImageType,
ViewOptionsAspectRatio,
// TODO
// ViewOptionsShowTitles, // ViewOptionsShowTitles,
ViewOptionsUseSeries, ViewOptionsUseSeries,
ViewOptionsCardHeight, ViewOptionsCardHeight,
ViewOptionsSpacing, ViewOptionsSpacing,
ViewOptionsContentScale, ViewOptionsContentScale,
// ViewOptionsApplyAll, // 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 = val GENRE_OPTIONS =
listOf( listOf(
ViewOptionsCardHeight, PreferenceGroup(
ViewOptionsSpacing, title = R.string.general,
ViewOptionsReset, preferences =
listOf(
ViewOptionsCardHeight,
ViewOptionsSpacing,
ViewOptionsReset,
),
),
) )
} }

View file

@ -151,8 +151,21 @@ fun HomeSettingsPage(
val row = val row =
state.rows state.rows
.first { it.id == dest.rowId } .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( HomeRowSettings(
title = row.title, title = row.title,
preferenceOptions = preferenceOptions,
viewOptions = row.config.viewOptions, viewOptions = row.config.viewOptions,
onViewOptionsChange = { onViewOptionsChange = {
viewModel.updateViewOptions(dest.rowId, it) viewModel.updateViewOptions(dest.rowId, it)
@ -160,7 +173,6 @@ fun HomeSettingsPage(
onApplyApplyAll = { onApplyApplyAll = {
viewModel.updateViewOptionsForAll(row.config.viewOptions) viewModel.updateViewOptionsForAll(row.config.viewOptions)
}, },
userGenreSettings = row.config is HomeRowConfig.Genres,
modifier = destModifier, modifier = destModifier,
) )
} }

View file

@ -8,9 +8,9 @@ import kotlinx.serialization.Serializable
/** /**
* A group of preferences * A group of preferences
*/ */
data class PreferenceGroup( data class PreferenceGroup<T>(
@param:StringRes val title: Int, @param:StringRes val title: Int,
val preferences: List<AppPreference<AppPreferences, out Any?>>, val preferences: List<AppPreference<T, out Any?>>,
val conditionalPreferences: List<ConditionalPreferences> = listOf(), val conditionalPreferences: List<ConditionalPreferences> = listOf(),
) )
@ -34,7 +34,6 @@ sealed interface PreferenceValidation {
enum class PreferenceScreenOption { enum class PreferenceScreenOption {
BASIC, BASIC,
ADVANCED, ADVANCED,
USER_INTERFACE,
SUBTITLES, SUBTITLES,
EXO_PLAYER, EXO_PLAYER,
MPV, 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.PlayerBackend
import com.github.damontecres.wholphin.preferences.advancedPreferences import com.github.damontecres.wholphin.preferences.advancedPreferences
import com.github.damontecres.wholphin.preferences.basicPreferences 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.preferences.updatePlaybackPreferences
import com.github.damontecres.wholphin.services.UpdateChecker import com.github.damontecres.wholphin.services.UpdateChecker
import com.github.damontecres.wholphin.ui.components.ConfirmDialog import com.github.damontecres.wholphin.ui.components.ConfirmDialog
@ -125,7 +124,6 @@ fun PreferencesContent(
when (preferenceScreenOption) { when (preferenceScreenOption) {
PreferenceScreenOption.BASIC -> basicPreferences PreferenceScreenOption.BASIC -> basicPreferences
PreferenceScreenOption.ADVANCED -> advancedPreferences PreferenceScreenOption.ADVANCED -> advancedPreferences
PreferenceScreenOption.USER_INTERFACE -> uiPreferences
PreferenceScreenOption.SUBTITLES -> SubtitleSettings.preferences PreferenceScreenOption.SUBTITLES -> SubtitleSettings.preferences
PreferenceScreenOption.EXO_PLAYER -> ExoPlayerPreferences PreferenceScreenOption.EXO_PLAYER -> ExoPlayerPreferences
PreferenceScreenOption.MPV -> MpvPreferences PreferenceScreenOption.MPV -> MpvPreferences
@ -134,7 +132,6 @@ fun PreferencesContent(
when (preferenceScreenOption) { when (preferenceScreenOption) {
PreferenceScreenOption.BASIC -> R.string.settings PreferenceScreenOption.BASIC -> R.string.settings
PreferenceScreenOption.ADVANCED -> R.string.advanced_settings PreferenceScreenOption.ADVANCED -> R.string.advanced_settings
PreferenceScreenOption.USER_INTERFACE -> R.string.ui_interface
PreferenceScreenOption.SUBTITLES -> R.string.subtitle_style PreferenceScreenOption.SUBTITLES -> R.string.subtitle_style
PreferenceScreenOption.EXO_PLAYER -> R.string.exoplayer_options PreferenceScreenOption.EXO_PLAYER -> R.string.exoplayer_options
PreferenceScreenOption.MPV -> R.string.mpv_options PreferenceScreenOption.MPV -> R.string.mpv_options
@ -526,7 +523,6 @@ fun PreferencesPage(
when (preferenceScreenOption) { when (preferenceScreenOption) {
PreferenceScreenOption.BASIC, PreferenceScreenOption.BASIC,
PreferenceScreenOption.ADVANCED, PreferenceScreenOption.ADVANCED,
PreferenceScreenOption.USER_INTERFACE,
PreferenceScreenOption.EXO_PLAYER, PreferenceScreenOption.EXO_PLAYER,
PreferenceScreenOption.MPV, PreferenceScreenOption.MPV,
-> { -> {

View file

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