bugfix-navigation - The one about Navigation Drift (refactor) - #1414
Merged
RadicalMuffinMan merged 2 commits intoSep 5, 2026
Merged
Conversation
…alignment - Derive _scrollToGridRow positioning directly from _gridGeometry (perLine, lineExtent, lineSpacing, leadingPad) to maintain single source of truth with SliverGridDelegateWithFixedCrossAxisCount. - Forward dynamic rowSpacing and gridTopPadding through _buildGridCard to account for focusOverhang across tvOS (1.12 scale), Android TV, and Desktop (Large card settings and Banner layouts). - Guard _scrollToGridRow and card onFocus against running while _isJumpingToLetter is active, preventing viewport conflicts during alphabet jumps. - Adjust viewport topPad to effectiveLeadingPad to prevent clipping of the scaled top-row card glow. - Add test/ui/library_browse_grid_focus_test.dart covering row offset parity across 200 rows under multiple platform focus scales. Fixes Moonfin-Client#1356
✅ Build SuccessfulAll platform builds passed. You can download the test artifacts below.
|
…he grid actually drew, drop the letter jump guards that were already cleared by the time focus landed, and back it with tests that measure a real sliver instead of repeating the formula
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.
Pull Request
Summary
This is a pretty big swing but I think it is worth it. Prompted by issue #1356, I looked into what was responsible for the drift and found that, while the problem is magnified on tvOS (details below), it also impacts Desktop (with keyboard/remote navigation) and AndroidTV. The goal of this PR is to prevent focus indicator drift during vertical scrolling and viewport yank-back during alphabet letter jumps in the library browse grid. Since this is a pretty impactful PR, here are additional details about the root of the issue and why it should be addressed.
Background & Problem
When navigating vertical library grids, focused cards scale up to indicate selection (
MediaCard.focusScale). To prevent focused cards from visually clipping neighboring elements or top screen bounds, the vertical sliver layout reserves spacing dynamically in library_browse_screen.dart:focusOverhang = isMobile ? 0.0 : MediaCard.focusGap(cellHeight, minimum: 0.0)rowSpacing = math.max(8.0, focusOverhang)gridTopPadding = 8.0 + focusOverhangOn tvOS, Apple TV guidelines specify a larger focus expansion (
focusScale = 1.12), producing a~16.92pxoverhang for standard poster cards (cellHeight ≈ 282px). On Android TV and Desktop,focusScale = 1.05. For standard cards on those platforms,focusOverhangis7.05px(clamped to8.0px), but for "Large" poster preferences or "Banner" views (cellHeight > 320px),focusOverhangexceeds8.0px(e.g.,9.0pxat360px).However, the programmatic focus scrolling method _scrollToGridRow was not using these dynamic values. At its invocation in _buildGridCard,
mainAxisSpacingwas hardcoded to8.0, andgridTopPaddingdefaulted to8.0. This created a progressive mathematical divergence between where the sliver grid actually positioned cards on screen and where _scrollToGridRow thought cards were located:~8.92pxerror accumulated per row. At row 30, the calculated offset was ~267px too high; at row 100, it was ~892px too high. As the user navigated downward, _scrollToGridRow falsely determined that the card was above the top viewport boundary and scrolled in reverse (upward), driving the focused card off the bottom of the screen.8.0px, viewing Large cards or Banner layouts suffered progressive drift (e.g. 109px drift over 100 rows). In addition, an ~7px top-padding offset error was present on all non-mobile platforms.8.0pxformula. This immediately yanked the viewport backward, throwing the freshly selected letter target off screen.Architectural Solution
To ensure long-term stability across all platforms (tvOS, Android TV, Desktop) and display configurations (Standard, Large, Banner), this PR refactors _scrollToGridRow to treat the active layout geometry (_gridGeometry) as the single source of truth:
perLine,lineExtent,lineSpacing, andleadingPaddirectly from _gridGeometry. The scroll controller andSliverGridDelegateWithFixedCrossAxisCountnow share identical mathematical coordinates without maintaining duplicated formulas.rowSpacingandgridTopPadding(8 + focusOverhang) so that any fallback calculations also mirror the rendered layout.topPadin _scrollToGridRow toeffectiveLeadingPad, ensuring the top-row card glow and 12% tvOS focus expansion are never clipped by the upper screen edge.Related Issues
Link related issues or tickets separated by commas.
Type of Change
Changes Made
List the key changes included in this PR.
rowSpacingandgridTopPaddingfrom _buildVerticalGrid through _buildGridCard to replace legacy hardcoded8.0pxvalues.topPad) toeffectiveLeadingPadto preserve focus glow clearance at the top of the grid.Platform
Testing
Describe how this change was tested.
Test Steps
flutter test test/ui/library_browse_grid_focus_test.dartandflutter test test/focus/.Screenshots (if applicable)
Include screenshots or recordings for UI changes.
Focus indicactor remains on screen and movement is smooth (except for when I hit loading transitions):
2026-09-05_10-00-17_PotPlayer64.mp4
Checklist