-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
802 player time api #814
base: main
Are you sure you want to change the base?
802 player time api #814
Changes from all commits
6e875d3
11e5b84
f6115a1
b0a5656
0b2c607
e0efad9
a68693e
fcc8786
7f6337b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/* | ||
* Copyright (c) SRG SSR. All rights reserved. | ||
* License information is available from the LICENSE file. | ||
*/ | ||
package ch.srgssr.pillarbox.demo.shared.ui | ||
|
||
import kotlinx.datetime.LocalTime | ||
import kotlinx.datetime.format.Padding | ||
import kotlinx.datetime.format.char | ||
|
||
/** | ||
* Local time formatter that format [LocalTime] to HH:mm:ss. | ||
*/ | ||
val localTimeFormatter by lazy { | ||
LocalTime.Format { | ||
hour(Padding.ZERO) | ||
char(':') | ||
minute(Padding.ZERO) | ||
char(':') | ||
second(Padding.ZERO) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,6 +51,7 @@ import ch.srgssr.pillarbox.demo.shared.R | |
import ch.srgssr.pillarbox.demo.shared.extension.onDpadEvent | ||
import ch.srgssr.pillarbox.demo.shared.ui.components.PillarboxSlider | ||
import ch.srgssr.pillarbox.demo.shared.ui.getFormatter | ||
import ch.srgssr.pillarbox.demo.shared.ui.localTimeFormatter | ||
import ch.srgssr.pillarbox.demo.shared.ui.player.metrics.MetricsOverlay | ||
import ch.srgssr.pillarbox.demo.shared.ui.settings.MetricsOverlayOptions | ||
import ch.srgssr.pillarbox.demo.tv.ui.player.compose.controls.PlayerError | ||
|
@@ -60,19 +61,24 @@ import ch.srgssr.pillarbox.demo.tv.ui.theme.paddings | |
import ch.srgssr.pillarbox.player.PillarboxExoPlayer | ||
import ch.srgssr.pillarbox.player.currentPositionAsFlow | ||
import ch.srgssr.pillarbox.player.extension.canSeek | ||
import ch.srgssr.pillarbox.player.extension.getUnixTimeMs | ||
import ch.srgssr.pillarbox.ui.extension.availableCommandsAsState | ||
import ch.srgssr.pillarbox.ui.extension.currentMediaMetadataAsState | ||
import ch.srgssr.pillarbox.ui.extension.currentPositionAsState | ||
import ch.srgssr.pillarbox.ui.extension.durationAsState | ||
import ch.srgssr.pillarbox.ui.extension.getCurrentChapterAsState | ||
import ch.srgssr.pillarbox.ui.extension.getCurrentCreditAsState | ||
import ch.srgssr.pillarbox.ui.extension.isCurrentMediaItemLiveAsState | ||
import ch.srgssr.pillarbox.ui.extension.playerErrorAsState | ||
import ch.srgssr.pillarbox.ui.widget.DelayedVisibilityState | ||
import ch.srgssr.pillarbox.ui.widget.maintainVisibleOnFocus | ||
import ch.srgssr.pillarbox.ui.widget.player.PlayerSurface | ||
import ch.srgssr.pillarbox.ui.widget.rememberDelayedVisibilityState | ||
import kotlinx.coroutines.delay | ||
import kotlinx.coroutines.flow.map | ||
import kotlinx.datetime.Instant | ||
import kotlinx.datetime.TimeZone | ||
import kotlinx.datetime.toLocalDateTime | ||
import kotlin.time.Duration.Companion.ZERO | ||
import kotlin.time.Duration.Companion.milliseconds | ||
import kotlin.time.Duration.Companion.seconds | ||
|
@@ -306,9 +312,19 @@ private fun PlayerTimeRow( | |
var compactMode by remember { | ||
mutableStateOf(true) | ||
} | ||
val isLive by player.isCurrentMediaItemLiveAsState() | ||
val positionTime = if (isLive) player.getUnixTimeMs(positionMs) else C.TIME_UNSET | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't we pass a |
||
val positionLabel = when (positionTime) { | ||
C.TIME_UNSET -> formatter(positionMs.milliseconds) | ||
|
||
else -> { | ||
val localTime = Instant.fromEpochMilliseconds(positionTime).toLocalDateTime(TimeZone.currentSystemDefault()).time | ||
localTimeFormatter.format(localTime) | ||
} | ||
} | ||
|
||
Text( | ||
text = "${formatter(positionMs.milliseconds)} / ${formatter(duration)}", | ||
text = "$positionLabel / ${formatter(duration)}", | ||
modifier = Modifier.padding( | ||
top = MaterialTheme.paddings.baseline, | ||
bottom = MaterialTheme.paddings.small, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
* Copyright (c) SRG SSR. All rights reserved. | ||
* License information is available from the LICENSE file. | ||
*/ | ||
package ch.srgssr.pillarbox.demo.ui.showcases.misc | ||
|
||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.foundation.lazy.LazyColumn | ||
import androidx.compose.material3.HorizontalDivider | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.material3.minimumInteractiveComponentSize | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.ui.Modifier | ||
import androidx.lifecycle.compose.collectAsStateWithLifecycle | ||
import androidx.lifecycle.viewmodel.compose.viewModel | ||
import ch.srgssr.pillarbox.demo.ui.components.DemoListHeaderView | ||
import ch.srgssr.pillarbox.demo.ui.components.DemoListItemView | ||
import ch.srgssr.pillarbox.demo.ui.components.DemoListSectionView | ||
import ch.srgssr.pillarbox.demo.ui.player.DemoPlayerView | ||
import ch.srgssr.pillarbox.demo.ui.theme.paddings | ||
import ch.srgssr.pillarbox.player.extension.seekToUnixTimeMs | ||
import kotlinx.datetime.Clock | ||
|
||
/** | ||
* Time-based content that demonstrates how to use timestamp-based api. | ||
*/ | ||
@Composable | ||
fun TimeBasedContent() { | ||
val viewModel: TimeBasedContentViewModel = viewModel() | ||
val player = viewModel.player | ||
val timedEvents by viewModel.deltaTimeEvents.collectAsStateWithLifecycle() | ||
|
||
LaunchedEffect(player) { | ||
player.play() | ||
} | ||
Comment on lines
+38
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because la flemme. But for sure we should play/pause player with lifecyle. |
||
Column { | ||
DemoPlayerView(player = player, modifier = Modifier.weight(1f)) | ||
LazyColumn( | ||
modifier = Modifier | ||
.padding(horizontal = MaterialTheme.paddings.baseline) | ||
.weight(1f), | ||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.paddings.small) | ||
) { | ||
item { | ||
DemoListHeaderView("Timed events") | ||
} | ||
item { | ||
DemoListSectionView { | ||
timedEvents.forEachIndexed { index, timedEvent -> | ||
DemoListItemView( | ||
title = timedEvent.name, | ||
subtitle = "Delta time ${timedEvent.delta}", | ||
modifier = Modifier | ||
.fillMaxWidth() | ||
.minimumInteractiveComponentSize() | ||
) { | ||
val now = Clock.System.now() | ||
player.seekToUnixTimeMs((now + timedEvent.delta).toEpochMilliseconds()) | ||
} | ||
|
||
if (index < timedEvents.lastIndex) { | ||
HorizontalDivider() | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* | ||
* Copyright (c) SRG SSR. All rights reserved. | ||
* License information is available from the LICENSE file. | ||
*/ | ||
package ch.srgssr.pillarbox.demo.ui.showcases.misc | ||
|
||
import android.app.Application | ||
import androidx.lifecycle.AndroidViewModel | ||
import androidx.lifecycle.viewModelScope | ||
import ch.srgssr.pillarbox.core.business.PillarboxExoPlayer | ||
import ch.srgssr.pillarbox.demo.shared.data.DemoItem | ||
import kotlinx.coroutines.flow.SharingStarted | ||
import kotlinx.coroutines.flow.StateFlow | ||
import kotlinx.coroutines.flow.flow | ||
import kotlinx.coroutines.flow.stateIn | ||
import kotlin.time.Duration | ||
import kotlin.time.Duration.Companion.hours | ||
import kotlin.time.Duration.Companion.seconds | ||
|
||
/** | ||
* A view model that exposes some timed events. | ||
* | ||
* @param application The [Application]. | ||
*/ | ||
class TimeBasedContentViewModel(application: Application) : AndroidViewModel(application) { | ||
|
||
/** | ||
* Player | ||
*/ | ||
val player = PillarboxExoPlayer(application) | ||
|
||
/** | ||
* Timed events | ||
*/ | ||
val deltaTimeEvents: StateFlow<List<DeltaTimeEvent>> = flow { | ||
emit( | ||
listOf( | ||
DeltaTimeEvent(name = "Now", Duration.ZERO), | ||
DeltaTimeEvent(name = "2 hours in the past", (-2).hours), | ||
DeltaTimeEvent(name = "1 hour in the past", (-1).hours), | ||
DeltaTimeEvent(name = "Near future", 30.seconds), | ||
DeltaTimeEvent(name = "In 1 hour", 1.hours), | ||
DeltaTimeEvent(name = "4 hours in the past", (-4).hours), | ||
) | ||
) | ||
}.stateIn(viewModelScope, SharingStarted.Lazily, emptyList()) | ||
|
||
init { | ||
player.setMediaItem(DemoItem.LiveTimestampVideoHLS.toMediaItem()) | ||
player.prepare() | ||
} | ||
|
||
override fun onCleared() { | ||
player.release() | ||
} | ||
|
||
/** | ||
* @property name Name of the event. | ||
* @property delta The delta [Duration] of the event from now. | ||
*/ | ||
data class DeltaTimeEvent( | ||
val name: String, | ||
val delta: Duration, | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update
CountdownView
to use this formatter, since it defined its own with the same configuration?