Show duration & ends at time on next up card (#1690)
## Description Adds the duration & ends at time to the next up card ### Related issues Closes #1664 ### Testing <!-- Describe how this change was tested and on what device(s) --> ## Screenshots <img width="660" height="241" alt="image" src="https://github.com/user-attachments/assets/7551843e-4f53-43fc-af2a-3e503ba6d03c" /> ## AI or LLM usage None
This commit is contained in:
parent
f74306a12c
commit
077b7e4570
2 changed files with 73 additions and 27 deletions
|
|
@ -10,10 +10,8 @@ import androidx.compose.foundation.layout.aspectRatio
|
|||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
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.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
|
|
@ -21,6 +19,7 @@ import androidx.compose.material.icons.filled.PlayArrow
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -29,7 +28,10 @@ import androidx.compose.ui.focus.focusRequester
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalResources
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
|
@ -47,10 +49,17 @@ import com.github.damontecres.wholphin.R
|
|||
import com.github.damontecres.wholphin.ui.AppColors
|
||||
import com.github.damontecres.wholphin.ui.AspectRatios
|
||||
import com.github.damontecres.wholphin.ui.PreviewTvSpec
|
||||
import com.github.damontecres.wholphin.ui.dot
|
||||
import com.github.damontecres.wholphin.ui.formatDuration
|
||||
import com.github.damontecres.wholphin.ui.formatTime
|
||||
import com.github.damontecres.wholphin.ui.theme.WholphinTheme
|
||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||
import com.github.damontecres.wholphin.ui.util.Clock
|
||||
import com.github.damontecres.wholphin.ui.util.LocalClock
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
import kotlin.time.toJavaDuration
|
||||
|
||||
/**
|
||||
* Layout for showing the next up episode during playback
|
||||
|
|
@ -64,6 +73,7 @@ fun NextUpEpisode(
|
|||
timeLeft: Duration?,
|
||||
modifier: Modifier = Modifier,
|
||||
aspectRatio: Float = AspectRatios.WIDE,
|
||||
runtime: Duration? = null,
|
||||
) {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
|
@ -122,9 +132,36 @@ fun NextUpEpisode(
|
|||
text = description ?: "",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 4,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier,
|
||||
)
|
||||
runtime?.let {
|
||||
val context = LocalContext.current
|
||||
val resources = LocalResources.current
|
||||
val now by LocalClock.current.now
|
||||
val text =
|
||||
remember(now, runtime) {
|
||||
buildAnnotatedString {
|
||||
append(resources.formatDuration(runtime))
|
||||
dot()
|
||||
val endsAt = now.plus(runtime.toJavaDuration())
|
||||
val endTimeStr = formatTime(context, endsAt)
|
||||
append(resources.getString(R.string.ends_at, endTimeStr))
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(top = 4.dp)
|
||||
.align(Alignment.Start),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,34 +226,41 @@ fun NextUpCard(
|
|||
@Composable
|
||||
private fun NextUpEpisodePreview() {
|
||||
WholphinTheme(true) {
|
||||
val theme = MaterialTheme.colorScheme
|
||||
val previewHandler =
|
||||
AsyncImagePreviewHandler {
|
||||
ColorImage(Color.Blue.toArgb())
|
||||
ColorImage(theme.surfaceVariant.toArgb())
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize().background(Color.Black),
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalAsyncImagePreviewHandler provides previewHandler,
|
||||
LocalClock provides Clock(),
|
||||
) {
|
||||
NextUpEpisode(
|
||||
title = "Episode Title",
|
||||
description =
|
||||
"This is the description of the episode. It might be long. " +
|
||||
"It might be very, very long and overflow the available space. " +
|
||||
"But it just keeps going and going.",
|
||||
imageUrl = "",
|
||||
onClick = {},
|
||||
aspectRatio = AspectRatios.WIDE,
|
||||
timeLeft = 30.seconds,
|
||||
runtime = 32.minutes + 20.seconds,
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(8.dp)
|
||||
.fillMaxHeight(.4f)
|
||||
.fillMaxWidth(.66f)
|
||||
.align(Alignment.BottomCenter)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
CompositionLocalProvider(LocalAsyncImagePreviewHandler provides previewHandler) {
|
||||
NextUpEpisode(
|
||||
title = "Episode Title",
|
||||
description =
|
||||
"This is the description of the episode. It might be long. " +
|
||||
"It might be very, very long and overflow the available space. " +
|
||||
"But it just keeps going and going.",
|
||||
imageUrl = "",
|
||||
onClick = {},
|
||||
aspectRatio = AspectRatios.FOUR_THREE,
|
||||
timeLeft = 30.seconds,
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(16.dp)
|
||||
.height(200.dp)
|
||||
.width(400.dp)
|
||||
// .fillMaxWidth(.4f)
|
||||
// .align(Alignment.BottomCenter)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ import com.github.damontecres.wholphin.util.Media3SubtitleOverride
|
|||
import io.github.peerless2012.ass.media.widget.AssSubtitleView
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.extensions.ticks
|
||||
import timber.log.Timber
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
|
@ -600,6 +601,7 @@ fun PlaybackPageContent(
|
|||
viewModel.playNextUp()
|
||||
},
|
||||
timeLeft = if (autoPlayEnabled) timeLeft.seconds else null,
|
||||
runtime = it.data.runTimeTicks?.ticks,
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(8.dp)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue