From c8b4f4998399d199fdba7cb33125421a6a076fa0 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 11 Nov 2026 12:46:23 +0100 Subject: [PATCH 1/4] fix: pin navigation-compose to 2.9.6 Navigation 2.10 rewrote NavHost predictive back. A swipe back started soon after a forward navigation seeks with the forward transitions (the screen slides left and dims while the previous one comes in from the right), holds, then snaps. A later swipe uses the new default scaleOut instead of the destination's pop transitions. Pin 2.9.6, which 3.1.0 shipped, and keep Dependabot off 2.10. Closes #1852 --- .github/dependabot.yml | 3 +++ changelog.d/next/1853.fixed.md | 1 + gradle/libs.versions.toml | 4 +++- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changelog.d/next/1853.fixed.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 161e0af18d..929a0c8cf4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -57,6 +57,9 @@ updates: - dependency-name: "com.google.devtools.ksp*" - dependency-name: "com.github.skydoves.compose.stability.analyzer*" - dependency-name: "androidx.compose:compose-bom" + # Navigation 2.10 breaks predictive back transitions (wrong pair, then a snap); stay on 2.9.x. + - dependency-name: "androidx.navigation:*" + versions: [">= 2.10.0"] groups: gradle: patterns: diff --git a/changelog.d/next/1853.fixed.md b/changelog.d/next/1853.fixed.md new file mode 100644 index 0000000000..3a10320e90 --- /dev/null +++ b/changelog.d/next/1853.fixed.md @@ -0,0 +1 @@ +Swiping back from a screen right after opening it slides it out smoothly again, instead of stalling half-faded and snapping away. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c9f42e1e39..5e8ca1168d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,7 +9,9 @@ hiltAndroidx = "1.4.0" kotlin = "2.3.21" ktor = "3.6.1" lifecycle = "2.10.0" -navCompose = "2.10.2" +# 2.10 breaks predictive back: a swipe soon after a navigation seeks with the forward transitions, +# then snaps. Stay on 2.9.x until a release fixes it (see .github/dependabot.yml). +navCompose = "2.9.6" room = "2.8.5" slf4j = "2.0.20" haze = "1.7.3" From d8be263a71d6c9395eac10be760a40a1122400c9 Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 11 Nov 2026 13:29:50 +0100 Subject: [PATCH 2/4] fix: pin navigation-compose to 2.9.8 2.9.8 is the newest 2.9.x and fixes a NavHost predictive-back race (b/500945998). The changelog fragment now covers both swipe timings. --- changelog.d/next/1853.fixed.md | 2 +- gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/changelog.d/next/1853.fixed.md b/changelog.d/next/1853.fixed.md index 3a10320e90..5bac566802 100644 --- a/changelog.d/next/1853.fixed.md +++ b/changelog.d/next/1853.fixed.md @@ -1 +1 @@ -Swiping back from a screen right after opening it slides it out smoothly again, instead of stalling half-faded and snapping away. +Swiping back from a screen slides it out like the Back button does, and other apps can no longer open Bitkit's internal screens. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5e8ca1168d..2c02319d15 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ ktor = "3.6.1" lifecycle = "2.10.0" # 2.10 breaks predictive back: a swipe soon after a navigation seeks with the forward transitions, # then snaps. Stay on 2.9.x until a release fixes it (see .github/dependabot.yml). -navCompose = "2.9.6" +navCompose = "2.9.8" room = "2.8.5" slf4j = "2.0.20" haze = "1.7.3" From c47eba02cabb998384f4a7fc4bbd4e9036eec36e Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 11 Nov 2026 13:29:50 +0100 Subject: [PATCH 3/4] fix: drop navigation destination extras from launch intents Navigation 2.10 honours deepLinkIds only from the app itself; 2.9 honours them from any caller. Bitkit never sets them, so MainActivity removes them before NavHost reads the intent. --- app/src/main/java/to/bitkit/ui/MainActivity.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index cf0fe8b3eb..420a0f6c9f 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -31,6 +31,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavController import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -114,6 +115,7 @@ class MainActivity : FragmentActivity() { importance = NotificationManager.IMPORTANCE_LOW ) + intent.removeNavDestinationExtras() val consumedLaunchIntent = savedInstanceState?.getString(KEY_CONSUMED_LAUNCH_INTENT) val currentLaunchIntent = intent.launchKey() if (currentLaunchIntent == null || currentLaunchIntent != consumedLaunchIntent) { @@ -282,11 +284,21 @@ class MainActivity : FragmentActivity() { return } + intent.removeNavDestinationExtras() super.onNewIntent(intent) setIntent(intent) handleLaunchIntent(intent) } + /** + * Navigation 2.9 opens the destination these extras name for any caller; 2.10 trusts them only from this app. + * Bitkit never sets them, so drop them: an exported launch can then reach only the declared deep links. + */ + private fun Intent.removeNavDestinationExtras() { + removeExtra(NavController.KEY_DEEP_LINK_IDS) + removeExtra(NavController.KEY_DEEP_LINK_ARGS) + } + private fun handleLaunchIntent(intent: Intent) { if (intent.getBooleanExtra(EXTRA_PAYKIT_SUBSCRIPTION_PAYMENT_DUE, false)) { intent.removeExtra(EXTRA_PAYKIT_SUBSCRIPTION_PAYMENT_DUE) From e2403adba8d32fcc7bce820c62a7f0f6c3dd4a2f Mon Sep 17 00:00:00 2001 From: Ovi Trif Date: Wed, 11 Nov 2026 13:47:52 +0100 Subject: [PATCH 4/4] fix: use literal nav extra keys in launch intent cleanup NavController.KEY_DEEP_LINK_IDS and KEY_DEEP_LINK_ARGS are restricted to androidx.navigation, so lint rejects them; the literals match their values. --- app/src/main/java/to/bitkit/ui/MainActivity.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/MainActivity.kt b/app/src/main/java/to/bitkit/ui/MainActivity.kt index 420a0f6c9f..df8e69d790 100644 --- a/app/src/main/java/to/bitkit/ui/MainActivity.kt +++ b/app/src/main/java/to/bitkit/ui/MainActivity.kt @@ -31,7 +31,6 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavController import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable @@ -295,8 +294,8 @@ class MainActivity : FragmentActivity() { * Bitkit never sets them, so drop them: an exported launch can then reach only the declared deep links. */ private fun Intent.removeNavDestinationExtras() { - removeExtra(NavController.KEY_DEEP_LINK_IDS) - removeExtra(NavController.KEY_DEEP_LINK_ARGS) + removeExtra("android-support-nav:controller:deepLinkIds") + removeExtra("android-support-nav:controller:deepLinkArgs") } private fun handleLaunchIntent(intent: Intent) {