Repository navigation
fix(navigation): guard forward navigation against repeat taps - #57
Merged
Merged
Conversation
Navigator.goTo always appended. In the two-pane list-detail layout the list stays on screen and the scene never transitions, so tapping the selected row again (or the add/edit FAB twice) pushed a second entry with the same key. It shares the first one's content key, ViewModel and saved state, so nothing visibly changes and the user has to press back twice to leave it. A lifecycle guard such as dropUnlessResumed cannot catch this: every entry in that scene stays RESUMED. Make goTo single-top: a no-op while the destination is already the current section's top entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
During a single-pane scene transition (Android and iOS animate it) the outgoing screen stays composed and clickable. Tapping a second posting row, or the add/edit FAB again, while the first navigation animates pushed another screen on top. Navigation 3 caps every entry in a transitioning scene at STARTED, so wrap the three forward-navigation clicks in dropUnlessResumed, as the Android UI-events guidance does. goTo's single-top check already covers a repeat of the same destination in every layout; this covers different destinations during the transition. Back arrows stay on goBack(from). The negative tests host the screen at STARTED through LifecycleRegistry.createUnsafe: on desktop, the registry's main-thread check runs runBlocking(Dispatchers.Main) and deadlocks under a swapped StandardTestDispatcher. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Code Coverage
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #56, which made back navigation pop only its own entry. This PR covers the forward direction with two complementary guards.
Problems
Changes
Navigator.goTois single-top: a no-op while the destination is already the current section's top entry. It is a pure back-stack check, so it works in every layout and at any timing.dropUnlessResumedwraps the three forward-navigation clicks (posting row, add FAB, edit FAB), following the Android UI-events guidance. Navigation 3 caps entries in a transitioning scene atSTARTED, so the second tap is dropped.dropUnlessResumedalone would not fix problem 1. With two panes,ListDetailSceneStrategykeeps one scene key for the whole list-detail stack, soNavDisplaynever transitions and every entry staysRESUMED. In turn,goTosingle-top alone cannot catch problem 2, where the destinations are different. Back arrows keepgoBack(from)from #56; wrapping them as well would be redundant.On desktop,
NavDisplay's default transition isNone, so the single-pane window does not exist there. Only the single-top check matters on desktop.Tests
NavigatorTest: repeatedgoTo(same)adds once; the same key below the top still appends;goTo(sectionRoot)is a no-op.STARTEDand assert the click is dropped (list row, add FAB, edit FAB). Mutation-checked: removing one guard fails exactly one test.LifecycleRegistry.createUnsafe. On desktop, the regular registry's main-thread check runsrunBlocking(Dispatchers.Main), which deadlocks in test classes that swap Main for aStandardTestDispatcher.:core:navigation:check,:feature:posting:impl:check, and postingjvmTestandtestAndroidHostTest.No public API change (the
goTosignature is unchanged), so noapiDump.🤖 Generated with Claude Code