Introduce MediaViewerFlickToDismiss and extract to its own file
This commit is contained in:
committed by
Benoit Marty
parent
2267a4b787
commit
f55da9027b
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.mediaviewer.impl.viewer
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import kotlinx.coroutines.delay
|
||||
import me.saket.telephoto.flick.FlickToDismiss
|
||||
import me.saket.telephoto.flick.FlickToDismissState
|
||||
import me.saket.telephoto.flick.rememberFlickToDismissState
|
||||
import kotlin.time.Duration
|
||||
|
||||
@Composable
|
||||
fun MediaViewerFlickToDismiss(
|
||||
onDismiss: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
onDragging: () -> Unit = {},
|
||||
content: @Composable BoxScope.() -> Unit,
|
||||
) {
|
||||
val flickState = rememberFlickToDismissState(dismissThresholdRatio = 0.1f, rotateOnDrag = false)
|
||||
DismissFlickEffects(
|
||||
flickState = flickState,
|
||||
onDismissing = { animationDuration ->
|
||||
delay(animationDuration / 3)
|
||||
onDismiss()
|
||||
},
|
||||
onDragging = onDragging,
|
||||
)
|
||||
FlickToDismiss(
|
||||
state = flickState,
|
||||
modifier = modifier.background(backgroundColorFor(flickState)),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DismissFlickEffects(
|
||||
flickState: FlickToDismissState,
|
||||
onDismissing: suspend (Duration) -> Unit,
|
||||
onDragging: suspend () -> Unit,
|
||||
) {
|
||||
val currentOnDismissing by rememberUpdatedState(onDismissing)
|
||||
val currentOnDragging by rememberUpdatedState(onDragging)
|
||||
|
||||
when (val gestureState = flickState.gestureState) {
|
||||
is FlickToDismissState.GestureState.Dismissing -> {
|
||||
LaunchedEffect(Unit) {
|
||||
currentOnDismissing(gestureState.animationDuration)
|
||||
}
|
||||
}
|
||||
is FlickToDismissState.GestureState.Dragging -> {
|
||||
LaunchedEffect(Unit) {
|
||||
currentOnDragging()
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun backgroundColorFor(flickState: FlickToDismissState): Color {
|
||||
val animatedAlpha by animateFloatAsState(
|
||||
targetValue = when (flickState.gestureState) {
|
||||
is FlickToDismissState.GestureState.Dismissed,
|
||||
is FlickToDismissState.GestureState.Dismissing -> 0f
|
||||
is FlickToDismissState.GestureState.Dragging,
|
||||
is FlickToDismissState.GestureState.Idle,
|
||||
is FlickToDismissState.GestureState.Resetting -> 1f - flickState.offsetFraction
|
||||
},
|
||||
label = "Background alpha",
|
||||
)
|
||||
return Color.Black.copy(alpha = animatedAlpha)
|
||||
}
|
||||
@@ -11,7 +11,6 @@ package io.element.android.libraries.mediaviewer.impl.viewer
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
@@ -81,13 +80,9 @@ import io.element.android.libraries.mediaviewer.impl.local.PlayableState
|
||||
import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.coroutines.delay
|
||||
import me.saket.telephoto.flick.FlickToDismiss
|
||||
import me.saket.telephoto.flick.FlickToDismissState
|
||||
import me.saket.telephoto.flick.rememberFlickToDismissState
|
||||
import me.saket.telephoto.zoomable.ZoomSpec
|
||||
import me.saket.telephoto.zoomable.rememberZoomableState
|
||||
import timber.log.Timber
|
||||
import kotlin.time.Duration
|
||||
|
||||
@Composable
|
||||
fun MediaViewerView(
|
||||
@@ -289,22 +284,13 @@ private fun MediaViewerPage(
|
||||
) {
|
||||
val currentShowOverlay by rememberUpdatedState(showOverlay)
|
||||
val currentOnShowOverlayChange by rememberUpdatedState(onShowOverlayChange)
|
||||
val flickState = rememberFlickToDismissState(dismissThresholdRatio = 0.1f, rotateOnDrag = false)
|
||||
|
||||
DismissFlickEffects(
|
||||
flickState = flickState,
|
||||
onDismissing = { animationDuration ->
|
||||
delay(animationDuration / 3)
|
||||
onDismiss()
|
||||
},
|
||||
MediaViewerFlickToDismiss(
|
||||
onDismiss = onDismiss,
|
||||
onDragging = {
|
||||
currentOnShowOverlayChange(false)
|
||||
}
|
||||
)
|
||||
|
||||
FlickToDismiss(
|
||||
state = flickState,
|
||||
modifier = modifier.background(backgroundColorFor(flickState))
|
||||
},
|
||||
modifier = modifier,
|
||||
) {
|
||||
val downloadedMedia by data.downloadedMedia
|
||||
val showProgress = rememberShowProgress(downloadedMedia)
|
||||
@@ -371,20 +357,9 @@ private fun MediaViewerLoadingPage(
|
||||
onDismiss: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val flickState = rememberFlickToDismissState(dismissThresholdRatio = 0.1f, rotateOnDrag = false)
|
||||
|
||||
DismissFlickEffects(
|
||||
flickState = flickState,
|
||||
onDismissing = { animationDuration ->
|
||||
delay(animationDuration / 3)
|
||||
onDismiss()
|
||||
},
|
||||
onDragging = {},
|
||||
)
|
||||
|
||||
FlickToDismiss(
|
||||
state = flickState,
|
||||
modifier = modifier.background(backgroundColorFor(flickState))
|
||||
MediaViewerFlickToDismiss(
|
||||
onDismiss = onDismiss,
|
||||
modifier = modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
@@ -403,20 +378,9 @@ private fun MediaViewerErrorPage(
|
||||
onDismiss: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val flickState = rememberFlickToDismissState(dismissThresholdRatio = 0.1f, rotateOnDrag = false)
|
||||
|
||||
DismissFlickEffects(
|
||||
flickState = flickState,
|
||||
onDismissing = { animationDuration ->
|
||||
delay(animationDuration / 3)
|
||||
onDismiss()
|
||||
},
|
||||
onDragging = {},
|
||||
)
|
||||
|
||||
FlickToDismiss(
|
||||
state = flickState,
|
||||
modifier = modifier.background(backgroundColorFor(flickState))
|
||||
MediaViewerFlickToDismiss(
|
||||
onDismiss = onDismiss,
|
||||
modifier = modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
@@ -432,30 +396,6 @@ private fun MediaViewerErrorPage(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DismissFlickEffects(
|
||||
flickState: FlickToDismissState,
|
||||
onDismissing: suspend (Duration) -> Unit,
|
||||
onDragging: suspend () -> Unit,
|
||||
) {
|
||||
val currentOnDismissing by rememberUpdatedState(onDismissing)
|
||||
val currentOnDragging by rememberUpdatedState(onDragging)
|
||||
|
||||
when (val gestureState = flickState.gestureState) {
|
||||
is FlickToDismissState.GestureState.Dismissing -> {
|
||||
LaunchedEffect(Unit) {
|
||||
currentOnDismissing(gestureState.animationDuration)
|
||||
}
|
||||
}
|
||||
is FlickToDismissState.GestureState.Dragging -> {
|
||||
LaunchedEffect(Unit) {
|
||||
currentOnDragging()
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberShowProgress(downloadedMedia: AsyncData<LocalMedia>): Boolean {
|
||||
var showProgress by remember {
|
||||
@@ -623,21 +563,6 @@ private fun ErrorView(
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun backgroundColorFor(flickState: FlickToDismissState): Color {
|
||||
val animatedAlpha by animateFloatAsState(
|
||||
targetValue = when (flickState.gestureState) {
|
||||
is FlickToDismissState.GestureState.Dismissed,
|
||||
is FlickToDismissState.GestureState.Dismissing -> 0f
|
||||
is FlickToDismissState.GestureState.Dragging,
|
||||
is FlickToDismissState.GestureState.Idle,
|
||||
is FlickToDismissState.GestureState.Resetting -> 1f - flickState.offsetFraction
|
||||
},
|
||||
label = "Background alpha",
|
||||
)
|
||||
return Color.Black.copy(alpha = animatedAlpha)
|
||||
}
|
||||
|
||||
// Only preview in dark, dark theme is forced on the Node.
|
||||
@Preview
|
||||
@Composable
|
||||
|
||||
Reference in New Issue
Block a user