Introduce MediaViewerFlickToDismiss and extract to its own file
This commit is contained in:
parent
621558a134
commit
e496bc38ad
2 changed files with 95 additions and 85 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue