From 956908a9bae972ec37f0d2d15f29997ffd34d096 Mon Sep 17 00:00:00 2001 From: Jacob Hagstedt Date: Sun, 18 Oct 2026 21:51:20 +0200 Subject: [PATCH] M8f: instant navigation, no transitions (D-108) NavHost enter, exit, pop and size transitions are None, so pushed screens, tab switches, editors and the session gate change at once instead of the default 700 ms cross-fade. NavTransitionsTest asserts the values. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B --- .../kotlin/se/hagstedt/kvitt/nav/KvittApp.kt | 11 +++++++- .../se/hagstedt/kvitt/nav/NavTransitions.kt | 27 +++++++++++++++++++ .../hagstedt/kvitt/nav/NavTransitionsTest.kt | 25 +++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 android/app/src/main/kotlin/se/hagstedt/kvitt/nav/NavTransitions.kt create mode 100644 android/app/src/test/kotlin/se/hagstedt/kvitt/nav/NavTransitionsTest.kt diff --git a/android/app/src/main/kotlin/se/hagstedt/kvitt/nav/KvittApp.kt b/android/app/src/main/kotlin/se/hagstedt/kvitt/nav/KvittApp.kt index 75578fa..487f186 100644 --- a/android/app/src/main/kotlin/se/hagstedt/kvitt/nav/KvittApp.kt +++ b/android/app/src/main/kotlin/se/hagstedt/kvitt/nav/KvittApp.kt @@ -149,7 +149,16 @@ private fun AppGraph(viewModel: AppViewModel, session: SessionState, updateCheck // Result snackbars are shown in the scaffold of the screen returned to (Home, S-5, S-8, S-10, S-12, S-16), which // each host [snackbar] (D-071). - NavHost(nav, startDestination = start) { + // D-108: every destination change is instant (NavTransitions). + NavHost( + nav, + startDestination = start, + enterTransition = NavTransitions.enter, + exitTransition = NavTransitions.exit, + popEnterTransition = NavTransitions.enter, + popExitTransition = NavTransitions.exit, + sizeTransform = NavTransitions.size, + ) { onboarding(viewModel, shell) topLevel(session, shell) accountsAndExpenses(viewModel, shell) diff --git a/android/app/src/main/kotlin/se/hagstedt/kvitt/nav/NavTransitions.kt b/android/app/src/main/kotlin/se/hagstedt/kvitt/nav/NavTransitions.kt new file mode 100644 index 0000000..b363cf2 --- /dev/null +++ b/android/app/src/main/kotlin/se/hagstedt/kvitt/nav/NavTransitions.kt @@ -0,0 +1,27 @@ +package se.hagstedt.kvitt.nav + +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.animation.SizeTransform +import androidx.navigation.NavBackStackEntry + +/** + * Destination changes are instant (D-108): no enter, exit, pop or size animation for pushed screens, tab switches, + * editors or the session gate (`NavHost` otherwise cross-fades every change over 700 ms). Motion inside a screen + * (ripples, expanding sections, the FAB, sheets) belongs to the components and is not affected. + * + * The `NavHost` lambdas only delegate to [enterTransition], [exitTransition] and [sizeTransform], which the unit + * test asserts (the transition scope is sealed and cannot be built outside a composition). + */ +internal object NavTransitions { + fun enterTransition(): EnterTransition = EnterTransition.None + + fun exitTransition(): ExitTransition = ExitTransition.None + + fun sizeTransform(): SizeTransform? = null + + val enter: AnimatedContentTransitionScope.() -> EnterTransition = { enterTransition() } + val exit: AnimatedContentTransitionScope.() -> ExitTransition = { exitTransition() } + val size: AnimatedContentTransitionScope.() -> SizeTransform? = { sizeTransform() } +} diff --git a/android/app/src/test/kotlin/se/hagstedt/kvitt/nav/NavTransitionsTest.kt b/android/app/src/test/kotlin/se/hagstedt/kvitt/nav/NavTransitionsTest.kt new file mode 100644 index 0000000..33a49ca --- /dev/null +++ b/android/app/src/test/kotlin/se/hagstedt/kvitt/nav/NavTransitionsTest.kt @@ -0,0 +1,25 @@ +package se.hagstedt.kvitt.nav + +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import org.junit.Assert.assertNull +import org.junit.Assert.assertSame +import org.junit.Test + +/** D-108: the app's `NavHost` changes destination without any animation. */ +class NavTransitionsTest { + @Test + fun enterIsNone() { + assertSame(EnterTransition.None, NavTransitions.enterTransition()) + } + + @Test + fun exitIsNone() { + assertSame(ExitTransition.None, NavTransitions.exitTransition()) + } + + @Test + fun noSizeTransform() { + assertNull(NavTransitions.sizeTransform()) + } +}