diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md index 3862b89afd6..2a02f81145d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.15.2 + +* Fixes regression where updating a marker hides its info window. + ## 2.15.1 * Fixes regression in displaying info windows. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/integration_test/google_maps_test.dart index 9c700671465..e106dbb2be8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/integration_test/google_maps_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/integration_test/google_maps_test.dart @@ -842,6 +842,65 @@ void main() { expect(iwVisibleStatus, false); }); + testWidgets('updating a marker does not hide its info window', + (WidgetTester tester) async { + final Key key = GlobalKey(); + const Marker marker = Marker( + markerId: MarkerId('marker'), + infoWindow: InfoWindow(title: 'InfoWindow')); + Set markers = {marker}; + + const ClusterManager clusterManager = + ClusterManager(clusterManagerId: ClusterManagerId('cluster_manager')); + final Set clusterManagers = { + clusterManager + }; + + final Completer controllerCompleter = + Completer(); + + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + markers: markers, + clusterManagers: clusterManagers, + onMapCreated: (ExampleGoogleMapController googleMapController) { + controllerCompleter.complete(googleMapController); + }, + ), + )); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await controller.showMarkerInfoWindow(marker.markerId); + bool iwVisibleStatus = + await controller.isMarkerInfoWindowShown(marker.markerId); + expect(iwVisibleStatus, true); + + // Update marker and ensure the info window remains visible when added to a + // cluster manager. + final Marker updatedMarker = marker.copyWith( + alphaParam: 0.5, + clusterManagerIdParam: clusterManager.clusterManagerId, + ); + markers = {updatedMarker}; + + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + clusterManagers: clusterManagers, + markers: Set.of(markers)), + )); + + iwVisibleStatus = await controller.isMarkerInfoWindowShown(marker.markerId); + expect(iwVisibleStatus, true); + }); + testWidgets('testTakeSnapshot', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); @@ -1110,6 +1169,46 @@ void main() { expect(markersAmountForClusterManager, markersPerClusterManager); } + // Move marker from the first cluster manager to the last. + final MarkerId markerIdToMove = markers.entries + .firstWhere((MapEntry entry) => + entry.value.clusterManagerId == + clusterManagers.first.clusterManagerId) + .key; + markers[markerIdToMove] = _copyMarkerWithClusterManagerId( + markers[markerIdToMove]!, clusterManagers.last.clusterManagerId); + + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + clusterManagers: clusterManagers, + markers: Set.of(markers.values)), + )); + + { + final List clusters = await inspector.getClusters( + mapId: controller.mapId, + clusterManagerId: clusterManagers.first.clusterManagerId); + final int markersAmountForClusterManager = clusters + .map((Cluster cluster) => cluster.count) + .reduce((int value, int element) => value + element); + //Check that first cluster manager has one less marker. + expect(markersAmountForClusterManager, markersPerClusterManager - 1); + } + + { + final List clusters = await inspector.getClusters( + mapId: controller.mapId, + clusterManagerId: clusterManagers.last.clusterManagerId); + final int markersAmountForClusterManager = clusters + .map((Cluster cluster) => cluster.count) + .reduce((int value, int element) => value + element); + // Check that last cluster manager has one more marker. + expect(markersAmountForClusterManager, markersPerClusterManager + 1); + } + // Remove markers from clusterManagers and test that clusterManagers are empty. for (final MapEntry entry in markers.entries) { markers[entry.key] = _copyMarkerWithClusterManagerId(entry.value, null); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.h index 3b090a3ed02..f10f2af2188 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.h @@ -16,7 +16,6 @@ NS_ASSUME_NONNULL_BEGIN @property(assign, nonatomic, readonly) BOOL consumeTapEvents; - (instancetype)initWithMarker:(GMSMarker *)marker markerIdentifier:(NSString *)markerIdentifier - clusterManagerIdentifier:(nullable NSString *)clusterManagerIdentifier mapView:(GMSMapView *)mapView; - (void)showInfoWindow; - (void)hideInfoWindow; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.m index 4db08d52e89..f86cb3620c2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.m @@ -24,19 +24,20 @@ @implementation FLTGoogleMapMarkerController - (instancetype)initWithMarker:(GMSMarker *)marker markerIdentifier:(NSString *)markerIdentifier - clusterManagerIdentifier:(nullable NSString *)clusterManagerIdentifier mapView:(GMSMapView *)mapView { self = [super init]; if (self) { _marker = marker; _markerIdentifier = [markerIdentifier copy]; - _clusterManagerIdentifier = [clusterManagerIdentifier copy]; _mapView = mapView; - FGMSetIdentifiersToMarkerUserData(_markerIdentifier, _clusterManagerIdentifier, _marker); } return self; } +- (void)setClusterManagerIdentifier:(nullable NSString *)clusterManagerIdentifier { + _clusterManagerIdentifier = clusterManagerIdentifier; +} + - (void)showInfoWindow { self.mapView.selectedMarker = self.marker; } @@ -110,6 +111,7 @@ - (void)setZIndex:(int)zIndex { - (void)updateFromPlatformMarker:(FGMPlatformMarker *)platformMarker registrar:(NSObject *)registrar screenScale:(CGFloat)screenScale { + [self setClusterManagerIdentifier:platformMarker.clusterManagerId]; [self setAlpha:platformMarker.alpha]; [self setAnchor:FGMGetCGPointForPigeonPoint(platformMarker.anchor)]; [self setDraggable:platformMarker.draggable]; @@ -126,6 +128,12 @@ - (void)updateFromPlatformMarker:(FGMPlatformMarker *)platformMarker [self setInfoWindowTitle:infoWindow.title snippet:infoWindow.snippet]; } + // Set the marker's user data with current identifiers. + FGMSetIdentifiersToMarkerUserData(self.markerIdentifier, self.clusterManagerIdentifier, + self.marker); + + // Ensure setVisible is called last as it adds the marker to the map, + // and must be done after all other parameters are set. [self setVisible:platformMarker.visible]; } @@ -173,7 +181,6 @@ - (void)addMarker:(FGMPlatformMarker *)markerToAdd { FLTGoogleMapMarkerController *controller = [[FLTGoogleMapMarkerController alloc] initWithMarker:marker markerIdentifier:markerIdentifier - clusterManagerIdentifier:clusterManagerIdentifier mapView:self.mapView]; [controller updateFromPlatformMarker:markerToAdd registrar:self.registrar @@ -196,20 +203,35 @@ - (void)changeMarkers:(NSArray *)markersToChange { - (void)changeMarker:(FGMPlatformMarker *)markerToChange { NSString *markerIdentifier = markerToChange.markerId; - NSString *clusterManagerIdentifier = markerToChange.clusterManagerId; FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[markerIdentifier]; if (!controller) { return; } + + NSString *clusterManagerIdentifier = markerToChange.clusterManagerId; NSString *previousClusterManagerIdentifier = [controller clusterManagerIdentifier]; - if (![previousClusterManagerIdentifier isEqualToString:clusterManagerIdentifier]) { - [self removeMarker:markerIdentifier]; - [self addMarker:markerToChange]; - } else { - [controller updateFromPlatformMarker:markerToChange - registrar:self.registrar - screenScale:[self getScreenScale]]; + [controller updateFromPlatformMarker:markerToChange + registrar:self.registrar + screenScale:[self getScreenScale]]; + + if ([controller.marker conformsToProtocol:@protocol(GMUClusterItem)]) { + if (previousClusterManagerIdentifier && + ![clusterManagerIdentifier isEqualToString:previousClusterManagerIdentifier]) { + // Remove marker from previous cluster manager if its cluster manager identifier is removed or + // changed. + GMUClusterManager *clusterManager = [_clusterManagersController + clusterManagerWithIdentifier:previousClusterManagerIdentifier]; + [clusterManager removeItem:(id)controller.marker]; + } + + if (clusterManagerIdentifier && + ![previousClusterManagerIdentifier isEqualToString:clusterManagerIdentifier]) { + // Add marker to cluster manager if its cluster manager identifier has changed. + GMUClusterManager *clusterManager = + [_clusterManagersController clusterManagerWithIdentifier:clusterManagerIdentifier]; + [clusterManager addItem:(id)controller.marker]; + } } } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml index 55c040865da..959b40bf106 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_ios description: iOS implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.15.1 +version: 2.15.2 environment: sdk: ^3.4.0