Media: continue improving VideoView
This commit is contained in:
parent
bb3b441b6c
commit
2bfb8093db
3 changed files with 85 additions and 24 deletions
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue