Improve position of video controlling buttons when top bars are present.

This commit is contained in:
Vitor Pamplona
2023-11-03 17:14:41 -04:00
parent e0d2a71b47
commit c1a59a1d21
@@ -29,6 +29,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -44,12 +45,11 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.isFinite import androidx.compose.ui.unit.isFinite
import androidx.compose.ui.unit.isSpecified import androidx.compose.ui.unit.isSpecified
@@ -71,6 +71,7 @@ import com.vitorpamplona.amethyst.ui.note.MuteIcon
import com.vitorpamplona.amethyst.ui.note.MutedIcon import com.vitorpamplona.amethyst.ui.note.MutedIcon
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.PinBottomIconSize import com.vitorpamplona.amethyst.ui.theme.PinBottomIconSize
import com.vitorpamplona.amethyst.ui.theme.Size0dp
import com.vitorpamplona.amethyst.ui.theme.Size22Modifier import com.vitorpamplona.amethyst.ui.theme.Size22Modifier
import com.vitorpamplona.amethyst.ui.theme.Size50Modifier import com.vitorpamplona.amethyst.ui.theme.Size50Modifier
import com.vitorpamplona.amethyst.ui.theme.VolumeBottomIconSize import com.vitorpamplona.amethyst.ui.theme.VolumeBottomIconSize
@@ -536,137 +537,132 @@ private fun RenderVideoPlayer(
mutableStateOf(false) mutableStateOf(false)
} }
val parentVideoPlaybackSize = remember { val videoPlaybackHeight = remember {
mutableStateOf<IntSize>(IntSize.Zero) mutableStateOf<Dp>(Dp.Unspecified)
} }
val videoPlaybackSize = remember { val localDensity = LocalDensity.current
mutableStateOf<IntSize>(IntSize.Zero)
}
BoxWithConstraints( BoxWithConstraints(
contentAlignment = Alignment.Center, modifier = Modifier
modifier = Modifier.fillMaxSize().onSizeChanged { .onGloballyPositioned { coordinates ->
parentVideoPlaybackSize.value = it videoPlaybackHeight.value = with(localDensity) { coordinates.size.height.toDp() }
} }
) { ) {
BoxWithConstraints( val borders = MaterialTheme.colorScheme.imageModifier
modifier = Modifier.onSizeChanged {
videoPlaybackSize.value = it
}
) {
val borders = MaterialTheme.colorScheme.imageModifier
val myModifier = remember { val myModifier = remember {
if (roundedCorner) { if (roundedCorner) {
modifier.then( modifier.then(
borders borders
.defaultMinSize(minHeight = 100.dp) .defaultMinSize(minHeight = 75.dp)
.align(Alignment.Center)
)
} else {
modifier
.fillMaxWidth()
.defaultMinSize(minHeight = 100.dp)
.align(Alignment.Center) .align(Alignment.Center)
} )
} else {
modifier
.fillMaxWidth()
.defaultMinSize(minHeight = 75.dp)
.align(Alignment.Center)
} }
}
val factory = remember(controller) { val factory = remember(controller) {
{ context: Context -> { context: Context ->
PlayerView(context).apply { PlayerView(context).apply {
player = controller player = controller
layoutParams = FrameLayout.LayoutParams( layoutParams = FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT ViewGroup.LayoutParams.WRAP_CONTENT
) )
controllerAutoShow = false controllerAutoShow = false
thumbData?.thumb?.let { defaultArtwork = it } thumbData?.thumb?.let { defaultArtwork = it }
hideController() hideController()
resizeMode = resizeMode =
if (maxHeight.isFinite) AspectRatioFrameLayout.RESIZE_MODE_FIT else AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH if (maxHeight.isFinite) AspectRatioFrameLayout.RESIZE_MODE_FIT else AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH
onDialog?.let { innerOnDialog -> onDialog?.let { innerOnDialog ->
setFullscreenButtonClickListener { setFullscreenButtonClickListener {
controller.pause() controller.pause()
innerOnDialog(it) innerOnDialog(it)
}
}
setControllerVisibilityListener(
PlayerView.ControllerVisibilityListener { visible ->
controllerVisible.value = visible == View.VISIBLE
onControllerVisibilityChanged?.let { callback ->
callback(visible == View.VISIBLE)
} }
} }
setControllerVisibilityListener( )
PlayerView.ControllerVisibilityListener { visible ->
controllerVisible.value = visible == View.VISIBLE
onControllerVisibilityChanged?.let { callback ->
callback(visible == View.VISIBLE)
}
}
)
}
} }
} }
}
AndroidView( AndroidView(
modifier = myModifier, modifier = myModifier,
factory = factory factory = factory
) )
waveform?.let { waveform?.let {
Waveform(it, controller, remember { Modifier.align(Alignment.Center) }) Waveform(it, controller, remember { Modifier.align(Alignment.Center) })
} }
val startingMuteState = remember(controller) { val startingMuteState = remember(controller) {
controller.volume < 0.001 controller.volume < 0.001
} }
val spaceModifier = remember { val topPadding = remember {
if (topPaddingForControllers.isSpecified && videoPlaybackSize.value.height > 0) { derivedStateOf {
val space = (abs(parentVideoPlaybackSize.value.height - videoPlaybackSize.value.height) / 2).dp if (topPaddingForControllers.isSpecified && videoPlaybackHeight.value.value > 0) {
val space = (abs(this.maxHeight.value - videoPlaybackHeight.value.value) / 2).dp
if (space > topPaddingForControllers) { if (space > topPaddingForControllers) {
Modifier Size0dp
} else { } else {
Modifier.padding(top = topPaddingForControllers - space) topPaddingForControllers - space
} }
} else { } else {
Modifier Size0dp
} }
} }
}
MuteButton( MuteButton(
controllerVisible, controllerVisible,
startingMuteState, startingMuteState,
spaceModifier topPadding
) { mute: Boolean -> ) { mute: Boolean ->
// makes the new setting the default for new creations. // makes the new setting the default for new creations.
DefaultMutedSetting.value = mute DefaultMutedSetting.value = mute
// if the user unmutes a video and it's not the current playing, switches to that one. // if the user unmutes a video and it's not the current playing, switches to that one.
if (!mute && keepPlayingMutex != null && keepPlayingMutex != controller) { if (!mute && keepPlayingMutex != null && keepPlayingMutex != controller) {
keepPlayingMutex?.stop()
keepPlayingMutex?.release()
keepPlayingMutex = null
}
controller.volume = if (mute) 0f else 1f
}
KeepPlayingButton(
keepPlaying,
controllerVisible,
topPadding,
Modifier.align(Alignment.TopEnd)
) { newKeepPlaying: Boolean ->
// If something else is playing and the user marks this video to keep playing, stops the other one.
if (newKeepPlaying) {
if (keepPlayingMutex != null && keepPlayingMutex != controller) {
keepPlayingMutex?.stop() keepPlayingMutex?.stop()
keepPlayingMutex?.release() keepPlayingMutex?.release()
}
keepPlayingMutex = controller
} else {
if (keepPlayingMutex == controller) {
keepPlayingMutex = null keepPlayingMutex = null
} }
controller.volume = if (mute) 0f else 1f
} }
KeepPlayingButton( keepPlaying.value = newKeepPlaying
keepPlaying,
controllerVisible,
spaceModifier.align(Alignment.TopEnd)
) { newKeepPlaying: Boolean ->
// If something else is playing and the user marks this video to keep playing, stops the other one.
if (newKeepPlaying) {
if (keepPlayingMutex != null && keepPlayingMutex != controller) {
keepPlayingMutex?.stop()
keepPlayingMutex?.release()
}
keepPlayingMutex = controller
} else {
if (keepPlayingMutex == controller) {
keepPlayingMutex = null
}
}
keepPlaying.value = newKeepPlaying
}
} }
} }
} }
@@ -826,7 +822,7 @@ fun LayoutCoordinates.getDistanceToVertCenterIfVisible(view: View): Float? {
private fun MuteButton( private fun MuteButton(
controllerVisible: MutableState<Boolean>, controllerVisible: MutableState<Boolean>,
startingMuteState: Boolean, startingMuteState: Boolean,
modifier: Modifier, topPadding: State<Dp>,
toggle: (Boolean) -> Unit toggle: (Boolean) -> Unit
) { ) {
val holdOn = remember { val holdOn = remember {
@@ -846,7 +842,7 @@ private fun MuteButton(
AnimatedVisibility( AnimatedVisibility(
visible = holdOn.value || controllerVisible.value, visible = holdOn.value || controllerVisible.value,
modifier = modifier, modifier = Modifier.padding(top = topPadding.value),
enter = remember { fadeIn() }, enter = remember { fadeIn() },
exit = remember { fadeOut() } exit = remember { fadeOut() }
) { ) {
@@ -880,6 +876,7 @@ private fun MuteButton(
private fun KeepPlayingButton( private fun KeepPlayingButton(
keepPlayingStart: MutableState<Boolean>, keepPlayingStart: MutableState<Boolean>,
controllerVisible: MutableState<Boolean>, controllerVisible: MutableState<Boolean>,
topPadding: State<Dp>,
alignment: Modifier, alignment: Modifier,
toggle: (Boolean) -> Unit toggle: (Boolean) -> Unit
) { ) {
@@ -887,7 +884,7 @@ private fun KeepPlayingButton(
AnimatedVisibility( AnimatedVisibility(
visible = controllerVisible.value, visible = controllerVisible.value,
modifier = alignment, modifier = alignment.padding(top = topPadding.value),
enter = remember { fadeIn() }, enter = remember { fadeIn() },
exit = remember { fadeOut() } exit = remember { fadeOut() }
) { ) {