mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Move stream labels to top of description (#323)
Follow up to #279 Closes #162 Move the stream labels to the top under the dot-separated details. Also move the rating up to the dot-separated details line and add it to home page.
This commit is contained in:
parent
5b96be6662
commit
0bfe3d2653
10 changed files with 114 additions and 112 deletions
|
|
@ -1,5 +1,6 @@
|
|||
package com.github.damontecres.wholphin.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -14,7 +15,7 @@ import coil3.compose.AsyncImage
|
|||
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
||||
|
||||
@Composable
|
||||
fun DetailsBackdropImage(
|
||||
fun BoxScope.DetailsBackdropImage(
|
||||
backdropImageUrl: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
|
@ -23,10 +24,11 @@ fun DetailsBackdropImage(
|
|||
AsyncImage(
|
||||
model = backdropImageUrl,
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Crop,
|
||||
contentScale = ContentScale.Fit,
|
||||
alignment = Alignment.TopEnd,
|
||||
modifier =
|
||||
modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.fillMaxHeight(.85f)
|
||||
.alpha(.75f)
|
||||
.drawWithContent {
|
||||
|
|
|
|||
|
|
@ -23,20 +23,26 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.tv.material3.LocalTextStyle
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
import androidx.tv.material3.Text
|
||||
import com.github.damontecres.wholphin.ui.PreviewTvSpec
|
||||
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
|
||||
|
||||
@Composable
|
||||
fun DotSeparatedRow(
|
||||
texts: List<String>,
|
||||
rating: Float? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
textStyle: TextStyle = MaterialTheme.typography.titleSmall,
|
||||
) {
|
||||
CompositionLocalProvider(LocalTextStyle provides textStyle) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
|
@ -47,7 +53,7 @@ fun DotSeparatedRow(
|
|||
style = textStyle,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
if (index != texts.lastIndex) {
|
||||
if (rating != null || index != texts.lastIndex) {
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
|
|
@ -58,5 +64,24 @@ fun DotSeparatedRow(
|
|||
)
|
||||
}
|
||||
}
|
||||
rating?.let {
|
||||
SimpleStarRating(
|
||||
communityRating = it,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewTvSpec
|
||||
@Composable
|
||||
private fun DotSeparatedRowPreview() {
|
||||
WholphinTheme {
|
||||
DotSeparatedRow(
|
||||
texts = listOf("2025", "1h 48m", "PG-13", "1h 30m left"),
|
||||
rating = 7.5f,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Star
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
|
@ -36,7 +37,6 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.tv.material3.Icon
|
||||
import androidx.tv.material3.LocalContentColor
|
||||
import androidx.tv.material3.MaterialTheme
|
||||
|
|
@ -77,17 +77,17 @@ val ratingBarHeight: Dp = 32.dp
|
|||
fun SimpleStarRating(
|
||||
communityRating: Float?,
|
||||
modifier: Modifier = Modifier,
|
||||
) = SimpleStarRating(
|
||||
) = CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) {
|
||||
SimpleStarRating(
|
||||
text = communityRating?.let { String.format(Locale.getDefault(), "%.1f", it) },
|
||||
modifier = modifier,
|
||||
textColor = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SimpleStarRating(
|
||||
text: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
textColor: Color = LocalContentColor.current,
|
||||
starColor: Color = FilledStarColor,
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -98,8 +98,6 @@ fun SimpleStarRating(
|
|||
if (text.isNotNullOrBlank()) {
|
||||
Text(
|
||||
text = text,
|
||||
fontSize = 14.sp,
|
||||
color = textColor,
|
||||
modifier = Modifier,
|
||||
)
|
||||
Icon(
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ fun StreamLabel(
|
|||
modifier =
|
||||
modifier
|
||||
.background(
|
||||
MaterialTheme.colorScheme.secondaryContainer,
|
||||
MaterialTheme.colorScheme.secondaryContainer.copy(alpha = .5f),
|
||||
// MaterialTheme.colorScheme.surfaceVariant,
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
).padding(vertical = 4.dp, horizontal = 6.dp),
|
||||
|
|
@ -245,8 +245,8 @@ private fun StreamLabelPreview() {
|
|||
.padding(8.dp),
|
||||
) {
|
||||
StreamLabel("1080p")
|
||||
StreamLabel("H264")
|
||||
StreamLabel("HDR")
|
||||
StreamLabel("H264")
|
||||
StreamLabel("AC3 5.1", icon = R.string.fa_volume_high, count = 2)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
|
|
@ -61,7 +62,6 @@ import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
|||
import com.github.damontecres.wholphin.ui.components.ExpandablePlayButtons
|
||||
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
||||
import com.github.damontecres.wholphin.ui.components.Optional
|
||||
import com.github.damontecres.wholphin.ui.components.VideoStreamDetails
|
||||
import com.github.damontecres.wholphin.ui.components.chooseStream
|
||||
import com.github.damontecres.wholphin.ui.components.chooseVersionParams
|
||||
import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel
|
||||
|
|
@ -391,7 +391,6 @@ fun MovieDetailsContent(
|
|||
Modifier
|
||||
.fillMaxWidth()
|
||||
.bringIntoViewRequester(bringIntoViewRequester),
|
||||
// .padding(bottom = 16.dp),
|
||||
) {
|
||||
MovieDetailsHeader(
|
||||
preferences = preferences,
|
||||
|
|
@ -399,7 +398,10 @@ fun MovieDetailsContent(
|
|||
chosenStreams = chosenStreams,
|
||||
bringIntoViewRequester = bringIntoViewRequester,
|
||||
overviewOnClick = overviewOnClick,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 32.dp, bottom = 16.dp),
|
||||
)
|
||||
ExpandablePlayButtons(
|
||||
resumePosition = resumePosition,
|
||||
|
|
@ -420,18 +422,13 @@ fun MovieDetailsContent(
|
|||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.focusRequester(focusRequesters[HEADER_ROW]),
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(bottom = 16.dp)
|
||||
.focusRequester(focusRequesters[HEADER_ROW]),
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
VideoStreamDetails(
|
||||
preferences = preferences,
|
||||
dto = dto,
|
||||
itemPlayback = chosenStreams?.itemPlayback,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
if (people.isNotEmpty()) {
|
||||
item {
|
||||
PersonRow(
|
||||
|
|
|
|||
|
|
@ -4,18 +4,17 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
|||
import androidx.compose.foundation.interaction.collectIsFocusedAsState
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.relocation.BringIntoViewRequester
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -27,7 +26,7 @@ import com.github.damontecres.wholphin.data.model.BaseItem
|
|||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.ui.components.DotSeparatedRow
|
||||
import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||
import com.github.damontecres.wholphin.ui.components.SimpleStarRating
|
||||
import com.github.damontecres.wholphin.ui.components.VideoStreamDetails
|
||||
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
||||
import com.github.damontecres.wholphin.ui.roundMinutes
|
||||
import com.github.damontecres.wholphin.ui.timeRemaining
|
||||
|
|
@ -54,51 +53,49 @@ fun MovieDetailsHeader(
|
|||
Text(
|
||||
text = movie.name ?: "",
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.displayMedium,
|
||||
style = MaterialTheme.typography.displaySmall,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.fillMaxWidth(.75f),
|
||||
)
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = Modifier.fillMaxWidth(.60f),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
val padding = 8.dp
|
||||
val details =
|
||||
remember(dto) {
|
||||
buildList {
|
||||
dto.productionYear?.let { add(it.toString()) }
|
||||
val duration = dto.runTimeTicks?.ticks
|
||||
duration
|
||||
?.roundMinutes
|
||||
?.toString()
|
||||
?.let {
|
||||
add(it)
|
||||
}
|
||||
dto.officialRating?.let(::add)
|
||||
?.let(::add)
|
||||
dto.timeRemaining?.roundMinutes?.let { add("$it left") }
|
||||
dto.officialRating?.let(::add)
|
||||
}
|
||||
}
|
||||
DotSeparatedRow(
|
||||
texts = details,
|
||||
rating = dto.communityRating,
|
||||
textStyle = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier,
|
||||
modifier = Modifier.padding(bottom = padding),
|
||||
)
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
SimpleStarRating(
|
||||
dto.communityRating,
|
||||
Modifier.height(20.dp),
|
||||
|
||||
VideoStreamDetails(
|
||||
preferences = preferences,
|
||||
dto = dto,
|
||||
itemPlayback = chosenStreams?.itemPlayback,
|
||||
modifier = Modifier.padding(bottom = padding),
|
||||
)
|
||||
}
|
||||
dto.taglines?.firstOrNull()?.let { tagline ->
|
||||
Text(
|
||||
text = tagline,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
fontStyle = FontStyle.Italic,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import com.github.damontecres.wholphin.data.ChosenStreams
|
|||
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.ui.components.ExpandablePlayButtons
|
||||
import com.github.damontecres.wholphin.ui.components.VideoStreamDetails
|
||||
import org.jellyfin.sdk.model.extensions.ticks
|
||||
import kotlin.time.Duration
|
||||
|
||||
|
|
@ -45,11 +44,5 @@ fun FocusedEpisodeFooter(
|
|||
buttonOnFocusChanged = {},
|
||||
modifier = Modifier,
|
||||
)
|
||||
VideoStreamDetails(
|
||||
preferences = preferences,
|
||||
dto = dto,
|
||||
itemPlayback = chosenStreams?.itemPlayback,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@ package com.github.damontecres.wholphin.ui.detail.series
|
|||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
|
|
@ -17,7 +15,7 @@ import com.github.damontecres.wholphin.data.model.BaseItem
|
|||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.ui.components.DotSeparatedRow
|
||||
import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||
import com.github.damontecres.wholphin.ui.components.SimpleStarRating
|
||||
import com.github.damontecres.wholphin.ui.components.VideoStreamDetails
|
||||
import com.github.damontecres.wholphin.ui.formatDateTime
|
||||
import com.github.damontecres.wholphin.ui.roundMinutes
|
||||
import com.github.damontecres.wholphin.ui.seasonEpisode
|
||||
|
|
@ -45,10 +43,8 @@ fun FocusedEpisodeHeader(
|
|||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier,
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
val details =
|
||||
remember(dto) {
|
||||
buildList {
|
||||
dto?.seasonEpisode?.let(::add)
|
||||
dto?.premiereDate?.let { add(formatDateTime(it)) }
|
||||
|
|
@ -56,24 +52,23 @@ fun FocusedEpisodeHeader(
|
|||
duration
|
||||
?.roundMinutes
|
||||
?.toString()
|
||||
?.let {
|
||||
add(it)
|
||||
}
|
||||
dto?.officialRating?.let(::add)
|
||||
?.let(::add)
|
||||
dto?.timeRemaining?.roundMinutes?.let { add("$it left") }
|
||||
dto?.officialRating?.let(::add)
|
||||
}
|
||||
}
|
||||
DotSeparatedRow(
|
||||
texts = details,
|
||||
rating = dto?.communityRating,
|
||||
textStyle = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
SimpleStarRating(
|
||||
dto?.communityRating,
|
||||
Modifier.height(20.dp),
|
||||
|
||||
if (dto != null) {
|
||||
VideoStreamDetails(
|
||||
preferences = preferences,
|
||||
dto = dto,
|
||||
itemPlayback = chosenStreams?.itemPlayback,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
OverviewText(
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.relocation.BringIntoViewRequester
|
||||
|
|
@ -30,6 +29,7 @@ import androidx.compose.ui.focus.onFocusChanged
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
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
|
||||
|
|
@ -60,7 +60,6 @@ import com.github.damontecres.wholphin.ui.components.ExpandablePlayButton
|
|||
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
||||
import com.github.damontecres.wholphin.ui.components.Optional
|
||||
import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||
import com.github.damontecres.wholphin.ui.components.SimpleStarRating
|
||||
import com.github.damontecres.wholphin.ui.data.AddPlaylistViewModel
|
||||
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialog
|
||||
import com.github.damontecres.wholphin.ui.data.ItemDetailsDialogInfo
|
||||
|
|
@ -584,23 +583,18 @@ fun SeriesDetailsHeader(
|
|||
)
|
||||
DotSeparatedRow(
|
||||
texts = details,
|
||||
rating = dto.communityRating,
|
||||
textStyle = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
|
||||
dto.genres?.letNotEmpty {
|
||||
Text(
|
||||
text = it.joinToString(", "),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
||||
SimpleStarRating(
|
||||
dto.communityRating,
|
||||
Modifier.height(20.dp),
|
||||
)
|
||||
|
||||
dto.overview?.let { overview ->
|
||||
OverviewText(
|
||||
overview = overview,
|
||||
|
|
|
|||
|
|
@ -502,6 +502,7 @@ fun HomePageHeader(
|
|||
if (details.isNotEmpty()) {
|
||||
DotSeparatedRow(
|
||||
texts = details,
|
||||
rating = item.data.communityRating,
|
||||
textStyle = MaterialTheme.typography.bodyLarge,
|
||||
modifier = Modifier,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue