Improving the Stability of VideoView

This commit is contained in:
Vitor Pamplona
2023-09-25 17:09:36 -04:00
parent af9b0b444c
commit b1edf4e934
2 changed files with 52 additions and 38 deletions
@@ -1,5 +1,6 @@
package com.vitorpamplona.amethyst.ui.components package com.vitorpamplona.amethyst.ui.components
import android.content.Context
import android.graphics.Rect import android.graphics.Rect
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
@@ -206,34 +207,36 @@ fun VideoViewInner(
) )
} }
val mediaItem = remember(videoUri) {
MediaItem.Builder()
.setMediaId(videoUri)
.setUri(videoUri)
.setMediaMetadata(
MediaMetadata.Builder()
.setArtist(authorName?.ifBlank { null })
.setTitle(title?.ifBlank { null } ?: videoUri)
.setArtworkUri(
try {
if (artworkUri != null) {
Uri.parse(artworkUri)
} else {
null
}
} catch (e: Exception) {
null
}
)
.build()
)
.build()
}
if (!automaticallyStartPlayback.value) { if (!automaticallyStartPlayback.value) {
ImageUrlWithDownloadButton(url = videoUri, showImage = automaticallyStartPlayback) ImageUrlWithDownloadButton(url = videoUri, showImage = automaticallyStartPlayback)
} else { } else {
VideoPlayerActiveMutex(videoUri) { activeOnScreen -> VideoPlayerActiveMutex(videoUri) { activeOnScreen ->
val mediaItem = remember(videoUri) {
mutableStateOf(
MediaItem.Builder()
.setMediaId(videoUri)
.setUri(videoUri)
.setMediaMetadata(
MediaMetadata.Builder()
.setArtist(authorName?.ifBlank { null })
.setTitle(title?.ifBlank { null } ?: videoUri)
.setArtworkUri(
try {
if (artworkUri != null) {
Uri.parse(artworkUri)
} else {
null
}
} catch (e: Exception) {
null
}
)
.build()
)
.build()
)
}
GetVideoController( GetVideoController(
mediaItem = mediaItem, mediaItem = mediaItem,
videoUri = videoUri, videoUri = videoUri,
@@ -258,7 +261,7 @@ fun VideoViewInner(
@Composable @Composable
@OptIn(UnstableApi::class) @OptIn(UnstableApi::class)
fun GetVideoController( fun GetVideoController(
mediaItem: MediaItem, mediaItem: MutableState<MediaItem>,
videoUri: String, videoUri: String,
defaultToStart: Boolean = false, defaultToStart: Boolean = false,
nostrUriCallback: String? = null, nostrUriCallback: String? = null,
@@ -311,7 +314,7 @@ fun GetVideoController(
} }
} }
controller.value?.setMediaItem(mediaItem) controller.value?.setMediaItem(mediaItem.value)
controller.value?.prepare() controller.value?.prepare()
} else if (controller.value != it) { } else if (controller.value != it) {
// discards the new controller because there is an existing one // discards the new controller because there is an existing one
@@ -329,7 +332,7 @@ fun GetVideoController(
it.volume = if (defaultToStart) 0f else 1f it.volume = if (defaultToStart) 0f else 1f
} }
it.setMediaItem(mediaItem) it.setMediaItem(mediaItem.value)
it.prepare() it.prepare()
} }
} }
@@ -347,7 +350,7 @@ fun GetVideoController(
it.volume = if (defaultToStart) 0f else 1f it.volume = if (defaultToStart) 0f else 1f
} }
it.setMediaItem(mediaItem) it.setMediaItem(mediaItem.value)
it.prepare() it.prepare()
} }
} }
@@ -394,7 +397,7 @@ fun GetVideoController(
} }
} }
controller.value?.setMediaItem(mediaItem) controller.value?.setMediaItem(mediaItem.value)
controller.value?.prepare() controller.value?.prepare()
} else if (controller.value != it) { } else if (controller.value != it) {
// discards the new controller because there is an existing one // discards the new controller because there is an existing one
@@ -460,7 +463,7 @@ fun VideoPlayerActiveMutex(videoUri: String, inner: @Composable (MutableState<Bo
} }
} }
Box( val myModifier = remember(videoUri) {
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.defaultMinSize(minHeight = 70.dp) .defaultMinSize(minHeight = 70.dp)
@@ -489,7 +492,9 @@ fun VideoPlayerActiveMutex(videoUri: String, inner: @Composable (MutableState<Bo
} }
} }
} }
) { }
Box(modifier = myModifier) {
inner(active) inner(active)
} }
} }
@@ -511,8 +516,6 @@ private fun RenderVideoPlayer(
activeOnScreen: MutableState<Boolean>, activeOnScreen: MutableState<Boolean>,
onDialog: ((Boolean) -> Unit)? onDialog: ((Boolean) -> Unit)?
) { ) {
val context = LocalContext.current
ControlWhenPlayerIsActive(controller, keepPlaying, automaticallyStartPlayback, activeOnScreen) ControlWhenPlayerIsActive(controller, keepPlaying, automaticallyStartPlayback, activeOnScreen)
val controllerVisible = remember(controller) { val controllerVisible = remember(controller) {
@@ -520,9 +523,11 @@ private fun RenderVideoPlayer(
} }
BoxWithConstraints() { BoxWithConstraints() {
AndroidView( val borders = MaterialTheme.colors.imageModifier
modifier = if (roundedCorner) {
MaterialTheme.colors.imageModifier val myModifier = remember {
if (roundedCorner) {
borders
.defaultMinSize(minHeight = 100.dp) .defaultMinSize(minHeight = 100.dp)
.align(Alignment.Center) .align(Alignment.Center)
} else { } else {
@@ -530,8 +535,11 @@ private fun RenderVideoPlayer(
.fillMaxWidth() .fillMaxWidth()
.defaultMinSize(minHeight = 100.dp) .defaultMinSize(minHeight = 100.dp)
.align(Alignment.Center) .align(Alignment.Center)
}, }
factory = { }
val factory = remember(controller) {
{ context: Context ->
PlayerView(context).apply { PlayerView(context).apply {
player = controller player = controller
layoutParams = FrameLayout.LayoutParams( layoutParams = FrameLayout.LayoutParams(
@@ -556,6 +564,11 @@ private fun RenderVideoPlayer(
) )
} }
} }
}
AndroidView(
modifier = myModifier,
factory = factory
) )
waveform?.let { waveform?.let {
@@ -63,6 +63,7 @@ class NostrChatroomFeedViewModel(val user: ChatroomKey, val account: Account) :
} }
} }
@Stable
class NostrVideoFeedViewModel(val account: Account) : FeedViewModel(VideoFeedFilter(account)) { class NostrVideoFeedViewModel(val account: Account) : FeedViewModel(VideoFeedFilter(account)) {
class Factory(val account: Account) : ViewModelProvider.Factory { class Factory(val account: Account) : ViewModelProvider.Factory {
override fun <NostrVideoFeedViewModel : ViewModel> create(modelClass: Class<NostrVideoFeedViewModel>): NostrVideoFeedViewModel { override fun <NostrVideoFeedViewModel : ViewModel> create(modelClass: Class<NostrVideoFeedViewModel>): NostrVideoFeedViewModel {