mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-23 19:26:17 +00:00
Add proper gesture when user navigates to or from a conversation.
This commit is contained in:
@@ -7,6 +7,8 @@ package org.thoughtcrime.securesms.window
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.content.res.Resources
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -14,6 +16,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.displayCutoutPadding
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
|
||||
@@ -30,9 +33,11 @@ import androidx.compose.material3.adaptive.navigation.NavigableListDetailPaneSca
|
||||
import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator
|
||||
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.layout
|
||||
@@ -42,6 +47,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.window.core.ExperimentalWindowCoreApi
|
||||
import androidx.window.core.layout.WindowHeightSizeClass
|
||||
import androidx.window.core.layout.WindowWidthSizeClass
|
||||
@@ -228,9 +234,28 @@ fun AppScaffold(
|
||||
NavigableListDetailPaneScaffold(
|
||||
navigator = navigator,
|
||||
listPane = {
|
||||
AnimatedPane {
|
||||
val offset by animateDp(
|
||||
targetWhenHiding = {
|
||||
(-48).dp
|
||||
},
|
||||
targetWhenShowing = {
|
||||
0.dp
|
||||
}
|
||||
)
|
||||
|
||||
val alpha by animateFloat {
|
||||
1f
|
||||
}
|
||||
|
||||
AnimatedPane(
|
||||
enterTransition = EnterTransition.None,
|
||||
exitTransition = ExitTransition.None,
|
||||
modifier = Modifier.zIndex(0f)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.alpha(alpha)
|
||||
.offset(x = offset)
|
||||
.clipToBounds()
|
||||
.layout { measurable, constraints ->
|
||||
val width = max(minPaneWidth.roundToPx(), constraints.maxWidth)
|
||||
@@ -258,9 +283,28 @@ fun AppScaffold(
|
||||
}
|
||||
},
|
||||
detailPane = {
|
||||
AnimatedPane {
|
||||
val offset by animateDp(
|
||||
targetWhenHiding = {
|
||||
48.dp
|
||||
},
|
||||
targetWhenShowing = {
|
||||
0.dp
|
||||
}
|
||||
)
|
||||
|
||||
val alpha by animateFloat {
|
||||
1f
|
||||
}
|
||||
|
||||
AnimatedPane(
|
||||
enterTransition = EnterTransition.None,
|
||||
exitTransition = ExitTransition.None,
|
||||
modifier = Modifier.zIndex(1f)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.alpha(alpha)
|
||||
.offset(x = offset)
|
||||
.clipToBounds()
|
||||
.layout { measurable, constraints ->
|
||||
val width = max(minPaneWidth.roundToPx(), constraints.maxWidth)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.window
|
||||
|
||||
import androidx.compose.animation.core.CubicBezierEasing
|
||||
import androidx.compose.animation.core.animateDp
|
||||
import androidx.compose.animation.core.animateFloat
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
||||
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
|
||||
import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldPaneScope
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
private val easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1f)
|
||||
|
||||
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
||||
@Composable
|
||||
fun ThreePaneScaffoldPaneScope.animateDp(
|
||||
targetWhenHiding: () -> Dp = { 0.dp },
|
||||
targetWhenShowing: () -> Dp
|
||||
): State<Dp> {
|
||||
return scaffoldStateTransition.animateDp(
|
||||
transitionSpec = { tween(durationMillis = 200, easing = easing) }
|
||||
) {
|
||||
val isHiding = it[paneRole] == PaneAdaptedValue.Hidden
|
||||
|
||||
if (isHiding) {
|
||||
targetWhenHiding()
|
||||
} else {
|
||||
targetWhenShowing()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
||||
@Composable
|
||||
fun ThreePaneScaffoldPaneScope.animateFloat(
|
||||
targetWhenHiding: () -> Float = { 0f },
|
||||
targetWhenShowing: () -> Float
|
||||
): State<Float> {
|
||||
return scaffoldStateTransition.animateFloat(
|
||||
transitionSpec = { tween(durationMillis = 200, easing = easing) }
|
||||
) {
|
||||
val isHiding = it[paneRole] == PaneAdaptedValue.Hidden
|
||||
|
||||
if (isHiding) {
|
||||
targetWhenHiding()
|
||||
} else {
|
||||
targetWhenShowing()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user