Add prefer logos instead of text titles setting (#1151)

## Description
Adds an advanced settings to prefer logos for titles instead of text. It
is enabled by default.

### Related issues
Closes #383

### Testing
Emulator & onn

## Screenshots
<details><summary>Click to show</summary>
<p>

### Home page
![logo_1
Large](https://github.com/user-attachments/assets/629a65ab-cf43-4050-af4c-5925763a5f4f)

### Series overview
![logo_2
Large](https://github.com/user-attachments/assets/13ca2d28-cc61-4f4e-abaa-61a310b5c707)

### Movie Page
![logo_movie
Large](https://github.com/user-attachments/assets/a590e6cf-452d-4313-b6a3-35c6f59dc1ff)

### Square-ish logo
![logo_square
Large](https://github.com/user-attachments/assets/7d1340c2-4a3e-42c3-b7bd-ae1114cb6645)

</p>
</details> 


## AI or LLM usage
None
This commit is contained in:
Ray 2026-03-29 10:38:23 -04:00 committed by GitHub
parent 253b203c02
commit 2485d2c644
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 290 additions and 122 deletions

View file

@ -501,6 +501,18 @@ sealed interface AppPreference<Pref, T> {
valueToIndex = { if (it != AppThemeColors.UNRECOGNIZED) it.number else 0 }, valueToIndex = { if (it != AppThemeColors.UNRECOGNIZED) it.number else 0 },
) )
val ShowLogos =
AppSwitchPreference<AppPreferences>(
title = R.string.prefer_logos,
defaultValue = true,
getter = { it.interfacePreferences.showLogos },
setter = { prefs, value ->
prefs.updateInterfacePreferences { showLogos = value }
},
summaryOn = R.string.enabled,
summaryOff = R.string.disabled,
)
val InstalledVersion = val InstalledVersion =
AppClickablePreference<AppPreferences>( AppClickablePreference<AppPreferences>(
title = R.string.installed_version, title = R.string.installed_version,
@ -1122,6 +1134,7 @@ val advancedPreferences =
preferences = preferences =
listOf( listOf(
AppPreference.ShowClock, AppPreference.ShowClock,
AppPreference.ShowLogos,
AppPreference.ManageMedia, AppPreference.ManageMedia,
AppPreference.CombineContinueNext, AppPreference.CombineContinueNext,
// Temporarily disabled, see https://github.com/damontecres/Wholphin/pull/127#issuecomment-3478058418 // Temporarily disabled, see https://github.com/damontecres/Wholphin/pull/127#issuecomment-3478058418

View file

@ -95,6 +95,7 @@ class AppPreferencesSerializer
AppPreference.NavDrawerSwitchOnFocus.defaultValue AppPreference.NavDrawerSwitchOnFocus.defaultValue
showClock = AppPreference.ShowClock.defaultValue showClock = AppPreference.ShowClock.defaultValue
backdropStyle = AppPreference.BackdropStylePref.defaultValue backdropStyle = AppPreference.BackdropStylePref.defaultValue
showLogos = AppPreference.ShowLogos.defaultValue
subtitlesPreferences = subtitlesPreferences =
SubtitlePreferences SubtitlePreferences

View file

@ -282,7 +282,7 @@ class AppUpgradeHandler
} }
} }
if (previous.isEqualOrBefore(Version.fromString("0.6.0-0-g0"))) { if (previous.isEqualOrBefore(Version.fromString("0.5.4-6-g0"))) {
appPreferences.updateData { appPreferences.updateData {
it.updateMusicPreferences { it.updateMusicPreferences {
showBackdrop = true showBackdrop = true
@ -291,5 +291,13 @@ class AppUpgradeHandler
} }
} }
} }
if (previous.isEqualOrBefore(Version.fromString("0.5.4-15-g0"))) {
appPreferences.updateData {
it.updateInterfacePreferences {
showLogos = AppPreference.ShowLogos.defaultValue
}
}
}
} }
} }

View file

@ -886,7 +886,7 @@ class HomeSettingsService
limit = limit, limit = limit,
enableUserData = true, enableUserData = true,
enableImages = true, enableImages = true,
enableImageTypes = listOf(ImageType.PRIMARY), enableImageTypes = listOf(ImageType.PRIMARY, ImageType.LOGO),
imageTypeLimit = 1, imageTypeLimit = 1,
) )
api.liveTvApi api.liveTvApi

View file

@ -20,7 +20,6 @@ import org.jellyfin.sdk.api.client.extensions.userLibraryApi
import org.jellyfin.sdk.api.client.extensions.userViewsApi import org.jellyfin.sdk.api.client.extensions.userViewsApi
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.api.ImageType
import org.jellyfin.sdk.model.api.UserDto import org.jellyfin.sdk.model.api.UserDto
import org.jellyfin.sdk.model.api.request.GetLatestMediaRequest import org.jellyfin.sdk.model.api.request.GetLatestMediaRequest
import org.jellyfin.sdk.model.api.request.GetNextUpRequest import org.jellyfin.sdk.model.api.request.GetNextUpRequest
@ -61,12 +60,13 @@ class LatestNextUpService
remove(BaseItemKind.EPISODE) remove(BaseItemKind.EPISODE)
} }
}, },
enableImageTypes = // enableImageTypes =
listOf( // listOf(
ImageType.PRIMARY, // ImageType.PRIMARY,
ImageType.THUMB, // ImageType.THUMB,
ImageType.BACKDROP, // ImageType.BACKDROP,
), // ImageType.LOGO,
// ),
) )
val items = val items =
api.itemsApi api.itemsApi
@ -98,6 +98,13 @@ class LatestNextUpService
enableUserData = true, enableUserData = true,
enableRewatching = enableRewatching, enableRewatching = enableRewatching,
nextUpDateCutoff = nextUpDateCutoff, nextUpDateCutoff = nextUpDateCutoff,
// enableImageTypes =
// listOf(
// ImageType.PRIMARY,
// ImageType.THUMB,
// ImageType.BACKDROP,
// ImageType.LOGO,
// ),
) )
val nextUp = val nextUp =
api.tvShowsApi api.tvShowsApi

View file

@ -114,7 +114,12 @@ class PlaylistCreator
req = req =
GetItemsRequest( GetItemsRequest(
parentId = item.id, parentId = item.id,
enableImageTypes = listOf(ImageType.PRIMARY, ImageType.THUMB), enableImageTypes =
listOf(
ImageType.PRIMARY,
ImageType.THUMB,
ImageType.LOGO,
),
includeItemTypes = includeItemTypes, includeItemTypes = includeItemTypes,
recursive = true, recursive = true,
excludeItemIds = listOf(item.id), excludeItemIds = listOf(item.id),

View file

@ -214,7 +214,7 @@ fun BannerCardWithTitle(
) { ) {
val focused by interactionSource.collectIsFocusedAsState() val focused by interactionSource.collectIsFocusedAsState()
val spaceBetween by animateDpAsState(if (focused) 12.dp else 4.dp) val spaceBetween by animateDpAsState(if (focused) 12.dp else 4.dp)
val spaceBelow by animateDpAsState(if (focused) 4.dp else 12.dp) val spaceBelow by animateDpAsState(if (focused) 0.dp else 8.dp)
val focusedAfterDelay by rememberFocusedAfterDelay(interactionSource) val focusedAfterDelay by rememberFocusedAfterDelay(interactionSource)
val aspectRationToUse = aspectRatio.coerceAtLeast(AspectRatios.MIN) val aspectRationToUse = aspectRatio.coerceAtLeast(AspectRatios.MIN)
val width = cardHeight * aspectRationToUse val width = cardHeight * aspectRationToUse

View file

@ -398,6 +398,7 @@ class CollectionFolderViewModel
ImageType.PRIMARY, ImageType.PRIMARY,
ImageType.THUMB, ImageType.THUMB,
ImageType.BACKDROP, ImageType.BACKDROP,
ImageType.LOGO,
), ),
includeItemTypes = includeItemTypes, includeItemTypes = includeItemTypes,
recursive = recursive, recursive = recursive,
@ -960,11 +961,12 @@ fun CollectionFolderGridContent(
AnimatedVisibility(viewOptions.showDetails) { AnimatedVisibility(viewOptions.showDetails) {
HomePageHeader( HomePageHeader(
item = focusedItem, item = focusedItem,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
modifier = modifier =
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.height(200.dp) .height(200.dp)
.padding(top = 48.dp, bottom = 32.dp, start = 8.dp), .padding(HeaderUtils.padding),
) )
} }
when (val state = loadingState) { when (val state = loadingState) {

View file

@ -0,0 +1,24 @@
package com.github.damontecres.wholphin.ui.components
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
object HeaderUtils {
val topPadding = 48.dp
val bottomPadding = 32.dp
val startPadding = 8.dp
val padding = PaddingValues(top = topPadding, bottom = bottomPadding, start = startPadding)
val height = 180.dp
val logoHeight = 60.dp
val modifier =
Modifier
.padding(padding)
.height(height)
}

View file

@ -207,6 +207,7 @@ fun RecommendedContent(
}, },
showClock = preferences.appPreferences.interfacePreferences.showClock, showClock = preferences.appPreferences.interfacePreferences.showClock,
onUpdateBackdrop = viewModel::updateBackdrop, onUpdateBackdrop = viewModel::updateBackdrop,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
modifier = modifier, modifier = modifier,
) )
} }

View file

