refactor(#619): kill DRAWER_GESTURE_SCREENS — screen-owned drawer gestures via HermesScaffold (#624)

Replaces the fragile DRAWER_GESTURE_SCREENS global set + defensive
LaunchedEffect(snapTo(Closed)) + closeDrawer callback workaround with a
single source of truth: each screen declares its drawer-gesture preference
via HermesScaffold's new drawerGesturesEnabled parameter (default true).

Architecture:
- DrawerGestureController holds the active gesture state. HermesScaffold
  reconciles each screen's preference into it via SideEffect; when a screen
  opts out while the drawer is open, the controller closes the drawer itself.
- LocalDrawerGestureController CompositionLocal flows the controller from
  MainNavigation down to ModalNavigationDrawer, which reads .enabled and
  passes it to Material's gesturesEnabled parameter.
- DisableDrawerGestures() helper for entry screens that don't use
  HermesScaffold (Landing, AuthLogin, PairingCodeEntry).
- All 6 Settings drill-down sub-pages pass drawerGesturesEnabled = false.
- NavigationController.closeDrawer removed; navigateTo no longer needs a
  synchronous drawer-dismiss hook.

Removes: DRAWER_GESTURE_SCREENS set, both LaunchedEffect(gesturesEnabled)
and LaunchedEffect(drawerGesturesEnabled) blocks, drawerGesturesEnabled
local state, closeDrawer callback on NavigationController.

Fixes the recurring drawer-scrim stuck-open bug class (PRs #445, #454, #455).

Verified: ktlintCheck, assembleDebug, testDebugUnitTest all green locally.

Co-authored-by: Hy4ri <hy4ri@users.noreply.github.com>
This commit is contained in:
M57andHy4ri authored and GitHub committed 2026-07-18 14:25:23 +03:00
1 parent 0c2b9679b7
commit 0a0b612d3a
5 files changed
+297 -204

No files matched your search

@@ -18,11 +18,6 @@ object NavigationController {
var backStack: NavBackStack<NavKey>? = null
var pendingSessionId: String? = null
// Set by MainNavigation so navigation can synchronously dismiss the drawer
// (e.g. when drilling into a non-gesture sub-page) before a recomposition,
// preventing the drawer's gesture surface from intercepting the first tap.
var closeDrawer: (() -> Unit)? = null
// Bottom-nav primary screens — dynamic, updated by Navigation.kt via
// updatePrimaryScreens() when the user customises the bottom nav bar.
// Default matches the default 5 bottom-nav items.
@@ -51,11 +46,11 @@ object NavigationController {
if (isPrimaryScreen(key)) {
stack.clear()
} else {
// Drilling into a sub-page (non-primary): dismiss the drawer
// synchronously so its gesture surface can't eat the next tap.
closeDrawer?.invoke()
}
// Drawer dismissal is handled by DrawerGestureController (issue #619):
// when a non-gesture sub-page composes, its HermesScaffold reconciles
// drawerGesturesEnabled=false and the controller closes the drawer
// itself via SideEffect. No synchronous closeDrawer callback here.
stack.add(key)
}