Problem
Map cluster bubbles are rendered in Google's default navy, which is the only
thing on the map that does not follow the app's colour language. At the zoom
the map opens at, most signals sit inside a bubble — so urgency, which pin
colour exists to communicate, is invisible for the majority of what is on
screen.
Design review finding COLOR-4 (docs/ai/DESIGN_UI_REVIEW_2026-08-25.md).
Why it is not a small fix
There is no hook for this anywhere in the Dart API.
ClusterManager (google_maps_flutter_platform_interface 2.9.5) carries a
clusterManagerId and an onClusterTap callback. That is the whole type.
- On Android,
ClusterManagersController.ClusterRenderer overrides
onBeforeClusterItemRendered (individual pins) and onClusterItemRendered,
but not onBeforeClusterRendered — so the bubble comes straight from the
Maps SDK utility library's DefaultClusterRenderer, with its built-in
bucket colours.
So the options are to fork the plugin on both platforms, or to stop using its
clustering.
Proposed approach — Dart-side clustering
Roughly 200 lines:
- Grid-cluster the visible signals on each camera idle (
_onCameraIdle
already exists in map_page.dart).
- Draw bubbles as
BitmapDescriptor.bytes from a canvas — circle plus count —
cached by (count bucket, colour).
- Colour each bubble by the highest urgency it contains, which is strictly
more information than a flat brand orange would be: a cluster holding an
amber signal reads amber.
- Tap still zooms to the cluster bounds.
Risks
- Touches the recurring far-pin InfoWindow bug: reclustering tears down the
open native InfoWindow, and the current workaround re-asserts it. A new
clustering path has to preserve that.
- Changes clustering behaviour on both platforms, so it needs a real device
pass rather than a widget test.
Already done
MapMarkerBuilder.clusterOf keeps SignalUrgency.red out of clustering
entirely, so a signal where an animal may die is always its own red pin at
every zoom. That is the one lever Dart has today, and it means the navy bubble
now only ever contains green and amber signals. This issue is the rest of it.
Problem
Map cluster bubbles are rendered in Google's default navy, which is the only
thing on the map that does not follow the app's colour language. At the zoom
the map opens at, most signals sit inside a bubble — so urgency, which pin
colour exists to communicate, is invisible for the majority of what is on
screen.
Design review finding COLOR-4 (
docs/ai/DESIGN_UI_REVIEW_2026-08-25.md).Why it is not a small fix
There is no hook for this anywhere in the Dart API.
ClusterManager(google_maps_flutter_platform_interface 2.9.5) carries aclusterManagerIdand anonClusterTapcallback. That is the whole type.ClusterManagersController.ClusterRendereroverridesonBeforeClusterItemRendered(individual pins) andonClusterItemRendered,but not
onBeforeClusterRendered— so the bubble comes straight from theMaps SDK utility library's
DefaultClusterRenderer, with its built-inbucket colours.
So the options are to fork the plugin on both platforms, or to stop using its
clustering.
Proposed approach — Dart-side clustering
Roughly 200 lines:
_onCameraIdlealready exists in
map_page.dart).BitmapDescriptor.bytesfrom a canvas — circle plus count —cached by (count bucket, colour).
more information than a flat brand orange would be: a cluster holding an
amber signal reads amber.
Risks
open native InfoWindow, and the current workaround re-asserts it. A new
clustering path has to preserve that.
pass rather than a widget test.
Already done
MapMarkerBuilder.clusterOfkeepsSignalUrgency.redout of clusteringentirely, so a signal where an animal may die is always its own red pin at
every zoom. That is the one lever Dart has today, and it means the navy bubble
now only ever contains green and amber signals. This issue is the rest of it.