Skip to content

feat: Add Android TV D-pad navigation support with tvOptions#2173

Open
TheNoumanDev wants to merge 35 commits into
mainfrom
android_TV_implementation
Open

feat: Add Android TV D-pad navigation support with tvOptions#2173
TheNoumanDev wants to merge 35 commits into
mainfrom
android_TV_implementation

Conversation

@TheNoumanDev

@TheNoumanDev TheNoumanDev commented Mar 6, 2026

Copy link
Copy Markdown
Member

Summary

  • Add D-pad focus navigation system for Android TV using coordinate-based tvOptions in YAML
  • Support both host app integration (via TVFocusProvider) and standalone mode for Ensemble(via TVFocusWidget)
  • Gate all TV code behind Device().isTV check to prevent impact on mobile/web

Key Changes

Core TV Infrastructure

  • device.dart: isTV getter checks Android TV system features (android.hardware.type.television, android.software.leanback)
  • tv_focus_provider.dart: Interface for host app focus integration with rowOffset/orderOffset support
  • tv_focus_widget.dart: Built-in D-pad navigation with grid-based focus traversal
  • tv_focus_order.dart: Coordinate system (row, order, isRowEntryPoint)
  • tv_focus_theme.dart: Focus styling resolution (theme > provider > primary color)

Widget Support

  • box_wrapper.dart: TV focus wrapping for BoxController-based widgets (~30 widgets)
  • form_helper.dart + input_wrapper.dart: TV focus support for FormFieldController widgets (~10 widgets)
  • controllers.dart: TVOptionsComposite class with focus styling overrides

Theme Integration

  • theme_loader.dart: Parse Tokens.TV.* for focus styling
  • theme_manager.dart: Pass tokensOverrides to include TV tokens in EnsembleThemeExtension
  • screen_controller.dart: Wrap externally navigated screens with Theme for TV focus colors

Example of style override:

Column:
    styles:
        tvOptions:
            row: 0
            order: 0
            isRowEntryPoint: true
            focusBorderRadius: 8  # Optional per-widget override
    onTap: ...

For testing purpose, release ensemble-v1.2.35-beta.1 version

Screen recording: https://drive.google.com/file/d/1dXP4UByfQRXY5DLpHA2V3pYHR_wPVWdc/view?usp=sharing

@TheNoumanDev TheNoumanDev force-pushed the android_TV_implementation branch from 0ec7c68 to 30b28fa Compare April 6, 2026 08:46
@TheNoumanDev TheNoumanDev force-pushed the android_TV_implementation branch from 9761dfb to 59a05bc Compare April 6, 2026 09:35
@TheNoumanDev TheNoumanDev force-pushed the android_TV_implementation branch from 93bef64 to 7fd5f77 Compare April 6, 2026 09:43
TheNoumanDev and others added 8 commits June 22, 2026 15:43
 - ensemble@1.2.46-beta.1
 - ensemble@1.2.46-beta.2
 - ensemble@1.2.46-beta.3
When a TabItem has a tabWidget defined, _TVTabButton now renders
it instead of the default icon+label, consistent with the non-TV
TabBar behavior.
…bility

Replace MediaQuery screen size with scrollable viewport bounds when
calculating whether a focused item is above/below the visible area.
This correctly handles scrollables that don't span the full screen.

Also fixes verticalPadding usage: it's now a positioning inset within
the viewport rather than a threshold relative to screen edges,
preventing horizontal navigation jitter.
 - ensemble@1.2.48-beta.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant