Voice message scrubbing improvements (#1847)

- Voice messages can be scrubbed (i.e. seeked to) even when they have not been played yet..
- The progress bar is displayed also when paused.
- Multiple voice messages can keep their state when paused.
- Tries to adhere as much as possible at the detailed "green cursor" behavior in the story (but might not be 100% compliant).

Story: https://github.com/vector-im/element-meta/issues/2113
This commit is contained in:
Marco Romano 2023-11-21 20:48:08 +01:00 committed by GitHub
parent 0649cf1706
commit de646e4e5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 381 additions and 208 deletions

View file

@ -77,6 +77,7 @@ class MediaPlayerImpl @Inject constructor(
_state.update {
it.copy(
isReady = playbackState == Player.STATE_READY,
isEnded = playbackState == Player.STATE_ENDED,
currentPosition = player.currentPosition,
duration = duration,
)
@ -95,16 +96,22 @@ class MediaPlayerImpl @Inject constructor(
MediaPlayer.State(
isReady = false,
isPlaying = false,
isEnded = false,
mediaId = null,
currentPosition = 0L,
duration = 0L
duration = null,
)
)
override val state: StateFlow<MediaPlayer.State> = _state.asStateFlow()
@OptIn(FlowPreview::class)
override suspend fun setMedia(uri: String, mediaId: String, mimeType: String): MediaPlayer.State {
override suspend fun setMedia(
uri: String,
mediaId: String,
mimeType: String,
startPositionMs: Long,
): MediaPlayer.State {
player.pause() // Must pause here otherwise if the player was playing it would keep on playing the new media item.
player.clearMediaItems()
player.setMediaItem(
@ -112,7 +119,8 @@ class MediaPlayerImpl @Inject constructor(
.setUri(uri)
.setMediaId(mediaId)
.setMimeType(mimeType)
.build()
.build(),
startPositionMs,
)
player.prepare()
// Will throw TimeoutCancellationException if the player is not ready after 1 second.
@ -129,7 +137,7 @@ class MediaPlayerImpl @Inject constructor(
// playing no sound.
// This is a workaround which will reload the media file.
player.getCurrentMediaItem()?.let {
player.setMediaItem(it)
player.setMediaItem(it, 0)
player.prepare()
player.play()
}

View file

@ -35,7 +35,7 @@ interface SimplePlayer {
val playbackState: Int
val duration: Long
fun clearMediaItems()
fun setMediaItem(mediaItem: MediaItem)
fun setMediaItem(mediaItem: MediaItem, startPositionMs: Long)
fun getCurrentMediaItem(): MediaItem?
fun prepare()
fun play()
@ -81,7 +81,7 @@ class SimplePlayerImpl(
override fun clearMediaItems() = p.clearMediaItems()
override fun setMediaItem(mediaItem: MediaItem) = p.setMediaItem(mediaItem)
override fun setMediaItem(mediaItem: MediaItem, startPositionMs: Long) = p.setMediaItem(mediaItem, startPositionMs)
override fun getCurrentMediaItem(): MediaItem? = p.currentMediaItem