diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CHANGELOG.md index dd1560e59d0a..74c22c66e382 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.19.0 + +* Adds support for tapping points of interest on the map. + ## 2.18.13 * Adopts new Pigeon async Swift support. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.swift index 2a0b6cebfa84..787c7788f3a7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.swift @@ -38,6 +38,27 @@ class StubBinaryMessenger: NSObject, FlutterBinaryMessenger { } } +/// Records POI tap callbacks for unit tests. +class MockMapEventHandler: TestMapEventHandler { + var lastTappedPointOfInterestPlaceIdentifier: String? + private var pointOfInterestTapContinuation: CheckedContinuation? + + func waitForPointOfInterestTap() async { + if lastTappedPointOfInterestPlaceIdentifier != nil { + return + } + await withCheckedContinuation { continuation in + pointOfInterestTapContinuation = continuation + } + } + + override func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws { + lastTappedPointOfInterestPlaceIdentifier = placeIdArg + pointOfInterestTapContinuation?.resume() + pointOfInterestTapContinuation = nil + } +} + class StubPluginRegistrar: NSObject, FlutterPluginRegistrar { var viewController: UIViewController? { nil } func publish(_ value: NSObject) {} @@ -167,6 +188,36 @@ class StubPluginRegistrar: NSObject, FlutterPluginRegistrar { #expect(mockTransactionWrapper.animationDuration == Double(durationMilliseconds) / 1000) } + @Test func didTapPOIForwardsPlaceIdentifierToCallbackApi() async { + let frame = CGRect(x: 0, y: 0, width: 100, height: 100) + let mapViewOptions = GMSMapViewOptions() + mapViewOptions.frame = frame + mapViewOptions.camera = GMSCameraPosition(latitude: 0, longitude: 0, zoom: 0) + + let mapView = PartiallyMockedMapView(options: mapViewOptions) + + let mapEventHandler = MockMapEventHandler() + let controller = GoogleMapController( + mapView: mapView, + viewIdentifier: 0, + creationParameters: emptyCreationParameters(), + assetProvider: TestAssetProvider(), + binaryMessenger: StubBinaryMessenger(), + callbackHandler: mapEventHandler + ) + + async let poiTapReceived: Void = mapEventHandler.waitForPointOfInterestTap() + controller.mapView( + mapView, + didTapPOIWithPlaceID: "place-123", + name: "Test Place", + location: CLLocationCoordinate2DMake(0, 0) + ) + await poiTapReceived + + #expect(mapEventHandler.lastTappedPointOfInterestPlaceIdentifier == "place-123") + } + @Test func inspectorAPICameraPosition() throws { let frame = CGRect(x: 0, y: 0, width: 100, height: 100) let mapViewOptions = GMSMapViewOptions() diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift index 83e76fdf5b80..20feceab0707 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift @@ -39,6 +39,8 @@ class TestMapEventHandler: MapEventDelegate { func didTapCircle(withIdentifier circleIdArg: String) async throws {} + func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws {} + func didTapCluster(_ clusterArg: PlatformCluster) async throws {} func didTapPolygon(withIdentifier polygonIdArg: String) async throws {} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/pubspec.yaml index 7d916be0452d..5eed7f7f69be 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - google_maps_flutter_platform_interface: ^2.14.1 + google_maps_flutter_platform_interface: ^2.17.0 dev_dependencies: flutter_test: diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/fake_google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/fake_google_maps_flutter_platform.dart index 3e8beefc78c4..f4bc1fd82c8f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/fake_google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/fake_google_maps_flutter_platform.dart @@ -206,6 +206,11 @@ class FakeGoogleMapsFlutterPlatform extends GoogleMapsFlutterPlatform { return mapEventStreamController.stream.whereType(); } + @override + Stream onPointOfInterestTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + @override Stream onTap({required int mapId}) { return mapEventStreamController.stream.whereType(); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapController.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapController.swift index cc99b83f3ccd..53557b1ab7b7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapController.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapController.swift @@ -59,7 +59,7 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV /// The Google Maps SDK map view managed by this controller. let mapView: GMSMapView /// The Pigeon callback API implementation, used to send events to the Dart side. - let dartCallbackHandler: MapsCallbackApi + let dartCallbackHandler: MapEventDelegate /// The main Pigeon API implementation, separate to avoid lifetime extension. let callHandler: MapCallHandler /// The inspector API implementation, separate to avoid lifetime extension. @@ -101,21 +101,47 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV options.mapID = GMSMapID(identifier: mapId) } + let binaryMessenger = registrar.messenger() self.init( mapView: GMSMapView(options: options), viewIdentifier: viewId, creationParameters: creationParameters, assetProvider: DefaultAssetProvider(registrar: registrar), - binaryMessenger: registrar.messenger() + binaryMessenger: binaryMessenger, + callbackHandler: MapsCallbackApi( + binaryMessenger: binaryMessenger, + messageChannelSuffix: String(format: "%lld", viewId) + ) ) } - init( + convenience init( mapView: GMSMapView, viewIdentifier viewId: Int64, creationParameters: PlatformMapViewCreationParams, assetProvider: AssetProvider, binaryMessenger: FlutterBinaryMessenger + ) { + self.init( + mapView: mapView, + viewIdentifier: viewId, + creationParameters: creationParameters, + assetProvider: assetProvider, + binaryMessenger: binaryMessenger, + callbackHandler: MapsCallbackApi( + binaryMessenger: binaryMessenger, + messageChannelSuffix: String(format: "%lld", viewId) + ) + ) + } + + init( + mapView: GMSMapView, + viewIdentifier viewId: Int64, + creationParameters: PlatformMapViewCreationParams, + assetProvider: AssetProvider, + binaryMessenger: FlutterBinaryMessenger, + callbackHandler: MapEventDelegate ) { self.mapView = mapView mapView.accessibilityElementsHidden = false @@ -134,10 +160,7 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV // End duplicate code. let pigeonSuffix = String(format: "%lld", viewId) - dartCallbackHandler = MapsCallbackApi( - binaryMessenger: binaryMessenger, - messageChannelSuffix: pigeonSuffix - ) + dartCallbackHandler = callbackHandler let markerType = creationParameters.mapConfiguration.markerType @@ -167,7 +190,8 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV heatmapsController = HeatmapsController(mapView: mapView) tileOverlaysController = TileOverlaysController( mapView: mapView, - tileProvider: dartCallbackHandler + tileProvider: (callbackHandler as? MapsCallbackApi) + ?? MapsCallbackApi(binaryMessenger: binaryMessenger, messageChannelSuffix: pigeonSuffix) ) groundOverlaysController = GroundOverlaysController( mapView: mapView, @@ -396,6 +420,15 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV } } + public func mapView( + _ mapView: GMSMapView, didTapPOIWithPlaceID placeID: String, name: String, + location: CLLocationCoordinate2D + ) { + Task { + try await dartCallbackHandler.didTapPointOfInterest(withPlaceIdentifier: placeID) + } + } + func interpretMapConfiguration(_ config: PlatformMapConfiguration) { // Any changes here must also be made to the `init` method above. See the comment there for // details. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/Messages.g.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/Messages.g.swift index 3689467b7fea..0439edf54b0e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/Messages.g.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/Messages.g.swift @@ -3455,6 +3455,8 @@ protocol MapsCallbackApiProtocol { @MainActor func didTapInfoWindowOfMarker(withIdentifier markerIdArg: String) async throws /// Called when a circle is tapped. @MainActor func didTapCircle(withIdentifier circleIdArg: String) async throws + /// Called when a point of interest is tapped. + @MainActor func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws /// Called when a marker cluster is tapped. @MainActor func didTapCluster(_ clusterArg: PlatformCluster) async throws /// Called when a polygon is tapped. @@ -3738,6 +3740,29 @@ class MapsCallbackApi: MapsCallbackApiProtocol { } } } + /// Called when a point of interest is tapped. + @MainActor func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws { + return try await withCheckedThrowingContinuation { continuation in + let channelName: String = + "dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPointOfInterestTap\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel( + name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([placeIdArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + continuation.resume(throwing: createConnectionError(withChannelName: channelName)) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + continuation.resume(throwing: PigeonError(code: code, message: message, details: details)) + } else { + continuation.resume() + } + } + } + } /// Called when a marker cluster is tapped. @MainActor func didTapCluster(_ clusterArg: PlatformCluster) async throws { return try await withCheckedThrowingContinuation { continuation in diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_maps_flutter_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_maps_flutter_ios.dart index 11df18180a50..252912f722cd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_maps_flutter_ios.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_maps_flutter_ios.dart @@ -182,6 +182,11 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { return _events(mapId).whereType(); } + @override + Stream onPointOfInterestTap({required int mapId}) { + return _events(mapId).whereType(); + } + @override Stream onGroundOverlayTap({required int mapId}) { return _events(mapId).whereType(); @@ -957,6 +962,11 @@ class HostMapMessageHandler implements MapsCallbackApi { streamController.add(CircleTapEvent(mapId, CircleId(circleId))); } + @override + void onPointOfInterestTap(String placeId) { + streamController.add(PointOfInterestTapEvent(mapId, PointOfInterestId(placeId))); + } + @override void onClusterTap(PlatformCluster cluster) { streamController.add( diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/messages.g.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/messages.g.dart index d5c89d021360..76c32ea35680 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/messages.g.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/messages.g.dart @@ -3456,6 +3456,9 @@ abstract class MapsCallbackApi { /// Called when a circle is tapped. void onCircleTap(String circleId); + /// Called when a point of interest is tapped. + void onPointOfInterestTap(String placeId); + /// Called when a marker cluster is tapped. void onClusterTap(PlatformCluster cluster); @@ -3751,6 +3754,31 @@ abstract class MapsCallbackApi { }); } } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPointOfInterestTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_placeId = args[0]! as String; + try { + api.onPointOfInterestTap(arg_placeId); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString()), + ); + } + }); + } + } { final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap$messageChannelSuffix', diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/messages.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/messages.dart index 3f620b692269..673502373e3a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/messages.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/messages.dart @@ -803,6 +803,10 @@ abstract class MapsCallbackApi { @SwiftFunction('didTapCircle(withIdentifier:)') void onCircleTap(String circleId); + /// Called when a point of interest is tapped. + @SwiftFunction('didTapPointOfInterest(withPlaceIdentifier:)') + void onPointOfInterestTap(String placeId); + /// Called when a marker cluster is tapped. @SwiftFunction('didTapCluster(_:)') void onClusterTap(PlatformCluster cluster); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pubspec.yaml index f069ebac61bd..1dbb90cdf9f6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_ios_sdk10 description: iOS implementation of the google_maps_flutter plugin using Google Maps SDK 10. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios_sdk10 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.18.13 +version: 2.19.0 environment: sdk: ^3.10.0 @@ -19,7 +19,7 @@ flutter: dependencies: flutter: sdk: flutter - google_maps_flutter_platform_interface: ^2.14.2 + google_maps_flutter_platform_interface: ^2.17.0 meta: ^1.10.0 stream_transform: ^2.0.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.dart index 6d21a3e81c1f..978a022a4194 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.dart @@ -903,6 +903,20 @@ void main() { expect((await stream.next).value.value, equals(objectId)); }); + test('points of interest send tap events to correct stream', () async { + const mapId = 1; + const placeId = 'place-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized(mapId); + + final stream = StreamQueue(maps.onPointOfInterestTap(mapId: mapId)); + + callbackHandler.onPointOfInterestTap(placeId); + + expect((await stream.next).value.value, equals(placeId)); + }); + test('clusters send tap events to correct stream', () async { const mapId = 1; const managerId = 'manager-id'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CHANGELOG.md index da0ffcd8f6da..7987544d27e7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.19.0 + +* Adds support for tapping points of interest on the map. + ## 2.18.14 * Adopts new Pigeon async Swift support. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.swift index 189a00f20440..9b87d2afc3de 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.swift @@ -38,6 +38,27 @@ class StubBinaryMessenger: NSObject, FlutterBinaryMessenger { } } +/// Records POI tap callbacks for unit tests. +class MockMapEventHandler: TestMapEventHandler { + var lastTappedPointOfInterestPlaceIdentifier: String? + private var pointOfInterestTapContinuation: CheckedContinuation? + + func waitForPointOfInterestTap() async { + if lastTappedPointOfInterestPlaceIdentifier != nil { + return + } + await withCheckedContinuation { continuation in + pointOfInterestTapContinuation = continuation + } + } + + override func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws { + lastTappedPointOfInterestPlaceIdentifier = placeIdArg + pointOfInterestTapContinuation?.resume() + pointOfInterestTapContinuation = nil + } +} + class StubPluginRegistrar: NSObject, FlutterPluginRegistrar { var viewController: UIViewController? { nil } func publish(_ value: NSObject) {} @@ -167,6 +188,36 @@ class StubPluginRegistrar: NSObject, FlutterPluginRegistrar { #expect(mockTransactionWrapper.animationDuration == Double(durationMilliseconds) / 1000) } + @Test func didTapPOIForwardsPlaceIdentifierToCallbackApi() async { + let frame = CGRect(x: 0, y: 0, width: 100, height: 100) + let mapViewOptions = GMSMapViewOptions() + mapViewOptions.frame = frame + mapViewOptions.camera = GMSCameraPosition(latitude: 0, longitude: 0, zoom: 0) + + let mapView = PartiallyMockedMapView(options: mapViewOptions) + + let mapEventHandler = MockMapEventHandler() + let controller = GoogleMapController( + mapView: mapView, + viewIdentifier: 0, + creationParameters: emptyCreationParameters(), + assetProvider: TestAssetProvider(), + binaryMessenger: StubBinaryMessenger(), + callbackHandler: mapEventHandler + ) + + async let poiTapReceived: Void = mapEventHandler.waitForPointOfInterestTap() + controller.mapView( + mapView, + didTapPOIWithPlaceID: "place-123", + name: "Test Place", + location: CLLocationCoordinate2DMake(0, 0) + ) + await poiTapReceived + + #expect(mapEventHandler.lastTappedPointOfInterestPlaceIdentifier == "place-123") + } + @Test func inspectorAPICameraPosition() throws { let frame = CGRect(x: 0, y: 0, width: 100, height: 100) let mapViewOptions = GMSMapViewOptions() diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift index 2c72dffe0570..d96ab18767d9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift @@ -39,6 +39,8 @@ class TestMapEventHandler: MapEventDelegate { func didTapCircle(withIdentifier circleIdArg: String) async throws {} + func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws {} + func didTapCluster(_ clusterArg: PlatformCluster) async throws {} func didTapPolygon(withIdentifier polygonIdArg: String) async throws {} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/pubspec.yaml index d041adc00616..336b6a750a50 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/pubspec.yaml @@ -18,7 +18,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - google_maps_flutter_platform_interface: ^2.14.1 + google_maps_flutter_platform_interface: ^2.17.0 dev_dependencies: flutter_test: diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/fake_google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/fake_google_maps_flutter_platform.dart index 3e8beefc78c4..f4bc1fd82c8f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/fake_google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/fake_google_maps_flutter_platform.dart @@ -206,6 +206,11 @@ class FakeGoogleMapsFlutterPlatform extends GoogleMapsFlutterPlatform { return mapEventStreamController.stream.whereType(); } + @override + Stream onPointOfInterestTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + @override Stream onTap({required int mapId}) { return mapEventStreamController.stream.whereType(); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.swift index cc99b83f3ccd..53557b1ab7b7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.swift @@ -59,7 +59,7 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV /// The Google Maps SDK map view managed by this controller. let mapView: GMSMapView /// The Pigeon callback API implementation, used to send events to the Dart side. - let dartCallbackHandler: MapsCallbackApi + let dartCallbackHandler: MapEventDelegate /// The main Pigeon API implementation, separate to avoid lifetime extension. let callHandler: MapCallHandler /// The inspector API implementation, separate to avoid lifetime extension. @@ -101,21 +101,47 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV options.mapID = GMSMapID(identifier: mapId) } + let binaryMessenger = registrar.messenger() self.init( mapView: GMSMapView(options: options), viewIdentifier: viewId, creationParameters: creationParameters, assetProvider: DefaultAssetProvider(registrar: registrar), - binaryMessenger: registrar.messenger() + binaryMessenger: binaryMessenger, + callbackHandler: MapsCallbackApi( + binaryMessenger: binaryMessenger, + messageChannelSuffix: String(format: "%lld", viewId) + ) ) } - init( + convenience init( mapView: GMSMapView, viewIdentifier viewId: Int64, creationParameters: PlatformMapViewCreationParams, assetProvider: AssetProvider, binaryMessenger: FlutterBinaryMessenger + ) { + self.init( + mapView: mapView, + viewIdentifier: viewId, + creationParameters: creationParameters, + assetProvider: assetProvider, + binaryMessenger: binaryMessenger, + callbackHandler: MapsCallbackApi( + binaryMessenger: binaryMessenger, + messageChannelSuffix: String(format: "%lld", viewId) + ) + ) + } + + init( + mapView: GMSMapView, + viewIdentifier viewId: Int64, + creationParameters: PlatformMapViewCreationParams, + assetProvider: AssetProvider, + binaryMessenger: FlutterBinaryMessenger, + callbackHandler: MapEventDelegate ) { self.mapView = mapView mapView.accessibilityElementsHidden = false @@ -134,10 +160,7 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV // End duplicate code. let pigeonSuffix = String(format: "%lld", viewId) - dartCallbackHandler = MapsCallbackApi( - binaryMessenger: binaryMessenger, - messageChannelSuffix: pigeonSuffix - ) + dartCallbackHandler = callbackHandler let markerType = creationParameters.mapConfiguration.markerType @@ -167,7 +190,8 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV heatmapsController = HeatmapsController(mapView: mapView) tileOverlaysController = TileOverlaysController( mapView: mapView, - tileProvider: dartCallbackHandler + tileProvider: (callbackHandler as? MapsCallbackApi) + ?? MapsCallbackApi(binaryMessenger: binaryMessenger, messageChannelSuffix: pigeonSuffix) ) groundOverlaysController = GroundOverlaysController( mapView: mapView, @@ -396,6 +420,15 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV } } + public func mapView( + _ mapView: GMSMapView, didTapPOIWithPlaceID placeID: String, name: String, + location: CLLocationCoordinate2D + ) { + Task { + try await dartCallbackHandler.didTapPointOfInterest(withPlaceIdentifier: placeID) + } + } + func interpretMapConfiguration(_ config: PlatformMapConfiguration) { // Any changes here must also be made to the `init` method above. See the comment there for // details. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Messages.g.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Messages.g.swift index 3689467b7fea..0439edf54b0e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Messages.g.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Messages.g.swift @@ -3455,6 +3455,8 @@ protocol MapsCallbackApiProtocol { @MainActor func didTapInfoWindowOfMarker(withIdentifier markerIdArg: String) async throws /// Called when a circle is tapped. @MainActor func didTapCircle(withIdentifier circleIdArg: String) async throws + /// Called when a point of interest is tapped. + @MainActor func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws /// Called when a marker cluster is tapped. @MainActor func didTapCluster(_ clusterArg: PlatformCluster) async throws /// Called when a polygon is tapped. @@ -3738,6 +3740,29 @@ class MapsCallbackApi: MapsCallbackApiProtocol { } } } + /// Called when a point of interest is tapped. + @MainActor func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws { + return try await withCheckedThrowingContinuation { continuation in + let channelName: String = + "dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPointOfInterestTap\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel( + name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([placeIdArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + continuation.resume(throwing: createConnectionError(withChannelName: channelName)) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + continuation.resume(throwing: PigeonError(code: code, message: message, details: details)) + } else { + continuation.resume() + } + } + } + } /// Called when a marker cluster is tapped. @MainActor func didTapCluster(_ clusterArg: PlatformCluster) async throws { return try await withCheckedThrowingContinuation { continuation in diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_maps_flutter_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_maps_flutter_ios.dart index 11df18180a50..252912f722cd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_maps_flutter_ios.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_maps_flutter_ios.dart @@ -182,6 +182,11 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { return _events(mapId).whereType(); } + @override + Stream onPointOfInterestTap({required int mapId}) { + return _events(mapId).whereType(); + } + @override Stream onGroundOverlayTap({required int mapId}) { return _events(mapId).whereType(); @@ -957,6 +962,11 @@ class HostMapMessageHandler implements MapsCallbackApi { streamController.add(CircleTapEvent(mapId, CircleId(circleId))); } + @override + void onPointOfInterestTap(String placeId) { + streamController.add(PointOfInterestTapEvent(mapId, PointOfInterestId(placeId))); + } + @override void onClusterTap(PlatformCluster cluster) { streamController.add( diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/messages.g.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/messages.g.dart index d5c89d021360..76c32ea35680 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/messages.g.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/messages.g.dart @@ -3456,6 +3456,9 @@ abstract class MapsCallbackApi { /// Called when a circle is tapped. void onCircleTap(String circleId); + /// Called when a point of interest is tapped. + void onPointOfInterestTap(String placeId); + /// Called when a marker cluster is tapped. void onClusterTap(PlatformCluster cluster); @@ -3751,6 +3754,31 @@ abstract class MapsCallbackApi { }); } } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPointOfInterestTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_placeId = args[0]! as String; + try { + api.onPointOfInterestTap(arg_placeId); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString()), + ); + } + }); + } + } { final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap$messageChannelSuffix', diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/messages.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/messages.dart index a9f2eae70806..a39bf066c24b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/messages.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/messages.dart @@ -803,6 +803,10 @@ abstract class MapsCallbackApi { @SwiftFunction('didTapCircle(withIdentifier:)') void onCircleTap(String circleId); + /// Called when a point of interest is tapped. + @SwiftFunction('didTapPointOfInterest(withPlaceIdentifier:)') + void onPointOfInterestTap(String placeId); + /// Called when a marker cluster is tapped. @SwiftFunction('didTapCluster(_:)') void onClusterTap(PlatformCluster cluster); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pubspec.yaml index 4fa42bc6f481..d05a9ac0b688 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_ios_sdk9 description: iOS implementation of the google_maps_flutter plugin using Google Maps SDK 9. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios_sdk9 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.18.14 +version: 2.19.0 environment: sdk: ^3.10.0 @@ -19,7 +19,7 @@ flutter: dependencies: flutter: sdk: flutter - google_maps_flutter_platform_interface: ^2.14.2 + google_maps_flutter_platform_interface: ^2.17.0 meta: ^1.10.0 stream_transform: ^2.0.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.dart index 6d21a3e81c1f..978a022a4194 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.dart @@ -903,6 +903,20 @@ void main() { expect((await stream.next).value.value, equals(objectId)); }); + test('points of interest send tap events to correct stream', () async { + const mapId = 1; + const placeId = 'place-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized(mapId); + + final stream = StreamQueue(maps.onPointOfInterestTap(mapId: mapId)); + + callbackHandler.onPointOfInterestTap(placeId); + + expect((await stream.next).value.value, equals(placeId)); + }); + test('clusters send tap events to correct stream', () async { const mapId = 1; const managerId = 'manager-id'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.swift b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.swift index e918732d5b1d..28d5c6378dee 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.swift @@ -38,6 +38,27 @@ class StubBinaryMessenger: NSObject, FlutterBinaryMessenger { } } +/// Records POI tap callbacks for unit tests. +class MockMapEventHandler: TestMapEventHandler { + var lastTappedPointOfInterestPlaceIdentifier: String? + private var pointOfInterestTapContinuation: CheckedContinuation? + + func waitForPointOfInterestTap() async { + if lastTappedPointOfInterestPlaceIdentifier != nil { + return + } + await withCheckedContinuation { continuation in + pointOfInterestTapContinuation = continuation + } + } + + override func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws { + lastTappedPointOfInterestPlaceIdentifier = placeIdArg + pointOfInterestTapContinuation?.resume() + pointOfInterestTapContinuation = nil + } +} + class StubPluginRegistrar: NSObject, FlutterPluginRegistrar { var viewController: UIViewController? { nil } func publish(_ value: NSObject) {} @@ -167,6 +188,36 @@ class StubPluginRegistrar: NSObject, FlutterPluginRegistrar { #expect(mockTransactionWrapper.animationDuration == Double(durationMilliseconds) / 1000) } + @Test func didTapPOIForwardsPlaceIdentifierToCallbackApi() async { + let frame = CGRect(x: 0, y: 0, width: 100, height: 100) + let mapViewOptions = GMSMapViewOptions() + mapViewOptions.frame = frame + mapViewOptions.camera = GMSCameraPosition(latitude: 0, longitude: 0, zoom: 0) + + let mapView = PartiallyMockedMapView(options: mapViewOptions) + + let mapEventHandler = MockMapEventHandler() + let controller = GoogleMapController( + mapView: mapView, + viewIdentifier: 0, + creationParameters: emptyCreationParameters(), + assetProvider: TestAssetProvider(), + binaryMessenger: StubBinaryMessenger(), + callbackHandler: mapEventHandler + ) + + async let poiTapReceived: Void = mapEventHandler.waitForPointOfInterestTap() + controller.mapView( + mapView, + didTapPOIWithPlaceID: "place-123", + name: "Test Place", + location: CLLocationCoordinate2DMake(0, 0) + ) + await poiTapReceived + + #expect(mapEventHandler.lastTappedPointOfInterestPlaceIdentifier == "place-123") + } + @Test func inspectorAPICameraPosition() throws { let frame = CGRect(x: 0, y: 0, width: 100, height: 100) let mapViewOptions = GMSMapViewOptions() diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift index be9370c2f997..c7ef526286cf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/TestUtils/TestMapEventHandler.swift @@ -39,6 +39,8 @@ class TestMapEventHandler: MapEventDelegate { func didTapCircle(withIdentifier circleIdArg: String) async throws {} + func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws {} + func didTapCluster(_ clusterArg: PlatformCluster) async throws {} func didTapPolygon(withIdentifier polygonIdArg: String) async throws {} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/fake_google_maps_flutter_platform.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/fake_google_maps_flutter_platform.dart index 3e8beefc78c4..f4bc1fd82c8f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/fake_google_maps_flutter_platform.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/fake_google_maps_flutter_platform.dart @@ -206,6 +206,11 @@ class FakeGoogleMapsFlutterPlatform extends GoogleMapsFlutterPlatform { return mapEventStreamController.stream.whereType(); } + @override + Stream onPointOfInterestTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + @override Stream onTap({required int mapId}) { return mapEventStreamController.stream.whereType(); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapController.swift b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapController.swift index cc99b83f3ccd..53557b1ab7b7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapController.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapController.swift @@ -59,7 +59,7 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV /// The Google Maps SDK map view managed by this controller. let mapView: GMSMapView /// The Pigeon callback API implementation, used to send events to the Dart side. - let dartCallbackHandler: MapsCallbackApi + let dartCallbackHandler: MapEventDelegate /// The main Pigeon API implementation, separate to avoid lifetime extension. let callHandler: MapCallHandler /// The inspector API implementation, separate to avoid lifetime extension. @@ -101,21 +101,47 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV options.mapID = GMSMapID(identifier: mapId) } + let binaryMessenger = registrar.messenger() self.init( mapView: GMSMapView(options: options), viewIdentifier: viewId, creationParameters: creationParameters, assetProvider: DefaultAssetProvider(registrar: registrar), - binaryMessenger: registrar.messenger() + binaryMessenger: binaryMessenger, + callbackHandler: MapsCallbackApi( + binaryMessenger: binaryMessenger, + messageChannelSuffix: String(format: "%lld", viewId) + ) ) } - init( + convenience init( mapView: GMSMapView, viewIdentifier viewId: Int64, creationParameters: PlatformMapViewCreationParams, assetProvider: AssetProvider, binaryMessenger: FlutterBinaryMessenger + ) { + self.init( + mapView: mapView, + viewIdentifier: viewId, + creationParameters: creationParameters, + assetProvider: assetProvider, + binaryMessenger: binaryMessenger, + callbackHandler: MapsCallbackApi( + binaryMessenger: binaryMessenger, + messageChannelSuffix: String(format: "%lld", viewId) + ) + ) + } + + init( + mapView: GMSMapView, + viewIdentifier viewId: Int64, + creationParameters: PlatformMapViewCreationParams, + assetProvider: AssetProvider, + binaryMessenger: FlutterBinaryMessenger, + callbackHandler: MapEventDelegate ) { self.mapView = mapView mapView.accessibilityElementsHidden = false @@ -134,10 +160,7 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV // End duplicate code. let pigeonSuffix = String(format: "%lld", viewId) - dartCallbackHandler = MapsCallbackApi( - binaryMessenger: binaryMessenger, - messageChannelSuffix: pigeonSuffix - ) + dartCallbackHandler = callbackHandler let markerType = creationParameters.mapConfiguration.markerType @@ -167,7 +190,8 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV heatmapsController = HeatmapsController(mapView: mapView) tileOverlaysController = TileOverlaysController( mapView: mapView, - tileProvider: dartCallbackHandler + tileProvider: (callbackHandler as? MapsCallbackApi) + ?? MapsCallbackApi(binaryMessenger: binaryMessenger, messageChannelSuffix: pigeonSuffix) ) groundOverlaysController = GroundOverlaysController( mapView: mapView, @@ -396,6 +420,15 @@ public class GoogleMapController: NSObject, GMSMapViewDelegate, FlutterPlatformV } } + public func mapView( + _ mapView: GMSMapView, didTapPOIWithPlaceID placeID: String, name: String, + location: CLLocationCoordinate2D + ) { + Task { + try await dartCallbackHandler.didTapPointOfInterest(withPlaceIdentifier: placeID) + } + } + func interpretMapConfiguration(_ config: PlatformMapConfiguration) { // Any changes here must also be made to the `init` method above. See the comment there for // details. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/Messages.g.swift b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/Messages.g.swift index 3689467b7fea..0439edf54b0e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/Messages.g.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/Messages.g.swift @@ -3455,6 +3455,8 @@ protocol MapsCallbackApiProtocol { @MainActor func didTapInfoWindowOfMarker(withIdentifier markerIdArg: String) async throws /// Called when a circle is tapped. @MainActor func didTapCircle(withIdentifier circleIdArg: String) async throws + /// Called when a point of interest is tapped. + @MainActor func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws /// Called when a marker cluster is tapped. @MainActor func didTapCluster(_ clusterArg: PlatformCluster) async throws /// Called when a polygon is tapped. @@ -3738,6 +3740,29 @@ class MapsCallbackApi: MapsCallbackApiProtocol { } } } + /// Called when a point of interest is tapped. + @MainActor func didTapPointOfInterest(withPlaceIdentifier placeIdArg: String) async throws { + return try await withCheckedThrowingContinuation { continuation in + let channelName: String = + "dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPointOfInterestTap\(messageChannelSuffix)" + let channel = FlutterBasicMessageChannel( + name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([placeIdArg] as [Any?]) { response in + guard let listResponse = response as? [Any?] else { + continuation.resume(throwing: createConnectionError(withChannelName: channelName)) + return + } + if listResponse.count > 1 { + let code: String = listResponse[0] as! String + let message: String? = nilOrValue(listResponse[1]) + let details: String? = nilOrValue(listResponse[2]) + continuation.resume(throwing: PigeonError(code: code, message: message, details: details)) + } else { + continuation.resume() + } + } + } + } /// Called when a marker cluster is tapped. @MainActor func didTapCluster(_ clusterArg: PlatformCluster) async throws { return try await withCheckedThrowingContinuation { continuation in diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_maps_flutter_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_maps_flutter_ios.dart index 11df18180a50..252912f722cd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_maps_flutter_ios.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_maps_flutter_ios.dart @@ -182,6 +182,11 @@ class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { return _events(mapId).whereType(); } + @override + Stream onPointOfInterestTap({required int mapId}) { + return _events(mapId).whereType(); + } + @override Stream onGroundOverlayTap({required int mapId}) { return _events(mapId).whereType(); @@ -957,6 +962,11 @@ class HostMapMessageHandler implements MapsCallbackApi { streamController.add(CircleTapEvent(mapId, CircleId(circleId))); } + @override + void onPointOfInterestTap(String placeId) { + streamController.add(PointOfInterestTapEvent(mapId, PointOfInterestId(placeId))); + } + @override void onClusterTap(PlatformCluster cluster) { streamController.add( diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/messages.g.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/messages.g.dart index d5c89d021360..76c32ea35680 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/messages.g.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/messages.g.dart @@ -3456,6 +3456,9 @@ abstract class MapsCallbackApi { /// Called when a circle is tapped. void onCircleTap(String circleId); + /// Called when a point of interest is tapped. + void onPointOfInterestTap(String placeId); + /// Called when a marker cluster is tapped. void onClusterTap(PlatformCluster cluster); @@ -3751,6 +3754,31 @@ abstract class MapsCallbackApi { }); } } + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPointOfInterestTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + final List args = message! as List; + final String arg_placeId = args[0]! as String; + try { + api.onPointOfInterestTap(arg_placeId); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString()), + ); + } + }); + } + } { final pigeonVar_channel = BasicMessageChannel( 'dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap$messageChannelSuffix', diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/messages.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/messages.dart index 5a87863f002a..81f43e8718e3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/messages.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/messages.dart @@ -803,6 +803,10 @@ abstract class MapsCallbackApi { @SwiftFunction('didTapCircle(withIdentifier:)') void onCircleTap(String circleId); + /// Called when a point of interest is tapped. + @SwiftFunction('didTapPointOfInterest(withPlaceIdentifier:)') + void onPointOfInterestTap(String placeId); + /// Called when a marker cluster is tapped. @SwiftFunction('didTapCluster(_:)') void onClusterTap(PlatformCluster cluster); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.dart index 6d21a3e81c1f..978a022a4194 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.dart @@ -903,6 +903,20 @@ void main() { expect((await stream.next).value.value, equals(objectId)); }); + test('points of interest send tap events to correct stream', () async { + const mapId = 1; + const placeId = 'place-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized(mapId); + + final stream = StreamQueue(maps.onPointOfInterestTap(mapId: mapId)); + + callbackHandler.onPointOfInterestTap(placeId); + + expect((await stream.next).value.value, equals(placeId)); + }); + test('clusters send tap events to correct stream', () async { const mapId = 1; const managerId = 'manager-id';