From 8fcca49a38ea55d5fbf88843672e048449bf305c Mon Sep 17 00:00:00 2001 From: Fadi George Date: Mon, 26 Oct 2026 19:38:06 -0700 Subject: [PATCH 1/4] chore: [SDK-5608] standardize push subscription UI in the Flutter demos Co-Authored-By: Claude Opus 5.5 --- examples/build.md | 9 ++- .../lib/services/preferences_service.dart | 6 ++ .../lib/viewmodels/app_viewmodel.dart | 44 +++++++++++ .../lib/widgets/sections/push_section.dart | 20 ++++- .../lib/widgets/sections/user_section.dart | 77 +++++++++++++++++++ .../lib/services/preferences_service.dart | 6 ++ .../demo/lib/viewmodels/app_viewmodel.dart | 44 +++++++++++ .../lib/widgets/sections/push_section.dart | 20 ++++- .../lib/widgets/sections/user_section.dart | 77 +++++++++++++++++++ 9 files changed, 300 insertions(+), 3 deletions(-) diff --git a/examples/build.md b/examples/build.md index a0bf28aa..1b7b6a45 100644 --- a/examples/build.md +++ b/examples/build.md @@ -140,7 +140,7 @@ if (_externalUserId != null) { } ``` -The cached `externalUserId` is the only value that drives an SDK call inside `loadInitialState()` -- it triggers `OneSignal.login(...)` so the SDK identity matches the persisted UI state. Push subscription id, opted-in flag, and permission are then read from the live SDK state, and the OneSignal ID is fetched via `OneSignal.User.getOnesignalId()`. +The cached `externalUserId` is the only value that drives an SDK call inside `loadInitialState()` -- it triggers `OneSignal.login(...)` so the SDK identity matches the persisted UI state. Push subscription id, opted-in flag, token, and permission are then read from the live SDK state, and the OneSignal ID is fetched via `OneSignal.User.getOnesignalId()`. ### Observers @@ -162,6 +162,13 @@ OneSignal.User.addObserver(...) - No global loading overlay. `vm.isLoading` is passed to `PairList(loading: ...)` in **aliases**, **emails**, **sms**, and **tags** sections only. `user_section.dart` has no loading UI. - The viewmodel uses a request-sequence counter (`_fetchSequence`) so stale REST results are dropped when a newer fetch is already in flight. +### Push Status +- The Push section shows a read-only **Status** row above the **Opted In** toggle: `Subscribed` when `pushSubscription.optedIn` is true, notification permission is granted, and a push token is present; otherwise `Unsubscribed`. `AppViewModel.isPushSubscribed` derives this from the push subscription and permission observers. + +### Language +- The User section has a **Language** dropdown (`Device Default` plus the shared language list) after External ID. The selection is cached in `PreferencesService` and reset to `Device Default` on logout. +- `Device Default` calls `OneSignal.User.setLanguage(...)` with the device locale language (`PlatformDispatcher.instance.locale`) instead of an empty string, because the Android bridge forwards `''` as `null`, which the native SDK rejects. + ### SnackBar Messages - `AppSnackBar` extension on `BuildContext` defined in `lib/theme.dart` exposes `context.showSnackBar(message)`. - The extension calls `ScaffoldMessenger.of(this)..hideCurrentSnackBar()..showSnackBar(SnackBar(content: Text(message), duration: _toastDuration))` for replace-on-show behavior. diff --git a/examples/demo-pods/lib/services/preferences_service.dart b/examples/demo-pods/lib/services/preferences_service.dart index 7fe89283..4df34f7c 100644 --- a/examples/demo-pods/lib/services/preferences_service.dart +++ b/examples/demo-pods/lib/services/preferences_service.dart @@ -6,6 +6,7 @@ class PreferencesService { static const _keyExternalUserId = 'external_user_id'; static const _keyLocationShared = 'location_shared'; static const _keyIamPaused = 'iam_paused'; + static const _keyLanguage = 'language'; late final SharedPreferences _prefs; @@ -39,4 +40,9 @@ class PreferencesService { bool get iamPaused => _prefs.getBool(_keyIamPaused) ?? false; Future setIamPaused(bool value) => _prefs.setBool(_keyIamPaused, value); + + // Language + String get language => _prefs.getString(_keyLanguage) ?? ''; + Future setLanguage(String value) => + _prefs.setString(_keyLanguage, value); } diff --git a/examples/demo-pods/lib/viewmodels/app_viewmodel.dart b/examples/demo-pods/lib/viewmodels/app_viewmodel.dart index 18d4429d..caead090 100644 --- a/examples/demo-pods/lib/viewmodels/app_viewmodel.dart +++ b/examples/demo-pods/lib/viewmodels/app_viewmodel.dart @@ -20,6 +20,15 @@ List> _mergePairs( List _mergeUnique(List prev, List next) => {...prev, ...next}.toList(); +String _deviceLanguageCode() { + final locale = PlatformDispatcher.instance.locale; + if (locale.languageCode != 'zh') return locale.languageCode; + final traditional = + locale.scriptCode == 'Hant' || + const {'TW', 'HK', 'MO'}.contains(locale.countryCode); + return traditional ? 'zh-Hant' : 'zh-Hans'; +} + class AppViewModel extends ChangeNotifier { final OneSignalApiService _apiService; final PreferencesService _prefs; @@ -76,6 +85,17 @@ class AppViewModel extends ChangeNotifier { bool _hasNotificationPermission = false; bool get hasNotificationPermission => _hasNotificationPermission; + String? _pushToken; + + bool get isPushSubscribed => + _pushEnabled && + _hasNotificationPermission && + (_pushToken?.isNotEmpty ?? false); + + // Empty means device default. + String _language = ''; + String get language => _language; + // IAM state bool _iamPaused = false; bool get iamPaused => _iamPaused; @@ -132,6 +152,7 @@ class AppViewModel extends ChangeNotifier { _iamPaused = _prefs.iamPaused; _locationShared = _prefs.locationShared; + _language = _prefs.language; if (_externalUserId != null) { OneSignal.login(_externalUserId!); @@ -139,6 +160,7 @@ class AppViewModel extends ChangeNotifier { _pushSubscriptionId = OneSignal.User.pushSubscription.id; _pushEnabled = OneSignal.User.pushSubscription.optedIn ?? false; + _pushToken = OneSignal.User.pushSubscription.token; _hasNotificationPermission = OneSignal.Notifications.permission; final onesignalId = await OneSignal.User.getOnesignalId(); @@ -165,6 +187,7 @@ class AppViewModel extends ChangeNotifier { OneSignal.User.pushSubscription.addObserver((state) { _pushSubscriptionId = state.current.id; _pushEnabled = state.current.optedIn; + _pushToken = state.current.token; String fmtToken(String? t) { if (t == null || t.isEmpty) return 'null'; @@ -255,12 +278,33 @@ class AppViewModel extends ChangeNotifier { try { await OneSignal.logout(); await _prefs.setExternalUserId(null); + await setLanguage(''); debugPrint('Logged out'); } catch (e) { debugPrint('Logout error: $e'); } } + // Language + Future setLanguage(String language) async { + _language = language; + notifyListeners(); + + try { + // The Android bridge forwards '' as null, which the native setLanguage + // rejects, so resolve the device language here instead. + await OneSignal.User.setLanguage( + language.isEmpty ? _deviceLanguageCode() : language, + ); + await _prefs.setLanguage(language); + debugPrint( + 'Language set to: ${language.isEmpty ? 'device default' : language}', + ); + } catch (e) { + debugPrint('Set language error: $e'); + } + } + // Consent Future setConsentRequired(bool value) async { _consentRequired = value; diff --git a/examples/demo-pods/lib/widgets/sections/push_section.dart b/examples/demo-pods/lib/widgets/sections/push_section.dart index ee9b3aee..b0b0aa6a 100644 --- a/examples/demo-pods/lib/widgets/sections/push_section.dart +++ b/examples/demo-pods/lib/widgets/sections/push_section.dart @@ -51,8 +51,26 @@ class PushSection extends StatelessWidget { ], ), const Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Status', + style: Theme.of(context).textTheme.bodyMedium, + ), + Semantics( + identifier: 'push_subscription_status', + container: true, + child: Text( + vm.isPushSubscribed ? 'Subscribed' : 'Unsubscribed', + style: Theme.of(context).textTheme.bodySmall, + ), + ), + ], + ), + const Divider(), ToggleRow( - label: 'Enabled', + label: 'Opted In', value: vm.pushEnabled, semanticsLabel: 'push_enabled_toggle', onChanged: vm.hasNotificationPermission diff --git a/examples/demo-pods/lib/widgets/sections/user_section.dart b/examples/demo-pods/lib/widgets/sections/user_section.dart index ea5fd715..6e405baf 100644 --- a/examples/demo-pods/lib/widgets/sections/user_section.dart +++ b/examples/demo-pods/lib/widgets/sections/user_section.dart @@ -7,6 +7,53 @@ import '../dialogs.dart'; import '../action_button.dart'; import '../section_card.dart'; +const _languageOptions = [ + ('Device Default', ''), + ('English', 'en'), + ('Arabic', 'ar'), + ('Azerbaijani', 'az'), + ('Bosnian', 'bs'), + ('Catalan', 'ca'), + ('Chinese (Simplified)', 'zh-Hans'), + ('Chinese (Traditional)', 'zh-Hant'), + ('Croatian', 'hr'), + ('Czech', 'cs'), + ('Danish', 'da'), + ('Dutch', 'nl'), + ('Estonian', 'et'), + ('Finnish', 'fi'), + ('French', 'fr'), + ('Georgian', 'ka'), + ('Bulgarian', 'bg'), + ('German', 'de'), + ('Greek', 'el'), + ('Hindi', 'hi'), + ('Hebrew', 'he'), + ('Hungarian', 'hu'), + ('Indonesian', 'id'), + ('Italian', 'it'), + ('Japanese', 'ja'), + ('Korean', 'ko'), + ('Latvian', 'lv'), + ('Lithuanian', 'lt'), + ('Malay', 'ms'), + ('Norwegian', 'nb'), + ('Persian', 'fa'), + ('Polish', 'pl'), + ('Portuguese', 'pt'), + ('Punjabi', 'pa'), + ('Romanian', 'ro'), + ('Russian', 'ru'), + ('Serbian', 'sr'), + ('Slovak', 'sk'), + ('Spanish', 'es'), + ('Swedish', 'sv'), + ('Thai', 'th'), + ('Turkish', 'tr'), + ('Ukrainian', 'uk'), + ('Vietnamese', 'vi'), +]; + class UserSection extends StatelessWidget { final VoidCallback? onInfoTap; @@ -68,6 +115,36 @@ class UserSection extends StatelessWidget { ), ], ), + const Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Language', + style: Theme.of(context).textTheme.bodyMedium, + ), + Semantics( + identifier: 'user_language_dropdown', + container: true, + child: DropdownButton( + value: + _languageOptions.any((o) => o.$2 == vm.language) + ? vm.language + : '', + isDense: true, + underline: const SizedBox.shrink(), + style: Theme.of(context).textTheme.bodySmall, + items: [ + for (final (name, code) in _languageOptions) + DropdownMenuItem(value: code, child: Text(name)), + ], + onChanged: (code) { + if (code != null) vm.setLanguage(code); + }, + ), + ), + ], + ), ], ), ), diff --git a/examples/demo/lib/services/preferences_service.dart b/examples/demo/lib/services/preferences_service.dart index 7fe89283..4df34f7c 100644 --- a/examples/demo/lib/services/preferences_service.dart +++ b/examples/demo/lib/services/preferences_service.dart @@ -6,6 +6,7 @@ class PreferencesService { static const _keyExternalUserId = 'external_user_id'; static const _keyLocationShared = 'location_shared'; static const _keyIamPaused = 'iam_paused'; + static const _keyLanguage = 'language'; late final SharedPreferences _prefs; @@ -39,4 +40,9 @@ class PreferencesService { bool get iamPaused => _prefs.getBool(_keyIamPaused) ?? false; Future setIamPaused(bool value) => _prefs.setBool(_keyIamPaused, value); + + // Language + String get language => _prefs.getString(_keyLanguage) ?? ''; + Future setLanguage(String value) => + _prefs.setString(_keyLanguage, value); } diff --git a/examples/demo/lib/viewmodels/app_viewmodel.dart b/examples/demo/lib/viewmodels/app_viewmodel.dart index 86ee62d9..1ea7e39b 100644 --- a/examples/demo/lib/viewmodels/app_viewmodel.dart +++ b/examples/demo/lib/viewmodels/app_viewmodel.dart @@ -21,6 +21,15 @@ List> _mergePairs( List _mergeUnique(List prev, List next) => {...prev, ...next}.toList(); +String _deviceLanguageCode() { + final locale = PlatformDispatcher.instance.locale; + if (locale.languageCode != 'zh') return locale.languageCode; + final traditional = + locale.scriptCode == 'Hant' || + const {'TW', 'HK', 'MO'}.contains(locale.countryCode); + return traditional ? 'zh-Hant' : 'zh-Hans'; +} + class AppViewModel extends ChangeNotifier { final OneSignalApiService _apiService; final PreferencesService _prefs; @@ -88,6 +97,17 @@ class AppViewModel extends ChangeNotifier { bool _hasNotificationPermission = false; bool get hasNotificationPermission => _hasNotificationPermission; + String? _pushToken; + + bool get isPushSubscribed => + _pushEnabled && + _hasNotificationPermission && + (_pushToken?.isNotEmpty ?? false); + + // Empty means device default. + String _language = ''; + String get language => _language; + // IAM state bool _iamPaused = false; bool get iamPaused => _iamPaused; @@ -144,6 +164,7 @@ class AppViewModel extends ChangeNotifier { _iamPaused = _prefs.iamPaused; _locationShared = _prefs.locationShared; + _language = _prefs.language; if (_externalUserId != null) { OneSignal.login(_externalUserId!); @@ -151,6 +172,7 @@ class AppViewModel extends ChangeNotifier { _pushSubscriptionId = OneSignal.User.pushSubscription.id; _pushEnabled = OneSignal.User.pushSubscription.optedIn ?? false; + _pushToken = OneSignal.User.pushSubscription.token; _hasNotificationPermission = OneSignal.Notifications.permission; final onesignalId = await OneSignal.User.getOnesignalId(); @@ -171,6 +193,7 @@ class AppViewModel extends ChangeNotifier { OneSignal.User.pushSubscription.addObserver((state) { _pushSubscriptionId = state.current.id; _pushEnabled = state.current.optedIn; + _pushToken = state.current.token; String fmtToken(String? t) { if (t == null || t.isEmpty) return 'null'; @@ -291,12 +314,33 @@ class AppViewModel extends ChangeNotifier { try { await OneSignal.logout(); await _prefs.setExternalUserId(null); + await setLanguage(''); LogService.info('Logged out'); } catch (e) { LogService.error('Logout error: $e'); } } + // Language + Future setLanguage(String language) async { + _language = language; + notifyListeners(); + + try { + // The Android bridge forwards '' as null, which the native setLanguage + // rejects, so resolve the device language here instead. + await OneSignal.User.setLanguage( + language.isEmpty ? _deviceLanguageCode() : language, + ); + await _prefs.setLanguage(language); + LogService.info( + 'Language set to: ${language.isEmpty ? 'device default' : language}', + ); + } catch (e) { + LogService.error('Set language error: $e'); + } + } + // Consent Future setConsentRequired(bool value) async { _consentRequired = value; diff --git a/examples/demo/lib/widgets/sections/push_section.dart b/examples/demo/lib/widgets/sections/push_section.dart index ee9b3aee..b0b0aa6a 100644 --- a/examples/demo/lib/widgets/sections/push_section.dart +++ b/examples/demo/lib/widgets/sections/push_section.dart @@ -51,8 +51,26 @@ class PushSection extends StatelessWidget { ], ), const Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Status', + style: Theme.of(context).textTheme.bodyMedium, + ), + Semantics( + identifier: 'push_subscription_status', + container: true, + child: Text( + vm.isPushSubscribed ? 'Subscribed' : 'Unsubscribed', + style: Theme.of(context).textTheme.bodySmall, + ), + ), + ], + ), + const Divider(), ToggleRow( - label: 'Enabled', + label: 'Opted In', value: vm.pushEnabled, semanticsLabel: 'push_enabled_toggle', onChanged: vm.hasNotificationPermission diff --git a/examples/demo/lib/widgets/sections/user_section.dart b/examples/demo/lib/widgets/sections/user_section.dart index efd53193..ad76dfa8 100644 --- a/examples/demo/lib/widgets/sections/user_section.dart +++ b/examples/demo/lib/widgets/sections/user_section.dart @@ -7,6 +7,53 @@ import '../dialogs.dart'; import '../action_button.dart'; import '../section_card.dart'; +const _languageOptions = [ + ('Device Default', ''), + ('English', 'en'), + ('Arabic', 'ar'), + ('Azerbaijani', 'az'), + ('Bosnian', 'bs'), + ('Catalan', 'ca'), + ('Chinese (Simplified)', 'zh-Hans'), + ('Chinese (Traditional)', 'zh-Hant'), + ('Croatian', 'hr'), + ('Czech', 'cs'), + ('Danish', 'da'), + ('Dutch', 'nl'), + ('Estonian', 'et'), + ('Finnish', 'fi'), + ('French', 'fr'), + ('Georgian', 'ka'), + ('Bulgarian', 'bg'), + ('German', 'de'), + ('Greek', 'el'), + ('Hindi', 'hi'), + ('Hebrew', 'he'), + ('Hungarian', 'hu'), + ('Indonesian', 'id'), + ('Italian', 'it'), + ('Japanese', 'ja'), + ('Korean', 'ko'), + ('Latvian', 'lv'), + ('Lithuanian', 'lt'), + ('Malay', 'ms'), + ('Norwegian', 'nb'), + ('Persian', 'fa'), + ('Polish', 'pl'), + ('Portuguese', 'pt'), + ('Punjabi', 'pa'), + ('Romanian', 'ro'), + ('Russian', 'ru'), + ('Serbian', 'sr'), + ('Slovak', 'sk'), + ('Spanish', 'es'), + ('Swedish', 'sv'), + ('Thai', 'th'), + ('Turkish', 'tr'), + ('Ukrainian', 'uk'), + ('Vietnamese', 'vi'), +]; + class UserSection extends StatelessWidget { final VoidCallback? onInfoTap; @@ -68,6 +115,36 @@ class UserSection extends StatelessWidget { ), ], ), + const Divider(), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Language', + style: Theme.of(context).textTheme.bodyMedium, + ), + Semantics( + identifier: 'user_language_dropdown', + container: true, + child: DropdownButton( + value: + _languageOptions.any((o) => o.$2 == vm.language) + ? vm.language + : '', + isDense: true, + underline: const SizedBox.shrink(), + style: Theme.of(context).textTheme.bodySmall, + items: [ + for (final (name, code) in _languageOptions) + DropdownMenuItem(value: code, child: Text(name)), + ], + onChanged: (code) { + if (code != null) vm.setLanguage(code); + }, + ), + ), + ], + ), ], ), ), From 58feeae05da90c1e2538c3ac88722b0092bde1bf Mon Sep 17 00:00:00 2001 From: Fadi George Date: Mon, 26 Oct 2026 19:48:15 -0700 Subject: [PATCH 2/4] fix: [SDK-5608] let setLanguage('') reset to the device language on Android The Android bridge turned '' into null, which the native non-null setLanguage rejects. Pass it through so the native SDK resolves the device language, matching iOS and the documented Dart behavior. The demos now send '' for Device Default. Co-Authored-By: Claude Opus 5.5 --- .../java/com/onesignal/flutter/OneSignalUser.java | 3 --- examples/build.md | 2 +- .../demo-pods/lib/viewmodels/app_viewmodel.dart | 15 +-------------- examples/demo/lib/viewmodels/app_viewmodel.dart | 15 +-------------- 4 files changed, 3 insertions(+), 32 deletions(-) diff --git a/android/src/main/java/com/onesignal/flutter/OneSignalUser.java b/android/src/main/java/com/onesignal/flutter/OneSignalUser.java index f5facb0b..99869e67 100644 --- a/android/src/main/java/com/onesignal/flutter/OneSignalUser.java +++ b/android/src/main/java/com/onesignal/flutter/OneSignalUser.java @@ -63,9 +63,6 @@ private void handleMethodCall(MethodCall call, Result result) { private void setLanguage(MethodCall call, Result result) { String language = call.argument("language"); - if (language != null && language.length() == 0) { - language = null; - } OneSignal.getUser().setLanguage(language); replySuccess(result, null); } diff --git a/examples/build.md b/examples/build.md index 1b7b6a45..bc78bddf 100644 --- a/examples/build.md +++ b/examples/build.md @@ -167,7 +167,7 @@ OneSignal.User.addObserver(...) ### Language - The User section has a **Language** dropdown (`Device Default` plus the shared language list) after External ID. The selection is cached in `PreferencesService` and reset to `Device Default` on logout. -- `Device Default` calls `OneSignal.User.setLanguage(...)` with the device locale language (`PlatformDispatcher.instance.locale`) instead of an empty string, because the Android bridge forwards `''` as `null`, which the native SDK rejects. +- `Device Default` calls `OneSignal.User.setLanguage('')`, which the native SDK resolves to the device language. ### SnackBar Messages - `AppSnackBar` extension on `BuildContext` defined in `lib/theme.dart` exposes `context.showSnackBar(message)`. diff --git a/examples/demo-pods/lib/viewmodels/app_viewmodel.dart b/examples/demo-pods/lib/viewmodels/app_viewmodel.dart index caead090..3ce94a82 100644 --- a/examples/demo-pods/lib/viewmodels/app_viewmodel.dart +++ b/examples/demo-pods/lib/viewmodels/app_viewmodel.dart @@ -20,15 +20,6 @@ List> _mergePairs( List _mergeUnique(List prev, List next) => {...prev, ...next}.toList(); -String _deviceLanguageCode() { - final locale = PlatformDispatcher.instance.locale; - if (locale.languageCode != 'zh') return locale.languageCode; - final traditional = - locale.scriptCode == 'Hant' || - const {'TW', 'HK', 'MO'}.contains(locale.countryCode); - return traditional ? 'zh-Hant' : 'zh-Hans'; -} - class AppViewModel extends ChangeNotifier { final OneSignalApiService _apiService; final PreferencesService _prefs; @@ -291,11 +282,7 @@ class AppViewModel extends ChangeNotifier { notifyListeners(); try { - // The Android bridge forwards '' as null, which the native setLanguage - // rejects, so resolve the device language here instead. - await OneSignal.User.setLanguage( - language.isEmpty ? _deviceLanguageCode() : language, - ); + await OneSignal.User.setLanguage(language); await _prefs.setLanguage(language); debugPrint( 'Language set to: ${language.isEmpty ? 'device default' : language}', diff --git a/examples/demo/lib/viewmodels/app_viewmodel.dart b/examples/demo/lib/viewmodels/app_viewmodel.dart index 1ea7e39b..794ed269 100644 --- a/examples/demo/lib/viewmodels/app_viewmodel.dart +++ b/examples/demo/lib/viewmodels/app_viewmodel.dart @@ -21,15 +21,6 @@ List> _mergePairs( List _mergeUnique(List prev, List next) => {...prev, ...next}.toList(); -String _deviceLanguageCode() { - final locale = PlatformDispatcher.instance.locale; - if (locale.languageCode != 'zh') return locale.languageCode; - final traditional = - locale.scriptCode == 'Hant' || - const {'TW', 'HK', 'MO'}.contains(locale.countryCode); - return traditional ? 'zh-Hant' : 'zh-Hans'; -} - class AppViewModel extends ChangeNotifier { final OneSignalApiService _apiService; final PreferencesService _prefs; @@ -327,11 +318,7 @@ class AppViewModel extends ChangeNotifier { notifyListeners(); try { - // The Android bridge forwards '' as null, which the native setLanguage - // rejects, so resolve the device language here instead. - await OneSignal.User.setLanguage( - language.isEmpty ? _deviceLanguageCode() : language, - ); + await OneSignal.User.setLanguage(language); await _prefs.setLanguage(language); LogService.info( 'Language set to: ${language.isEmpty ? 'device default' : language}', From 018c3bd34ce8670b11f3b6166d053d9e1dd9cc5f Mon Sep 17 00:00:00 2001 From: Fadi George Date: Tue, 27 Oct 2026 10:50:47 -0700 Subject: [PATCH 3/4] chore: [SDK-5608] cap the language dropdown height in the demos Co-Authored-By: Claude Opus 5.5 --- examples/demo-pods/lib/widgets/sections/user_section.dart | 1 + examples/demo/lib/widgets/sections/user_section.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/demo-pods/lib/widgets/sections/user_section.dart b/examples/demo-pods/lib/widgets/sections/user_section.dart index 6e405baf..67f7fc21 100644 --- a/examples/demo-pods/lib/widgets/sections/user_section.dart +++ b/examples/demo-pods/lib/widgets/sections/user_section.dart @@ -132,6 +132,7 @@ class UserSection extends StatelessWidget { ? vm.language : '', isDense: true, + menuMaxHeight: 320, underline: const SizedBox.shrink(), style: Theme.of(context).textTheme.bodySmall, items: [ diff --git a/examples/demo/lib/widgets/sections/user_section.dart b/examples/demo/lib/widgets/sections/user_section.dart index ad76dfa8..1886e951 100644 --- a/examples/demo/lib/widgets/sections/user_section.dart +++ b/examples/demo/lib/widgets/sections/user_section.dart @@ -132,6 +132,7 @@ class UserSection extends StatelessWidget { ? vm.language : '', isDense: true, + menuMaxHeight: 320, underline: const SizedBox.shrink(), style: Theme.of(context).textTheme.bodySmall, items: [ From a5d19ec23f176db717975f19cd34c85e3f67885f Mon Sep 17 00:00:00 2001 From: Fadi George Date: Tue, 27 Oct 2026 11:08:39 -0700 Subject: [PATCH 4/4] chore: [SDK-5608] right-align the selected language in the demos Co-Authored-By: Claude Opus 5.5 --- examples/demo-pods/lib/widgets/sections/user_section.dart | 1 + examples/demo/lib/widgets/sections/user_section.dart | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/demo-pods/lib/widgets/sections/user_section.dart b/examples/demo-pods/lib/widgets/sections/user_section.dart index 67f7fc21..48fb2968 100644 --- a/examples/demo-pods/lib/widgets/sections/user_section.dart +++ b/examples/demo-pods/lib/widgets/sections/user_section.dart @@ -133,6 +133,7 @@ class UserSection extends StatelessWidget { : '', isDense: true, menuMaxHeight: 320, + alignment: AlignmentDirectional.centerEnd, underline: const SizedBox.shrink(), style: Theme.of(context).textTheme.bodySmall, items: [ diff --git a/examples/demo/lib/widgets/sections/user_section.dart b/examples/demo/lib/widgets/sections/user_section.dart index 1886e951..8e1a23b3 100644 --- a/examples/demo/lib/widgets/sections/user_section.dart +++ b/examples/demo/lib/widgets/sections/user_section.dart @@ -133,6 +133,7 @@ class UserSection extends StatelessWidget { : '', isDense: true, menuMaxHeight: 320, + alignment: AlignmentDirectional.centerEnd, underline: const SizedBox.shrink(), style: Theme.of(context).textTheme.bodySmall, items: [