mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-17 15:32:01 +00:00
feat: landscape posters
This commit is contained in:
parent
1a59fc0a20
commit
2d1ab47919
10 changed files with 212 additions and 35 deletions
|
|
@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
|
@ -98,6 +99,9 @@ fun NuvioPosterCard(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
shape: NuvioPosterShape = NuvioPosterShape.Poster,
|
shape: NuvioPosterShape = NuvioPosterShape.Poster,
|
||||||
detailLine: String? = null,
|
detailLine: String? = null,
|
||||||
|
showTitleBelow: Boolean = true,
|
||||||
|
bottomLeftLogoUrl: String? = null,
|
||||||
|
bottomLeftText: String? = null,
|
||||||
isWatched: Boolean = false,
|
isWatched: Boolean = false,
|
||||||
onClick: (() -> Unit)? = null,
|
onClick: (() -> Unit)? = null,
|
||||||
onLongClick: (() -> Unit)? = null,
|
onLongClick: (() -> Unit)? = null,
|
||||||
|
|
@ -105,6 +109,7 @@ fun NuvioPosterCard(
|
||||||
val posterCardStyle = rememberPosterCardStyleUiState()
|
val posterCardStyle = rememberPosterCardStyleUiState()
|
||||||
val cardWidth = shape.cardWidth(basePosterWidthDp = posterCardStyle.widthDp)
|
val cardWidth = shape.cardWidth(basePosterWidthDp = posterCardStyle.widthDp)
|
||||||
val cardShape = RoundedCornerShape(posterCardStyle.cornerRadiusDp.dp)
|
val cardShape = RoundedCornerShape(posterCardStyle.cornerRadiusDp.dp)
|
||||||
|
val catalogLogoOverlaySize = catalogLogoOverlaySize(basePosterWidthDp = posterCardStyle.widthDp)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier.width(cardWidth),
|
modifier = modifier.width(cardWidth),
|
||||||
|
|
@ -137,6 +142,35 @@ fun NuvioPosterCard(
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!bottomLeftLogoUrl.isNullOrBlank() || !bottomLeftText.isNullOrBlank()) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomStart)
|
||||||
|
.padding(horizontal = 10.dp, vertical = 10.dp),
|
||||||
|
) {
|
||||||
|
if (!bottomLeftLogoUrl.isNullOrBlank()) {
|
||||||
|
AsyncImage(
|
||||||
|
model = bottomLeftLogoUrl,
|
||||||
|
contentDescription = "$title logo",
|
||||||
|
modifier = Modifier
|
||||||
|
.width(catalogLogoOverlaySize.width)
|
||||||
|
.height(catalogLogoOverlaySize.height),
|
||||||
|
contentScale = ContentScale.Fit,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Text(
|
||||||
|
text = bottomLeftText.orEmpty(),
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier.widthIn(max = catalogLogoOverlaySize.textMaxWidth),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NuvioAnimatedWatchedBadge(
|
NuvioAnimatedWatchedBadge(
|
||||||
isVisible = isWatched,
|
isVisible = isWatched,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -144,6 +178,7 @@ fun NuvioPosterCard(
|
||||||
.padding(6.dp),
|
.padding(6.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (showTitleBelow) {
|
||||||
Text(
|
Text(
|
||||||
text = title,
|
text = title,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
|
@ -162,6 +197,9 @@ fun NuvioPosterCard(
|
||||||
} else {
|
} else {
|
||||||
Box(modifier = Modifier.height(0.dp))
|
Box(modifier = Modifier.height(0.dp))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Box(modifier = Modifier.height(0.dp))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,16 +293,28 @@ private val NuvioPosterShape.aspectRatio: Float
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
NuvioPosterShape.Poster -> 0.675f
|
NuvioPosterShape.Poster -> 0.675f
|
||||||
NuvioPosterShape.Square -> 1f
|
NuvioPosterShape.Square -> 1f
|
||||||
NuvioPosterShape.Landscape -> 1.77f
|
NuvioPosterShape.Landscape -> PosterLandscapeAspectRatio
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val LandscapeWidthScale = 180f / 110f
|
private data class CatalogLogoOverlaySize(
|
||||||
|
val width: Dp,
|
||||||
|
val height: Dp,
|
||||||
|
val textMaxWidth: Dp,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun catalogLogoOverlaySize(basePosterWidthDp: Int): CatalogLogoOverlaySize =
|
||||||
|
when {
|
||||||
|
basePosterWidthDp <= 108 -> CatalogLogoOverlaySize(width = 72.dp, height = 18.dp, textMaxWidth = 92.dp)
|
||||||
|
basePosterWidthDp <= 120 -> CatalogLogoOverlaySize(width = 80.dp, height = 20.dp, textMaxWidth = 104.dp)
|
||||||
|
basePosterWidthDp <= 132 -> CatalogLogoOverlaySize(width = 88.dp, height = 22.dp, textMaxWidth = 112.dp)
|
||||||
|
else -> CatalogLogoOverlaySize(width = 96.dp, height = 24.dp, textMaxWidth = 124.dp)
|
||||||
|
}
|
||||||
|
|
||||||
private fun NuvioPosterShape.cardWidth(basePosterWidthDp: Int): Dp =
|
private fun NuvioPosterShape.cardWidth(basePosterWidthDp: Int): Dp =
|
||||||
when (this) {
|
when (this) {
|
||||||
NuvioPosterShape.Poster -> basePosterWidthDp.dp
|
NuvioPosterShape.Poster -> basePosterWidthDp.dp
|
||||||
NuvioPosterShape.Square -> basePosterWidthDp.dp
|
NuvioPosterShape.Square -> basePosterWidthDp.dp
|
||||||
NuvioPosterShape.Landscape -> (basePosterWidthDp * LandscapeWidthScale).dp
|
NuvioPosterShape.Landscape -> landscapePosterWidth(basePosterWidthDp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.nuvio.app.core.ui
|
||||||
|
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
internal const val PosterLandscapeAspectRatio = 1.77f
|
||||||
|
private const val PosterLandscapeWidthScale = 180f / 110f
|
||||||
|
|
||||||
|
internal fun landscapePosterWidth(basePosterWidthDp: Int): Dp =
|
||||||
|
(basePosterWidthDp * PosterLandscapeWidthScale).dp
|
||||||
|
|
||||||
|
internal fun landscapePosterHeightForWidth(width: Dp): Dp =
|
||||||
|
(width.value / PosterLandscapeAspectRatio).dp
|
||||||
|
|
@ -17,12 +17,14 @@ private data class StoredPosterCardStylePreferences(
|
||||||
val widthDp: Int = DefaultPosterCardWidthDp,
|
val widthDp: Int = DefaultPosterCardWidthDp,
|
||||||
val heightDp: Int = DefaultPosterCardHeightDp,
|
val heightDp: Int = DefaultPosterCardHeightDp,
|
||||||
val cornerRadiusDp: Int = DefaultPosterCardCornerRadiusDp,
|
val cornerRadiusDp: Int = DefaultPosterCardCornerRadiusDp,
|
||||||
|
val catalogLandscapeModeEnabled: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class PosterCardStyleUiState(
|
data class PosterCardStyleUiState(
|
||||||
val widthDp: Int = DefaultPosterCardWidthDp,
|
val widthDp: Int = DefaultPosterCardWidthDp,
|
||||||
val heightDp: Int = DefaultPosterCardHeightDp,
|
val heightDp: Int = DefaultPosterCardHeightDp,
|
||||||
val cornerRadiusDp: Int = DefaultPosterCardCornerRadiusDp,
|
val cornerRadiusDp: Int = DefaultPosterCardCornerRadiusDp,
|
||||||
|
val catalogLandscapeModeEnabled: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
object PosterCardStyleRepository {
|
object PosterCardStyleRepository {
|
||||||
|
|
@ -69,6 +71,13 @@ object PosterCardStyleRepository {
|
||||||
persist()
|
persist()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setCatalogLandscapeModeEnabled(enabled: Boolean) {
|
||||||
|
ensureLoaded()
|
||||||
|
if (_uiState.value.catalogLandscapeModeEnabled == enabled) return
|
||||||
|
_uiState.value = _uiState.value.copy(catalogLandscapeModeEnabled = enabled)
|
||||||
|
persist()
|
||||||
|
}
|
||||||
|
|
||||||
fun resetToDefaults() {
|
fun resetToDefaults() {
|
||||||
ensureLoaded()
|
ensureLoaded()
|
||||||
if (_uiState.value == PosterCardStyleUiState()) return
|
if (_uiState.value == PosterCardStyleUiState()) return
|
||||||
|
|
@ -97,6 +106,7 @@ object PosterCardStyleRepository {
|
||||||
widthDp = widthDp,
|
widthDp = widthDp,
|
||||||
heightDp = heightDp,
|
heightDp = heightDp,
|
||||||
cornerRadiusDp = cornerRadiusDp,
|
cornerRadiusDp = cornerRadiusDp,
|
||||||
|
catalogLandscapeModeEnabled = stored.catalogLandscapeModeEnabled,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
PosterCardStyleUiState()
|
PosterCardStyleUiState()
|
||||||
|
|
@ -110,6 +120,7 @@ object PosterCardStyleRepository {
|
||||||
widthDp = _uiState.value.widthDp,
|
widthDp = _uiState.value.widthDp,
|
||||||
heightDp = _uiState.value.heightDp,
|
heightDp = _uiState.value.heightDp,
|
||||||
cornerRadiusDp = _uiState.value.cornerRadiusDp,
|
cornerRadiusDp = _uiState.value.cornerRadiusDp,
|
||||||
|
catalogLandscapeModeEnabled = _uiState.value.catalogLandscapeModeEnabled,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ import androidx.compose.ui.unit.sp
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import coil3.compose.LocalPlatformContext
|
import coil3.compose.LocalPlatformContext
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
|
import com.nuvio.app.core.ui.landscapePosterHeightForWidth
|
||||||
|
import com.nuvio.app.core.ui.landscapePosterWidth
|
||||||
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
||||||
import com.nuvio.app.features.details.components.DetailPosterRailSection
|
import com.nuvio.app.features.details.components.DetailPosterRailSection
|
||||||
import com.nuvio.app.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
|
|
@ -157,6 +159,17 @@ private fun PersonDetailContent(
|
||||||
animatedVisibilityScope: AnimatedVisibilityScope? = null,
|
animatedVisibilityScope: AnimatedVisibilityScope? = null,
|
||||||
) {
|
) {
|
||||||
val posterCardStyle = rememberPosterCardStyleUiState()
|
val posterCardStyle = rememberPosterCardStyleUiState()
|
||||||
|
val isLandscapeShelfMode = posterCardStyle.catalogLandscapeModeEnabled
|
||||||
|
val skeletonPosterWidth = if (isLandscapeShelfMode) {
|
||||||
|
landscapePosterWidth(posterCardStyle.widthDp)
|
||||||
|
} else {
|
||||||
|
posterCardStyle.widthDp.dp
|
||||||
|
}
|
||||||
|
val skeletonPosterHeight = if (isLandscapeShelfMode) {
|
||||||
|
landscapePosterHeightForWidth(skeletonPosterWidth)
|
||||||
|
} else {
|
||||||
|
posterCardStyle.heightDp.dp
|
||||||
|
}
|
||||||
val accentColor = MaterialTheme.colorScheme.primary
|
val accentColor = MaterialTheme.colorScheme.primary
|
||||||
|
|
||||||
val allCredits = remember(person.movieCredits, person.tvCredits) {
|
val allCredits = remember(person.movieCredits, person.tvCredits) {
|
||||||
|
|
@ -448,6 +461,17 @@ private fun PersonDetailSkeleton(
|
||||||
animatedVisibilityScope: AnimatedVisibilityScope? = null,
|
animatedVisibilityScope: AnimatedVisibilityScope? = null,
|
||||||
) {
|
) {
|
||||||
val posterCardStyle = rememberPosterCardStyleUiState()
|
val posterCardStyle = rememberPosterCardStyleUiState()
|
||||||
|
val isLandscapeShelfMode = posterCardStyle.catalogLandscapeModeEnabled
|
||||||
|
val skeletonPosterWidth = if (isLandscapeShelfMode) {
|
||||||
|
landscapePosterWidth(posterCardStyle.widthDp)
|
||||||
|
} else {
|
||||||
|
posterCardStyle.widthDp.dp
|
||||||
|
}
|
||||||
|
val skeletonPosterHeight = if (isLandscapeShelfMode) {
|
||||||
|
landscapePosterHeightForWidth(skeletonPosterWidth)
|
||||||
|
} else {
|
||||||
|
posterCardStyle.heightDp.dp
|
||||||
|
}
|
||||||
val accentColor = MaterialTheme.colorScheme.primary
|
val accentColor = MaterialTheme.colorScheme.primary
|
||||||
val avatarCacheKey = avatarTransitionKey
|
val avatarCacheKey = avatarTransitionKey
|
||||||
val platformContext = LocalPlatformContext.current
|
val platformContext = LocalPlatformContext.current
|
||||||
|
|
@ -602,14 +626,15 @@ private fun PersonDetailSkeleton(
|
||||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
) {
|
) {
|
||||||
repeat(4) {
|
repeat(4) {
|
||||||
Column(modifier = Modifier.width(110.dp)) {
|
Column(modifier = Modifier.width(skeletonPosterWidth)) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(110.dp)
|
.width(skeletonPosterWidth)
|
||||||
.height(163.dp)
|
.height(skeletonPosterHeight)
|
||||||
.clip(RoundedCornerShape(posterCardStyle.cornerRadiusDp.dp))
|
.clip(RoundedCornerShape(posterCardStyle.cornerRadiusDp.dp))
|
||||||
.background(MaterialTheme.colorScheme.surfaceVariant),
|
.background(MaterialTheme.colorScheme.surfaceVariant),
|
||||||
)
|
)
|
||||||
|
if (!isLandscapeShelfMode) {
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
Spacer(modifier = Modifier.height(6.dp))
|
||||||
SkeletonLine(
|
SkeletonLine(
|
||||||
widthFraction = 1f,
|
widthFraction = 1f,
|
||||||
|
|
@ -623,6 +648,7 @@ private fun PersonDetailSkeleton(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
|
import com.nuvio.app.core.ui.landscapePosterHeightForWidth
|
||||||
|
import com.nuvio.app.core.ui.landscapePosterWidth
|
||||||
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
||||||
import com.nuvio.app.features.details.components.DetailPosterRailSection
|
import com.nuvio.app.features.details.components.DetailPosterRailSection
|
||||||
import com.nuvio.app.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
|
|
@ -299,6 +301,17 @@ private fun EntityHeroSection(
|
||||||
@Composable
|
@Composable
|
||||||
private fun EntityBrowseSkeleton() {
|
private fun EntityBrowseSkeleton() {
|
||||||
val posterCardStyle = rememberPosterCardStyleUiState()
|
val posterCardStyle = rememberPosterCardStyleUiState()
|
||||||
|
val isLandscapeShelfMode = posterCardStyle.catalogLandscapeModeEnabled
|
||||||
|
val skeletonPosterWidth = if (isLandscapeShelfMode) {
|
||||||
|
landscapePosterWidth(posterCardStyle.widthDp)
|
||||||
|
} else {
|
||||||
|
posterCardStyle.widthDp.dp
|
||||||
|
}
|
||||||
|
val skeletonPosterHeight = if (isLandscapeShelfMode) {
|
||||||
|
landscapePosterHeightForWidth(skeletonPosterWidth)
|
||||||
|
} else {
|
||||||
|
posterCardStyle.heightDp.dp
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -355,8 +368,8 @@ private fun EntityBrowseSkeleton() {
|
||||||
repeat(4) {
|
repeat(4) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(110.dp)
|
.width(skeletonPosterWidth)
|
||||||
.height(163.dp)
|
.height(skeletonPosterHeight)
|
||||||
.clip(RoundedCornerShape(posterCardStyle.cornerRadiusDp.dp))
|
.clip(RoundedCornerShape(posterCardStyle.cornerRadiusDp.dp))
|
||||||
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f)),
|
.background(MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f)),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import com.nuvio.app.core.ui.NuvioShelfSection
|
import com.nuvio.app.core.ui.NuvioShelfSection
|
||||||
import com.nuvio.app.core.ui.NuvioViewAllPillSize
|
import com.nuvio.app.core.ui.NuvioViewAllPillSize
|
||||||
|
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
||||||
import com.nuvio.app.features.home.HomeCatalogSection
|
import com.nuvio.app.features.home.HomeCatalogSection
|
||||||
import com.nuvio.app.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
import com.nuvio.app.features.home.stableKey
|
import com.nuvio.app.features.home.stableKey
|
||||||
|
|
@ -62,6 +63,8 @@ private fun HomeCatalogRowSectionContent(
|
||||||
onPosterClick: ((MetaPreview) -> Unit)?,
|
onPosterClick: ((MetaPreview) -> Unit)?,
|
||||||
onPosterLongClick: ((MetaPreview) -> Unit)?,
|
onPosterLongClick: ((MetaPreview) -> Unit)?,
|
||||||
) {
|
) {
|
||||||
|
val posterCardStyle = rememberPosterCardStyleUiState()
|
||||||
|
|
||||||
NuvioShelfSection(
|
NuvioShelfSection(
|
||||||
title = section.title,
|
title = section.title,
|
||||||
entries = entries,
|
entries = entries,
|
||||||
|
|
@ -74,6 +77,7 @@ private fun HomeCatalogRowSectionContent(
|
||||||
) { item ->
|
) { item ->
|
||||||
HomePosterCard(
|
HomePosterCard(
|
||||||
item = item,
|
item = item,
|
||||||
|
useLandscapeBackdropMode = posterCardStyle.catalogLandscapeModeEnabled,
|
||||||
isWatched = WatchingState.isPosterWatched(
|
isWatched = WatchingState.isPosterWatched(
|
||||||
watchedKeys = watchedKeys,
|
watchedKeys = watchedKeys,
|
||||||
item = item,
|
item = item,
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.nuvio.app.core.ui.NuvioShelfSection
|
import com.nuvio.app.core.ui.NuvioShelfSection
|
||||||
|
import com.nuvio.app.core.ui.PosterLandscapeAspectRatio
|
||||||
import com.nuvio.app.core.ui.posterCardClickable
|
import com.nuvio.app.core.ui.posterCardClickable
|
||||||
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
||||||
import com.nuvio.app.features.collection.Collection
|
import com.nuvio.app.features.collection.Collection
|
||||||
|
|
@ -99,7 +100,7 @@ private fun CollectionFolderCard(
|
||||||
}
|
}
|
||||||
PosterShape.Landscape -> {
|
PosterShape.Landscape -> {
|
||||||
cardWidth = 180.dp
|
cardWidth = 180.dp
|
||||||
aspectRatio = 1.77f
|
aspectRatio = PosterLandscapeAspectRatio
|
||||||
}
|
}
|
||||||
PosterShape.Square -> {
|
PosterShape.Square -> {
|
||||||
cardWidth = 120.dp
|
cardWidth = 120.dp
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import androidx.compose.ui.Modifier
|
||||||
import com.nuvio.app.core.format.formatReleaseDateForDisplay
|
import com.nuvio.app.core.format.formatReleaseDateForDisplay
|
||||||
import com.nuvio.app.core.ui.NuvioPosterCard
|
import com.nuvio.app.core.ui.NuvioPosterCard
|
||||||
import com.nuvio.app.core.ui.NuvioPosterShape
|
import com.nuvio.app.core.ui.NuvioPosterShape
|
||||||
|
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
||||||
import com.nuvio.app.features.home.MetaPreview
|
import com.nuvio.app.features.home.MetaPreview
|
||||||
import com.nuvio.app.features.home.PosterShape
|
import com.nuvio.app.features.home.PosterShape
|
||||||
|
|
||||||
|
|
@ -12,16 +13,23 @@ import com.nuvio.app.features.home.PosterShape
|
||||||
fun HomePosterCard(
|
fun HomePosterCard(
|
||||||
item: MetaPreview,
|
item: MetaPreview,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
useLandscapeBackdropMode: Boolean = false,
|
||||||
isWatched: Boolean = false,
|
isWatched: Boolean = false,
|
||||||
onClick: (() -> Unit)? = null,
|
onClick: (() -> Unit)? = null,
|
||||||
onLongClick: (() -> Unit)? = null,
|
onLongClick: (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
|
val posterCardStyle = rememberPosterCardStyleUiState()
|
||||||
|
val isLandscapeMode = useLandscapeBackdropMode || posterCardStyle.catalogLandscapeModeEnabled
|
||||||
|
|
||||||
NuvioPosterCard(
|
NuvioPosterCard(
|
||||||
title = item.name,
|
title = item.name,
|
||||||
imageUrl = item.poster,
|
imageUrl = if (isLandscapeMode) (item.banner ?: item.poster) else item.poster,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
shape = item.posterShape.toNuvioPosterShape(),
|
shape = if (isLandscapeMode) NuvioPosterShape.Landscape else item.posterShape.toNuvioPosterShape(),
|
||||||
detailLine = item.releaseInfo?.let { formatReleaseDateForDisplay(it) },
|
detailLine = if (isLandscapeMode) null else item.releaseInfo?.let { formatReleaseDateForDisplay(it) },
|
||||||
|
showTitleBelow = !isLandscapeMode,
|
||||||
|
bottomLeftLogoUrl = if (isLandscapeMode) item.logo else null,
|
||||||
|
bottomLeftText = if (isLandscapeMode && item.logo.isNullOrBlank()) item.name else null,
|
||||||
isWatched = isWatched,
|
isWatched = isWatched,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onLongClick = onLongClick,
|
onLongClick = onLongClick,
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
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 com.nuvio.app.core.ui.landscapePosterHeightForWidth
|
||||||
|
import com.nuvio.app.core.ui.landscapePosterWidth
|
||||||
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -182,6 +184,16 @@ fun HomeSkeletonHero(
|
||||||
fun HomeSkeletonRow(modifier: Modifier = Modifier) {
|
fun HomeSkeletonRow(modifier: Modifier = Modifier) {
|
||||||
val brush = rememberHomeSkeletonBrush()
|
val brush = rememberHomeSkeletonBrush()
|
||||||
val posterCardStyle = rememberPosterCardStyleUiState()
|
val posterCardStyle = rememberPosterCardStyleUiState()
|
||||||
|
val skeletonWidth = if (posterCardStyle.catalogLandscapeModeEnabled) {
|
||||||
|
landscapePosterWidth(posterCardStyle.widthDp)
|
||||||
|
} else {
|
||||||
|
posterCardStyle.widthDp.dp
|
||||||
|
}
|
||||||
|
val skeletonHeight = if (posterCardStyle.catalogLandscapeModeEnabled) {
|
||||||
|
landscapePosterHeightForWidth(skeletonWidth)
|
||||||
|
} else {
|
||||||
|
posterCardStyle.heightDp.dp
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
|
@ -211,8 +223,8 @@ fun HomeSkeletonRow(modifier: Modifier = Modifier) {
|
||||||
repeat(4) {
|
repeat(4) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(posterCardStyle.widthDp.dp)
|
.width(skeletonWidth)
|
||||||
.height(posterCardStyle.heightDp.dp)
|
.height(skeletonHeight)
|
||||||
.clip(RoundedCornerShape(posterCardStyle.cornerRadiusDp.dp))
|
.clip(RoundedCornerShape(posterCardStyle.cornerRadiusDp.dp))
|
||||||
.background(brush),
|
.background(brush),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.FilterChip
|
import androidx.compose.material3.FilterChip
|
||||||
import androidx.compose.material3.FilterChipDefaults
|
import androidx.compose.material3.FilterChipDefaults
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
|
import androidx.compose.material3.SwitchDefaults
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -51,8 +53,10 @@ internal fun LazyListScope.posterCustomizationSettingsContent(
|
||||||
isTablet = isTablet,
|
isTablet = isTablet,
|
||||||
widthDp = uiState.widthDp,
|
widthDp = uiState.widthDp,
|
||||||
cornerRadiusDp = uiState.cornerRadiusDp,
|
cornerRadiusDp = uiState.cornerRadiusDp,
|
||||||
|
catalogLandscapeModeEnabled = uiState.catalogLandscapeModeEnabled,
|
||||||
onWidthSelected = PosterCardStyleRepository::setWidthDp,
|
onWidthSelected = PosterCardStyleRepository::setWidthDp,
|
||||||
onCornerRadiusSelected = PosterCardStyleRepository::setCornerRadiusDp,
|
onCornerRadiusSelected = PosterCardStyleRepository::setCornerRadiusDp,
|
||||||
|
onCatalogLandscapeModeChange = PosterCardStyleRepository::setCatalogLandscapeModeEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -65,8 +69,10 @@ private fun PosterCardStyleControls(
|
||||||
isTablet: Boolean,
|
isTablet: Boolean,
|
||||||
widthDp: Int,
|
widthDp: Int,
|
||||||
cornerRadiusDp: Int,
|
cornerRadiusDp: Int,
|
||||||
|
catalogLandscapeModeEnabled: Boolean,
|
||||||
onWidthSelected: (Int) -> Unit,
|
onWidthSelected: (Int) -> Unit,
|
||||||
onCornerRadiusSelected: (Int) -> Unit,
|
onCornerRadiusSelected: (Int) -> Unit,
|
||||||
|
onCatalogLandscapeModeChange: (Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
val widthOptions = listOf(
|
val widthOptions = listOf(
|
||||||
PresetOption("Compact", 104),
|
PresetOption("Compact", 104),
|
||||||
|
|
@ -111,6 +117,39 @@ private fun PosterCardStyleControls(
|
||||||
options = radiusOptions,
|
options = radiusOptions,
|
||||||
onSelected = onCornerRadiusSelected,
|
onSelected = onCornerRadiusSelected,
|
||||||
)
|
)
|
||||||
|
PosterLandscapeModeToggleRow(
|
||||||
|
checked = catalogLandscapeModeEnabled,
|
||||||
|
onCheckedChange = onCatalogLandscapeModeChange,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PosterLandscapeModeToggleRow(
|
||||||
|
checked: Boolean,
|
||||||
|
onCheckedChange: (Boolean) -> Unit,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Landscape mode for shelf posters",
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
)
|
||||||
|
Switch(
|
||||||
|
checked = checked,
|
||||||
|
onCheckedChange = onCheckedChange,
|
||||||
|
colors = SwitchDefaults.colors(
|
||||||
|
checkedThumbColor = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
checkedTrackColor = MaterialTheme.colorScheme.primary,
|
||||||
|
uncheckedThumbColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
uncheckedTrackColor = MaterialTheme.colorScheme.outlineVariant,
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue