Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5ff97dc
Added the Tv navigation support
TheNoumanDev Mar 6, 2026
370e028
Merge branch 'main' into android_TV_implementation
TheNoumanDev Mar 6, 2026
aea5ef4
chore(release): publish packages
TheNoumanDev Mar 6, 2026
ac926c6
merged main and resolved conflicts
TheNoumanDev Mar 27, 2026
96af6b0
chore(release): publish packages
TheNoumanDev Mar 27, 2026
0ccfcfc
FIxed vertical jerk issue
TheNoumanDev Mar 29, 2026
1da8810
chore(release): publish packages
TheNoumanDev Mar 29, 2026
30b28fa
Add lockHorizontalNavigation and scroll animation options for TV
TheNoumanDev Apr 6, 2026
59a05bc
Merge branch 'main' into android_TV_implementation
TheNoumanDev Apr 6, 2026
7fd5f77
fixed controller file
TheNoumanDev Apr 6, 2026
b9e7bc4
chore(release): publish packages
TheNoumanDev Apr 6, 2026
39fc3dd
Merge main into android_TV_implementation
TheNoumanDev Apr 17, 2026
2083fab
enhance TV focus navigation with delegate options and autoplay controls
TheNoumanDev Apr 22, 2026
3808021
chore(release): publish packages
TheNoumanDev Apr 23, 2026
8b916eb
fixed the scrolling issue and the focus border issues
TheNoumanDev May 20, 2026
cdfd4b2
chore(release): publish packages
TheNoumanDev May 20, 2026
ca53846
added the styling for focused state of button and wrapper widgets
TheNoumanDev May 22, 2026
f21318d
chore(release): publish packages
TheNoumanDev May 22, 2026
ed557c4
merged main and resolved conflicts
TheNoumanDev Jun 3, 2026
9fe6ea2
Merge remote android_TV_implementation branch
TheNoumanDev Jun 3, 2026
992bda6
added teh scrollBar option to support focus
TheNoumanDev Jun 5, 2026
10c0ce9
updated the auto focus property
TheNoumanDev Jun 5, 2026
341f280
added docs for TV guide for now
TheNoumanDev Jun 5, 2026
abaaa8b
chore(release): publish packages
TheNoumanDev Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
439 changes: 439 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

1,474 changes: 1,474 additions & 0 deletions docs/TV_DEVELOPER_GUIDE.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion modules/adobe_analytics/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies:
ensemble:
git:
url: https://github.com/EnsembleUI/ensemble.git
ref: ensemble-v1.2.44
ref: ensemble-v1.2.38-beta.7
path: modules/ensemble

flutter_aepcore: ^5.0.0
Expand Down
2 changes: 1 addition & 1 deletion modules/auth/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ dependencies:
ensemble:
git:
url: https://github.com/EnsembleUI/ensemble.git
ref: ensemble-v1.2.44
ref: ensemble-v1.2.38-beta.7
path: modules/ensemble

ensemble_ts_interpreter: ^1.0.7
Expand Down
2 changes: 1 addition & 1 deletion modules/bracket/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies:
ensemble:
git:
url: https://github.com/EnsembleUI/ensemble.git
ref: ensemble-v1.2.44
ref: ensemble-v1.2.38-beta.7
path: modules/ensemble

dev_dependencies:
Expand Down
4 changes: 2 additions & 2 deletions modules/camera/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ dependencies:
ensemble:
git:
url: https://github.com/EnsembleUI/ensemble.git
ref: ensemble-v1.2.44
ref: ensemble-v1.2.38-beta.7
path: modules/ensemble
ensemble_ts_interpreter: ^1.0.7

# QR Code scanner module (for backward compatibility re-export)
ensemble_qr_scanner:
git:
url: https://github.com/EnsembleUI/ensemble.git
ref: ensemble-v1.2.44
ref: ensemble-v1.2.38-beta.7
path: modules/qr_scanner

collection: ^1.17.1
Expand Down
2 changes: 1 addition & 1 deletion modules/chat/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies:
ensemble:
git:
url: https://github.com/EnsembleUI/ensemble.git
ref: ensemble-v1.2.44
ref: ensemble-v1.2.38-beta.7
path: modules/ensemble

ensemble_ts_interpreter: ^1.0.7
Expand Down
2 changes: 1 addition & 1 deletion modules/connect/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies:
ensemble:
git:
url: https://github.com/EnsembleUI/ensemble.git
ref: ensemble-v1.2.44
ref: ensemble-v1.2.38-beta.7
path: modules/ensemble