@ -0,0 +1,95 @@
package com.github.damontecres.wholphin.ui.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.widthIn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import coil3.compose.AsyncImage
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.ui.LocalImageUrlService
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.ImageType
@Composable
fun TitleOrLogo(
title: String?,
logoImageUrl: String?,
showLogo: Boolean,
modifier: Modifier = Modifier,
) {
var imageError by remember { mutableStateOf(false) }
Box(
modifier = modifier.heightIn(max = HeaderUtils.logoHeight),
) {
if (showLogo && logoImageUrl != null && !imageError) {
AsyncImage(
model = logoImageUrl,
contentDescription = title,
contentScale = ContentScale.Fit,
modifier =
Modifier
.height(HeaderUtils.logoHeight)
.widthIn(max = 320.dp),
)
} else {
Title(title, Modifier)
}
}
}
@Composable
private fun Title(
title: String?,
modifier: Modifier = Modifier,
) {
Text(
text = title ?: "",
color = MaterialTheme.colorScheme.onSurface,
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.SemiBold,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
modifier = modifier,
)
}
@Composable
fun TitleOrLogo(
item: BaseItem?,
showLogo: Boolean,
modifier: Modifier = Modifier,
) {
val logoImageUrl = rememberLogoUrl(item)
TitleOrLogo(
title = item?.title,
logoImageUrl = logoImageUrl,
showLogo = showLogo,
modifier = modifier,
)
}
@Composable
fun rememberLogoUrl(item: BaseItem?): String? {
val imageUrlService = LocalImageUrlService.current
return remember(item?.id) {
if (item?.type == BaseItemKind.EPISODE && item.data.seriesId != null && item.data.parentLogoImageTag != null) {
imageUrlService.getItemImageUrl(item.data.seriesId!!, ImageType.LOGO)
} else if (ImageType.LOGO in item?.data?.imageTags.orEmpty()) {
imageUrlService.getItemImageUrl(item, ImageType.LOGO)
} else {
null
}
}
}

View file

