Media: continue improving VideoView

This commit is contained in:
ganfra 2023-05-26 11:29:49 +02:00
parent bb3b441b6c
commit 2bfb8093db
3 changed files with 85 additions and 24 deletions

View file

@ -35,9 +35,9 @@ import androidx.media3.common.MediaItem
import androidx.media3.common.MimeTypes import androidx.media3.common.MimeTypes
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.AspectRatioFrameLayout import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView import androidx.media3.ui.PlayerView
import io.element.android.features.messages.impl.media.local.exoplayer.ExoPlayerWrapper
import io.element.android.libraries.designsystem.R import io.element.android.libraries.designsystem.R
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
import me.saket.telephoto.zoomable.ZoomSpec import me.saket.telephoto.zoomable.ZoomSpec
@ -114,8 +114,7 @@ fun MediaVideoView(
} }
} }
val exoPlayer = remember { val exoPlayer = remember {
ExoPlayer.Builder(context) ExoPlayerWrapper.create(context)
.build()
.apply { .apply {
addListener(playerListener) addListener(playerListener)
this.prepare() this.prepare()
@ -133,6 +132,8 @@ fun MediaVideoView(
factory = { factory = {
PlayerView(context).apply { PlayerView(context).apply {
player = exoPlayer player = exoPlayer
setShowPreviousButton(false)
setShowNextButton(false)
resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT resizeMode = AspectRatioFrameLayout.RESIZE_MODE_FIT
layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
controllerShowTimeoutMs = 3000 controllerShowTimeoutMs = 3000
@ -145,7 +146,10 @@ fun MediaVideoView(
when (event) { when (event) {
Lifecycle.Event.ON_RESUME -> exoPlayer.play() Lifecycle.Event.ON_RESUME -> exoPlayer.play()
Lifecycle.Event.ON_PAUSE -> exoPlayer.pause() Lifecycle.Event.ON_PAUSE -> exoPlayer.pause()
Lifecycle.Event.ON_DESTROY -> exoPlayer.release() Lifecycle.Event.ON_DESTROY -> {
exoPlayer.release()
exoPlayer.removeListener(playerListener)
}
else -> Unit else -> Unit
} }
} }

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.messages.impl.media.local.exoplayer
import android.content.Context
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
/**
* Wrapper around ExoPlayer to disable some commands.
* Necessary to hide the settings wheels from the player.
*/
@UnstableApi
class ExoPlayerWrapper(private val exoPlayer: ExoPlayer) : ExoPlayer by exoPlayer {
override fun isCommandAvailable(command: Int): Boolean {
return availableCommands.contains(command)
}
override fun getAvailableCommands(): Player.Commands {
return exoPlayer.availableCommands
.buildUpon()
.remove(Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS)
.build()
}
companion object {
fun create(context: Context): ExoPlayer {
return ExoPlayerWrapper(
ExoPlayer.Builder(context).build()
)
}
}
}

View file

@ -17,6 +17,9 @@
package io.element.android.features.messages.impl.media.viewer package io.element.android.features.messages.impl.media.viewer
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@ -116,28 +119,33 @@ private fun ThumbnailView(
showThumbnail: Boolean, showThumbnail: Boolean,
showProgress: Boolean, showProgress: Boolean,
) { ) {
if (!showThumbnail) return AnimatedVisibility(
visible = showThumbnail,
Box( enter = fadeIn(),
modifier = Modifier.fillMaxSize(), exit = fadeOut()
contentAlignment = Alignment.Center
) { ) {
val mediaRequestData = MediaRequestData( Box(
source = thumbnailSource,
kind = MediaRequestData.Kind.Content
)
AsyncImage(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
model = mediaRequestData, contentAlignment = Alignment.Center
contentScale = ContentScale.Fit, ) {
contentDescription = null, val mediaRequestData = MediaRequestData(
) source = thumbnailSource,
if (showProgress) { kind = MediaRequestData.Kind.Content
Box( )
modifier = Modifier.roundedBackground(), AsyncImage(
contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize(),
) { model = mediaRequestData,
CircularProgressIndicator() alpha = 0.8f,
contentScale = ContentScale.Fit,
contentDescription = null,
)
if (showProgress) {
Box(
modifier = Modifier.roundedBackground(),
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator()
}
} }
} }
} }