Repository navigation
feat: Add Android TV D-pad navigation support with tvOptions - #2173
Merged
Merged
Conversation
- ensemble@1.2.35-beta.1
- ensemble@1.2.38-beta.1
- ensemble@1.2.38-beta.2
TheNoumanDev
force-pushed
the
android_TV_implementation
branch
from
April 6, 2026 08:46
0ec7c68 to
30b28fa
Compare
TheNoumanDev
force-pushed
the
android_TV_implementation
branch
from
April 6, 2026 09:35
9761dfb to
59a05bc
Compare
TheNoumanDev
force-pushed
the
android_TV_implementation
branch
from
April 6, 2026 09:43
93bef64 to
7fd5f77
Compare
- ensemble@1.2.38-beta.3
- ensemble@1.2.38-beta.4
- ensemble@1.2.38-beta.5
- ensemble@1.2.38-beta.6
- ensemble@1.2.38-beta.7
The merge of main into android_TV_implementation landed the flutter-upgrade TODO/ignore block below the cacheExtent argument, so the `// ignore: deprecated_member_use` no longer applied to it and the comment merged into the padding explanation. Move the block back above the argument and drop the now-inaccurate const from the suggested ScrollCacheExtent call, since the extent is user-configurable. Comment-only change; no behavior change.
…tion Brings in PR #2387 (page-scoped PageEventBus, API disposal guards, storage cleanup). Conflict resolved in modules/ensemble/lib/framework/scope.dart: kept the branch's shared-resource dispose split and adopted the incoming isDisposed semantics. pageData._disposed is set on the root-scope path only, because child scopes already early-return and must not mark the page disposed. That keeps PR #2387's API onResponse/onError disposal guards effective while child-scope teardown still leaves the page alive. The incoming PageEventBus model indexing applies unchanged in the branch's _listenToBindingSource (the incoming change targeted the pre-branch method name listen()).
feat(tv): add opt-in focusHighlightColor, outside and gap scrollbar options
Feat/tabbar focus onback
In the default focus-scroll mode, the whole-page pager reveal and the enclosing horizontal lane scroll ran together, both measured from the item's pre-move position. A peeking slide inside a horizontal lane was therefore moved twice and focus ended off screen. Run the lane scroll after the page move completes and is laid out, and only if the item is still focused.
fix(tv): preserve pager alignment during focus scroll
fix: scroll tab content back to the top when Back returns focus to the tab
fix: keep carousel state and focus through rebuilds and slide changes
…a new widget instance EWidgetState.didUpdateWidget released the old widget instance's binding owner, which cancelled every subscription keyed on that instance. Widgets that subscribe through a direct listen() call (Conditional, TabBar, item templates) register once in didChangeDependencies, keyed on the widget they had at that time. When a parent rebuilt its subtree from the model, Flutter kept the child State but handed it a new widget instance, so the child lost its only subscriptions and never reacted to data changes again. In the KPN InHome app this left a Conditional on ensemble.storage.hasDnsBackup frozen after the RestoreSettings screen's load APIs responded, so the restored-settings UI never updated. Introduce PageBindingManager.transferBindingOwner: cancel the old instance's managed subscriptions (the new instance re-registered its own while it was built), re-key the remaining direct subscriptions to the new instance and move the owner count with them so dispose() still releases everything. Add a regression test with a nested Conditional under a rebuilding parent that checks reactivity, a stable listener count across repeated rebuilds and full cleanup on unmount.
…isteners fix(scope): keep direct listen() subscriptions when a State receives a new widget instance
usmanvrtx
requested review from
sharjeelyunus
and removed request for
sharjeelyunus
November 10, 2026 14:34
sharjeelyunus
approved these changes
Nov 10, 2026
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.
Summary
Add D-pad focus navigation system for Android TV with coordinate-based
tvOptionsin YAML. All TV code gated behindDevice().isTVcheck.Key Changes
Core TV Framework
row,order,isRowEntryPoint)Widget Support
TVOptionsCompositewith focus stylingLayout Support
scrollbarOptions) with fallback (direct) focus when the list has no focusable itemsdelegateHorizontalNavigation,interceptHorizontalNavtabWidgetsupport, plusfocusIndicatorColor/focusTabColor/tvRowTheme Integration
Tokens.TV.*for focus stylingisTVgetter for Android TV detectionFocus Styling Properties under
tvOptionsrow,order,isRowEntryPoint,rememberRowPosition,focusGroup,edges,focusBorderColor,focusBorderWidth,focusBorderRadius,scale,elevation,opacityExample
Developer docs
Comprehensive developer guide:
modules/ensemble/doc/tv_developer_guide.mdNon-TV Changes (this branch)
Cross-platform changes not behind the TV flag:
New properties:
allowRedirectto block HTTP redirects (newRedirectBlockingHttpClient, redirect-keyed cache)indicatorLeadingWidget/indicatorTrailingWidgetautofocus+${widget.hasFocus}getterscalelayout knob, opt-in tab borders (borderColor/borderWidth/selectedBorderColor/selectedBorderWidth),roundIndex/matchIndextemplate bindingsImprovements & fixes:
shouldRepaintreturns real conditions, crash guards (_scrollToSelectedTab,_onPageChanged), default match scope-name typomarch→matchtokensOverrides), controlleridpropagation, external-navigation themingDemo
Video: https://drive.google.com/file/d/1mZfg8hNFv9m0QkUy0S3P1C4Xkt287tfc/view?usp=sharing
To test the KPN Android TV app, download this APK and install on the Tv emulator or real device: https://dev.azure.com/kpn/_apis/resources/Containers/28001799/android_apk?itemPath=android_apk%2Fapp-kpnandroidtvstaging-release.apk