@ -11,7 +11,6 @@ import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@ -50,6 +49,7 @@ import com.github.damontecres.wholphin.ui.components.DialogItem
import com.github.damontecres.wholphin.ui.components.DialogParams import com.github.damontecres.wholphin.ui.components.DialogParams
import com.github.damontecres.wholphin.ui.components.DialogPopup import com.github.damontecres.wholphin.ui.components.DialogPopup
import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.HeaderUtils
import com.github.damontecres.wholphin.ui.components.LoadingPage import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.components.Optional import com.github.damontecres.wholphin.ui.components.Optional
import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel
@ -379,11 +379,13 @@ fun CollectionDetailsContent(
if (state.viewOptions.cardViewOptions.showDetails) { if (state.viewOptions.cardViewOptions.showDetails) {
HomePageHeader( HomePageHeader(
item = focusedItem, item = focusedItem,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
modifier = modifier =
Modifier Modifier
.padding(top = 48.dp, start = 8.dp) .padding(
.fillMaxHeight(.33f) top = HeaderUtils.topPadding,
.fillMaxWidth(), bottom = 8.dp,
).height(HeaderUtils.height),
) )
} }
} }
@ -412,15 +414,16 @@ fun CollectionDetailsContent(
) { ) {
CollectionDetailsHeader( CollectionDetailsHeader(
collection = state.collection!!, collection = state.collection!!,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
logoImageUrl = state.logoImageUrl, logoImageUrl = state.logoImageUrl,
overviewOnClick = overviewOnClick, overviewOnClick = overviewOnClick,
bringIntoViewRequester = bringIntoViewRequester, bringIntoViewRequester = bringIntoViewRequester,
modifier = modifier =
Modifier Modifier
.padding(top = 48.dp, start = 8.dp) .padding(
// TODO top = HeaderUtils.topPadding,
.fillMaxHeight(.36f) bottom = HeaderUtils.bottomPadding,
.fillMaxWidth(), ).height(HeaderUtils.height),
) )
CollectionButtons( CollectionButtons(
state = state, state = state,

View file

@ -3,28 +3,24 @@ package com.github.damontecres.wholphin.ui.detail.collection
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.relocation.BringIntoViewRequester import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
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.Text import androidx.tv.material3.Text
import coil3.compose.AsyncImage
import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.ui.components.GenreText import com.github.damontecres.wholphin.ui.components.GenreText
import com.github.damontecres.wholphin.ui.components.HeaderUtils
import com.github.damontecres.wholphin.ui.components.OverviewText import com.github.damontecres.wholphin.ui.components.OverviewText
import com.github.damontecres.wholphin.ui.components.QuickDetails import com.github.damontecres.wholphin.ui.components.QuickDetails
import com.github.damontecres.wholphin.ui.components.TitleOrLogo
import com.github.damontecres.wholphin.ui.letNotEmpty import com.github.damontecres.wholphin.ui.letNotEmpty
import com.github.damontecres.wholphin.util.ExceptionHandler import com.github.damontecres.wholphin.util.ExceptionHandler
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -32,6 +28,7 @@ import kotlinx.coroutines.launch
@Composable @Composable
fun CollectionDetailsHeader( fun CollectionDetailsHeader(
collection: BaseItem, collection: BaseItem,
showLogo: Boolean,
logoImageUrl: String?, logoImageUrl: String?,
overviewOnClick: () -> Unit, overviewOnClick: () -> Unit,
bringIntoViewRequester: BringIntoViewRequester, bringIntoViewRequester: BringIntoViewRequester,
@ -44,28 +41,15 @@ fun CollectionDetailsHeader(
verticalArrangement = Arrangement.spacedBy(4.dp), verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = modifier, modifier = modifier,
) { ) {
if (logoImageUrl != null) { TitleOrLogo(
AsyncImage( title = collection.name,
model = logoImageUrl, showLogo = showLogo,
contentDescription = collection.name, logoImageUrl = logoImageUrl,
modifier = Modifier.height(80.dp), modifier =
alignment = Alignment.TopStart, Modifier
contentScale = ContentScale.Fit, .fillMaxWidth(.75f)
) .padding(start = HeaderUtils.startPadding),
} else { )
// Title
Text(
text = collection.name ?: "",
color = MaterialTheme.colorScheme.onBackground,
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.SemiBold),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier =
Modifier
.fillMaxWidth(.75f)
.padding(start = 8.dp),
)
}
Column( Column(
verticalArrangement = Arrangement.spacedBy(4.dp), verticalArrangement = Arrangement.spacedBy(4.dp),
@ -74,18 +58,18 @@ fun CollectionDetailsHeader(
QuickDetails( QuickDetails(
collection.ui.quickDetails, collection.ui.quickDetails,
collection.timeRemainingOrRuntime, collection.timeRemainingOrRuntime,
Modifier.padding(start = 8.dp), Modifier.padding(start = HeaderUtils.startPadding),
) )
dto.genres?.letNotEmpty { dto.genres?.letNotEmpty {
GenreText(it, Modifier.padding(start = 8.dp)) GenreText(it, Modifier.padding(start = HeaderUtils.startPadding))
} }
dto.taglines?.firstOrNull()?.let { tagline -> dto.taglines?.firstOrNull()?.let { tagline ->
Text( Text(
text = tagline, text = tagline,
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
fontStyle = FontStyle.Italic, fontStyle = FontStyle.Italic,
modifier = Modifier.padding(start = 8.dp), modifier = Modifier.padding(start = HeaderUtils.startPadding),
) )
} }

View file

@ -83,6 +83,7 @@ fun CollectionRows(
onUpdateBackdrop = {}, onUpdateBackdrop = {},
headerComposable = {}, headerComposable = {},
takeFocus = false, takeFocus = false,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
modifier = Modifier, modifier = Modifier,
) )
} }

View file

@ -62,6 +62,7 @@ import kotlinx.coroutines.withContext
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.userLibraryApi 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.ImageType
import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.ItemSortBy
import org.jellyfin.sdk.model.api.SortOrder import org.jellyfin.sdk.model.api.SortOrder
import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest
@ -139,13 +140,12 @@ class CollectionViewModel
.content .content
.let { BaseItem(it, false) } .let { BaseItem(it, false) }
backdropService.submit(collection) backdropService.submit(collection)
val logoImageUrl = null val logoImageUrl =
// TODO add logo back if (ImageType.LOGO in collection.data.imageTags.orEmpty()) {
// if (ImageType.LOGO in collection.data.imageTags.orEmpty()) { imageUrlService.getItemImageUrl(collection, ImageType.LOGO)
// imageUrlService.getItemImageUrl(collection, ImageType.LOGO) } else {
// } else { null
// null }
// }
_state.update { _state.update {
it.copy( it.copy(
collection = collection, collection = collection,

View file

@ -36,6 +36,7 @@ import com.github.damontecres.wholphin.ui.components.DialogParams
import com.github.damontecres.wholphin.ui.components.DialogPopup import com.github.damontecres.wholphin.ui.components.DialogPopup
import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.ExpandablePlayButtons import com.github.damontecres.wholphin.ui.components.ExpandablePlayButtons
import com.github.damontecres.wholphin.ui.components.HeaderUtils
import com.github.damontecres.wholphin.ui.components.LoadingPage import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.components.Optional import com.github.damontecres.wholphin.ui.components.Optional
import com.github.damontecres.wholphin.ui.components.chooseStream import com.github.damontecres.wholphin.ui.components.chooseStream
@ -332,7 +333,7 @@ fun EpisodeDetailsContent(
Box(modifier = modifier) { Box(modifier = modifier) {
LazyColumn( LazyColumn(
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(vertical = 8.dp), contentPadding = PaddingValues(bottom = 8.dp),
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
) { ) {
item { item {
@ -352,7 +353,7 @@ fun EpisodeDetailsContent(
modifier = modifier =
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(top = 32.dp, bottom = 16.dp), .padding(top = HeaderUtils.topPadding, bottom = 16.dp),
) )
ExpandablePlayButtons( ExpandablePlayButtons(
resumePosition = resumePosition, resumePosition = resumePosition,

View file

@ -51,6 +51,7 @@ import com.github.damontecres.wholphin.ui.components.DialogParams
import com.github.damontecres.wholphin.ui.components.DialogPopup import com.github.damontecres.wholphin.ui.components.DialogPopup
import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.ExpandablePlayButtons import com.github.damontecres.wholphin.ui.components.ExpandablePlayButtons
import com.github.damontecres.wholphin.ui.components.HeaderUtils
import com.github.damontecres.wholphin.ui.components.LoadingPage import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.components.Optional import com.github.damontecres.wholphin.ui.components.Optional
import com.github.damontecres.wholphin.ui.components.chooseStream import com.github.damontecres.wholphin.ui.components.chooseStream
@ -439,7 +440,7 @@ fun MovieDetailsContent(
Box(modifier = modifier) { Box(modifier = modifier) {
LazyColumn( LazyColumn(
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(vertical = 8.dp), contentPadding = PaddingValues(bottom = 8.dp),
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
) { ) {
item { item {
@ -459,7 +460,7 @@ fun MovieDetailsContent(
modifier = modifier =
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(top = 40.dp, bottom = 16.dp), .padding(top = HeaderUtils.topPadding, bottom = 16.dp),
) )
ExpandablePlayButtons( ExpandablePlayButtons(
resumePosition = resumePosition, resumePosition = resumePosition,

View file

@ -13,8 +13,6 @@ import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.tv.material3.MaterialTheme import androidx.tv.material3.MaterialTheme
@ -24,8 +22,10 @@ import com.github.damontecres.wholphin.data.ChosenStreams
import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.preferences.UserPreferences import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.ui.components.GenreText import com.github.damontecres.wholphin.ui.components.GenreText
import com.github.damontecres.wholphin.ui.components.HeaderUtils
import com.github.damontecres.wholphin.ui.components.OverviewText import com.github.damontecres.wholphin.ui.components.OverviewText
import com.github.damontecres.wholphin.ui.components.QuickDetails import com.github.damontecres.wholphin.ui.components.QuickDetails
import com.github.damontecres.wholphin.ui.components.TitleOrLogo
import com.github.damontecres.wholphin.ui.components.VideoStreamDetails import com.github.damontecres.wholphin.ui.components.VideoStreamDetails
import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.isNotNullOrBlank
import com.github.damontecres.wholphin.ui.letNotEmpty import com.github.damontecres.wholphin.ui.letNotEmpty
@ -50,16 +50,13 @@ fun MovieDetailsHeader(
modifier = modifier, modifier = modifier,
) { ) {
// Title // Title
Text( TitleOrLogo(
text = movie.name ?: "", item = movie,
color = MaterialTheme.colorScheme.onBackground, showLogo = preferences.appPreferences.interfacePreferences.showLogos,
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.SemiBold),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = modifier =
Modifier Modifier
.fillMaxWidth(.75f) .fillMaxWidth(.75f)
.padding(start = 8.dp), .padding(start = HeaderUtils.startPadding),
) )
Column( Column(
@ -69,24 +66,29 @@ fun MovieDetailsHeader(
QuickDetails( QuickDetails(
movie.ui.quickDetails, movie.ui.quickDetails,
movie.timeRemainingOrRuntime, movie.timeRemainingOrRuntime,
Modifier.padding(start = 8.dp), Modifier.padding(start = HeaderUtils.startPadding),
) )
dto.genres?.letNotEmpty { dto.genres?.letNotEmpty {
GenreText(it, Modifier.padding(start = 8.dp)) GenreText(it, Modifier.padding(start = HeaderUtils.startPadding))
} }
VideoStreamDetails( VideoStreamDetails(
chosenStreams = chosenStreams, chosenStreams = chosenStreams,
numberOfVersions = movie.data.mediaSourceCount ?: 0, numberOfVersions = movie.data.mediaSourceCount ?: 0,
modifier = Modifier.padding(start = 8.dp, top = 4.dp, bottom = 16.dp), modifier =
Modifier.padding(
start = HeaderUtils.startPadding,
top = 4.dp,
bottom = 16.dp,
),
) )
dto.taglines?.firstOrNull()?.let { tagline -> dto.taglines?.firstOrNull()?.let { tagline ->
Text( Text(
text = tagline, text = tagline,
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
fontStyle = FontStyle.Italic, fontStyle = FontStyle.Italic,
modifier = Modifier.padding(start = 8.dp), modifier = Modifier.padding(start = HeaderUtils.startPadding),
) )
} }
@ -122,7 +124,7 @@ fun MovieDetailsHeader(
text = stringResource(R.string.directed_by, it), text = stringResource(R.string.directed_by, it),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurface, color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.padding(start = 8.dp), modifier = Modifier.padding(start = HeaderUtils.startPadding),
) )
} }
} }

View file

@ -13,6 +13,7 @@ import com.github.damontecres.wholphin.data.ChosenStreams
import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.preferences.UserPreferences import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.ui.components.EpisodeName import com.github.damontecres.wholphin.ui.components.EpisodeName
import com.github.damontecres.wholphin.ui.components.HeaderUtils
import com.github.damontecres.wholphin.ui.components.OverviewText import com.github.damontecres.wholphin.ui.components.OverviewText
import com.github.damontecres.wholphin.ui.components.QuickDetails import com.github.damontecres.wholphin.ui.components.QuickDetails
import com.github.damontecres.wholphin.ui.components.VideoStreamDetails import com.github.damontecres.wholphin.ui.components.VideoStreamDetails
@ -32,17 +33,21 @@ fun FocusedEpisodeHeader(
verticalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier, modifier = modifier,
) { ) {
EpisodeName(dto, modifier = Modifier.padding(start = 8.dp)) EpisodeName(dto, modifier = Modifier.padding(start = HeaderUtils.startPadding))
ep?.ui?.quickDetails?.let { ep?.ui?.quickDetails?.let {
QuickDetails(it, ep.timeRemainingOrRuntime, Modifier.padding(start = 8.dp)) QuickDetails(
it,
ep.timeRemainingOrRuntime,
Modifier.padding(start = HeaderUtils.startPadding),
)
} }
if (dto != null) { if (dto != null) {
VideoStreamDetails( VideoStreamDetails(
chosenStreams = chosenStreams, chosenStreams = chosenStreams,
numberOfVersions = dto.mediaSourceCount ?: 0, numberOfVersions = dto.mediaSourceCount ?: 0,
modifier = Modifier.padding(start = 8.dp), modifier = Modifier.padding(start = HeaderUtils.startPadding),
) )
} }
OverviewText( OverviewText(

View file

@ -37,14 +37,10 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ExtrasItem import com.github.damontecres.wholphin.data.ExtrasItem
import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.BaseItem
@ -69,10 +65,12 @@ import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.ExpandableFaButton import com.github.damontecres.wholphin.ui.components.ExpandableFaButton
import com.github.damontecres.wholphin.ui.components.ExpandablePlayButton import com.github.damontecres.wholphin.ui.components.ExpandablePlayButton
import com.github.damontecres.wholphin.ui.components.GenreText import com.github.damontecres.wholphin.ui.components.GenreText
import com.github.damontecres.wholphin.ui.components.HeaderUtils
import com.github.damontecres.wholphin.ui.components.LoadingPage import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.components.Optional import com.github.damontecres.wholphin.ui.components.Optional
import com.github.damontecres.wholphin.ui.components.OverviewText import com.github.damontecres.wholphin.ui.components.OverviewText
import com.github.damontecres.wholphin.ui.components.QuickDetails import com.github.damontecres.wholphin.ui.components.QuickDetails
import com.github.damontecres.wholphin.ui.components.TitleOrLogo
import com.github.damontecres.wholphin.ui.components.TrailerButton import com.github.damontecres.wholphin.ui.components.TrailerButton
import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialog import com.github.damontecres.wholphin.ui.data.ItemDetailsDialog
@ -386,7 +384,6 @@ fun SeriesDetailsContent(
Column( Column(
modifier = modifier =
Modifier Modifier
.padding(vertical = 16.dp)
.fillMaxSize(), .fillMaxSize(),
) { ) {
LazyColumn( LazyColumn(
@ -397,18 +394,19 @@ fun SeriesDetailsContent(
item { item {
SeriesDetailsHeader( SeriesDetailsHeader(
series = series, series = series,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
overviewOnClick = overviewOnClick, overviewOnClick = overviewOnClick,
modifier = modifier =
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.bringIntoViewRequester(bringIntoViewRequester) .bringIntoViewRequester(bringIntoViewRequester)
.padding(top = 32.dp, bottom = 16.dp), .padding(top = HeaderUtils.topPadding, bottom = 16.dp),
) )
Row( Row(
horizontalArrangement = Arrangement.spacedBy(16.dp), horizontalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier =
Modifier Modifier
.padding(start = 8.dp) .padding(start = HeaderUtils.startPadding)
.focusRequester(focusRequesters[HEADER_ROW]) .focusRequester(focusRequesters[HEADER_ROW])
.focusRestorer(playFocusRequester) .focusRestorer(playFocusRequester)
.focusGroup() .focusGroup()
@ -684,6 +682,7 @@ fun SeriesDetailsContent(
@Composable @Composable
fun SeriesDetailsHeader( fun SeriesDetailsHeader(
series: BaseItem, series: BaseItem,
showLogo: Boolean,
overviewOnClick: () -> Unit, overviewOnClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -693,24 +692,25 @@ fun SeriesDetailsHeader(
verticalArrangement = Arrangement.spacedBy(4.dp), verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = modifier, modifier = modifier,
) { ) {
Text( TitleOrLogo(
text = series.name ?: stringResource(R.string.unknown), item = series,
color = MaterialTheme.colorScheme.onBackground, showLogo = showLogo,
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.SemiBold),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = modifier =
Modifier Modifier
.fillMaxWidth(.75f) .fillMaxWidth(.75f)
.padding(start = 8.dp), .padding(start = HeaderUtils.startPadding),
) )
Column( Column(
verticalArrangement = Arrangement.spacedBy(4.dp), verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.fillMaxWidth(.60f), modifier = Modifier.fillMaxWidth(.60f),
) { ) {
QuickDetails(series.ui.quickDetails, null, Modifier.padding(start = 8.dp)) QuickDetails(
series.ui.quickDetails,
null,
Modifier.padding(start = HeaderUtils.startPadding),
)
dto.genres?.letNotEmpty { dto.genres?.letNotEmpty {
GenreText(it, Modifier.padding(start = 8.dp, bottom = 8.dp)) GenreText(it, Modifier.padding(start = HeaderUtils.startPadding, bottom = 8.dp))
} }
dto.overview?.let { overview -> dto.overview?.let { overview ->
OverviewText( OverviewText(

View file

@ -52,9 +52,10 @@ import com.github.damontecres.wholphin.ui.AspectRatios
import com.github.damontecres.wholphin.ui.cards.BannerCard import com.github.damontecres.wholphin.ui.cards.BannerCard
import com.github.damontecres.wholphin.ui.cards.PersonRow import com.github.damontecres.wholphin.ui.cards.PersonRow
import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.HeaderUtils
import com.github.damontecres.wholphin.ui.components.LoadingPage import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.components.SeriesName
import com.github.damontecres.wholphin.ui.components.TabRow import com.github.damontecres.wholphin.ui.components.TabRow
import com.github.damontecres.wholphin.ui.components.TitleOrLogo
import com.github.damontecres.wholphin.ui.ifElse import com.github.damontecres.wholphin.ui.ifElse
import com.github.damontecres.wholphin.ui.logTab import com.github.damontecres.wholphin.ui.logTab
import com.github.damontecres.wholphin.ui.playback.isPlayKeyUp import com.github.damontecres.wholphin.ui.playback.isPlayKeyUp
@ -143,10 +144,12 @@ fun SeriesOverviewContent(
.bringIntoViewRequester(bringIntoViewRequester), .bringIntoViewRequester(bringIntoViewRequester),
) { ) {
val paddingValues = val paddingValues =
if (preferences.appPreferences.interfacePreferences.showClock) { remember(preferences.appPreferences.interfacePreferences.showClock) {
PaddingValues(start = 0.dp, end = 184.dp) if (preferences.appPreferences.interfacePreferences.showClock) {
} else { PaddingValues(start = 0.dp, end = 184.dp)
PaddingValues(start = 0.dp, end = 16.dp) } else {
PaddingValues(start = 0.dp, end = 16.dp)
}
} }
TabRow( TabRow(
selectedTabIndex = selectedTabIndex, selectedTabIndex = selectedTabIndex,
@ -164,7 +167,11 @@ fun SeriesOverviewContent(
.padding(bottom = 4.dp) .padding(bottom = 4.dp)
.fillMaxWidth(), .fillMaxWidth(),
) )
SeriesName(series.name, Modifier.padding(start = 8.dp)) TitleOrLogo(
item = series,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
modifier = Modifier.padding(start = HeaderUtils.startPadding),
)
FocusedEpisodeHeader( FocusedEpisodeHeader(
preferences = preferences, preferences = preferences,
ep = focusedEpisode, ep = focusedEpisode,

View file

@ -250,6 +250,8 @@ fun SeerrDiscoverPage(
overviewTwoLines = true, overviewTwoLines = true,
quickDetails = details, quickDetails = details,
timeRemaining = null, timeRemaining = null,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
logoImageUrl = null, // TODO
modifier = modifier =
Modifier Modifier
.padding(top = 24.dp, bottom = 16.dp, start = 32.dp) .padding(top = 24.dp, bottom = 16.dp, start = 32.dp)

View file

@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@ -39,7 +38,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
@ -61,9 +59,12 @@ import com.github.damontecres.wholphin.ui.components.DialogPopup
import com.github.damontecres.wholphin.ui.components.EpisodeName import com.github.damontecres.wholphin.ui.components.EpisodeName
import com.github.damontecres.wholphin.ui.components.ErrorMessage import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.FocusableItemRow import com.github.damontecres.wholphin.ui.components.FocusableItemRow
import com.github.damontecres.wholphin.ui.components.HeaderUtils
import com.github.damontecres.wholphin.ui.components.LoadingPage import com.github.damontecres.wholphin.ui.components.LoadingPage
import com.github.damontecres.wholphin.ui.components.QuickDetails import com.github.damontecres.wholphin.ui.components.QuickDetails
import com.github.damontecres.wholphin.ui.components.RowColumnItem import com.github.damontecres.wholphin.ui.components.RowColumnItem
import com.github.damontecres.wholphin.ui.components.TitleOrLogo
import com.github.damontecres.wholphin.ui.components.rememberLogoUrl
import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel
import com.github.damontecres.wholphin.ui.data.RowColumn import com.github.damontecres.wholphin.ui.data.RowColumn
import com.github.damontecres.wholphin.ui.detail.MoreDialogActions import com.github.damontecres.wholphin.ui.detail.MoreDialogActions
@ -172,6 +173,7 @@ fun HomePage(
loadingState = refreshing, loadingState = refreshing,
showClock = preferences.appPreferences.interfacePreferences.showClock, showClock = preferences.appPreferences.interfacePreferences.showClock,
onUpdateBackdrop = viewModel::updateBackdrop, onUpdateBackdrop = viewModel::updateBackdrop,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
modifier = modifier, modifier = modifier,
) )
dialog?.let { params -> dialog?.let { params ->
@ -222,6 +224,7 @@ fun HomePageContent(
onClickPlay: (RowColumn, BaseItem) -> Unit, onClickPlay: (RowColumn, BaseItem) -> Unit,
showClock: Boolean, showClock: Boolean,
onUpdateBackdrop: (BaseItem) -> Unit, onUpdateBackdrop: (BaseItem) -> Unit,
showLogo: Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
loadingState: LoadingState? = null, loadingState: LoadingState? = null,
listState: LazyListState = rememberLazyListState(), listState: LazyListState = rememberLazyListState(),
@ -230,10 +233,8 @@ fun HomePageContent(
headerComposable: @Composable (focusedItem: BaseItem?) -> Unit = { focusedItem -> headerComposable: @Composable (focusedItem: BaseItem?) -> Unit = { focusedItem ->
HomePageHeader( HomePageHeader(
item = focusedItem, item = focusedItem,
modifier = showLogo = showLogo,
Modifier modifier = HeaderUtils.modifier,
.padding(top = 48.dp, bottom = 32.dp, start = 8.dp)
.fillMaxHeight(.33f),
) )
}, },
) { ) {
@ -410,6 +411,7 @@ fun HomePageContent(
@Composable @Composable
fun HomePageHeader( fun HomePageHeader(
item: BaseItem?, item: BaseItem?,
showLogo: Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val isEpisode = item?.type == BaseItemKind.EPISODE val isEpisode = item?.type == BaseItemKind.EPISODE
@ -421,6 +423,8 @@ fun HomePageHeader(
overviewTwoLines = isEpisode, overviewTwoLines = isEpisode,
quickDetails = item?.ui?.quickDetails ?: AnnotatedString(""), quickDetails = item?.ui?.quickDetails ?: AnnotatedString(""),
timeRemaining = item?.timeRemainingOrRuntime, timeRemaining = item?.timeRemainingOrRuntime,
showLogo = showLogo,
logoImageUrl = rememberLogoUrl(item),
modifier = modifier, modifier = modifier,
) )
} }
@ -433,31 +437,28 @@ fun HomePageHeader(
overviewTwoLines: Boolean, overviewTwoLines: Boolean,
quickDetails: AnnotatedString?, quickDetails: AnnotatedString?,
timeRemaining: Duration?, timeRemaining: Duration?,
showLogo: Boolean,
logoImageUrl: String?,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Column( Column(
verticalArrangement = Arrangement.spacedBy(4.dp), verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = modifier, modifier = modifier,
) { ) {
title?.let { TitleOrLogo(
Text( title = title,
text = it, logoImageUrl = logoImageUrl,
style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.SemiBold), showLogo = showLogo,
color = MaterialTheme.colorScheme.onBackground, modifier = Modifier.fillMaxWidth(.75f),
maxLines = 1, )
overflow = TextOverflow.Ellipsis,
modifier = Modifier.fillMaxWidth(.75f),
)
}
Column( Column(
verticalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier =
Modifier Modifier
.fillMaxWidth(.6f) .fillMaxWidth(.6f),
.fillMaxHeight(),
) { ) {
subtitle?.let { if (subtitle != null) {
EpisodeName(it) EpisodeName(subtitle)
} }
QuickDetails(quickDetails ?: AnnotatedString(""), timeRemaining) QuickDetails(quickDetails ?: AnnotatedString(""), timeRemaining)
val overviewModifier = val overviewModifier =

View file

@ -32,6 +32,7 @@ import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.model.HomeRowConfig import com.github.damontecres.wholphin.data.model.HomeRowConfig
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
import com.github.damontecres.wholphin.preferences.AppPreferences import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.ui.components.ConfirmDialog import com.github.damontecres.wholphin.ui.components.ConfirmDialog
import com.github.damontecres.wholphin.ui.data.RowColumn import com.github.damontecres.wholphin.ui.data.RowColumn
import com.github.damontecres.wholphin.ui.detail.search.SearchForDialog import com.github.damontecres.wholphin.ui.detail.search.SearchForDialog
@ -51,6 +52,7 @@ val settingsWidth = 360.dp
@Composable @Composable
fun HomeSettingsPage( fun HomeSettingsPage(
preferences: UserPreferences,
modifier: Modifier, modifier: Modifier,
viewModel: HomeSettingsViewModel = hiltViewModel(), viewModel: HomeSettingsViewModel = hiltViewModel(),
) { ) {
@ -310,6 +312,7 @@ fun HomeSettingsPage(
listState = listState, listState = listState,
takeFocus = false, takeFocus = false,
showEmptyRows = true, showEmptyRows = true,
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
modifier = modifier =
Modifier Modifier
.fillMaxHeight() .fillMaxHeight()

View file

@ -69,7 +69,7 @@ fun DestinationContent(
} }
is Destination.HomeSettings -> { is Destination.HomeSettings -> {
HomeSettingsPage(modifier) HomeSettingsPage(preferences, modifier)
} }
is Destination.PlaybackList, is Destination.PlaybackList,

View file

@ -167,6 +167,7 @@ message InterfacePreferences {
SubtitlePreferences hdr_subtitles_preferences = 10; SubtitlePreferences hdr_subtitles_preferences = 10;
ScreensaverPreferences screensaver_preference = 11; ScreensaverPreferences screensaver_preference = 11;
bool enable_media_management = 12; bool enable_media_management = 12;
bool show_logos = 13;
} }
message AdvancedPreferences { message AdvancedPreferences {

View file

@ -747,5 +747,6 @@
<string name="continue_string">Continue</string> <string name="continue_string">Continue</string>
<string name="select_all">Select all</string> <string name="select_all">Select all</string>
<string name="separate_types">Separate types</string> <string name="separate_types">Separate types</string>
<string name="prefer_logos">Prefer showing logos for titles</string>
</resources> </resources>