plaid_flutter: ^3.1.2
Expand Down
2 changes: 1 addition & 1 deletion modules/contacts/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies:
ensemble:
git:
url: https://github.com/EnsembleUI/ensemble.git
ref: ensemble-v1.2.44
ref: ensemble-v1.2.38-beta.7
path: modules/ensemble

flutter_contacts: ^1.1.7+1
Expand Down
2 changes: 1 addition & 1 deletion modules/deeplink/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies:
ensemble:
git:
url: https://github.com/EnsembleUI/ensemble.git
ref: ensemble-v1.2.44
ref: ensemble-v1.2.38-beta.7
path: modules/ensemble

flutter_branch_sdk: ^7.0.1
Expand Down
71 changes: 71 additions & 0 deletions modules/ensemble/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
## 1.2.38-beta.7

- **REFACTOR**(tabbar): remove useIndexedTab setter duplication from TabBarController. ([faafd299](https://github.com/ensembleUI/ensemble/commit/faafd2996c3f0a9b9609acfba4e3286165e2ca80))
- **REFACTOR**(cdn): improve secret management and artifact handling in CdnDefinitionProvider. ([a2c87792](https://github.com/ensembleUI/ensemble/commit/a2c877925a4d2ac489aab8c5a89f3e66e4dd5a98))
- **FIX**(upload): scope cancelAll to upload Workmanager tags only. ([4d763ac4](https://github.com/ensembleUI/ensemble/commit/4d763ac4c883363a96a6a5b8b3c264bf8fb3f0b3))
- **FIX**(upload): schedule every background batch with unique Workmanager names. ([33829f9b](https://github.com/ensembleUI/ensemble/commit/33829f9b49da513c587a2e603609cf8d1af49723))
- **FIX**(navigation): clamp navigateViewGroup index before PageController.jumpToPage. ([0ce6723a](https://github.com/ensembleUI/ensemble/commit/0ce6723a14095823fb5d2f1ba3938c45f76c289d))
- **FIX**(upload): complete cancelAll when some tasks are already completed. ([93cfc387](https://github.com/ensembleUI/ensemble/commit/93cfc387e700a5a1cb1c327b85f68a8ac56011d2))
- **FIX**(storage): defer binding dispatches until public storage clear completes. ([8c2a52de](https://github.com/ensembleUI/ensemble/commit/8c2a52de1e84c078ff01905c3bce07428f5dc5ba))
- **FIX**(listview): sync ListViewCore scroll controller when parent swaps it. ([c792a8a6](https://github.com/ensembleUI/ensemble/commit/c792a8a673196a1ae2eedf92ef488be438644602))
- **FIX**(page): cancel header timers and dedupe storage event listeners. ([2c45e427](https://github.com/ensembleUI/ensemble/commit/2c45e4273678ff91007d486137e264dedc9c2251))
- **FIX**(navigation): clamp ViewGroup tab index when payloads shrink. ([2b62b4a2](https://github.com/ensembleUI/ensemble/commit/2b62b4a2072862c27e9292ca0d38cefa1d1d9fad))
- **FIX**(security): block path traversal in local bundled screen resolution. ([b317c925](https://github.com/ensembleUI/ensemble/commit/b317c9256d96cd01f3183866d3f5e38bfe9b6ff7))
- **FIX**(layout): restore scroll controller when leaving footer scope. ([9f20ea43](https://github.com/ensembleUI/ensemble/commit/9f20ea43ddb389d6a718122dc01240fc5d3d3932))
- **FIX**(listview): dispose owned scroll controller. ([e5d1c101](https://github.com/ensembleUI/ensemble/commit/e5d1c101080f49ac0596f09d93c1d2df4e4dff22))
- **FIX**(security): reject unsafe screen selectors in remote definition fetches. ([db7de5b2](https://github.com/ensembleUI/ensemble/commit/db7de5b28f45c0dd2438ff7d0e1bea61bba1da6d))
- **FIX**(security): sanitize saveFile names before writing to storage. ([a3db4674](https://github.com/ensembleUI/ensemble/commit/a3db467427bd473e3b1a02c113369bcdaa75b6a4))
- **FIX**(security): stop WebView from bypassing TLS and unsafe-browsing defaults. ([a51ba979](https://github.com/ensembleUI/ensemble/commit/a51ba979ddb12fa3cb48af0f436e5a1cb1057fc7))
- **FIX**(device): update screenOrientation to use enum name for clarity. ([41b9dee0](https://github.com/ensembleUI/ensemble/commit/41b9dee0c974a06882db5edbd1219084ad81fc9c))
- **FIX**(cdn): reset invalid manifest cache state. ([4e060421](https://github.com/ensembleUI/ensemble/commit/4e060421ebf7ba2121284ba93c825db7370b8f2d))
- **FEAT**(device): streamline MediaQuery capability and add device metric notifications. ([991650b6](https://github.com/ensembleUI/ensemble/commit/991650b6666e615eca2e9b7f8418af847a08d3d0))
- **FEAT**(tab): fix persistentTabBar behavior with listview. ([ed51255a](https://github.com/ensembleUI/ensemble/commit/ed51255a0b8456c9ec3654f6ddce1e315cae9d77))
- **FEAT**(tabbar): add indexed tab mode with on-demand tab building and caching. ([93cd430b](https://github.com/ensembleUI/ensemble/commit/93cd430b0b700ae123ddf378f627ab884067f515))
- **FEAT**(cdn): enhance CdnDefinitionProvider with environment variable handling and secret management. ([42669188](https://github.com/ensembleUI/ensemble/commit/42669188ea423c9dba5beac449ee38853f01b88b))
- **FEAT**(tab): add persistentTabBar option for keep the tab pinned. ([bbafb0d1](https://github.com/ensembleUI/ensemble/commit/bbafb0d1c3be1f321cbe92f3cc0d8598e476dde0))
- **DOCS**(ensemble): document storage.clear and multipart upload paths. ([d88fb624](https://github.com/ensembleUI/ensemble/commit/d88fb624b68136d3f006eac5ea7c6bc78752e1e2))
- **DOCS**(ensemble): document runtime security and device metric bindings. ([b7087842](https://github.com/ensembleUI/ensemble/commit/b7087842440ae498e11e1f088ddbfcc3f8d7dc5b))
- **DOCS**: update package and module READMEs. ([74306617](https://github.com/ensembleUI/ensemble/commit/74306617e40588dc149587bddd7a9c7ca87fc5bf))
- **DOCS**: move layout widget notes out of package readme. ([fc901707](https://github.com/ensembleUI/ensemble/commit/fc9017078bd2147c6486352e886a347a04ef6dcc))
- **DOCS**: document layout widget scroll and tab behavior. ([ba64173e](https://github.com/ensembleUI/ensemble/commit/ba64173e4433c49d6907c78494970639d5a93748))

## 1.2.44

- **FIX**(upload): scope cancelAll to upload Workmanager tags only. ([4d763ac4](https://github.com/ensembleUI/ensemble/commit/4d763ac4c883363a96a6a5b8b3c264bf8fb3f0b3))
Expand Down Expand Up @@ -41,6 +72,20 @@
- **REFACTOR**(cdn): improve secret management and artifact handling in CdnDefinitionProvider. ([a2c87792](https://github.com/ensembleUI/ensemble/commit/a2c877925a4d2ac489aab8c5a89f3e66e4dd5a98))
- **FEAT**(cdn): enhance CdnDefinitionProvider with environment variable handling and secret management. ([42669188](https://github.com/ensembleUI/ensemble/commit/42669188ea423c9dba5beac449ee38853f01b88b))

## 1.2.38-beta.6

- releaseing new beta version

## 1.2.38-beta.5

- Releasing new beta version for TV

## 1.2.38-beta.4

- **FIX**(incorrect header format): explicit convertion of header entry into string. ([84ead788](https://github.com/ensembleUI/ensemble/commit/84ead788a7cd0b1aee50292eabf07bc8ae3c490d))
- **FEAT**(image): enhance header evaluation for dynamic HTTP headers in image requests. ([e24544fe](https://github.com/ensembleUI/ensemble/commit/e24544fe2587a4119f6c4a8242e9b51948eef57c))
- **FEAT**(image): add support for custom HTTP headers in image requests. ([3a304a2c](https://github.com/ensembleUI/ensemble/commit/3a304a2cd01a2af6046a327a9380cf259cb1e37e))

## 1.2.39

- **FIX**(incorrect header format): explicit convertion of header entry into string. ([84ead788](https://github.com/ensembleUI/ensemble/commit/84ead788a7cd0b1aee50292eabf07bc8ae3c490d))
Expand All @@ -52,6 +97,26 @@
- **FEAT**(action): add ActionType.executeAction to ActionInvokable class. ([b5cc5a4a](https://github.com/ensembleUI/ensemble/commit/b5cc5a4af5ac95b0ed4971349f5cf5ab9a481672))
- **FEAT**(lottie): add custom Lottie decoder for .lottie file ext support. ([cc73e7cf](https://github.com/ensembleUI/ensemble/commit/cc73e7cf87475a7e538b0c88a099a90c5c63af21))

## 1.2.38-beta.3

- **FIX**(invoke_api_action): handle FirestoreResponse in error handling. ([c8cb1c7b](https://github.com/ensembleUI/ensemble/commit/c8cb1c7b1bb97405bc61893338b1aeab53838a8f))
- **FEAT**(dotenv): implement dotenv bundle parsing and refactor config loading. ([0a987c94](https://github.com/ensembleUI/ensemble/commit/0a987c94aef06e2b220fca85c1d8f43c707fd506))

## 1.2.38-beta.2

- Releasing new beta version 1.2.38.2

## 1.2.38-beta.1

- **FIX**(phone_contact): replace RuntimeError with debugPrint for missing contact photo. ([b36b399d](https://github.com/ensembleUI/ensemble/commit/b36b399d91fad26e46e14f0845c624a3f8b768c9))
- **FIX**(firestore_types): handle FirestoreTimestamp conversion in EnsembleFieldValue class. ([a4e8dba0](https://github.com/ensembleUI/ensemble/commit/a4e8dba0142250eee12b09fd012ae85e5ac18f2f))
- **FIX**(page_model): convert keys to strings in merged global actions. ([4dcb7e4a](https://github.com/ensembleUI/ensemble/commit/4dcb7e4a888a6259cb4f1a8daceb6338731ec6c8))
- **FEAT**(action): add ActionType.executeAction to ActionInvokable class. ([b5cc5a4a](https://github.com/ensembleUI/ensemble/commit/b5cc5a4af5ac95b0ed4971349f5cf5ab9a481672))
- **FEAT**(lottie): add custom Lottie decoder for .lottie file ext support. ([cc73e7cf](https://github.com/ensembleUI/ensemble/commit/cc73e7cf87475a7e538b0c88a099a90c5c63af21))
- **FEAT**(env): enhance environment variable loading and parsing. ([b7666ceb](https://github.com/ensembleUI/ensemble/commit/b7666ceb292427ad24445cc3080a68e9aca8c47a))
- **FEAT**(cdn_provider): add runtime translation refresh and testing capabilities. ([c9ba1fd2](https://github.com/ensembleUI/ensemble/commit/c9ba1fd23c34031c96e2248f1b05cf2ba2b4bc88))
- **FEAT**(secure_storage): enhance secure storage actions with optional encryption parameters. ([dee0bb57](https://github.com/ensembleUI/ensemble/commit/dee0bb571152e95b4cdc658924b2399c6b4f58b4))

## 1.2.38

- **FEAT**(env): enhance environment variable loading and parsing. ([b7666ceb](https://github.com/ensembleUI/ensemble/commit/b7666ceb292427ad24445cc3080a68e9aca8c47a))
Expand All @@ -76,6 +141,12 @@
- **FIX**(page_model): add 'Actions' to the list of available types in PageModel. ([6dc07f06](https://github.com/ensembleUI/ensemble/commit/6dc07f06e447c5cdbf49be6f29a54e74fa6987e5))
- **FEAT**(actions): introduce reusable action execution framework. ([482d7de9](https://github.com/ensembleUI/ensemble/commit/482d7de922433bb41a282cfdd018f13866fe511f))

## 1.2.35-beta.1

- **FIX**(execute_action): update payload key from 'action' to 'body' in ExecuteActionAction class. ([7e1b8466](https://github.com/ensembleUI/ensemble/commit/7e1b846611b4da27f21fa3474d8a6de05b40b768))
- **FIX**(page_model): add 'Actions' to the list of available types in PageModel. ([6dc07f06](https://github.com/ensembleUI/ensemble/commit/6dc07f06e447c5cdbf49be6f29a54e74fa6987e5))
- **FEAT**(actions): introduce reusable action execution framework. ([482d7de9](https://github.com/ensembleUI/ensemble/commit/482d7de922433bb41a282cfdd018f13866fe511f))

## 1.2.34

- **FEAT**(remote_config): add Firebase Remote Config integration. ([906f0133](https://github.com/ensembleUI/ensemble/commit/906f013322dcda45a1740db24b5e21f63ea372e5))
Expand Down
31 changes: 31 additions & 0 deletions modules/ensemble/lib/ensemble_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'package:ensemble/framework/event/change_locale_events.dart';
import 'package:ensemble/framework/storage_manager.dart';
import 'package:ensemble/framework/theme/theme_loader.dart';
import 'package:ensemble/framework/theme_manager.dart';
import 'package:ensemble/framework/tv/tv_focus_provider.dart';
import 'package:ensemble/framework/widget/error_screen.dart';
import 'package:ensemble/framework/widget/screen.dart';
import 'package:ensemble/ios_deep_link_manager.dart';
Expand Down Expand Up @@ -108,6 +109,7 @@ class EnsembleApp extends StatefulWidget {
this.onAppLoad,
this.forcedLocale,
this.child,
this.tvFocusProvider,
GlobalKey<NavigatorState>? navigatorKey,
ScrollController? screenScroller,
}) {
Expand Down Expand Up @@ -139,6 +141,12 @@ class EnsembleApp extends StatefulWidget {
/// use this if you want the App to start out with this local
final Locale? forcedLocale;

/// Optional TV focus provider from host app.
/// When provided, Ensemble widgets will use the host app's focus system
/// instead of Ensemble's built-in TVFocusWidget. This enables seamless
/// D-pad navigation between host app and Ensemble content.
final TVFocusProvider? tvFocusProvider;

@override
State<StatefulWidget> createState() => EnsembleAppState();
}
Expand Down Expand Up @@ -421,6 +429,19 @@ class EnsembleAppState extends State<EnsembleApp> with WidgetsBindingObserver {
EnsembleThemeManager().currentTheme()?.appThemeData == null) {
//backward compatibility in case apps are using the old style of App level theming that is at the root level
theme = config.getAppTheme();

// Preserve tvFocusTheme from EnsembleThemeManager if available
// This ensures TV focus styling works even with legacy themes
final currentThemeData = EnsembleThemeManager().currentTheme()?.appThemeData;
final tvFocusTheme = currentThemeData?.extension<EnsembleThemeExtension>()?.tvFocusTheme;
if (tvFocusTheme != null) {
final existingExtension = theme.extension<EnsembleThemeExtension>();
if (existingExtension != null) {
theme = theme.copyWith(
extensions: [existingExtension.copyWith(tvFocusTheme: tvFocusTheme)],
);
}
}
} else {
theme = EnsembleThemeManager().currentTheme()!.appThemeData;
}
Expand Down Expand Up @@ -472,6 +493,16 @@ class EnsembleAppState extends State<EnsembleApp> with WidgetsBindingObserver {
// child: app,
// );
// }

// Wrap with TV focus provider if provided by host app
// This enables host app's focus system to manage Ensemble widgets
if (widget.tvFocusProvider != null) {
app = TVFocusProviderScope(
provider: widget.tvFocusProvider!,
child: app,
);
}

return app;
}

Expand Down
27 changes: 27 additions & 0 deletions modules/ensemble/lib/framework/device.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class Device
"macOsInfo": () => DeviceMacOsInfo(),
"windowsInfo": () => DeviceWindowsInfo(),

// TV detection
"isTV": () => isTV,

// @deprecated. backward compatibility
DevicePlatform.web.name: () => DeviceWebInfo()
};
Expand All @@ -74,6 +77,7 @@ class Device
'isWeb': () => platform == DevicePlatform.web,
'isMacOS': () => platform == DevicePlatform.macos,
'isWindows': () => platform == DevicePlatform.windows,
'isTV': () => isTV,

// deprecated. Should be using Action instead
'openAppSettings': (target) => openAppSettings(target),
Expand Down Expand Up @@ -129,8 +133,31 @@ mixin DeviceInfoCapability {
static MacOsDeviceInfo? macOsInfo;
static WindowsDeviceInfo? windowsInfo;

// Android TV detection cache
static bool? _isTV;

DevicePlatform? get platform => _platform;

/// Returns true if the device is an Android TV
/// Checks for TV-specific system features
bool get isTV {
if (_isTV != null) return _isTV!;

// Only Android devices can be TVs (for now)
if (kIsWeb || _platform != DevicePlatform.android || androidInfo == null) {
_isTV = false;
return false;
}

// Check for TV system features
final systemFeatures = androidInfo!.systemFeatures;
_isTV = systemFeatures.contains('android.hardware.type.television') ||
systemFeatures.contains('android.software.leanback') ||
systemFeatures.contains('android.software.leanback_only');

return _isTV!;
}

/// initialize device info
void initDeviceInfo() async {
try {
Expand Down
Loading
Loading