mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Updates to series overview
This commit is contained in:
parent
31b4881d7c
commit
f96ed850b7
5 changed files with 83 additions and 37 deletions
|
|
@ -5,6 +5,8 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
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.Row
|
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.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
|
@ -12,6 +14,8 @@ import androidx.compose.material.icons.filled.CheckCircle
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
@ -25,13 +29,14 @@ import com.github.damontecres.dolphin.ui.isNotNullOrBlank
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BannerCard(
|
fun BannerCard(
|
||||||
imageUrl: String,
|
imageUrl: String?,
|
||||||
cornerText: String?,
|
cornerText: String?,
|
||||||
played: Boolean,
|
played: Boolean,
|
||||||
|
playPercent: Double,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
cardWidth: Dp = 160.dp,
|
cardWidth: Dp = 200.dp,
|
||||||
cardHeight: Dp = cardWidth * 9 / 16,
|
cardHeight: Dp = cardWidth * 9 / 16,
|
||||||
interactionSource: MutableInteractionSource? = null,
|
interactionSource: MutableInteractionSource? = null,
|
||||||
) {
|
) {
|
||||||
|
|
@ -52,7 +57,10 @@ fun BannerCard(
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier.align(Alignment.TopEnd),
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.align(Alignment.TopEnd)
|
||||||
|
.padding(4.dp),
|
||||||
) {
|
) {
|
||||||
if (played) {
|
if (played) {
|
||||||
Icon(
|
Icon(
|
||||||
|
|
@ -61,20 +69,37 @@ fun BannerCard(
|
||||||
tint = MaterialTheme.colorScheme.border.copy(alpha = 1f),
|
tint = MaterialTheme.colorScheme.border.copy(alpha = 1f),
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.size(48.dp)
|
.size(24.dp),
|
||||||
.padding(8.dp),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (cornerText.isNotNullOrBlank()) {
|
if (cornerText.isNotNullOrBlank()) {
|
||||||
Text(
|
Box(
|
||||||
text = cornerText,
|
modifier =
|
||||||
style = MaterialTheme.typography.bodySmall,
|
Modifier
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
.background(AppColors.TransparentBlack50),
|
||||||
modifier = Modifier.background(AppColors.TransparentBlack50),
|
) {
|
||||||
)
|
Text(
|
||||||
|
text = cornerText,
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
modifier = Modifier.padding(4.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (playPercent > 0 && playPercent < 100) {
|
||||||
|
Box(
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.align(Alignment.BottomStart)
|
||||||
|
.background(
|
||||||
|
MaterialTheme.colorScheme.tertiary,
|
||||||
|
).clip(RectangleShape)
|
||||||
|
.height(4.dp)
|
||||||
|
.fillMaxWidth((playPercent / 100).toFloat()),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ class SeriesViewModel
|
||||||
ItemFields.PRIMARY_IMAGE_ASPECT_RATIO,
|
ItemFields.PRIMARY_IMAGE_ASPECT_RATIO,
|
||||||
ItemFields.CHILD_COUNT,
|
ItemFields.CHILD_COUNT,
|
||||||
ItemFields.MEDIA_STREAMS,
|
ItemFields.MEDIA_STREAMS,
|
||||||
|
ItemFields.OVERVIEW,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
val pager = ItemPager(api, request, viewModelScope)
|
val pager = ItemPager(api, request, viewModelScope)
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ fun FocusedEpisodeFooter(
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
) {
|
) {
|
||||||
dto.mediaStreams
|
dto.mediaStreams
|
||||||
?.firstOrNull { it.type == MediaStreamType.VIDEO }
|
?.firstOrNull { it.type == MediaStreamType.VIDEO }
|
||||||
|
|
@ -133,12 +133,17 @@ fun FocusedEpisodeFooter(
|
||||||
dto.mediaStreams
|
dto.mediaStreams
|
||||||
?.firstOrNull { it.type == MediaStreamType.AUDIO }
|
?.firstOrNull { it.type == MediaStreamType.AUDIO }
|
||||||
?.let { stream ->
|
?.let { stream ->
|
||||||
stream.displayTitle?.let {
|
// TODO probably a cleaner way to do this
|
||||||
TitleValueText(
|
// Removes part of "5.1 Surround - English - AAC - Default"
|
||||||
"Audio",
|
stream.displayTitle
|
||||||
it,
|
?.replace(" - Default", "")
|
||||||
)
|
?.ifBlank { null }
|
||||||
}
|
?.let {
|
||||||
|
TitleValueText(
|
||||||
|
"Audio",
|
||||||
|
it,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dto.mediaStreams
|
dto.mediaStreams
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ fun FocusedEpisodeHeader(
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = dto.episodeTitle ?: dto.name ?: "",
|
text = dto.episodeTitle ?: dto.name ?: "",
|
||||||
style = MaterialTheme.typography.headlineMedium,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
)
|
)
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -64,18 +64,20 @@ fun FocusedEpisodeHeader(
|
||||||
}
|
}
|
||||||
DotSeparatedRow(
|
DotSeparatedRow(
|
||||||
texts = details,
|
texts = details,
|
||||||
textStyle = MaterialTheme.typography.titleLarge,
|
textStyle = MaterialTheme.typography.titleSmall,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(
|
dto.criticRating?.let {
|
||||||
text = "Critic: ${dto.criticRating}",
|
Text(
|
||||||
style = MaterialTheme.typography.bodySmall,
|
text = "Critic: ${dto.criticRating}",
|
||||||
modifier = Modifier,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
)
|
modifier = Modifier,
|
||||||
|
)
|
||||||
|
}
|
||||||
StarRating(
|
StarRating(
|
||||||
rating100 =
|
rating100 =
|
||||||
dto
|
dto
|
||||||
|
|
@ -115,11 +117,14 @@ fun FocusedEpisodeHeader(
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = overview,
|
text = overview,
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
maxLines = 3,
|
maxLines = 3,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.padding(8.dp),
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.height(60.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.drawWithContent
|
import androidx.compose.ui.draw.drawWithContent
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
|
@ -38,7 +39,7 @@ import androidx.tv.material3.TabRow
|
||||||
import androidx.tv.material3.Text
|
import androidx.tv.material3.Text
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import com.github.damontecres.dolphin.data.model.BaseItem
|
import com.github.damontecres.dolphin.data.model.BaseItem
|
||||||
import com.github.damontecres.dolphin.ui.cards.ItemCard
|
import com.github.damontecres.dolphin.ui.cards.BannerCard
|
||||||
import com.github.damontecres.dolphin.ui.ifElse
|
import com.github.damontecres.dolphin.ui.ifElse
|
||||||
import com.github.damontecres.dolphin.ui.isNotNullOrBlank
|
import com.github.damontecres.dolphin.ui.isNotNullOrBlank
|
||||||
|
|
||||||
|
|
@ -81,7 +82,8 @@ fun SeriesOverviewContent(
|
||||||
alignment = Alignment.TopEnd,
|
alignment = Alignment.TopEnd,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxHeight(.5f)
|
.fillMaxHeight(.6f)
|
||||||
|
.alpha(.4f)
|
||||||
.drawWithContent {
|
.drawWithContent {
|
||||||
drawContent()
|
drawContent()
|
||||||
drawRect(
|
drawRect(
|
||||||
|
|
@ -110,8 +112,10 @@ fun SeriesOverviewContent(
|
||||||
selectedTabIndex = selectedTabIndex,
|
selectedTabIndex = selectedTabIndex,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.ifElse(focusRequesters.size > selectedTabIndex, { Modifier.focusRestorer(focusRequesters[selectedTabIndex]) })
|
.ifElse(
|
||||||
.focusRequester(tabRowFocusRequester)
|
focusRequesters.size > selectedTabIndex,
|
||||||
|
{ Modifier.focusRestorer(focusRequesters[selectedTabIndex]) },
|
||||||
|
).focusRequester(tabRowFocusRequester)
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
|
|
@ -142,7 +146,7 @@ fun SeriesOverviewContent(
|
||||||
series.name?.let {
|
series.name?.let {
|
||||||
Text(
|
Text(
|
||||||
text = it,
|
text = it,
|
||||||
style = MaterialTheme.typography.headlineLarge,
|
style = MaterialTheme.typography.headlineMedium,
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +159,7 @@ fun SeriesOverviewContent(
|
||||||
overviewOnClick = {
|
overviewOnClick = {
|
||||||
// TODO show full overview dialog
|
// TODO show full overview dialog
|
||||||
},
|
},
|
||||||
modifier = Modifier,
|
modifier = Modifier.fillMaxWidth(.66f),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -165,7 +169,7 @@ fun SeriesOverviewContent(
|
||||||
LazyRow(
|
LazyRow(
|
||||||
state = state,
|
state = state,
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
contentPadding = PaddingValues(start = 32.dp),
|
contentPadding = PaddingValues(start = 16.dp),
|
||||||
modifier = modifier.focusRestorer(firstItemFocusRequester),
|
modifier = modifier.focusRestorer(firstItemFocusRequester),
|
||||||
) {
|
) {
|
||||||
itemsIndexed(episodes) { index, episode ->
|
itemsIndexed(episodes) { index, episode ->
|
||||||
|
|
@ -173,8 +177,11 @@ fun SeriesOverviewContent(
|
||||||
if (interactionSource.collectIsFocusedAsState().value) {
|
if (interactionSource.collectIsFocusedAsState().value) {
|
||||||
onFocus.invoke(SeasonEpisode(selectedTabIndex, index))
|
onFocus.invoke(SeasonEpisode(selectedTabIndex, index))
|
||||||
}
|
}
|
||||||
ItemCard(
|
BannerCard(
|
||||||
item = episode,
|
imageUrl = episode?.imageUrl,
|
||||||
|
cornerText = "E${episode?.data?.indexNumber}",
|
||||||
|
played = episode?.data?.userData?.played ?: false,
|
||||||
|
playPercent = episode?.data?.userData?.playedPercentage ?: 0.0,
|
||||||
onClick = { if (episode != null) onClick.invoke(episode) },
|
onClick = { if (episode != null) onClick.invoke(episode) },
|
||||||
onLongClick = { if (episode != null) onLongClick.invoke(episode) },
|
onLongClick = { if (episode != null) onLongClick.invoke(episode) },
|
||||||
modifier =
|
modifier =
|
||||||
|
|
@ -195,7 +202,10 @@ fun SeriesOverviewContent(
|
||||||
playOnClick = {},
|
playOnClick = {},
|
||||||
moreOnClick = {},
|
moreOnClick = {},
|
||||||
watchOnClick = {},
|
watchOnClick = {},
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(start = 16.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue