From c3679fbca445d5a5c92f65e34d0def11e6dd6c03 Mon Sep 17 00:00:00 2001 From: Damian Cruz Date: Mon, 4 May 2026 14:07:01 +0200 Subject: [PATCH 1/8] fix: sync theme updates with the map-ready message --- lib/src/controller.dart | 33 ++++++++++++++++++++++++++++++++- lib/src/situm_map_view.dart | 20 ++++++++++++++++++-- lib/wayfinding.dart | 1 + 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 545d5ac..09c7caa 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -28,6 +28,8 @@ class MapViewController { // it finishes loading. String? _lastStatusToSend; String? _lastErrorToSend; + Brightness? _lastThemeToSend; + bool _isMapReady = false; List mapViewerStatusesFilter = [ 'STARTING', @@ -111,9 +113,18 @@ class MapViewController { /// Reloads the [MapView] using the current configuration by reloading the /// underlying platform web view controller. void reload() async { + _onMapWillLoad(); _webViewController.reload(); } + /// Sets the viewer theme according to the current platform brightness. + void setTheme(Brightness brightness) { + _lastThemeToSend = brightness; + if (_isMapReady) { + _sendTheme(brightness); + } + } + /// Selects the given Building in the map. /// To set the initial Building use [MapViewConfiguration]. void selectBuilding(String identifier) async { @@ -272,7 +283,8 @@ class MapViewController { /// Select a floor of the current building by its [Floor.identifier]. /// /// **NOTE**: introducing an invalid identifier may result in unexpected behaviours. - void selectFloor(String identifier, {SelectCartographyOptions? options}) async { + void selectFloor(String identifier, + {SelectCartographyOptions? options}) async { int floorId = int.tryParse(identifier) ?? 0; final message = { "identifier": floorId, @@ -315,7 +327,12 @@ class MapViewController { // WYF internal utils: + void _onMapWillLoad() { + _isMapReady = false; + } + void _onMapIsReady() { + _isMapReady = true; _widgetLoadCallback(this); if (_lastStatusToSend != null) { _setCurrentLocationStatus(_lastStatusToSend!); @@ -326,6 +343,9 @@ class MapViewController { } _ensureTalkBackCompatibility(); _sendViewerConfigMessage(); + if (_lastThemeToSend != null) { + _sendTheme(_lastThemeToSend!); + } } void _notifyMapViewError(MapViewError payload) { @@ -347,6 +367,17 @@ class MapViewController { _sendMessage(WV_APP_CONFIG, jsonEncode(configItems)); } + void _sendTheme(Brightness brightness) { + dynamic message = { + "theme": brightness == Brightness.dark ? 'dark' : 'light' + }; + + _sendMessage( + WV_MESSAGE_APP_SET_THEME, + jsonEncode(message), + ); + } + void _setRoute( DirectionsMessage directionsMessage, SitumRoute situmRoute) async { situmRoute.rawContent["identifier"] = directionsMessage.identifier; diff --git a/lib/src/situm_map_view.dart b/lib/src/situm_map_view.dart index 3f804db..23a9f60 100644 --- a/lib/src/situm_map_view.dart +++ b/lib/src/situm_map_view.dart @@ -31,7 +31,7 @@ class MapView extends StatefulWidget { State createState() => _MapViewState(); } -class _MapViewState extends State { +class _MapViewState extends State with WidgetsBindingObserver { static MapViewController? wyfController; static PlatformWebViewController? webViewController; static PlatformWebViewWidget? webViewWidget; @@ -44,6 +44,7 @@ class _MapViewState extends State { @override void initState() { super.initState(); + WidgetsBinding.instance.addObserver(this); mapViewConfiguration = widget.configuration; // Avoid re-initializations of the underlying WebView (PlatformView) if @@ -51,6 +52,7 @@ class _MapViewState extends State { if (webViewWidget != null && mapViewConfiguration.persistUnderlyingWidget == true) { _shouldDisplayBlankScreen = false; + _syncPlatformTheme(); return; } @@ -155,12 +157,14 @@ class _MapViewState extends State { // avoid receiving messages while in an inconsistent state. _InternalMessageBridge.register(_onMapViewerMessageUpdateInternalState); _loadWithConfig(mapViewConfiguration); + _syncPlatformTheme(); } void _loadWithConfig(MapViewConfiguration configuration) async { setState(() { _shouldDisplayMainFrameError = false; }); + wyfController?._onMapWillLoad(); if (webViewController is AndroidWebViewController) { AndroidWebViewController.enableDebugging(configuration.enableDebugging); } @@ -176,6 +180,12 @@ class _MapViewState extends State { ?.loadRequest(LoadRequestParams(uri: Uri.parse(mapViewUrl))); } + void _syncPlatformTheme() { + wyfController?.setTheme( + WidgetsBinding.instance.platformDispatcher.platformBrightness, + ); + } + void _displayBlankScreen(bool value) { if (mounted) { setState(() { @@ -221,9 +231,14 @@ class _MapViewState extends State { } } + @override + void didChangePlatformBrightness() { + _syncPlatformTheme(); + } + @override void dispose() { - super.dispose(); + WidgetsBinding.instance.removeObserver(this); // IMPORTANT: We use a static reference to support the // "persistUnderlyingWidget" feature. Because of that, this state must be // explicitly unregistered when disposed; otherwise it may continue receiving @@ -231,6 +246,7 @@ class _MapViewState extends State { // unwanted rebuilds in an inconsistent state. _InternalMessageBridge.unregister(); // wyfController?.onWidgetDisposed(); + super.dispose(); } void _onErrorRetryLoad() { diff --git a/lib/wayfinding.dart b/lib/wayfinding.dart index 9ec191b..84495a3 100644 --- a/lib/wayfinding.dart +++ b/lib/wayfinding.dart @@ -60,6 +60,7 @@ const WV_MESSAGE_CALIBRATION_STOPPED = "calibration.stopped"; // Configuration const WV_APP_CONFIG = "app.set_config_item"; +const WV_MESSAGE_UI_SET_THEME = "ui.set_preferred_theme"; const WV_APP_CONFIG_ITEM_TTS_ENGINE = "internal.tts.engine"; // Location actions From e769f53d0c94bdf5af1dcd2874628b8a874fa77c Mon Sep 17 00:00:00 2001 From: Damian Cruz Date: Mon, 4 May 2026 14:08:58 +0200 Subject: [PATCH 2/8] added changelog unreleased --- CHANGELOG_UNRELEASED.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG_UNRELEASED.md b/CHANGELOG_UNRELEASED.md index cee465e..e248cd2 100644 --- a/CHANGELOG_UNRELEASED.md +++ b/CHANGELOG_UNRELEASED.md @@ -8,4 +8,8 @@ actions such as selecting a POI or starting navigation from outside the map screen (e.g., from a list or a notification). Since the MapViewController is only available once the MapView has fully loaded, this helper provides a simple, awaitable ensureMapViewController() method—powered by a - Dart Completer—that resolves automatically when the controller becomes ready. \ No newline at end of file + Dart Completer—that resolves automatically when the controller becomes ready. + +### Added + +- Added new message to let map-viewer know what's the current device preferred color scheme. \ No newline at end of file From 8a30b48467494e009962aaa145c737854115d443 Mon Sep 17 00:00:00 2001 From: Damian Cruz Date: Tue, 5 May 2026 08:37:58 +0200 Subject: [PATCH 3/8] fix: remove _onMapWillLoad method due to its simplicity --- lib/src/controller.dart | 6 +----- lib/src/situm_map_view.dart | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 09c7caa..415c93d 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -113,7 +113,7 @@ class MapViewController { /// Reloads the [MapView] using the current configuration by reloading the /// underlying platform web view controller. void reload() async { - _onMapWillLoad(); + _isMapReady = false; _webViewController.reload(); } @@ -327,10 +327,6 @@ class MapViewController { // WYF internal utils: - void _onMapWillLoad() { - _isMapReady = false; - } - void _onMapIsReady() { _isMapReady = true; _widgetLoadCallback(this); diff --git a/lib/src/situm_map_view.dart b/lib/src/situm_map_view.dart index 23a9f60..3c85021 100644 --- a/lib/src/situm_map_view.dart +++ b/lib/src/situm_map_view.dart @@ -164,7 +164,7 @@ class _MapViewState extends State with WidgetsBindingObserver { setState(() { _shouldDisplayMainFrameError = false; }); - wyfController?._onMapWillLoad(); + wyfController?._isMapReady = false; if (webViewController is AndroidWebViewController) { AndroidWebViewController.enableDebugging(configuration.enableDebugging); } From 9b04a8c916902fda2cabaa7736753c8f60d94160 Mon Sep 17 00:00:00 2001 From: Damian Cruz Date: Tue, 5 May 2026 13:13:58 +0200 Subject: [PATCH 4/8] remove _isMapReady and update WV_MESSAGE_UI_SET_THEME --- lib/src/controller.dart | 9 ++------- lib/src/situm_map_view.dart | 1 - 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 415c93d..b2295a9 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -29,7 +29,6 @@ class MapViewController { String? _lastStatusToSend; String? _lastErrorToSend; Brightness? _lastThemeToSend; - bool _isMapReady = false; List mapViewerStatusesFilter = [ 'STARTING', @@ -113,16 +112,13 @@ class MapViewController { /// Reloads the [MapView] using the current configuration by reloading the /// underlying platform web view controller. void reload() async { - _isMapReady = false; _webViewController.reload(); } /// Sets the viewer theme according to the current platform brightness. void setTheme(Brightness brightness) { _lastThemeToSend = brightness; - if (_isMapReady) { - _sendTheme(brightness); - } + _sendTheme(brightness); } /// Selects the given Building in the map. @@ -328,7 +324,6 @@ class MapViewController { // WYF internal utils: void _onMapIsReady() { - _isMapReady = true; _widgetLoadCallback(this); if (_lastStatusToSend != null) { _setCurrentLocationStatus(_lastStatusToSend!); @@ -369,7 +364,7 @@ class MapViewController { }; _sendMessage( - WV_MESSAGE_APP_SET_THEME, + WV_MESSAGE_UI_SET_THEME, jsonEncode(message), ); } diff --git a/lib/src/situm_map_view.dart b/lib/src/situm_map_view.dart index 3c85021..e58c0e4 100644 --- a/lib/src/situm_map_view.dart +++ b/lib/src/situm_map_view.dart @@ -164,7 +164,6 @@ class _MapViewState extends State with WidgetsBindingObserver { setState(() { _shouldDisplayMainFrameError = false; }); - wyfController?._isMapReady = false; if (webViewController is AndroidWebViewController) { AndroidWebViewController.enableDebugging(configuration.enableDebugging); } From caadfc66784c64af1b3684a52f351e81510d81f8 Mon Sep 17 00:00:00 2001 From: Damian Cruz Date: Tue, 5 May 2026 13:21:58 +0200 Subject: [PATCH 5/8] remove _lastThemeToSend --- lib/src/controller.dart | 5 ----- lib/src/situm_map_view.dart | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/src/controller.dart b/lib/src/controller.dart index b2295a9..49cc021 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -28,7 +28,6 @@ class MapViewController { // it finishes loading. String? _lastStatusToSend; String? _lastErrorToSend; - Brightness? _lastThemeToSend; List mapViewerStatusesFilter = [ 'STARTING', @@ -117,7 +116,6 @@ class MapViewController { /// Sets the viewer theme according to the current platform brightness. void setTheme(Brightness brightness) { - _lastThemeToSend = brightness; _sendTheme(brightness); } @@ -334,9 +332,6 @@ class MapViewController { } _ensureTalkBackCompatibility(); _sendViewerConfigMessage(); - if (_lastThemeToSend != null) { - _sendTheme(_lastThemeToSend!); - } } void _notifyMapViewError(MapViewError payload) { diff --git a/lib/src/situm_map_view.dart b/lib/src/situm_map_view.dart index e58c0e4..90fc4ca 100644 --- a/lib/src/situm_map_view.dart +++ b/lib/src/situm_map_view.dart @@ -270,6 +270,7 @@ class _MapViewState extends State with WidgetsBindingObserver { _shouldDisplayMainFrameError = false; } }); + _syncPlatformTheme(); } } } From 0de4a5c3ff69425cb8d69c3ed35895ea6aada4b1 Mon Sep 17 00:00:00 2001 From: Damian Cruz Date: Tue, 5 May 2026 13:34:04 +0200 Subject: [PATCH 6/8] remove unnecesary _syncPlatformTheme --- lib/src/situm_map_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/situm_map_view.dart b/lib/src/situm_map_view.dart index 90fc4ca..986af88 100644 --- a/lib/src/situm_map_view.dart +++ b/lib/src/situm_map_view.dart @@ -157,7 +157,6 @@ class _MapViewState extends State with WidgetsBindingObserver { // avoid receiving messages while in an inconsistent state. _InternalMessageBridge.register(_onMapViewerMessageUpdateInternalState); _loadWithConfig(mapViewConfiguration); - _syncPlatformTheme(); } void _loadWithConfig(MapViewConfiguration configuration) async { From 2c15fca03d04c45a6100ecc84d86fe3fecfc2342 Mon Sep 17 00:00:00 2001 From: Damian Cruz Date: Tue, 5 May 2026 13:37:14 +0200 Subject: [PATCH 7/8] remove another unnecesary _syncPlatformTheme --- lib/src/situm_map_view.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/situm_map_view.dart b/lib/src/situm_map_view.dart index 986af88..3c7ef8a 100644 --- a/lib/src/situm_map_view.dart +++ b/lib/src/situm_map_view.dart @@ -52,7 +52,6 @@ class _MapViewState extends State with WidgetsBindingObserver { if (webViewWidget != null && mapViewConfiguration.persistUnderlyingWidget == true) { _shouldDisplayBlankScreen = false; - _syncPlatformTheme(); return; } From a9ffe4a4f7e5f9c6a4b7ed27337887af043765b8 Mon Sep 17 00:00:00 2001 From: Damian Cruz Date: Tue, 5 May 2026 14:10:59 +0200 Subject: [PATCH 8/8] change theme to preferredTheme and make method private --- lib/src/controller.dart | 14 +++++++++----- lib/src/situm_map_view.dart | 8 ++++---- lib/wayfinding.dart | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/src/controller.dart b/lib/src/controller.dart index 49cc021..f9af034 100644 --- a/lib/src/controller.dart +++ b/lib/src/controller.dart @@ -114,9 +114,13 @@ class MapViewController { _webViewController.reload(); } - /// Sets the viewer theme according to the current platform brightness. - void setTheme(Brightness brightness) { - _sendTheme(brightness); + /// Sets the viewer `preferredTheme` according to the current platform brightness. + /// + /// This does not override a theme already selected by the user inside the + /// webview; it only provides the preferred theme when the viewer applies system + /// preferences. + void _setPreferredTheme(Brightness brightness) { + _sendPreferredTheme(brightness); } /// Selects the given Building in the map. @@ -353,13 +357,13 @@ class MapViewController { _sendMessage(WV_APP_CONFIG, jsonEncode(configItems)); } - void _sendTheme(Brightness brightness) { + void _sendPreferredTheme(Brightness brightness) { dynamic message = { "theme": brightness == Brightness.dark ? 'dark' : 'light' }; _sendMessage( - WV_MESSAGE_UI_SET_THEME, + WV_MESSAGE_UI_SET_PREFERRED_THEME, jsonEncode(message), ); } diff --git a/lib/src/situm_map_view.dart b/lib/src/situm_map_view.dart index 3c7ef8a..c8f43c5 100644 --- a/lib/src/situm_map_view.dart +++ b/lib/src/situm_map_view.dart @@ -177,8 +177,8 @@ class _MapViewState extends State with WidgetsBindingObserver { ?.loadRequest(LoadRequestParams(uri: Uri.parse(mapViewUrl))); } - void _syncPlatformTheme() { - wyfController?.setTheme( + void _syncPlatformPreferredTheme() { + wyfController?._setPreferredTheme( WidgetsBinding.instance.platformDispatcher.platformBrightness, ); } @@ -230,7 +230,7 @@ class _MapViewState extends State with WidgetsBindingObserver { @override void didChangePlatformBrightness() { - _syncPlatformTheme(); + _syncPlatformPreferredTheme(); } @override @@ -268,7 +268,7 @@ class _MapViewState extends State with WidgetsBindingObserver { _shouldDisplayMainFrameError = false; } }); - _syncPlatformTheme(); + _syncPlatformPreferredTheme(); } } } diff --git a/lib/wayfinding.dart b/lib/wayfinding.dart index 84495a3..bb8d829 100644 --- a/lib/wayfinding.dart +++ b/lib/wayfinding.dart @@ -60,7 +60,7 @@ const WV_MESSAGE_CALIBRATION_STOPPED = "calibration.stopped"; // Configuration const WV_APP_CONFIG = "app.set_config_item"; -const WV_MESSAGE_UI_SET_THEME = "ui.set_preferred_theme"; +const WV_MESSAGE_UI_SET_PREFERRED_THEME = "ui.set_preferred_theme"; const WV_APP_CONFIG_ITEM_TTS_ENGINE = "internal.tts.engine"; // Location actions