fix(tab): avoid TabController crash when all conditional tabs are hidden#2241
Draft
cursor[bot] wants to merge 1 commit into
Draft
fix(tab): avoid TabController crash when all conditional tabs are hidden#2241cursor[bot] wants to merge 1 commit into
cursor[bot] wants to merge 1 commit into
Conversation
When every tab has a conditional visible binding that evaluates to false, handleConditionalTabs() can leave zero visible items. TabController asserts length >= 1, which crashed the app during _reinitializeTabController. Use a placeholder length of 1 when no tabs are visible (build already returns shrink) and skip tab selection listeners until tabs return. Align ScrollableTabBar with the same guard and selectedIndex clamp. Co-authored-by: Sharjeel Yunus <sharjeelyunus@users.noreply.github.com>
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.
Description
Fixes an app crash when every tab in a
TabBarorScrollableTabBaruses a conditionalvisiblebinding and all bindings evaluate to false at runtime.Bug and impact
Trigger: A screen with tabs where each item has
visible: ${someCondition}(or equivalent), and runtime evaluation sets every condition to false (e.g. user clears a filter that controlled all tab visibility).Impact:
handleConditionalTabs()calls_reinitializeTabController(), which createdTabController(length: 0). Flutter assertslength >= 1, causing a framework assertion crash.Root cause
updateVisibleItems()can produce an empty visible tab list, but_initializeTabController()passeditems.lengthdirectly toTabControllerwithout guarding zero.Fix
effectiveTabControllerLength()so controller length is never below 1 when no tabs are visible (UI already returnsSizedBox.shrink()).notifyListeneron the placeholder controller when there are no visible tabs.ScrollableTabBarand clampselectedIndexwhen reinitializing (matchingTabBar).Validation
modules/ensemble/test/effective_tab_controller_length_test.dart.flutter test test/effective_tab_controller_length_test.dartfrommodules/ensembleperAGENTS.md.Duplicate check
gh pr list): no PR addressesTabController/ conditional tab visibility with zero visible items. Open drafts cover storage.clear ordering (fix(storage): defer binding updates until ensemble.storage.clear() completes #2231), upload batching (fix(upload): schedule all background batches with unique Workmanager work names #2239), upload cancelAll (fix(upload): complete cancelAll when some uploads already finished #2235), and navigateViewGroup clamping (fix(navigation): clamp navigateViewGroup index before PageController.jumpToPage #2238) — different code paths.TabController,handleConditionalTabs, and empty tab scenarios: none found.useIndexedTabproperty for smooth tab switching with lazy-loaded indexed building #2190 indexed tabs) did not handle the zero-length controller case.