From 723b0490531478196ce136cc1a497354c210a683 Mon Sep 17 00:00:00 2001 From: ateeb-infocusp Date: Tue, 10 Mar 2026 16:06:00 +0530 Subject: [PATCH 1/3] Improve back gesture handling and animations in AppScaffoldNavigator. --- .../window/AppScaffoldAnimationState.kt | 8 +++- .../securesms/window/AppScaffoldAnimators.kt | 43 +++++++++++-------- .../securesms/window/AppScaffoldNavigator.kt | 22 +++++++--- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimationState.kt b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimationState.kt index 39b31d3cd15..605855a25eb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimationState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimationState.kt @@ -81,6 +81,10 @@ class AppScaffoldAnimationStateFactory( private val EMPTY_STATE = AppScaffoldAnimationState( alpha = mutableStateOf(1f) ) + + private val HIDDEN_STATE = AppScaffoldAnimationState( + alpha = mutableStateOf(0f) + ) } private var latestListSeekState: AppScaffoldAnimationState = EMPTY_STATE @@ -100,6 +104,7 @@ class AppScaffoldAnimationStateFactory( } AppScaffoldNavigator.NavigationState.RELEASE -> defaultListReleaseAnimationState(latestListSeekState) + AppScaffoldNavigator.NavigationState.CANCEL -> HIDDEN_STATE } } @@ -117,6 +122,7 @@ class AppScaffoldAnimationStateFactory( } AppScaffoldNavigator.NavigationState.RELEASE -> defaultDetailReleaseAnimationState(latestDetailSeekState) + AppScaffoldNavigator.NavigationState.CANCEL -> defaultDetailInitAnimationState() } } -} +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimators.kt b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimators.kt index a614bfd8a97..e29d7f05e4a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimators.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimators.kt @@ -16,7 +16,6 @@ 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.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.unit.Dp @@ -220,24 +219,32 @@ fun ThreePaneScaffoldPaneScope.defaultDetailSeekAnimationState(): AppScaffoldAni @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable fun ThreePaneScaffoldPaneScope.defaultDetailReleaseAnimationState(from: AppScaffoldAnimationState): AppScaffoldAnimationState { - val scale = remember { from.contentScale } - val offset = remember { from.contentOffset } - val corners = remember { from.contentCorners } + val initialScale = remember { from.contentScale } + val initialOffset = remember { from.contentOffset } - val scaleState = remember { mutableStateOf(scale) } - val offsetState = remember { mutableStateOf(offset) } - val cornersState = remember { mutableStateOf(corners) } + val scale = animateFloat( + targetWhenHiding = { initialScale }, + targetWhenShowing = { 1f } + ) + + val offset = animateDp( + targetWhenHiding = { initialOffset }, + targetWhenShowing = { 0.dp } + ) + + val cornersState = animateDp( + targetWhenHiding = { 0.dp }, + targetWhenShowing = { 0.dp } + ) val alpha = animateFloat { 1f } - return remember { - AppScaffoldAnimationState( - scale = scaleState, - scaleMinimum = from.scaleMinimum, - offset = offsetState, - corners = cornersState, - cornersMaximum = from.cornersMaximum, - alpha = alpha - ) - } -} + return AppScaffoldAnimationState( + scale = scale, + scaleMinimum = from.scaleMinimum, + offset = offset, + corners = cornersState, + cornersMaximum = 0.dp, + alpha = alpha + ) +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt index c057d54094c..d0357165790 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt @@ -22,6 +22,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.unit.Dp import androidx.window.core.layout.WindowSizeClass +import org.signal.libsignal.protocol.logging.Log import org.thoughtcrime.securesms.keyvalue.SignalStore /** @@ -35,17 +36,19 @@ open class AppScaffoldNavigator @RememberInComposition constructor(private va var state: NavigationState by mutableStateOf(NavigationState.ENTER) private set + private var wasSeekInProgress = false + override suspend fun navigateTo(pane: ThreePaneScaffoldRole, contentKey: T?) { + wasSeekInProgress = false state = NavigationState.ENTER return delegate.navigateTo(pane, contentKey) } override suspend fun navigateBack(backNavigationBehavior: BackNavigationBehavior): Boolean { - if (state == NavigationState.SEEK) { + if (state == NavigationState.SEEK || wasSeekInProgress) { + wasSeekInProgress = false state = NavigationState.RELEASE - } - - if (state == NavigationState.ENTER) { + } else if (state == NavigationState.ENTER) { state = NavigationState.EXIT } @@ -54,7 +57,11 @@ open class AppScaffoldNavigator @RememberInComposition constructor(private va override suspend fun seekBack(backNavigationBehavior: BackNavigationBehavior, fraction: Float) { if (fraction > 0f && state != NavigationState.SEEK) { + wasSeekInProgress = true state = NavigationState.SEEK + } else if (fraction == 0f && state == NavigationState.SEEK) { + state = NavigationState.CANCEL + state = NavigationState.ENTER } return delegate.seekBack(backNavigationBehavior, fraction) @@ -82,7 +89,12 @@ open class AppScaffoldNavigator @RememberInComposition constructor(private va /** * The user has let go of a seek and will go back. */ - RELEASE + RELEASE, + + /** + * The user has cancelled the back gesture. + */ + CANCEL } } From ed8b8460fb33c599c28503147e961670bc9ab443 Mon Sep 17 00:00:00 2001 From: ateeb-infocusp Date: Wed, 11 Mar 2026 15:19:17 +0530 Subject: [PATCH 2/3] Remove a redundant Log import --- .../org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt index d0357165790..442008ce201 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt @@ -22,7 +22,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.unit.Dp import androidx.window.core.layout.WindowSizeClass -import org.signal.libsignal.protocol.logging.Log import org.thoughtcrime.securesms.keyvalue.SignalStore /** From 2dcccf5e26d53cd1e1ce8b21a031cdf65e966301 Mon Sep 17 00:00:00 2001 From: ateeb-infocusp Date: Mon, 23 Mar 2026 12:02:45 +0530 Subject: [PATCH 3/3] Simplify back gesture state handling by removing the CANCEL state. --- .../securesms/window/AppScaffoldAnimationState.kt | 6 ------ .../securesms/window/AppScaffoldNavigator.kt | 12 +++--------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimationState.kt b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimationState.kt index 605855a25eb..382a9f7edd1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimationState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldAnimationState.kt @@ -81,10 +81,6 @@ class AppScaffoldAnimationStateFactory( private val EMPTY_STATE = AppScaffoldAnimationState( alpha = mutableStateOf(1f) ) - - private val HIDDEN_STATE = AppScaffoldAnimationState( - alpha = mutableStateOf(0f) - ) } private var latestListSeekState: AppScaffoldAnimationState = EMPTY_STATE @@ -104,7 +100,6 @@ class AppScaffoldAnimationStateFactory( } AppScaffoldNavigator.NavigationState.RELEASE -> defaultListReleaseAnimationState(latestListSeekState) - AppScaffoldNavigator.NavigationState.CANCEL -> HIDDEN_STATE } } @@ -122,7 +117,6 @@ class AppScaffoldAnimationStateFactory( } AppScaffoldNavigator.NavigationState.RELEASE -> defaultDetailReleaseAnimationState(latestDetailSeekState) - AppScaffoldNavigator.NavigationState.CANCEL -> defaultDetailInitAnimationState() } } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt index 442008ce201..8c03a7ae792 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/window/AppScaffoldNavigator.kt @@ -58,8 +58,7 @@ open class AppScaffoldNavigator @RememberInComposition constructor(private va if (fraction > 0f && state != NavigationState.SEEK) { wasSeekInProgress = true state = NavigationState.SEEK - } else if (fraction == 0f && state == NavigationState.SEEK) { - state = NavigationState.CANCEL + } else if (fraction < 0.001f && state == NavigationState.SEEK) { state = NavigationState.ENTER } @@ -88,12 +87,7 @@ open class AppScaffoldNavigator @RememberInComposition constructor(private va /** * The user has let go of a seek and will go back. */ - RELEASE, - - /** - * The user has cancelled the back gesture. - */ - CANCEL + RELEASE } } @@ -144,4 +138,4 @@ fun rememberThreePaneScaffoldNavigatorDelegate( defaultPanePreferredWidth = defaultPanePreferredWidth ) ) -} +} \ No newline at end of file