From b3a55b01e022a669465d5528ad935bb4641e8924 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Fri, 16 Jan 2026 11:30:04 -0500 Subject: [PATCH 01/19] Add shared code and sdk9 --- .../google_maps_flutter_android/CHANGELOG.md | 4 - .../android/build.gradle | 2 +- .../google_maps_flutter_android/pubspec.yaml | 2 +- .../FGMClusterManagersController.h | 2 +- .../FGMConversionUtils.h | 2 +- .../FLTGoogleMapHeatmapController.h | 2 +- .../GoogleMapsUtilsTrampoline.h | 12 + .../pigeons/messages.dart | 3 + .../google_maps_flutter_ios/pubspec.yaml | 2 + .../test/google_maps_flutter_ios_test.dart | 3 +- .../test/package_specific_test_import.dart | 11 + .../tool/run_tests.dart | 102 + .../tool/sync_shared_files.dart | 198 + .../google_maps_flutter_ios/tool/utils.dart | 55 + .../google_maps_flutter_ios_sdk9/AUTHORS | 68 + .../google_maps_flutter_ios_sdk9/CHANGELOG.md | 216 + .../google_maps_flutter_ios_sdk9/LICENSE | 25 + .../google_maps_flutter_ios_sdk9/README.md | 25 + .../example/.metadata | 8 + .../example/README.md | 13 + .../example/assets/2.0x/red_square.png | Bin 0 -> 304 bytes .../example/assets/3.0x/red_square.png | Bin 0 -> 312 bytes .../example/assets/night_mode.json | 162 + .../example/assets/red_square.png | Bin 0 -> 195 bytes .../integration_test/google_maps_test.dart | 2257 +++++++++ .../integration_test/resources/icon_image.png | Bin 0 -> 1257 bytes .../resources/icon_image_base64.dart | 49 + .../ios/Flutter/AppFrameworkInfo.plist | 28 + .../example/ios/Flutter/Debug.xcconfig | 2 + .../example/ios/Flutter/Release.xcconfig | 2 + .../example/ios/Podfile | 45 + .../ios/Runner.xcodeproj/project.pbxproj | 858 ++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Runner.xcscheme | 128 + .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../example/ios/Runner/AppDelegate.swift | 21 + .../AppIcon.appiconset/Contents.json | 122 + .../Icon-App-1024x1024@1x.png | Bin 0 -> 11112 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 29 + .../example/ios/Runner/Info.plist | 53 + .../ios/Runner/Runner-Bridging-Header.h | 5 + .../RunnerTests/ExtractIconFromDataTests.m | 352 ++ .../FGMClusterManagersControllerTests.m | 145 + .../RunnerTests/FGMConversionsUtilsTests.m | 429 ++ .../FLTGoogleMapHeatmapControllerTests.m | 118 + .../FLTTileProviderControllerTests.m | 36 + .../GoogleMapsCircleControllerTests.m | 104 + .../GoogleMapsGroundOverlayControllerTests.m | 281 ++ .../GoogleMapsMarkerControllerTests.m | 361 ++ .../GoogleMapsPolygonControllerTests.m | 112 + .../GoogleMapsPolylineControllerTests.m | 181 + .../example/ios/RunnerTests/GoogleMapsTests.m | 212 + .../GoogleMapsTileOverlayControllerTests.m | 73 + .../example/ios/RunnerTests/Info.plist | 22 + .../ios/RunnerTests/PartiallyMockedMapView.h | 17 + .../ios/RunnerTests/PartiallyMockedMapView.m | 34 + .../ios/RunnerTests/assets/widegamut.png | Bin 0 -> 3025 bytes .../ios/RunnerUITests/GoogleMapsUITests.m | 288 ++ .../example/ios/RunnerUITests/Info.plist | 22 + .../example/lib/animate_camera.dart | 204 + .../example/lib/clustering.dart | 288 ++ .../example/lib/custom_marker_icon.dart | 55 + .../example/lib/example_google_map.dart | 676 +++ .../example/lib/ground_overlay.dart | 311 ++ .../example/lib/lite_mode.dart | 46 + .../example/lib/main.dart | 53 + .../example/lib/map_click.dart | 105 + .../example/lib/map_coordinates.dart | 105 + .../example/lib/map_map_id.dart | 100 + .../example/lib/map_ui.dart | 341 ++ .../example/lib/maps_demo.dart | 42 + .../example/lib/marker_icons.dart | 355 ++ .../example/lib/move_camera.dart | 161 + .../example/lib/padding.dart | 169 + .../example/lib/page.dart | 14 + .../example/lib/place_circle.dart | 227 + .../example/lib/place_marker.dart | 417 ++ .../example/lib/place_polygon.dart | 298 ++ .../example/lib/place_polyline.dart | 322 ++ .../example/lib/scrolling_map.dart | 112 + .../example/lib/snapshot.dart | 81 + .../example/lib/tile_overlay.dart | 147 + .../example/pubspec.yaml | 33 + .../example/test/example_google_map_test.dart | 176 + .../fake_google_maps_flutter_platform.dart | 350 ++ .../example/test_driver/integration_test.dart | 7 + .../ios/google_maps_flutter_ios_sdk9.podspec | 37 + .../Package.swift | 44 + .../FGMCATransactionWrapper.m | 23 + .../FGMClusterManagersController.m | 128 + .../FGMConversionUtils.m | 288 ++ .../FGMGroundOverlayController.m | 211 + .../FGMImageUtils.m | 235 + .../FGMMarkerUserData.m | 34 + .../FLTGoogleMapHeatmapController.m | 140 + .../FLTGoogleMapTileOverlayController.m | 199 + .../FLTGoogleMapsPlugin.m | 19 + .../GoogleMapCircleController.m | 130 + .../GoogleMapController.m | 838 ++++ .../GoogleMapMarkerController.m | 343 ++ .../GoogleMapPolygonController.m | 146 + .../GoogleMapPolylineController.m | 140 + .../Resources/PrivacyInfo.xcprivacy | 123 + .../google_maps_flutter_pigeon_messages.g.m | 3446 +++++++++++++ .../FGMCATransactionWrapper.h | 20 + .../FGMClusterManagersController.h | 56 + .../FGMConversionUtils.h | 97 + .../FGMGroundOverlayController.h | 64 + .../FGMGroundOverlayController_Test.h | 29 + .../FGMImageUtils.h | 20 + .../FGMMarkerUserData.h | 37 + .../FLTGoogleMapHeatmapController.h | 59 + .../FLTGoogleMapHeatmapController_Test.h | 17 + .../FLTGoogleMapTileOverlayController.h | 40 + .../FLTGoogleMapTileOverlayController_Test.h | 17 + .../FLTGoogleMapsPlugin.h | 20 + .../GoogleMapCircleController.h | 30 + .../GoogleMapCircleController_Test.h | 21 + .../GoogleMapController.h | 34 + .../GoogleMapController_Test.h | 59 + .../GoogleMapMarkerController.h | 55 + .../GoogleMapMarkerController_Test.h | 31 + .../GoogleMapPolygonController.h | 27 + .../GoogleMapPolygonController_Test.h | 17 + .../GoogleMapPolylineController.h | 27 + .../GoogleMapPolylineController_Test.h | 25 + .../GoogleMapsUtilsTrampoline.h | 12 + .../google_maps_flutter_pigeon_messages.g.h | 940 ++++ .../lib/google_maps_flutter_ios_sdk9.dart | 5 + .../lib/src/google_map_inspector_ios.dart | 277 ++ .../lib/src/google_maps_flutter_ios.dart | 1467 ++++++ .../lib/src/messages.g.dart | 4311 +++++++++++++++++ .../pigeons/copyright.txt | 3 + .../pigeons/messages.dart | 871 ++++ .../google_maps_flutter_ios_sdk9/pubspec.yaml | 39 + .../test/google_maps_flutter_ios_test.dart | 1357 ++++++ .../google_maps_flutter_ios_test.mocks.dart | 351 ++ .../test/package_specific_test_import.dart | 11 + .../tool/run_tests.dart | 102 + .../tool/sync_shared_files.dart | 198 + .../tool/utils.dart | 55 + .../README.md | 31 + .../integration_test/google_maps_test.dart | 2257 +++++++++ .../resources/icon_image_base64.dart | 49 + .../example/ios/Runner/AppDelegate.swift | 21 + .../ios/Runner/Runner-Bridging-Header.h | 5 + .../RunnerTests/ExtractIconFromDataTests.m | 352 ++ .../FGMClusterManagersControllerTests.m | 145 + .../RunnerTests/FGMConversionsUtilsTests.m | 429 ++ .../FLTGoogleMapHeatmapControllerTests.m | 118 + .../FLTTileProviderControllerTests.m | 36 + .../GoogleMapsCircleControllerTests.m | 104 + .../GoogleMapsGroundOverlayControllerTests.m | 281 ++ .../GoogleMapsMarkerControllerTests.m | 361 ++ .../GoogleMapsPolygonControllerTests.m | 112 + .../GoogleMapsPolylineControllerTests.m | 181 + .../example/ios/RunnerTests/GoogleMapsTests.m | 212 + .../GoogleMapsTileOverlayControllerTests.m | 73 + .../ios/RunnerTests/PartiallyMockedMapView.h | 17 + .../ios/RunnerTests/PartiallyMockedMapView.m | 34 + .../ios/RunnerUITests/GoogleMapsUITests.m | 288 ++ .../example/lib/animate_camera.dart | 204 + .../example/lib/clustering.dart | 288 ++ .../example/lib/custom_marker_icon.dart | 55 + .../example/lib/example_google_map.dart | 676 +++ .../example/lib/ground_overlay.dart | 311 ++ .../example/lib/lite_mode.dart | 46 + .../example/lib/main.dart | 53 + .../example/lib/map_click.dart | 105 + .../example/lib/map_coordinates.dart | 105 + .../example/lib/map_map_id.dart | 100 + .../example/lib/map_ui.dart | 341 ++ .../example/lib/maps_demo.dart | 42 + .../example/lib/marker_icons.dart | 355 ++ .../example/lib/move_camera.dart | 161 + .../example/lib/padding.dart | 169 + .../example/lib/page.dart | 14 + .../example/lib/place_circle.dart | 227 + .../example/lib/place_marker.dart | 417 ++ .../example/lib/place_polygon.dart | 298 ++ .../example/lib/place_polyline.dart | 322 ++ .../example/lib/scrolling_map.dart | 112 + .../example/lib/snapshot.dart | 81 + .../example/lib/tile_overlay.dart | 147 + .../example/test/example_google_map_test.dart | 176 + .../fake_google_maps_flutter_platform.dart | 350 ++ .../example/test_driver/integration_test.dart | 7 + .../FGMCATransactionWrapper.m | 23 + .../FGMClusterManagersController.m | 128 + .../FGMConversionUtils.m | 288 ++ .../FGMGroundOverlayController.m | 211 + .../google_maps_flutter_ios/FGMImageUtils.m | 235 + .../FGMMarkerUserData.m | 34 + .../FLTGoogleMapHeatmapController.m | 140 + .../FLTGoogleMapTileOverlayController.m | 199 + .../FLTGoogleMapsPlugin.m | 19 + .../GoogleMapCircleController.m | 130 + .../GoogleMapController.m | 838 ++++ .../GoogleMapMarkerController.m | 343 ++ .../GoogleMapPolygonController.m | 146 + .../GoogleMapPolylineController.m | 140 + .../google_maps_flutter_pigeon_messages.g.m | 3446 +++++++++++++ .../FGMCATransactionWrapper.h | 20 + .../FGMClusterManagersController.h | 56 + .../FGMConversionUtils.h | 97 + .../FGMGroundOverlayController.h | 64 + .../FGMGroundOverlayController_Test.h | 29 + .../google_maps_flutter_ios/FGMImageUtils.h | 20 + .../FGMMarkerUserData.h | 37 + .../FLTGoogleMapHeatmapController.h | 59 + .../FLTGoogleMapHeatmapController_Test.h | 17 + .../FLTGoogleMapTileOverlayController.h | 40 + .../FLTGoogleMapTileOverlayController_Test.h | 17 + .../FLTGoogleMapsPlugin.h | 20 + .../GoogleMapCircleController.h | 30 + .../GoogleMapCircleController_Test.h | 21 + .../GoogleMapController.h | 34 + .../GoogleMapController_Test.h | 59 + .../GoogleMapMarkerController.h | 55 + .../GoogleMapMarkerController_Test.h | 31 + .../GoogleMapPolygonController.h | 27 + .../GoogleMapPolygonController_Test.h | 17 + .../GoogleMapPolylineController.h | 27 + .../GoogleMapPolylineController_Test.h | 25 + .../GoogleMapsUtilsTrampoline.h | 12 + .../google_maps_flutter_pigeon_messages.g.h | 940 ++++ .../lib/src/google_map_inspector_ios.dart | 277 ++ .../lib/src/google_maps_flutter_ios.dart | 1467 ++++++ .../lib/src/messages.g.dart | 4311 +++++++++++++++++ .../pigeons/copyright.txt | 3 + .../pigeons/messages.dart | 871 ++++ .../test/google_maps_flutter_ios_test.dart | 1357 ++++++ .../google_maps_flutter_ios_test.mocks.dart | 351 ++ .../tool/run_tests.dart | 102 + .../tool/sync_shared_files.dart | 198 + .../tool/utils.dart | 55 + 257 files changed, 57236 insertions(+), 11 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios/test/package_specific_test_import.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios/tool/run_tests.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/AUTHORS create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CHANGELOG.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/LICENSE create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/README.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/.metadata create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/README.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/2.0x/red_square.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/3.0x/red_square.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/night_mode.json create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/red_square.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/google_maps_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/resources/icon_image.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/resources/icon_image_base64.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/Release.xcconfig create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Podfile create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/AppDelegate.swift create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Info.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/ExtractIconFromDataTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMClusterManagersControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMConversionsUtilsTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTTileProviderControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/Info.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/PartiallyMockedMapView.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/PartiallyMockedMapView.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/assets/widegamut.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/Info.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/animate_camera.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/clustering.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/custom_marker_icon.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/example_google_map.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/ground_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/lite_mode.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/main.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_click.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_coordinates.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_map_id.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_ui.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/maps_demo.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/marker_icons.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/move_camera.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/padding.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/page.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_circle.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_marker.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_polygon.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_polyline.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/scrolling_map.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/snapshot.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/tile_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/pubspec.yaml create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/example_google_map_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/fake_google_maps_flutter_platform.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test_driver/integration_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9.podspec create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/google_maps_flutter_ios_sdk9.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_map_inspector_ios.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_maps_flutter_ios.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/messages.g.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/copyright.txt create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/messages.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pubspec.yaml create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.mocks.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/package_specific_test_import.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/run_tests.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/README.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/integration_test/google_maps_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/integration_test/resources/icon_image_base64.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/Runner/AppDelegate.swift create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/ExtractIconFromDataTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMClusterManagersControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMConversionsUtilsTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTTileProviderControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/PartiallyMockedMapView.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/PartiallyMockedMapView.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/animate_camera.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/clustering.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/custom_marker_icon.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/example_google_map.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/ground_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/lite_mode.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/main.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_click.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_coordinates.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_map_id.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_ui.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/maps_demo.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/marker_icons.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/move_camera.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/padding.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/page.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_circle.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_marker.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_polygon.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_polyline.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/scrolling_map.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/snapshot.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/tile_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/example_google_map_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/fake_google_maps_flutter_platform.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test_driver/integration_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMCATransactionWrapper.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMClusterManagersController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMConversionUtils.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMGroundOverlayController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMImageUtils.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMMarkerUserData.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapHeatmapController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapTileOverlayController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapsPlugin.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapCircleController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapMarkerController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapPolygonController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapPolylineController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMCATransactionWrapper.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMClusterManagersController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMConversionUtils.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMGroundOverlayController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMGroundOverlayController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMImageUtils.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMMarkerUserData.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapTileOverlayController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapTileOverlayController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapsPlugin.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapCircleController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapCircleController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapMarkerController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapMarkerController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolygonController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolygonController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolylineController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolylineController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_map_inspector_ios.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_maps_flutter_ios.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/messages.g.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/copyright.txt create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/messages.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.mocks.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/run_tests.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index 9533a9fff420..68385a54afcc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,7 +1,3 @@ -## 2.18.10 - -* Bump com.google.maps.android:android-maps-utils from 3.19.1 to 3.20.1. - ## 2.18.9 * Updates heatmaps passed between Dart and native to use typed data. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle b/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle index 34cd54da77a8..b5acf9a90ccb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle @@ -38,7 +38,7 @@ android { dependencies { implementation("androidx.annotation:annotation:1.9.1") implementation("com.google.android.gms:play-services-maps:19.2.0") - implementation("com.google.maps.android:android-maps-utils:3.20.1") + implementation("com.google.maps.android:android-maps-utils:3.19.1") androidTestImplementation("androidx.test:runner:1.7.0") androidTestImplementation("androidx.test:rules:1.7.0") androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0") diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index 4f41e83037e8..afea608e130b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.18.10 +version: 2.18.9 environment: sdk: ^3.9.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMClusterManagersController.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMClusterManagersController.h index 98afbb34d1f0..394f9e3d71e0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMClusterManagersController.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMClusterManagersController.h @@ -4,8 +4,8 @@ @import Flutter; @import GoogleMaps; -@import GoogleMapsUtils; +#import "GoogleMapsUtilsTrampoline.h" #import "google_maps_flutter_pigeon_messages.g.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMConversionUtils.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMConversionUtils.h index c7821882297c..45c13797099b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMConversionUtils.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMConversionUtils.h @@ -5,8 +5,8 @@ @import Flutter; @import Foundation; @import GoogleMaps; -@import GoogleMapsUtils; +#import "GoogleMapsUtilsTrampoline.h" #import "google_maps_flutter_pigeon_messages.g.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController.h index edba379ac0e3..a9c306abe7c4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController.h @@ -4,8 +4,8 @@ @import Flutter; @import GoogleMaps; -@import GoogleMapsUtils; +#import "GoogleMapsUtilsTrampoline.h" #import "google_maps_flutter_pigeon_messages.g.h" NS_ASSUME_NONNULL_BEGIN diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h new file mode 100644 index 000000000000..cf6399b5b39e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h @@ -0,0 +1,12 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// If Swift Package Manager is in use, Objective-C headers are available under the +// GoogleMapsUtilsObjC package. When using CocoaPods, the headers are provided by the +// GoogleMapsUtils package. +#ifdef FGM_USING_COCOAPODS +@import GoogleMapsUtils; +#else +@import GoogleMapsUtilsObjC; +#endif diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/pigeons/messages.dart b/packages/google_maps_flutter/google_maps_flutter_ios/pigeons/messages.dart index 233e91151b36..87885a3a4390 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/pigeons/messages.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/pigeons/messages.dart @@ -16,6 +16,9 @@ import 'package:pigeon/pigeon.dart'; 'ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.m', objcOptions: ObjcOptions(prefix: 'FGM'), copyrightHeader: 'pigeons/copyright.txt', + // Use the base package name so that the generated code can be shared + // across the implementation copies. + dartPackageName: 'google_maps_flutter_ios', ), ) /// Pigeon equivalent of MapType 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 d2b6449e77e3..29172616d2d7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml @@ -28,8 +28,10 @@ dev_dependencies: flutter_test: sdk: flutter mockito: ^5.4.4 + path: ^1.8.0 pigeon: ^26.1.0 plugin_platform_interface: ^2.1.7 + process: ^5.0.5 topics: - google-maps diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart index 23c7fd0c9fac..4dee18297412 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart @@ -7,13 +7,12 @@ import 'package:async/async.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:google_maps_flutter_ios/google_maps_flutter_ios.dart'; -import 'package:google_maps_flutter_ios/src/messages.g.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import 'google_maps_flutter_ios_test.mocks.dart'; +import 'package_specific_test_import.dart'; @GenerateNiceMocks(>[MockSpec()]) void main() { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/test/package_specific_test_import.dart b/packages/google_maps_flutter/google_maps_flutter_ios/test/package_specific_test_import.dart new file mode 100644 index 000000000000..5c58007ecaad --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/test/package_specific_test_import.dart @@ -0,0 +1,11 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is a separate file so that all test files that need to import the +// implementation package can do so without causing diffs among the shared code +// due to the package names being different. This way, all the test files can +// be shared exactly, and only this file needs to diverge between the packages. + +export 'package:google_maps_flutter_ios/google_maps_flutter_ios.dart'; +export 'package:google_maps_flutter_ios/src/messages.g.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/run_tests.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/run_tests.dart new file mode 100644 index 000000000000..114db5c7b00f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/run_tests.dart @@ -0,0 +1,102 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: avoid_print + +// Ensures that all files that are intended to be shared between +// google_maps_flutter_ios_* packages are in sync with the shared source of +// truth. See google_maps_flutter_ios_shared_code/README.md for details. +// +// Called from the custom-tests CI action. + +import 'dart:async'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +import 'utils.dart'; + +Future main(List args) async { + // There's no reason to run this on multiple platforms in CI, so limit it to + // macOS where local development of this package will be happening. + if (!Platform.isMacOS) { + print('Skipping for non-macOS host'); + exit(0); + } + + final Directory packageRoot = Directory( + p.dirname(Platform.script.path), + ).parent; + final String packageName = p.basename(packageRoot.path); + final sharedSourceRoot = Directory( + p.join(packageRoot.parent.path, 'google_maps_flutter_ios_shared_code'), + ); + + var failed = false; + for (final FileSystemEntity entity in sharedSourceRoot.listSync( + recursive: true, + )) { + if (entity is! File) { + continue; + } + final String relativePath = p.relative( + entity.path, + from: sharedSourceRoot.path, + ); + // The shared source README.md is not part of the shared source of truth, + // just an explanation of this source-sharing system. + if (relativePath == 'README.md') { + continue; + } + + // Adjust the paths to account for the package name being part of the + // directory structure for Swift packages. + final String packagePath = p.join( + packageRoot.path, + packageRelativePathForSharedSourceRelativePath(packageName, relativePath), + ); + + print('Validating $relativePath'); + final packageFile = File(packagePath); + if (!packageFile.existsSync()) { + print(' File $relativePath does not exist in $packageName'); + failed = true; + continue; + } + final String expectedContents = normalizedFileContents(entity); + final String contents = normalizedFileContents(packageFile); + if (contents != expectedContents) { + print(' File $relativePath does not match expected contents:'); + await _printDiff(entity, packageFile); + failed = true; + } + } + + if (failed) { + print(''' + +If the changes you made should be shared with other copies of the +implementation, copy the changes to google_maps_flutter_ios_* directories: + dart run tool/sync_shared_files.dart +To validate that the changes have been shared correctly, run this tool again. + +If the changes you made should only be made to one copy of the implementation, +discuss with your reviewer or #hackers-ecosystem on Discord about the best +approach to sharing as much code as can still be shared. + +For more information on the code sharing structure used by this package, see +the google_maps_flutter_ios_shared_code/README.md file. + '''); + exit(1); + } +} + +Future _printDiff(File expected, File actual) async { + final Process process = await Process.start('diff', [ + '-u', + expected.absolute.path, + actual.absolute.path, + ], mode: ProcessStartMode.inheritStdio); + await process.exitCode; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart new file mode 100644 index 000000000000..1a423bba92e6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart @@ -0,0 +1,198 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: avoid_print + +// Synchronizes files that are intended to be shared between +// google_maps_flutter_ios_* packages with the shared source of truth and other +// copies. See google_maps_flutter_ios_shared_code/README.md for details. + +import 'dart:async'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +import 'utils.dart'; + +const String _sharedSourceRootName = 'google_maps_flutter_ios_shared_code'; + +Future main(List args) async { + final Directory packageRoot = Directory( + p.dirname(Platform.script.path), + ).parent; + final String packageName = p.basename(packageRoot.path); + final sharedSourceRoot = Directory( + p.join(packageRoot.parent.path, _sharedSourceRootName), + ); + + _syncSharedFiles(packageRoot, packageName, sharedSourceRoot); + _reportUnsharedFiles(packageRoot, packageName, sharedSourceRoot); +} + +void _syncSharedFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List otherImplementationPackages = sharedSourceRoot.parent + .listSync() + .whereType() + .map((e) => p.basename(e.path)) + .where( + (name) => + name.startsWith('google_maps_flutter_ios') && + name != _sharedSourceRootName && + name != packageName, + ) + .toList(); + + final copiedFiles = []; + final missingFiles = []; + for (final FileSystemEntity entity in sharedSourceRoot.listSync( + recursive: true, + )) { + if (entity is! File) { + continue; + } + final String relativePath = p.relative( + entity.path, + from: sharedSourceRoot.path, + ); + // The shared source README.md is not part of the shared source of truth, + // just an explanation of this source-sharing system. + if (relativePath == 'README.md') { + continue; + } + + // Adjust the paths to account for the package name being part of the + // directory structure for Swift packages. + final String packagePath = p.join( + packageRoot.path, + packageRelativePathForSharedSourceRelativePath(packageName, relativePath), + ); + + final packageFile = File(packagePath); + if (!packageFile.existsSync()) { + missingFiles.add(relativePath); + continue; + } + final String sharedContents = normalizedFileContents(entity); + final String newContents = normalizedFileContents(packageFile); + if (newContents != sharedContents) { + copiedFiles.add(relativePath); + // Copy to shared source. + _syncFile(packageFile, entity.path, 'google_maps_flutter_ios'); + // Copy to other implementation packages. + for (final otherPackageName in otherImplementationPackages) { + final String otherPackagePath = p.join( + packageRoot.parent.path, + otherPackageName, + packageRelativePathForSharedSourceRelativePath( + otherPackageName, + relativePath, + ), + ); + _syncFile(packageFile, otherPackagePath, otherPackageName); + } + } + } + + if (copiedFiles.isNotEmpty) { + print('Copied files:'); + for (final file in copiedFiles) { + print(' $file'); + } + } + if (missingFiles.isNotEmpty) { + print( + 'This package is missing the following files from the shared source:', + ); + for (final file in missingFiles) { + print(' $file'); + } + print( + 'If these files should no longer be shared, remove them from the shared source.', + ); + } +} + +/// Syncs a file from the given source to a destination package. +/// +/// If the file needs special handling of package names that appear within the +/// contents of the file, it will update the package name in the file to match +/// the destination package name. +void _syncFile( + File source, + String destinationPath, + String destinationPackageName, +) { + source.copySync(destinationPath); + if ([ + // The Pigeon definition file has output paths that must use the + // package name, to follow Swift package naming rules. + '/pigeons/', + // The mock needs to import the package. + '.mocks.dart', + ].any((pattern) => source.absolute.path.contains(pattern))) { + updatePackageNameInPathReferences( + File(destinationPath), + destinationPackageName, + ); + } +} + +void _reportUnsharedFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List codeFiles = packageRoot + .listSync(recursive: true) + .whereType() + // Only report code files. + .where( + (file) => + ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), + ) + // Flutter-generated files aren't expected to be shared. + .where((file) => !file.path.contains('GeneratedPluginRegistrant')) + // Ignore intermediate file directories. + .where((file) => !_isInIntermediateDirectory(file.path)) + .toList(); + + final unsharedFiles = []; + for (final file in codeFiles) { + final String relativePath = p.relative(file.path, from: packageRoot.path); + final String sharedPath = p.join( + sharedSourceRoot.path, + sharedSourceRelativePathForPackagePath(relativePath), + ); + final sharedFile = File(sharedPath); + if (!sharedFile.existsSync()) { + unsharedFiles.add(relativePath); + } + } + + if (unsharedFiles.isNotEmpty) { + print('\nThe following code files are not shared with other packages:'); + for (final file in unsharedFiles) { + print(' $file'); + } + print( + 'If this is not intentional, copy the relevant files to ' + '$_sharedSourceRootName, then re-run this tool.', + ); + } +} + +bool _isInIntermediateDirectory(String path) { + return [ + '.dart_tool', + '.symlinks', + '.build', + 'build', + 'ephemeral', + 'Pods', + ].any((dir) => path.contains('/$dir/')); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart new file mode 100644 index 000000000000..d311e4f64891 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +/// Adjusts a package-relative path to account for the package name being part of +/// the directory structure for Swift packages. +String sharedSourceRelativePathForPackagePath(String packageRelativePath) { + return packageRelativePath.replaceAll( + RegExp(r'/google_maps_flutter_ios[_\w\d]*/'), + '/google_maps_flutter_ios/', + ); +} + +/// Adjusts a shared-source-relative path to account for the package name being +/// part of the directory structure for Swift packages. +String packageRelativePathForSharedSourceRelativePath( + String packageName, + String sharedSourceRelativePath, +) { + return sharedSourceRelativePath.replaceAll( + '/google_maps_flutter_ios/', + '/$packageName/', + ); +} + +/// Returns the contents of the file with any differences caused only by the +/// package name removed. +String normalizedFileContents(File file) { + return file + .readAsStringSync() + // Ignore differences caused only by the package name. + .replaceAll( + RegExp(r'google_maps_flutter_ios_[\w\d]+'), + 'google_maps_flutter_ios', + ) + // Package name diffs could change line wrapping, so collapse whitespace. + .replaceAll(RegExp(r'[\s\n]+'), ' ') + .trim(); +} + +/// Updates the contents of [file] to replace any occurrences of variants of the +/// package name in things that look like paths with [packageName]. +/// +/// This should only be used on files where this is the only option, and where +/// the diffs are known to be safe, as not all instances of the package name +/// should be replaced in all files. +void updatePackageNameInPathReferences(File file, String packageName) { + final String newContents = file.readAsStringSync().replaceAllMapped( + RegExp(r'google_maps_flutter_ios[_\w\d]*([:/])'), + (match) => '$packageName${match.group(1)}', + ); + file.writeAsStringSync(newContents); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/AUTHORS b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/AUTHORS new file mode 100644 index 000000000000..4fc3ace39f0f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/AUTHORS @@ -0,0 +1,68 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +The Chromium Authors +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> +Taha Tesser +Joonas Kerttula 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 new file mode 100644 index 000000000000..fa6e19caf286 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CHANGELOG.md @@ -0,0 +1,216 @@ +## 2.16.1 + +* Updates heatmaps passed between Dart and native to use typed data. + +## 2.16.0 + +* Adds compatibility with SDK version 10.x for apps targeting iOS 16+. + +## 2.15.8 + +* Replaces internal use of deprecated methods. + +## 2.15.7 + +* Updates to Pigeon 26. + +## 2.15.6 + +* Fixes potential flickers of default property values when adding objects to + the map. +* Updates minimum supported SDK version to Flutter 3.32/Dart 3.8. + +## 2.15.5 + +* Fixes `kCGImageAlphaPremultipliedLast` implicit conversion from enumeration type warning. + +## 2.15.4 + +* Deprecates `zIndex` parameter in Marker in favor of `zIndexInt`. + +## 2.15.3 + +* Fixes new analysis warnings. +* Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. + +## 2.15.2 + +* Fixes regression where updating a marker hides its info window. + +## 2.15.1 + +* Fixes regression in displaying info windows. + +## 2.15.0 + +* Adds support for animating the camera with a duration. + +## 2.14.0 + +* Adds support for ground overlay. +* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. + +## 2.13.2 + +* Updates most objects passed from Dart to native to use typed data. + +## 2.13.1 + +* Updates Pigeon for non-nullable collection type support. + +## 2.13.0 + +* Updates map configuration and platform view creation parameters to use Pigeon. +* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. + +## 2.12.0 + +* Adds support for marker clustering. + +## 2.11.0 + +* Adds support for heatmap layers. + +## 2.10.0 + +* Converts Obj-C->Dart calls to Pigeon. + +## 2.9.0 + +* Converts additional platform calls to Pigeon. + +## 2.8.2 + +* Converts inspector interface platform calls to Pigeon. + +## 2.8.1 + +* Improves Objective-C type handling. + +## 2.8.0 + +* Adds compatibility with SDK version 9.x for apps targetting iOS 15+. + +## 2.7.0 + +* Adds support for BitmapDescriptor classes `AssetMapBitmap` and `BytesMapBitmap`. + +## 2.6.1 + +* Adds support for patterns in polylines. + +## 2.6.0 + +* Updates the minimum allowed verison of the Google Maps SDK to 8.4, for privacy + manifest support. + * This means that applications using this package can no longer support + iOS 13 or 14, as the versions of the Google Maps SDK that support those + versions do not have privacy manifests, so cannot be used in published + applications once the new App Store enforcement of manifests takes effect. +* Includes the Google Maps SDK's [GoogleMapsPrivacy bundle](https://developers.google.com/maps/documentation/ios-sdk/config#add-apple-privacy-manifest-file) + manifest entries direct in the plugin, so that package clients do not need to + manually add that privacy bundle to the application build. + +## 2.5.2 + +* Fixes the tile overlay not correctly displaying on physical ios devices. + +## 2.5.1 + +* Makes the tile overlay callback invoke the platform channel on the platform thread. + +## 2.5.0 + +* Adds support for `MapConfiguration.style`. +* Adds support for `getStyleError`. + +## 2.4.2 + +* Fixes a bug in "takeSnapshot" function that incorrectly returns a blank image on iOS 17. + +## 2.4.1 + +* Restores the workaround to exclude arm64 simulator builds, as it is still necessary for applications targeting iOS 12. + +## 2.4.0 + +* Adds support for arm64 simulators. +* Updates minimum supported SDK version to Flutter 3.16.6. +* Removes support for iOS 11. + +## 2.3.6 + +* Adds privacy manifest. + +## 2.3.5 + +* Updates minimum required plugin_platform_interface version to 2.1.7. + +## 2.3.4 + +* Fixes new lint warnings. + +## 2.3.3 + +* Adds support for version 8 of the Google Maps SDK in apps targeting iOS 14+. +* Updates minimum supported SDK version to Flutter 3.10/Dart 3.0. + +## 2.3.2 + +* Fixes an issue where the onDragEnd callback for marker is not called. + +## 2.3.1 + +* Adds pub topics to package metadata. + +## 2.3.0 + +* Adds implementation for `cloudMapId` parameter to support cloud-based maps styling. +* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. +* Fixes unawaited_futures violations. + +## 2.2.3 + +* Removes obsolete null checks on non-nullable values. +* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. + +## 2.2.2 + +* Sets an upper bound on the `GoogleMaps` SDK version that can be used, to + avoid future breakage. + +## 2.2.1 + +* Clarifies explanation of endorsement in README. +* Aligns Dart and Flutter SDK constraints. + +## 2.2.0 + +* Updates minimum Flutter version to 3.3 and iOS 11. + +## 2.1.14 + +* Updates links for the merge of flutter/plugins into flutter/packages. + +## 2.1.13 + +* Updates code for stricter lint checks. +* Updates code for new analysis options. +* Re-enable XCUITests: testUserInterface. +* Remove unnecessary `RunnerUITests` target from Podfile of the example app. + +## 2.1.12 + +* Updates imports for `prefer_relative_imports`. +* Updates minimum Flutter version to 2.10. +* Fixes violations of new analysis option use_named_constants. +* Fixes avoid_redundant_argument_values lint warnings and minor typos. + +## 2.1.11 + +* Precaches Google Maps services initialization and syncing. + +## 2.1.10 + +* Splits iOS implementation out of `google_maps_flutter` as a federated + implementation. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/LICENSE b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/LICENSE new file mode 100644 index 000000000000..29b709dac6c7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/LICENSE @@ -0,0 +1,25 @@ +Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/README.md new file mode 100644 index 000000000000..20fae87c8855 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/README.md @@ -0,0 +1,25 @@ +# google\_maps\_flutter\_ios + +The iOS implementation of [`google_maps_flutter`][1]. + +## Usage + +This package is [endorsed][2], which means you can simply use +`google_maps_flutter` normally. This package will be automatically included in +your app when you do, so you do not need to add it to your `pubspec.yaml`. + +However, if you `import` this package to use any of its APIs directly, you +should add it to your `pubspec.yaml` as usual. + +## Supported Heatmap Options + +| Field | Supported | +| ---------------------------- | :-------: | +| Heatmap.dissipating | x | +| Heatmap.maxIntensity | x | +| Heatmap.minimumZoomIntensity | ✓ | +| Heatmap.maximumZoomIntensity | ✓ | +| HeatmapGradient.colorMapSize | ✓ | + +[1]: https://pub.dev/packages/google_maps_flutter +[2]: https://flutter.dev/to/endorsed-federated-plugin diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/.metadata b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/.metadata new file mode 100644 index 000000000000..46e884ce48d1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/.metadata @@ -0,0 +1,8 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 3ea4d06340a97a1e9d7cae97567c64e0569dcaa2 + channel: beta diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/README.md new file mode 100644 index 000000000000..2d527ff468c8 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/README.md @@ -0,0 +1,13 @@ +# Platform Implementation Test App + +This is a test app for manual testing and automated integration testing +of this platform implementation. It is not intended to demonstrate actual use of +this package, since the intent is that plugin clients use the app-facing +package. + +Unless you are making changes to this implementation package, this example is +very unlikely to be relevant. + +## Versions + +This example requires iOS 14, so will select a 8.x GoogleMaps SDK version. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/2.0x/red_square.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/2.0x/red_square.png new file mode 100644 index 0000000000000000000000000000000000000000..0f82237796bf8fd2f178f9e758330b88cf715db2 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeK3?y%aJ*@^(Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uxs6XMFi@E-`O@66Nz ziZCX5ySp&{XVSd~vL>4nJh^c}wqi2xH2cRH(iKnkC`(qX^4o2nTuqlgyLPDM{ zjv*GOlM^IZ7bl4HG(F^GV0pm6cSViEBhjN@7W>RdP`(kYX@0FtpS)Fwr$M z2r)FZGBC0-FwiwH2a=`jO&~8KH00)|WTsW3YcRAjHic*~j#{}AsDZ)L)z4*}Q$iB} Dk-bi6 literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/3.0x/red_square.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/3.0x/red_square.png new file mode 100644 index 0000000000000000000000000000000000000000..7e2739974e7bb4101cc42f520ece096cb2f5ade7 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^6F``e8A#skDEJMeSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPMC&ZPZf#LuE|04GK z{y-7NByV>Y#{W#Z_kbME0*}aI1_m)z5N7lYQuzQBWH0gbb!C6d!o|U8+TNu22`D7x z>EamTas2H;Lq;I)(1Nf2xxD-f7#JR0XW-hvz-VXkX+BU~wZt`|BqgyV)hf9t6-Y4{ z85mmX8kp!B8iW{{S{WExnHuXFm|GbbJl~bP0 Hl+XkKwG2>~ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/night_mode.json b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/night_mode.json new file mode 100644 index 000000000000..1f16e003a920 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/night_mode.json @@ -0,0 +1,162 @@ +[ + { + "elementType": "geometry", + "stylers": [ + { + "color": "#242f3e" + } + ] + }, + { + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#746855" + } + ] + }, + { + "elementType": "labels.text.stroke", + "stylers": [ + { + "color": "#242f3e" + } + ] + }, + { + "featureType": "administrative.locality", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#d59563" + } + ] + }, + { + "featureType": "poi", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#d59563" + } + ] + }, + { + "featureType": "poi.park", + "elementType": "geometry", + "stylers": [ + { + "color": "#263c3f" + } + ] + }, + { + "featureType": "poi.park", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#6b9a76" + } + ] + }, + { + "featureType": "road", + "elementType": "geometry", + "stylers": [ + { + "color": "#38414e" + } + ] + }, + { + "featureType": "road", + "elementType": "geometry.stroke", + "stylers": [ + { + "color": "#212a37" + } + ] + }, + { + "featureType": "road", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#9ca5b3" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "geometry", + "stylers": [ + { + "color": "#746855" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "geometry.stroke", + "stylers": [ + { + "color": "#1f2835" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#f3d19c" + } + ] + }, + { + "featureType": "transit", + "elementType": "geometry", + "stylers": [ + { + "color": "#2f3948" + } + ] + }, + { + "featureType": "transit.station", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#d59563" + } + ] + }, + { + "featureType": "water", + "elementType": "geometry", + "stylers": [ + { + "color": "#17263c" + } + ] + }, + { + "featureType": "water", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#515c6d" + } + ] + }, + { + "featureType": "water", + "elementType": "labels.text.stroke", + "stylers": [ + { + "color": "#17263c" + } + ] + } +] + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/red_square.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/assets/red_square.png new file mode 100644 index 0000000000000000000000000000000000000000..650a2dee711d0d404163de8d0e479d68e31d1662 GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=CqbAk63)r1AkM7~$#S7?R=q_WVZP1_OZu2ihZzoWI>~S6qbP0l+XkKvphU~ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/google_maps_test.dart new file mode 100644 index 000000000000..824dea7d30c5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/google_maps_test.dart @@ -0,0 +1,2257 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_example/example_google_map.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'resources/icon_image_base64.dart'; + +const LatLng _kInitialMapCenter = LatLng(0, 0); +const double _kInitialZoomLevel = 5; +const CameraPosition _kInitialCameraPosition = CameraPosition( + target: _kInitialMapCenter, + zoom: _kInitialZoomLevel, +); +const String _kCloudMapId = '000000000000000'; // Dummy map ID. + +// The tolerance value for floating-point comparisons in the tests. +// This value was selected as the minimum possible value that the test passes. +// There are multiple float conversions and calculations when data is converted +// between Dart and platform implementations. +const double _floatTolerance = 1e-6; +const double _kTestCameraZoomLevel = 10; +const double _kTestZoomByAmount = 2; +const LatLng _kTestMapCenter = LatLng(65, 25.5); +const CameraPosition _kTestCameraPosition = CameraPosition( + target: _kTestMapCenter, + zoom: _kTestCameraZoomLevel, + bearing: 1.0, + tilt: 1.0, +); +final LatLngBounds _testCameraBounds = LatLngBounds( + northeast: const LatLng(50, -65), + southwest: const LatLng(28.5, -123), +); +final ValueVariant _cameraUpdateTypeVariants = + ValueVariant(CameraUpdateType.values.toSet()); + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + GoogleMapsFlutterPlatform.instance.enableDebugInspection(); + + testWidgets('testCompassToggle', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + compassEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool compassEnabled = await inspector.isCompassEnabled(mapId: mapId); + expect(compassEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + compassEnabled = await inspector.isCompassEnabled(mapId: mapId); + expect(compassEnabled, true); + }); + + testWidgets('testMapToolbar returns false', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool mapToolbarEnabled = await inspector.isMapToolbarEnabled( + mapId: mapId, + ); + // This is only supported on Android, so should always return false. + expect(mapToolbarEnabled, false); + }); + + testWidgets('updateMinMaxZoomLevels', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + const initialZoomLevel = MinMaxZoomPreference(4, 8); + const finalZoomLevel = MinMaxZoomPreference(6, 10); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + minMaxZoomPreference: initialZoomLevel, + onMapCreated: (ExampleGoogleMapController c) async { + controllerCompleter.complete(c); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + MinMaxZoomPreference zoomLevel = await inspector.getMinMaxZoomLevels( + mapId: controller.mapId, + ); + expect(zoomLevel, equals(initialZoomLevel)); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + minMaxZoomPreference: finalZoomLevel, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + zoomLevel = await inspector.getMinMaxZoomLevels(mapId: controller.mapId); + expect(zoomLevel, equals(finalZoomLevel)); + }); + + testWidgets('testZoomGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + zoomGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool zoomGesturesEnabled = await inspector.areZoomGesturesEnabled( + mapId: mapId, + ); + expect(zoomGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + zoomGesturesEnabled = await inspector.areZoomGesturesEnabled(mapId: mapId); + expect(zoomGesturesEnabled, true); + }); + + testWidgets('testZoomControlsEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool zoomControlsEnabled = await inspector.areZoomControlsEnabled( + mapId: mapId, + ); + + /// Zoom Controls functionality is not available on iOS at the moment. + expect(zoomControlsEnabled, false); + }); + + testWidgets('testRotateGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + rotateGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool rotateGesturesEnabled = await inspector.areRotateGesturesEnabled( + mapId: mapId, + ); + expect(rotateGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + rotateGesturesEnabled = await inspector.areRotateGesturesEnabled( + mapId: mapId, + ); + expect(rotateGesturesEnabled, true); + }); + + testWidgets('testTiltGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tiltGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool tiltGesturesEnabled = await inspector.areTiltGesturesEnabled( + mapId: mapId, + ); + expect(tiltGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + tiltGesturesEnabled = await inspector.areTiltGesturesEnabled(mapId: mapId); + expect(tiltGesturesEnabled, true); + }); + + testWidgets('testScrollGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + scrollGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool scrollGesturesEnabled = await inspector.areScrollGesturesEnabled( + mapId: mapId, + ); + expect(scrollGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + scrollGesturesEnabled = await inspector.areScrollGesturesEnabled( + mapId: mapId, + ); + expect(scrollGesturesEnabled, true); + }); + + testWidgets( + 'testInitialCenterLocationAtCenter', + (WidgetTester tester) async { + await tester.binding.setSurfaceSize(const Size(800, 600)); + + final mapControllerCompleter = Completer(); + final Key key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapControllerCompleter.complete(controller); + }, + ), + ), + ); + final ExampleGoogleMapController mapController = + await mapControllerCompleter.future; + + await tester.pumpAndSettle(); + + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + final ScreenCoordinate coordinate = await mapController + .getScreenCoordinate(_kInitialCameraPosition.target); + final Rect rect = tester.getRect(find.byKey(key)); + expect(coordinate.x, (rect.center.dx - rect.topLeft.dx).round()); + expect(coordinate.y, (rect.center.dy - rect.topLeft.dy).round()); + + await tester.binding.setSurfaceSize(null); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets( + 'testGetVisibleRegion', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final zeroLatLngBounds = LatLngBounds( + southwest: const LatLng(0, 0), + northeast: const LatLng(0, 0), + ); + + final mapControllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapControllerCompleter.complete(controller); + }, + ), + ), + ); + await tester.pumpAndSettle(); + + final ExampleGoogleMapController mapController = + await mapControllerCompleter.future; + + final LatLngBounds firstVisibleRegion = await mapController + .getVisibleRegion(); + + expect(firstVisibleRegion, isNotNull); + expect(firstVisibleRegion.southwest, isNotNull); + expect(firstVisibleRegion.northeast, isNotNull); + expect(firstVisibleRegion, isNot(zeroLatLngBounds)); + expect(firstVisibleRegion.contains(_kInitialMapCenter), isTrue); + + // Making a new `LatLngBounds` about (10, 10) distance south west to the `firstVisibleRegion`. + // The size of the `LatLngBounds` is 10 by 10. + final southWest = LatLng( + firstVisibleRegion.southwest.latitude - 20, + firstVisibleRegion.southwest.longitude - 20, + ); + final northEast = LatLng( + firstVisibleRegion.southwest.latitude - 10, + firstVisibleRegion.southwest.longitude - 10, + ); + final newCenter = LatLng( + (northEast.latitude + southWest.latitude) / 2, + (northEast.longitude + southWest.longitude) / 2, + ); + + expect(firstVisibleRegion.contains(northEast), isFalse); + expect(firstVisibleRegion.contains(southWest), isFalse); + + final latLngBounds = LatLngBounds( + southwest: southWest, + northeast: northEast, + ); + + // TODO(iskakaushik): non-zero padding is needed for some device configurations + // https://github.com/flutter/flutter/issues/30575 + const double padding = 0; + await mapController.moveCamera( + CameraUpdate.newLatLngBounds(latLngBounds, padding), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final LatLngBounds secondVisibleRegion = await mapController + .getVisibleRegion(); + + expect(secondVisibleRegion, isNotNull); + expect(secondVisibleRegion.southwest, isNotNull); + expect(secondVisibleRegion.northeast, isNotNull); + expect(secondVisibleRegion, isNot(zeroLatLngBounds)); + + expect(firstVisibleRegion, isNot(secondVisibleRegion)); + expect(secondVisibleRegion.contains(newCenter), isTrue); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets('testTraffic', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + trafficEnabled: true, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool isTrafficEnabled = await inspector.isTrafficEnabled(mapId: mapId); + expect(isTrafficEnabled, true); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + isTrafficEnabled = await inspector.isTrafficEnabled(mapId: mapId); + expect(isTrafficEnabled, false); + }); + + testWidgets('testBuildings', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool isBuildingsEnabled = await inspector.areBuildingsEnabled( + mapId: mapId, + ); + expect(isBuildingsEnabled, true); + }); + + testWidgets('testMyLocationButtonToggle', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool myLocationButtonEnabled = await inspector.isMyLocationButtonEnabled( + mapId: mapId, + ); + expect(myLocationButtonEnabled, true); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + myLocationButtonEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + myLocationButtonEnabled = await inspector.isMyLocationButtonEnabled( + mapId: mapId, + ); + expect(myLocationButtonEnabled, false); + }); + + testWidgets('testMyLocationButton initial value false', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + myLocationButtonEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool myLocationButtonEnabled = await inspector + .isMyLocationButtonEnabled(mapId: mapId); + expect(myLocationButtonEnabled, false); + }); + + testWidgets('testMyLocationButton initial value true', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool myLocationButtonEnabled = await inspector + .isMyLocationButtonEnabled(mapId: mapId); + expect(myLocationButtonEnabled, true); + }); + + testWidgets('testSetMapStyle valid Json String', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + const mapStyle = + '[{"elementType":"geometry","stylers":[{"color":"#242f3e"}]}]'; + await GoogleMapsFlutterPlatform.instance.setMapStyle( + mapStyle, + mapId: controller.mapId, + ); + }); + + testWidgets('testSetMapStyle invalid Json String', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + try { + await GoogleMapsFlutterPlatform.instance.setMapStyle( + 'invalid_value', + mapId: controller.mapId, + ); + fail('expected MapStyleException'); + } on MapStyleException catch (e) { + expect(e.cause, isNotNull); + expect(await controller.getStyleError(), isNotNull); + } + }); + + testWidgets('testSetMapStyle null string', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + await GoogleMapsFlutterPlatform.instance.setMapStyle( + null, + mapId: controller.mapId, + ); + }); + + testWidgets('testGetLatLng', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + final LatLngBounds visibleRegion = await controller.getVisibleRegion(); + final LatLng topLeft = await controller.getLatLng( + const ScreenCoordinate(x: 0, y: 0), + ); + final northWest = LatLng( + visibleRegion.northeast.latitude, + visibleRegion.southwest.longitude, + ); + + expect(topLeft, northWest); + }); + + testWidgets( + 'testGetZoomLevel', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + double zoom = await controller.getZoomLevel(); + expect(zoom, _kInitialZoomLevel); + + await controller.moveCamera(CameraUpdate.zoomTo(7)); + await tester.pumpAndSettle(); + zoom = await controller.getZoomLevel(); + expect(zoom, equals(7)); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets( + 'testScreenCoordinate', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + final LatLngBounds visibleRegion = await controller.getVisibleRegion(); + final northWest = LatLng( + visibleRegion.northeast.latitude, + visibleRegion.southwest.longitude, + ); + final ScreenCoordinate topLeft = await controller.getScreenCoordinate( + northWest, + ); + expect(topLeft, const ScreenCoordinate(x: 0, y: 0)); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets('testResizeWidget', (WidgetTester tester) async { + final controllerCompleter = Completer(); + final map = ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) async { + controllerCompleter.complete(controller); + }, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MaterialApp( + home: Scaffold(body: SizedBox(height: 100, width: 100, child: map)), + ), + ), + ); + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MaterialApp( + home: Scaffold(body: SizedBox(height: 400, width: 400, child: map)), + ), + ), + ); + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + // Simple call to make sure that the app hasn't crashed. + final LatLngBounds bounds1 = await controller.getVisibleRegion(); + final LatLngBounds bounds2 = await controller.getVisibleRegion(); + expect(bounds1, bounds2); + }); + + testWidgets('testToggleInfoWindow', (WidgetTester tester) async { + const marker = Marker( + markerId: MarkerId('marker'), + infoWindow: InfoWindow(title: 'InfoWindow'), + ); + final markers = {marker}; + + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + onMapCreated: (ExampleGoogleMapController googleMapController) { + controllerCompleter.complete(googleMapController); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + bool iwVisibleStatus = await controller.isMarkerInfoWindowShown( + marker.markerId, + ); + expect(iwVisibleStatus, false); + + await controller.showMarkerInfoWindow(marker.markerId); + iwVisibleStatus = await controller.isMarkerInfoWindowShown(marker.markerId); + expect(iwVisibleStatus, true); + + await controller.hideMarkerInfoWindow(marker.markerId); + iwVisibleStatus = await controller.isMarkerInfoWindowShown(marker.markerId); + expect(iwVisibleStatus, false); + }); + + testWidgets('updating a marker does not hide its info window', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + const marker = Marker( + markerId: MarkerId('marker'), + infoWindow: InfoWindow(title: 'InfoWindow'), + ); + var markers = {marker}; + + const clusterManager = ClusterManager( + clusterManagerId: ClusterManagerId('cluster_manager'), + ); + final clusterManagers = {clusterManager}; + + final 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 controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final Uint8List? bytes = await controller.takeSnapshot(); + expect(bytes?.isNotEmpty, true); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets('set tileOverlay correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final tileOverlay1 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + transparency: 0.2, + ); + + final tileOverlay2 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_2'), + tileProvider: _DebugTileProvider(), + zIndex: 1, + visible: false, + transparency: 0.3, + fadeIn: false, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1, tileOverlay2}, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + final TileOverlay tileOverlayInfo1 = (await inspector.getTileOverlayInfo( + tileOverlay1.mapsId, + mapId: mapId, + ))!; + final TileOverlay tileOverlayInfo2 = (await inspector.getTileOverlayInfo( + tileOverlay2.mapsId, + mapId: mapId, + ))!; + + expect(tileOverlayInfo1.visible, isTrue); + expect(tileOverlayInfo1.fadeIn, isTrue); + expect( + tileOverlayInfo1.transparency, + moreOrLessEquals(0.2, epsilon: 0.001), + ); + expect(tileOverlayInfo1.zIndex, 2); + + expect(tileOverlayInfo2.visible, isFalse); + expect(tileOverlayInfo2.fadeIn, isFalse); + expect( + tileOverlayInfo2.transparency, + moreOrLessEquals(0.3, epsilon: 0.001), + ); + expect(tileOverlayInfo2.zIndex, 1); + }); + + testWidgets('update tileOverlays correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + final tileOverlay1 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + transparency: 0.2, + ); + + final tileOverlay2 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_2'), + tileProvider: _DebugTileProvider(), + zIndex: 3, + transparency: 0.5, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1, tileOverlay2}, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + final tileOverlay1New = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 1, + visible: false, + transparency: 0.3, + fadeIn: false, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1New}, + onMapCreated: (ExampleGoogleMapController controller) { + fail('update: OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final TileOverlay tileOverlayInfo1 = (await inspector.getTileOverlayInfo( + tileOverlay1.mapsId, + mapId: mapId, + ))!; + final TileOverlay? tileOverlayInfo2 = await inspector.getTileOverlayInfo( + tileOverlay2.mapsId, + mapId: mapId, + ); + + expect(tileOverlayInfo1.visible, isFalse); + expect(tileOverlayInfo1.fadeIn, isFalse); + expect( + tileOverlayInfo1.transparency, + moreOrLessEquals(0.3, epsilon: 0.001), + ); + expect(tileOverlayInfo1.zIndex, 1); + + expect(tileOverlayInfo2, isNull); + }); + + testWidgets('remove tileOverlays correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + final tileOverlay1 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + transparency: 0.2, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1}, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + final TileOverlay? tileOverlayInfo1 = await inspector.getTileOverlayInfo( + tileOverlay1.mapsId, + mapId: mapId, + ); + + expect(tileOverlayInfo1, isNull); + }); + + testWidgets('marker clustering', (WidgetTester tester) async { + final Key key = GlobalKey(); + const clusterManagersAmount = 2; + const markersPerClusterManager = 5; + final markers = {}; + final clusterManagers = {}; + + for (var i = 0; i < clusterManagersAmount; i++) { + final clusterManagerId = ClusterManagerId('cluster_manager_$i'); + final clusterManager = ClusterManager(clusterManagerId: clusterManagerId); + clusterManagers.add(clusterManager); + } + + for (final cm in clusterManagers) { + for (var i = 0; i < markersPerClusterManager; i++) { + final markerId = MarkerId('${cm.clusterManagerId.value}_marker_$i'); + final marker = Marker( + markerId: markerId, + clusterManagerId: cm.clusterManagerId, + position: LatLng( + _kInitialMapCenter.latitude + i, + _kInitialMapCenter.longitude, + ), + ); + markers[markerId] = marker; + } + } + + final controllerCompleter = Completer(); + + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + clusterManagers: clusterManagers, + markers: Set.of(markers.values), + onMapCreated: (ExampleGoogleMapController googleMapController) { + controllerCompleter.complete(googleMapController); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + for (final cm in clusterManagers) { + final List clusters = await inspector.getClusters( + mapId: controller.mapId, + clusterManagerId: cm.clusterManagerId, + ); + final int markersAmountForClusterManager = clusters + .map((Cluster cluster) => cluster.count) + .reduce((int value, int element) => value + element); + 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); + } + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + clusterManagers: clusterManagers, + markers: Set.of(markers.values), + ), + ), + ); + + for (final cm in clusterManagers) { + final List clusters = await inspector.getClusters( + mapId: controller.mapId, + clusterManagerId: cm.clusterManagerId, + ); + expect(clusters.length, 0); + } + }); + + testWidgets('testSetStyleMapId', (WidgetTester tester) async { + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + mapId: _kCloudMapId, + ), + ), + ); + }); + + testWidgets('getStyleError reports last error', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + style: '[[[this is an invalid style', + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final String? error = await controller.getStyleError(); + expect(error, isNotNull); + }); + + testWidgets('getStyleError returns null for a valid style', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + // An empty array is the simplest valid style. + style: '[]', + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final String? error = await controller.getStyleError(); + expect(error, isNull); + }); + + testWidgets('markerWithAssetMapBitmap', (WidgetTester tester) async { + final markers = { + Marker( + markerId: const MarkerId('1'), + icon: AssetMapBitmap('assets/red_square.png', imagePixelRatio: 1.0), + ), + }; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + ), + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithAssetMapBitmapCreate', (WidgetTester tester) async { + final imageConfiguration = ImageConfiguration( + devicePixelRatio: tester.view.devicePixelRatio, + ); + final markers = { + Marker( + markerId: const MarkerId('1'), + icon: await AssetMapBitmap.create( + imageConfiguration, + 'assets/red_square.png', + ), + ), + }; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + ), + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithBytesMapBitmap', (WidgetTester tester) async { + final Uint8List bytes = const Base64Decoder().convert(iconImageBase64); + final markers = { + Marker( + markerId: const MarkerId('1'), + icon: BytesMapBitmap( + bytes, + imagePixelRatio: tester.view.devicePixelRatio, + ), + ), + }; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + ), + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithLegacyAsset', (WidgetTester tester) async { + //tester.view.devicePixelRatio = 2.0; + const imageConfiguration = ImageConfiguration( + devicePixelRatio: 2.0, + size: Size(100, 100), + ); + final markers = { + Marker( + markerId: const MarkerId('1'), + // Intentionally testing the deprecated code path. + // ignore: deprecated_member_use + icon: await BitmapDescriptor.fromAssetImage( + imageConfiguration, + 'assets/red_square.png', + ), + ), + }; + final controllerCompleter = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + onMapCreated: (ExampleGoogleMapController controller) => + controllerCompleter.complete(controller), + ), + ), + ); + + await controllerCompleter.future; + }); + + testWidgets('markerWithLegacyBytes', (WidgetTester tester) async { + tester.view.devicePixelRatio = 2.0; + final Uint8List bytes = const Base64Decoder().convert(iconImageBase64); + // Intentionally testing the deprecated code path. + // ignore: deprecated_member_use + final BitmapDescriptor icon = BitmapDescriptor.fromBytes(bytes); + + final markers = {Marker(markerId: const MarkerId('1'), icon: icon)}; + final controllerCompleter = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + onMapCreated: (ExampleGoogleMapController controller) => + controllerCompleter.complete(controller), + ), + ), + ); + await controllerCompleter.future; + }); + + group('GroundOverlay', () { + final kGroundOverlayBounds = LatLngBounds( + southwest: const LatLng(37.77483, -122.41942), + northeast: const LatLng(37.78183, -122.39105), + ); + + final groundOverlayBounds1 = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('bounds_1'), + bounds: kGroundOverlayBounds, + image: AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ), + ); + + final groundOverlayPosition1 = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('position_1'), + position: kGroundOverlayBounds.northeast, + width: 100, + height: 100, + anchor: const Offset(0.1, 0.2), + zoomLevel: 14.0, + image: AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ), + ); + + void expectGroundOverlayEquals( + GroundOverlay source, + GroundOverlay response, + ) { + expect(response.groundOverlayId, source.groundOverlayId); + expect( + response.transparency, + moreOrLessEquals(source.transparency, epsilon: _floatTolerance), + ); + expect( + response.bearing, + moreOrLessEquals(source.bearing, epsilon: _floatTolerance), + ); + + // Only test bounds if it was given in the original object + if (source.bounds != null) { + expect(response.bounds, source.bounds); + } + + // Only test position if it was given in the original object + if (source.position != null) { + expect(response.position, source.position); + } + + expect(response.clickable, source.clickable); + expect(response.zIndex, source.zIndex); + expect(response.zoomLevel, source.zoomLevel); + expect( + response.anchor?.dx, + moreOrLessEquals(source.anchor!.dx, epsilon: _floatTolerance), + ); + expect( + response.anchor?.dy, + moreOrLessEquals(source.anchor!.dy, epsilon: _floatTolerance), + ); + } + + testWidgets('set ground overlays correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final groundOverlayBounds2 = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('bounds_2'), + bounds: groundOverlayBounds1.bounds!, + image: groundOverlayBounds1.image, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1, + groundOverlayBounds2, + groundOverlayPosition1, + }, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + if (inspector.supportsGettingGroundOverlayInfo()) { + final GroundOverlay groundOverlayBoundsInfo1 = (await inspector + .getGroundOverlayInfo(groundOverlayBounds1.mapsId, mapId: mapId))!; + final GroundOverlay groundOverlayBoundsInfo2 = (await inspector + .getGroundOverlayInfo(groundOverlayBounds2.mapsId, mapId: mapId))!; + final GroundOverlay groundOverlayPositionInfo1 = (await inspector + .getGroundOverlayInfo( + groundOverlayPosition1.mapsId, + mapId: mapId, + ))!; + + expectGroundOverlayEquals( + groundOverlayBounds1, + groundOverlayBoundsInfo1, + ); + expectGroundOverlayEquals( + groundOverlayBounds2, + groundOverlayBoundsInfo2, + ); + expectGroundOverlayEquals( + groundOverlayPosition1, + groundOverlayPositionInfo1, + ); + } + }); + + testWidgets('update ground overlays correctly', ( + WidgetTester tester, + ) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1, + groundOverlayPosition1, + }, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + final GroundOverlay groundOverlayBounds1New = groundOverlayBounds1 + .copyWith( + bearingParam: 10, + clickableParam: false, + transparencyParam: 0.5, + visibleParam: false, + zIndexParam: 10, + ); + + final GroundOverlay groundOverlayPosition1New = groundOverlayPosition1 + .copyWith( + bearingParam: 10, + clickableParam: false, + transparencyParam: 0.5, + visibleParam: false, + zIndexParam: 10, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1New, + groundOverlayPosition1New, + }, + onMapCreated: (ExampleGoogleMapController controller) { + fail('update: OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + if (inspector.supportsGettingGroundOverlayInfo()) { + final GroundOverlay groundOverlayBounds1Info = (await inspector + .getGroundOverlayInfo(groundOverlayBounds1.mapsId, mapId: mapId))!; + final GroundOverlay groundOverlayPosition1Info = (await inspector + .getGroundOverlayInfo( + groundOverlayPosition1.mapsId, + mapId: mapId, + ))!; + + expectGroundOverlayEquals( + groundOverlayBounds1New, + groundOverlayBounds1Info, + ); + expectGroundOverlayEquals( + groundOverlayPosition1New, + groundOverlayPosition1Info, + ); + } + }); + + testWidgets('remove ground overlays correctly', ( + WidgetTester tester, + ) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1, + groundOverlayPosition1, + }, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + if (inspector.supportsGettingGroundOverlayInfo()) { + final GroundOverlay? groundOverlayBounds1Info = await inspector + .getGroundOverlayInfo(groundOverlayBounds1.mapsId, mapId: mapId); + final GroundOverlay? groundOverlayPositionInfo = await inspector + .getGroundOverlayInfo(groundOverlayPosition1.mapsId, mapId: mapId); + + expect(groundOverlayBounds1Info, isNull); + expect(groundOverlayPositionInfo, isNull); + } + }); + }); + + testWidgets( + 'testAnimateCameraWithoutDuration', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + /// Completer to track when the camera has come to rest. + Completer? cameraIdleCompleter; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onCameraIdle: () { + if (cameraIdleCompleter != null && + !cameraIdleCompleter.isCompleted) { + cameraIdleCompleter.complete(); + } + }, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and + // `mapControllerCompleter.complete(controller)` above should happen in + // `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + // Create completer for camera idle event. + cameraIdleCompleter = Completer(); + + final CameraUpdate cameraUpdate = _getCameraUpdateForType( + _cameraUpdateTypeVariants.currentValue!, + ); + await controller.animateCamera(cameraUpdate); + + // Immediately after calling animateCamera, check that the camera hasn't + // reached its final position. This relies on the assumption that the + // camera move is animated and won't complete instantly. + final CameraPosition beforeFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + beforeFinishedPosition, + null, + controller, + (Matcher matcher) => isNot(matcher), + ); + + // Wait for the animation to complete (onCameraIdle). + expect(cameraIdleCompleter.isCompleted, isFalse); + await cameraIdleCompleter.future; + + // After onCameraIdle event, the camera should be at the final position. + final CameraPosition afterFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + afterFinishedPosition, + beforeFinishedPosition, + controller, + (Matcher matcher) => matcher, + ); + + await tester.pumpAndSettle(); + }, + variant: _cameraUpdateTypeVariants, + // Hanging in CI, https://github.com/flutter/flutter/issues/166139 + skip: true, + ); + + /// Tests animating the camera with specified durations to verify timing + /// behavior. + /// + /// This test checks two scenarios: short and long animation durations. + /// It uses a midpoint duration to ensure the short animation completes in + /// less time and the long animation takes more time than that midpoint. + /// This ensures that the animation duration is respected by the platform and + /// that the default camera animation duration does not affect the test + /// results. + testWidgets( + 'testAnimateCameraWithDuration', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + /// Completer to track when the camera has come to rest. + Completer? cameraIdleCompleter; + + const shortCameraAnimationDurationMS = 200; + const longCameraAnimationDurationMS = 1000; + + /// Calculate the midpoint duration of the animation test, which will + /// serve as a reference to verify that animations complete more quickly + /// with shorter durations and more slowly with longer durations. + const int animationDurationMiddlePoint = + (shortCameraAnimationDurationMS + longCameraAnimationDurationMS) ~/ 2; + + // Stopwatch to measure the time taken for the animation to complete. + final stopwatch = Stopwatch(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onCameraIdle: () { + if (cameraIdleCompleter != null && + !cameraIdleCompleter.isCompleted) { + stopwatch.stop(); + cameraIdleCompleter.complete(); + } + }, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and + // `mapControllerCompleter.complete(controller)` above should happen in + // `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + // Create completer for camera idle event. + cameraIdleCompleter = Completer(); + + // Start stopwatch to check the time taken for the animation to complete. + // Stopwatch is stopped on camera idle callback. + stopwatch.reset(); + stopwatch.start(); + + // First phase with shorter animation duration. + final CameraUpdate cameraUpdateShort = _getCameraUpdateForType( + _cameraUpdateTypeVariants.currentValue!, + ); + await controller.animateCamera( + cameraUpdateShort, + duration: const Duration(milliseconds: shortCameraAnimationDurationMS), + ); + + // Wait for the animation to complete (onCameraIdle). + expect(cameraIdleCompleter.isCompleted, isFalse); + await cameraIdleCompleter.future; + + // For short animation duration, check that the animation is completed + // faster than the midpoint benchmark. + expect( + stopwatch.elapsedMilliseconds, + lessThan(animationDurationMiddlePoint), + ); + + // Reset camera to initial position before testing long duration. + await controller.moveCamera( + CameraUpdate.newCameraPosition(_kInitialCameraPosition), + ); + await tester.pumpAndSettle(); + + // Create completer for camera idle event. + cameraIdleCompleter = Completer(); + + // Start stopwatch to check the time taken for the animation to complete. + // Stopwatch is stopped on camera idle callback. + stopwatch.reset(); + stopwatch.start(); + + // Second phase with longer animation duration. + final CameraUpdate cameraUpdateLong = _getCameraUpdateForType( + _cameraUpdateTypeVariants.currentValue!, + ); + await controller.animateCamera( + cameraUpdateLong, + duration: const Duration(milliseconds: longCameraAnimationDurationMS), + ); + + // Immediately after calling animateCamera, check that the camera hasn't + // reached its final position. This relies on the assumption that the + // camera move is animated and won't complete instantly. + final CameraPosition beforeFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + beforeFinishedPosition, + null, + controller, + (Matcher matcher) => isNot(matcher), + ); + + // Wait for the animation to complete (onCameraIdle). + expect(cameraIdleCompleter.isCompleted, isFalse); + await cameraIdleCompleter.future; + + // For longer animation duration, check that the animation is completed + // slower than the midpoint benchmark. + expect( + stopwatch.elapsedMilliseconds, + greaterThan(animationDurationMiddlePoint), + ); + + // Camera should be at the final position. + final CameraPosition afterFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + afterFinishedPosition, + beforeFinishedPosition, + controller, + (Matcher matcher) => matcher, + ); + + await tester.pumpAndSettle(); + }, + variant: _cameraUpdateTypeVariants, + // Hanging in CI, https://github.com/flutter/flutter/issues/166139 + skip: true, + ); +} + +class _DebugTileProvider implements TileProvider { + _DebugTileProvider() { + boxPaint.isAntiAlias = true; + boxPaint.color = Colors.blue; + boxPaint.strokeWidth = 2.0; + boxPaint.style = PaintingStyle.stroke; + } + + static const int width = 100; + static const int height = 100; + static final Paint boxPaint = Paint(); + static const TextStyle textStyle = TextStyle(color: Colors.red, fontSize: 20); + + @override + Future getTile(int x, int y, int? zoom) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final textSpan = TextSpan(text: '$x,$y', style: textStyle); + final textPainter = TextPainter( + text: textSpan, + textDirection: TextDirection.ltr, + ); + textPainter.layout(maxWidth: width.toDouble()); + textPainter.paint(canvas, Offset.zero); + canvas.drawRect( + Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), + boxPaint, + ); + final ui.Picture picture = recorder.endRecording(); + final Uint8List byteData = await picture + .toImage(width, height) + .then( + (ui.Image image) => image.toByteData(format: ui.ImageByteFormat.png), + ) + .then((ByteData? byteData) => byteData!.buffer.asUint8List()); + return Tile(width, height, byteData); + } +} + +Marker _copyMarkerWithClusterManagerId( + Marker marker, + ClusterManagerId? clusterManagerId, +) { + return Marker( + markerId: marker.markerId, + alpha: marker.alpha, + anchor: marker.anchor, + consumeTapEvents: marker.consumeTapEvents, + draggable: marker.draggable, + flat: marker.flat, + icon: marker.icon, + infoWindow: marker.infoWindow, + position: marker.position, + rotation: marker.rotation, + visible: marker.visible, + zIndexInt: marker.zIndexInt, + onTap: marker.onTap, + onDragStart: marker.onDragStart, + onDrag: marker.onDrag, + onDragEnd: marker.onDragEnd, + clusterManagerId: clusterManagerId, + ); +} + +CameraUpdate _getCameraUpdateForType(CameraUpdateType type) { + return switch (type) { + CameraUpdateType.newCameraPosition => CameraUpdate.newCameraPosition( + _kTestCameraPosition, + ), + CameraUpdateType.newLatLng => CameraUpdate.newLatLng(_kTestMapCenter), + CameraUpdateType.newLatLngBounds => CameraUpdate.newLatLngBounds( + _testCameraBounds, + 0, + ), + CameraUpdateType.newLatLngZoom => CameraUpdate.newLatLngZoom( + _kTestMapCenter, + _kTestCameraZoomLevel, + ), + CameraUpdateType.scrollBy => CameraUpdate.scrollBy(10, 10), + CameraUpdateType.zoomBy => CameraUpdate.zoomBy( + _kTestZoomByAmount, + const Offset(1, 1), + ), + CameraUpdateType.zoomTo => CameraUpdate.zoomTo(_kTestCameraZoomLevel), + CameraUpdateType.zoomIn => CameraUpdate.zoomIn(), + CameraUpdateType.zoomOut => CameraUpdate.zoomOut(), + }; +} + +Future _checkCameraUpdateByType( + CameraUpdateType type, + CameraPosition currentPosition, + CameraPosition? oldPosition, + ExampleGoogleMapController controller, + Matcher Function(Matcher matcher) wrapMatcher, +) async { + // As the target might differ a bit from the expected target, a threshold is + // used. + const latLngThreshold = 0.05; + + switch (type) { + case CameraUpdateType.newCameraPosition: + expect( + currentPosition.bearing, + wrapMatcher(equals(_kTestCameraPosition.bearing)), + ); + expect( + currentPosition.zoom, + wrapMatcher(equals(_kTestCameraPosition.zoom)), + ); + expect( + currentPosition.tilt, + wrapMatcher(equals(_kTestCameraPosition.tilt)), + ); + expect( + currentPosition.target.latitude, + wrapMatcher( + closeTo(_kTestCameraPosition.target.latitude, latLngThreshold), + ), + ); + expect( + currentPosition.target.longitude, + wrapMatcher( + closeTo(_kTestCameraPosition.target.longitude, latLngThreshold), + ), + ); + case CameraUpdateType.newLatLng: + expect( + currentPosition.target.latitude, + wrapMatcher(closeTo(_kTestMapCenter.latitude, latLngThreshold)), + ); + expect( + currentPosition.target.longitude, + wrapMatcher(closeTo(_kTestMapCenter.longitude, latLngThreshold)), + ); + case CameraUpdateType.newLatLngBounds: + final LatLngBounds bounds = await controller.getVisibleRegion(); + expect( + bounds.northeast.longitude, + wrapMatcher( + closeTo(_testCameraBounds.northeast.longitude, latLngThreshold), + ), + ); + expect( + bounds.southwest.longitude, + wrapMatcher( + closeTo(_testCameraBounds.southwest.longitude, latLngThreshold), + ), + ); + case CameraUpdateType.newLatLngZoom: + expect( + currentPosition.target.latitude, + wrapMatcher(closeTo(_kTestMapCenter.latitude, latLngThreshold)), + ); + expect( + currentPosition.target.longitude, + wrapMatcher(closeTo(_kTestMapCenter.longitude, latLngThreshold)), + ); + expect(currentPosition.zoom, wrapMatcher(equals(_kTestCameraZoomLevel))); + case CameraUpdateType.scrollBy: + // For scrollBy, just check that the location has changed. + if (oldPosition != null) { + expect( + currentPosition.target.latitude, + isNot(equals(oldPosition.target.latitude)), + ); + expect( + currentPosition.target.longitude, + isNot(equals(oldPosition.target.longitude)), + ); + } + case CameraUpdateType.zoomBy: + expect( + currentPosition.zoom, + wrapMatcher(equals(_kInitialZoomLevel + _kTestZoomByAmount)), + ); + case CameraUpdateType.zoomTo: + expect(currentPosition.zoom, wrapMatcher(equals(_kTestCameraZoomLevel))); + case CameraUpdateType.zoomIn: + expect(currentPosition.zoom, wrapMatcher(equals(_kInitialZoomLevel + 1))); + case CameraUpdateType.zoomOut: + expect(currentPosition.zoom, wrapMatcher(equals(_kInitialZoomLevel - 1))); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/resources/icon_image.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/resources/icon_image.png new file mode 100644 index 0000000000000000000000000000000000000000..920b93f74d7875578cfddd9fb3a86ffc91cc66aa GIT binary patch literal 1257 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|T2doC(|mmy zw18|523AHP24;{FAY@>aVqgWc85q16rQz%#Mh&PMCI*J~Oa>OHnkXO*0v4nJa0`PlBg3pY5xV%QuQiw3qZOUY$~jP%-qzHM1_jnoV;SI3R@+x3M(KRB&@Hb09I0xZL1XF8=&Bv zUzDm~s%N5Spk&9TprBw=l#*r@P?Wt5Z@Sn2DRmzV368|&p4rRy77T3YHG z80i}s=>k>g7FXt#Bv$C=6)QswftllyTAW;zSx}OhpQivaH!&%{w8U0P31kr*K-^i9 znTD__uNdkrpa=CqGWv#k2KsQbfm&@qqE`MznW;dVLFU^T+JIG}h(YbK(Fa+MGhS)(5hysGVj@1S=_(gPCCO{ zqhwks#Vc``|8 z#o#O*d;N2|BC{jvU{z}(n^^Vap!a1%`y(*n{sOkJ|#X3oe;O!Zo?Dnhr)@GQ`z`?mdD=yHSxr< zDy_rs-x{jCabub6U?S+*S@!Va>4+T*Hmzz(*!gva0^=QR?pv-qbGCN6d|Si4{*vsJ zlH0zk1sd5rv=;3+XYfL0!@WaC`Ahb=eYxm+=guaBQ~enqLO(hNXMfPrI^{pDhK z-4_e9Y*sb;Jj~0Qs$sV`^@y=`QNlJK=FPXKOL(O1`}w`Gn*UDUbd&Ixz5e<2va`xH z41-N}zw;G7BCl8SdS-H5ozdgaGryVtGld%!O3p1V7HRwR?9co=RqwyAbPax;#ec&s zvsY)SyxMWE30Fc-y!yt-7}jeScd5ucNzCQ_c1QOYYo)m6PP)2@Gs?hW+Rx4&FMFT6 zT8Ccju)dun6cb3O7sF#-G(!!nzha!-kf?C|8-&R&#t@} QJ5YZ2boFyt=akR{0O*p@82|tP literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/resources/icon_image_base64.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/resources/icon_image_base64.dart new file mode 100644 index 000000000000..6b576e010572 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/integration_test/resources/icon_image_base64.dart @@ -0,0 +1,49 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// This constant holds the base64-encoded data of a 16x16 PNG image of the +/// Flutter logo. +/// +/// See `icon_image.png` source in the same directory. +/// +/// To create or update this image, follow these steps: +/// 1. Create or update a 16x16 PNG image. +/// 2. Convert the image to a base64 string using a script below. +/// 3. Replace the existing base64 string below with the new one. +/// +/// Example of converting an image to base64 in Dart: +/// ```dart +/// import 'dart:convert'; +/// import 'dart:io'; +/// +/// void main() async { +/// final bytes = await File('icon_image.png').readAsBytes(); +/// final base64String = base64Encode(bytes); +/// print(base64String); +/// } +/// ``` +const String iconImageBase64 = + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAIRlWElmTU' + '0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIA' + 'AIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQ' + 'AAABCgAwAEAAAAAQAAABAAAAAAx28c8QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1M' + 'OmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIH' + 'g6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8v' + 'd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcm' + 'lwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFk' + 'b2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk' + '9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6' + 'eG1wbWV0YT4KTMInWQAAAplJREFUOBF1k01ME1EQx2fe7tIPoGgTE6AJgQQSPaiH9oAtkFbsgX' + 'jygFcT0XjSkxcTDxtPJh6MR28ePMHBBA8cNLSIony0oBhEMVETP058tE132+7uG3cW24DAXN57' + '2fn9/zPz3iIcEdEl0nIxtNLr1IlVeoMadkubKmoL+u2SzAV8IjV5Ekt4GN+A8+VOUPwLarOI2G' + 'Vpqq0i4JQorwQxPtWHVZ1IKP8LNGDXGaSyqARFxDGo7MJBy4XVf3AyQ+qTHnTEXoF9cFUy3OkY' + '0oWxmWFtD5xNoc1sQ6AOn1+hCNTkkhKow8KFZV77tVs2O9dhFvBm0IA/U0RhZ7/ocEx23oUDlh' + 'h8HkNjZIN8Lb3gOU8gOp7AKJHCB2/aNZkTftHumNzzbtl2CBPZHqxw8mHhVZBeoz6w5DvhE2FZ' + 'lQYPjKdd2/qRyKZ6KsPv7TEk7EYEk0A0EUmJduHRy1i4oLKqgmC59ZggAdwrC9pFuWy1iUT2rA' + 'uv0h2UdNtNqxCBBkgqorjOMOgksN7CxQ90vEb00U3c3LIwyo9o8FXxQVNr8Coqyk+S5EPBXnjt' + 'xRmc4TegI7qWbvBkeeUbGMnTCd4nZnYeDOWIEtlC6cKK/JJepY3hZSvN33jovO6L0XFqPKqBTO' + 'FuapUoPr1lxDM7cmC2TAOz25cYSGa++feBew/cjpc0V+mNT29/HZp3KDFTNLvuTRPEHy5065lj' + 'Xn4y41XM+wP/AlcycRmdc3MUhvLm/J/ceu/3qUVT62oP2EZpjSylHybHSpDUVcjq9gEBVo0+Xt' + 'JyN2IWRO+3QUforRoKnZLVsglaMECW+YmMSj9M3SrC6Lg71CMiqWfUrJ6ywzefhnZ+G69BaKdB' + 'WhXQAn6wzDUpfUPw7MrmX/WhbfmKblw+AAAAAElFTkSuQmCC'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/AppFrameworkInfo.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 000000000000..6fe4034356ac --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + UIRequiredDeviceCapabilities + + arm64 + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/Debug.xcconfig b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000000..e8efba114687 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/Release.xcconfig b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000000..399e9340e6f6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Podfile b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Podfile new file mode 100644 index 000000000000..37d20e51d606 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Podfile @@ -0,0 +1,45 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '15.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + + pod 'OCMock', '~> 3.9.1' + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000000..27d1133df09f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,858 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 0DD7B6C32B744EEF00E857FD /* FLTTileProviderControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD7B6C22B744EEF00E857FD /* FLTTileProviderControllerTests.m */; }; + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 2A6906C72D263DF4001F8426 /* GoogleMapsGroundOverlayControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */; }; + 2BDE99378062AE3E60B40021 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */; }; + 330909FF2D99B7A60077A751 /* GoogleMapsMarkerControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */; }; + 339355BA2EB3E50300EBF864 /* GoogleMapsCircleControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */; }; + 339355BD2EB3E56300EBF864 /* GoogleMapsTileOverlayControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */; }; + 339355BF2EB535A600EBF864 /* FLTGoogleMapHeatmapControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */; }; + 339DF1F02F1FE49800748863 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339DF1EF2F1FE49300748863 /* AppDelegate.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 478116522BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */; }; + 528F16832C62941000148160 /* FGMClusterManagersControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 528F16822C62941000148160 /* FGMClusterManagersControllerTests.m */; }; + 528F16872C62952700148160 /* ExtractIconFromDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 528F16862C62952700148160 /* ExtractIconFromDataTests.m */; }; + 6851F3562835BC180032B7C8 /* FGMConversionsUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6851F3552835BC180032B7C8 /* FGMConversionsUtilsTests.m */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 982F2A6C27BADE17003C81F4 /* PartiallyMockedMapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */; }; + B3A7FA04ABB7B84780729949 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61A9A8623F5CA9BBC813DC6B /* Pods_Runner.framework */; }; + F269303B2BB389BF00BF17C4 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = F269303A2BB389BF00BF17C4 /* assets */; }; + F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */; }; + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + F7151F15265D7ED70028CB91 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; + F7151F23265D7EE50028CB91 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0DD7B6C22B744EEF00E857FD /* FLTTileProviderControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTTileProviderControllerTests.m; sourceTree = ""; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsGroundOverlayControllerTests.m; sourceTree = ""; }; + 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsMarkerControllerTests.m; sourceTree = ""; }; + 339355B82EB3E4D500EBF864 /* GoogleMapsPolygonControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsPolygonControllerTests.m; sourceTree = ""; }; + 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsCircleControllerTests.m; sourceTree = ""; }; + 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsTileOverlayControllerTests.m; sourceTree = ""; }; + 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTGoogleMapHeatmapControllerTests.m; sourceTree = ""; }; + 339DF1EF2F1FE49300748863 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 339DF1F12F1FE4AD00748863 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsPolylineControllerTests.m; sourceTree = ""; }; + 528F16822C62941000148160 /* FGMClusterManagersControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FGMClusterManagersControllerTests.m; sourceTree = ""; }; + 528F16862C62952700148160 /* ExtractIconFromDataTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExtractIconFromDataTests.m; sourceTree = ""; }; + 61A9A8623F5CA9BBC813DC6B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6851F3552835BC180032B7C8 /* FGMConversionsUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FGMConversionsUtilsTests.m; sourceTree = ""; }; + 733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 982F2A6A27BADE17003C81F4 /* PartiallyMockedMapView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PartiallyMockedMapView.h; sourceTree = ""; }; + 982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PartiallyMockedMapView.m; sourceTree = ""; }; + B7AFC65E3DD5AC60D834D83D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + E52C6A6210A56F027C582EF9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + EA0E91726245EDC22B97E8B9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + F269303A2BB389BF00BF17C4 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = ""; }; + F7151F10265D7ED70028CB91 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsTests.m; sourceTree = ""; }; + F7151F14265D7ED70028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F7151F1E265D7EE50028CB91 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsUITests.m; sourceTree = ""; }; + F7151F22265D7EE50028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + B3A7FA04ABB7B84780729949 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F0D265D7ED70028CB91 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2BDE99378062AE3E60B40021 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F1B265D7EE50028CB91 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1E7CF0857EFC88FC263CF3B2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 61A9A8623F5CA9BBC813DC6B /* Pods_Runner.framework */, + 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + F7151F11265D7ED70028CB91 /* RunnerTests */, + F7151F1F265D7EE50028CB91 /* RunnerUITests */, + 97C146EF1CF9000F007C117D /* Products */, + A189CFE5474BF8A07908B2E0 /* Pods */, + 1E7CF0857EFC88FC263CF3B2 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + F7151F10265D7ED70028CB91 /* RunnerTests.xctest */, + F7151F1E265D7EE50028CB91 /* RunnerUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 339DF1EF2F1FE49300748863 /* AppDelegate.swift */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 339DF1F12F1FE4AD00748863 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + A189CFE5474BF8A07908B2E0 /* Pods */ = { + isa = PBXGroup; + children = ( + B7AFC65E3DD5AC60D834D83D /* Pods-Runner.debug.xcconfig */, + EA0E91726245EDC22B97E8B9 /* Pods-Runner.release.xcconfig */, + E52C6A6210A56F027C582EF9 /* Pods-RunnerTests.debug.xcconfig */, + 733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + F7151F11265D7ED70028CB91 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + F269303A2BB389BF00BF17C4 /* assets */, + 528F16862C62952700148160 /* ExtractIconFromDataTests.m */, + 528F16822C62941000148160 /* FGMClusterManagersControllerTests.m */, + 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */, + 6851F3552835BC180032B7C8 /* FGMConversionsUtilsTests.m */, + 0DD7B6C22B744EEF00E857FD /* FLTTileProviderControllerTests.m */, + F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */, + 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */, + 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */, + 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */, + 339355B82EB3E4D500EBF864 /* GoogleMapsPolygonControllerTests.m */, + 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */, + 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */, + 982F2A6A27BADE17003C81F4 /* PartiallyMockedMapView.h */, + 982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */, + F7151F14265D7ED70028CB91 /* Info.plist */, + ); + path = RunnerTests; + sourceTree = ""; + }; + F7151F1F265D7EE50028CB91 /* RunnerUITests */ = { + isa = PBXGroup; + children = ( + F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */, + F7151F22265D7EE50028CB91 /* Info.plist */, + ); + path = RunnerUITests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 74BF216DF17B0C7F983459BD /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + BB6BD9A1101E970BEF85B6D2 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; + F7151F0F265D7ED70028CB91 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = F7151F19265D7ED70028CB91 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + D067548A17DC238B80D2BD12 /* [CP] Check Pods Manifest.lock */, + F7151F0C265D7ED70028CB91 /* Sources */, + F7151F0D265D7ED70028CB91 /* Frameworks */, + F7151F0E265D7ED70028CB91 /* Resources */, + DF182F6A1B9E41DA05BFCB87 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + F7151F16265D7ED70028CB91 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = F7151F10265D7ED70028CB91 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + F7151F1D265D7EE50028CB91 /* RunnerUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = F7151F25265D7EE50028CB91 /* Build configuration list for PBXNativeTarget "RunnerUITests" */; + buildPhases = ( + F7151F1A265D7EE50028CB91 /* Sources */, + F7151F1B265D7EE50028CB91 /* Frameworks */, + F7151F1C265D7EE50028CB91 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + F7151F24265D7EE50028CB91 /* PBXTargetDependency */, + ); + name = RunnerUITests; + productName = RunnerUITests; + productReference = F7151F1E265D7EE50028CB91 /* RunnerUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = "The Flutter Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 2620; + }; + F7151F0F265D7ED70028CB91 = { + CreatedOnToolsVersion = 12.5; + ProvisioningStyle = Automatic; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + F7151F1D265D7EE50028CB91 = { + CreatedOnToolsVersion = 12.5; + ProvisioningStyle = Automatic; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + F7151F0F265D7ED70028CB91 /* RunnerTests */, + F7151F1D265D7EE50028CB91 /* RunnerUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F0E265D7ED70028CB91 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F269303B2BB389BF00BF17C4 /* assets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F1C265D7EE50028CB91 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 74BF216DF17B0C7F983459BD /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + BB6BD9A1101E970BEF85B6D2 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/GoogleMaps/GoogleMapsResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/google_maps_flutter_ios_sdk9/google_maps_flutter_ios_sdk9_privacy.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMapsResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/google_maps_flutter_ios_sdk9_privacy.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + D067548A17DC238B80D2BD12 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + DF182F6A1B9E41DA05BFCB87 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 339DF1F02F1FE49800748863 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F0C265D7ED70028CB91 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 528F16832C62941000148160 /* FGMClusterManagersControllerTests.m in Sources */, + 339355BA2EB3E50300EBF864 /* GoogleMapsCircleControllerTests.m in Sources */, + 339355BF2EB535A600EBF864 /* FLTGoogleMapHeatmapControllerTests.m in Sources */, + 339355BD2EB3E56300EBF864 /* GoogleMapsTileOverlayControllerTests.m in Sources */, + F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */, + 6851F3562835BC180032B7C8 /* FGMConversionsUtilsTests.m in Sources */, + 982F2A6C27BADE17003C81F4 /* PartiallyMockedMapView.m in Sources */, + 330909FF2D99B7A60077A751 /* GoogleMapsMarkerControllerTests.m in Sources */, + 478116522BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m in Sources */, + 2A6906C72D263DF4001F8426 /* GoogleMapsGroundOverlayControllerTests.m in Sources */, + 0DD7B6C32B744EEF00E857FD /* FLTTileProviderControllerTests.m in Sources */, + 528F16872C62952700148160 /* ExtractIconFromDataTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F1A265D7EE50028CB91 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + F7151F16265D7ED70028CB91 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = F7151F15265D7ED70028CB91 /* PBXContainerItemProxy */; + }; + F7151F24265D7EE50028CB91 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = F7151F23265D7EE50028CB91 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.googleMobileMapsExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.googleMobileMapsExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 6.0; + }; + name = Release; + }; + F7151F17265D7ED70028CB91 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E52C6A6210A56F027C582EF9 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + INFOPLIST_FILE = RunnerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + }; + name = Debug; + }; + F7151F18265D7ED70028CB91 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + INFOPLIST_FILE = RunnerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + }; + name = Release; + }; + F7151F26265D7EE50028CB91 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = RunnerUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = Runner; + }; + name = Debug; + }; + F7151F27265D7EE50028CB91 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = RunnerUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = Runner; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F7151F19265D7ED70028CB91 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F7151F17265D7ED70028CB91 /* Debug */, + F7151F18265D7ED70028CB91 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F7151F25265D7EE50028CB91 /* Build configuration list for PBXNativeTarget "RunnerUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F7151F26265D7EE50028CB91 /* Debug */, + F7151F27265D7EE50028CB91 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..919434a6254f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000000..3ea203b77e3b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/AppDelegate.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000000..a382ba8b736e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,21 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter +import GoogleMaps +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + var mapsApiKey = ProcessInfo.processInfo.environment["MAPS_API_KEY"] ?? "YOUR KEY HERE" + GMSServices.provideAPIKey(mapsApiKey) + + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000000..d36b1fab2d9d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..3d43d11e66f4de3da27ed045ca4fe38ad8b48094 GIT binary patch literal 11112 zcmeHN3sh5A)((b(k1DoWZSj%R+R=^`Y(b;ElB$1^R>iT7q6h&WAVr806i~>Gqn6rM z>3}bMG&oq%DIriqR35=rtEdos5L6z)YC*Xq0U-$_+Il@RaU zXYX%+``hR28`(B*uJ6G9&iz>|)PS%!)9N`7=LcmcxH}k69HPyT-%S zH7+jBCC<%76cg_H-n41cTqnKn`u_V9p~XaTLUe3s{KRPSTeK6apP4Jg%VQ$e#72ms zxyWzmGSRwN?=fRgpx!?W&ZsrLfuhAsRxm%;_|P@3@3~BJwY4ZVBJ3f&$5x>`^fD?d zI+z!v#$!gz%FtL*%mR^Uwa*8LJFZ_;X!y$cD??W#c)31l@ervOa_Qk86R{HJiZb$f z&&&0xYmB{@D@yl~^l5IXtB_ou{xFiYP(Jr<9Ce{jCN z<3Rf2TD%}_N?y>bgWq|{`RKd}n>P4e8Z-D+(fn^4)+|pv$DcR&i+RHNhv$71F*McT zl`phYBlb;wO`b7)*10XF6UXhY9`@UR*6-#(Zp`vyU(__*te6xYtV&N0(zjMtev{tZ zapmGin===teMXjsS0>CYxUy<2izOKOPai0}!B9+6q$s3CF8W{xUwz?A0ADO5&BsiB z{SFt|KehNd-S#eiDq!y&+mW9N_!wH-i~q|oNm=mEzkx}B?Ehe%q$tK8f=QY#*6rH9 zNHHaG(9WBqzP!!TMEktSVuh$i$4A^b25LK}&1*4W?ul*5pZYjL1OZ@X9?3W7Y|T6} z1SXx0Wn-|!A;fZGGlYn9a1Jz5^8)~v#mXhmm>um{QiGG459N}L<&qyD+sy_ixD@AP zW0XV6w#3(JW>TEV}MD=O0O>k5H>p#&|O zD2mGf0Cz7+>l7`NuzGobt;(o@vb9YiOpHN8QJ9Uva|i7R?7nnq;L_iq+ZqPv*oGu! zN@GuJ9fm;yrEFga63m?1qy|5&fd32<%$yP$llh}Udrp>~fb>M>R55I@BsGYhCj8m1 zC=ziFh4@hoytpfrJlr}FsV|C(aV4PZ^8^`G29(+!Bk8APa#PemJqkF zE{IzwPaE)I&r`OxGk*vPErm6sGKaQJ&6FODW$;gAl_4b_j!oH4yE@ zP~Cl4?kp>Ccc~Nm+0kjIb`U0N7}zrQEN5!Ju|}t}LeXi!baZOyhlWha5lq{Ld2rdo zGz7hAJQt<6^cxXTe0xZjmADL85cC&H+~Lt2siIIh{$~+U#&#^{Ub22IA|ea6 z5j12XLc`~dh$$1>3o0Cgvo*ybi$c*z>n=5L&X|>Wy1~eagk;lcEnf^2^2xB=e58Z` z@Rw{1ssK)NRV+2O6c<8qFl%efHE;uy!mq(Xi1P*H2}LMi z3EqWN2U?eW{J$lSFxDJg-=&RH!=6P9!y|S~gmjg)gPKGMxq6r9cNIhW` zS})-obO}Ao_`;=>@fAwU&=|5$J;?~!s4LN2&XiMXEl>zk9M}tVEg#kkIkbKp%Ig2QJ2aCILCM1E=aN*iuz>;q#T_I7aVM=E4$m_#OWLnXQnFUnu?~(X>$@NP zBJ@Zw>@bmErSuW7SR2=6535wh-R`WZ+5dLqwTvw}Ks8~4F#hh0$Qn^l-z=;>D~St( z-1yEjCCgd*z5qXa*bJ7H2Tk54KiX&=Vd}z?%dcc z`N8oeYUKe17&|B5A-++RHh8WQ%;gN{vf%05@jZF%wn1Z_yk#M~Cn(i@MB_mpcbLj5 zR#QAtC`k=tZ*h|){Mjz`7bNL zGWOW=bjQhX@`Vw^xn#cVwn28c2D9vOb0TLLy~-?-%gOyHSeJ9a>P}5OF5$n}k-pvUa*pvLw)KvG~>QjNWS3LY1f*OkFwPZ5qC@+3^Bt=HZbf`alKY#{pn zdY}NEIgo1sd)^TPxVzO{uvU$|Z-jkK0p1x##LexgQ$zx1^bNPOG*u2RmZkIM!zFVz zz|IsP3I?qrlmjGS2w_(azCvGTnf~flqogV@Q%mH{76uLU(>UB zQZ?*ys3BO&TV{Pj_qEa-hkH7mOMe_Bnu3%CXCgu90XNKf$N)PUc3Ei-&~@tT zI^49Lm^+=TrI=h4h=W@jW{GjWd{_kVuSzAL6Pi@HKYYnnNbtcYdIRww+jY$(30=#p8*if(mzbvau z00#}4Qf+gH&ce_&8y3Z@CZV>b%&Zr7xuPSSqOmoaP@arwPrMx^jQBQQi>YvBUdpBn zI``MZ3I3HLqp)@vk^E|~)zw$0$VI_RPsL9u(kqulmS`tnb%4U)hm{)h@bG*jw@Y*#MX;Th1wu3TrO}Srn_+YWYesEgkO1 zv?P8uWB)is;#&=xBBLf+y5e4?%y>_8$1KwkAJ8UcW|0CIz89{LydfJKr^RF=JFPi}MAv|ecbuZ!YcTSxsD$(Pr#W*oytl?@+2 zXBFb32Kf_G3~EgOS7C`8w!tx}DcCT%+#qa76VSbnHo;4(oJ7)}mm?b5V65ir`7Z}s zR2)m15b#E}z_2@rf34wo!M^CnVoi# ze+S(IK({C6u=Sm{1>F~?)8t&fZpOOPcby;I3jO;7^xmLKM(<%i-nyj9mgw9F1Lq4|DZUHZ4)V9&6fQM(ZxbG{h+}(koiTu`SQw6#6q2Yg z-d+1+MRp$zYT2neIR2cKij2!R;C~ooQ3<;^8)_Gch&ZyEtiQwmF0Mb_)6)4lVEBF< zklXS7hvtu30uJR`3OzcqUNOdYsfrKSGkIQAk|4=&#ggxdU4^Y(;)$8}fQ>lTgQdJ{ zzie8+1$3@E;|a`kzuFh9Se}%RHTmBg)h$eH;gttjL_)pO^10?!bNev6{mLMaQpY<< z7M^ZXrg>tw;vU@9H=khbff?@nu)Yw4G% zGxobPTUR2p_ed7Lvx?dkrN^>Cv$Axuwk;Wj{5Z@#$sK@f4{7SHg%2bpcS{(~s;L(mz@9r$cK@m~ef&vf%1@ z@8&@LLO2lQso|bJD6}+_L1*D^}>oqg~$NipL>QlP3 zM#ATSy@ycMkKs5-0X8nFAtMhO_=$DlWR+@EaZ}`YduRD4A2@!at3NYRHmlENea9IF zN*s>mi?zy*Vv+F+&4-o`Wj}P3mLGM*&M(z|;?d82>hQkkY?e-hJ47mWOLCPL*MO04 z3lE(n2RM=IIo;Z?I=sKJ_h=iJHbQ2<}WW0b@I6Qf-{T=Qn#@N0yG5xH&ofEy^mZMPzd22nR`t!Q)VkNgf*VOxE z$XhOunG3ZN#`Ks$Hp~}`OX5vmHP={GYUJ+-g0%PS$*Qi5+-40M47zJ24vK1#? zb$s^%r?+>#lw$mpZaMa1aO%wlPm3~cno_(S%U&-R;6eK(@`CjswAW2)HfZ>ptItaZ|XqQ z&sHVVL>WCe|E4iPb2~gS5ITs6xfg(kmt&3$YcI=zTuqj37t|+9ojCr(G^ul#p{>k) zM94pI>~5VZ$!*Qurq<@RIXgP3sx-2kL$1Q~da%rnNIh?)&+c~*&e~CYPDhPYjb+Xu zKg5w^XB3(_9{Waa4E(-J-Kq_u6t_k?a8kEHqai-N-4#`SRerO!h}!cS%SMC<)tGix zOzVP^_t!HN&HIPL-ZpcgWitHM&yFRC7!k4zSI+-<_uQ}|tX)n{Ib;X>Xx>i_d*KkH zCzogKQFpP1408_2!ofU|iBq2R8hW6G zuqJs9Tyw{u%-uWczPLkM!MfKfflt+NK9Vk8E!C>AsJwNDRoe2~cL+UvqNP|5J8t)( z0$iMa!jhudJ+fqFn+um&@Oj6qXJd_3-l`S^I1#0fnt!z3?D*hAHr*u(*wR@`4O z#avrtg%s`Fh{?$FtBFM^$@@hW!8ZfF4;=n0<8In&X}-Rp=cd0TqT_ne46$j^r}FzE z26vX^!PzScuQfFfl1HEZ{zL?G88mcc76zHGizWiykBf4m83Z${So-+dZ~YGhm*RO7 zB1gdIdqnFi?qw+lPRFW5?}CQ3Me3G^muvll&4iN+*5#_mmIu;loULMwb4lu9U*dFM z-Sr**(0Ei~u=$3<6>C-G6z4_LNCx||6YtjS)<;hf)YJTPKXW+w%hhCTUAInIse9>r zl2YU6nRb$u-FJlWN*{{%sm_gi_UP5{=?5}5^D2vPzM=oPfNw~azZQ#P zl5z8RtSSiTIpEohC15i-Q1Bk{3&ElsD0uGAOxvbk29VUDmmA0w;^v`W#0`};O3DVE z&+-ca*`YcN%z*#VXWK9Qa-OEME#fykF%|7o=1Y+eF;Rtv0W4~kKRDx9YBHOWhC%^I z$Jec0cC7o37}Xt}cu)NH5R}NT+=2Nap*`^%O)vz?+{PV<2~qX%TzdJOGeKj5_QjqR&a3*K@= P-1+_A+?hGkL;m(J7kc&K literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..28c6bf03016f6c994b70f38d1b7346e5831b531f GIT binary patch literal 564 zcmV-40?Yl0P)Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 zcmds$`#;kQ7{|XelZftyR5~xW7?MLxS4^|Hw3&P7^y)@A9Fj{Xm1~_CIV^XZ%SLBn zA;!r`GqGHg=7>xrB{?psZQs88ZaedDoagm^KF{a*>G|dJWRSe^I$DNW008I^+;Kjt z>9p3GNR^I;v>5_`+91i(*G;u5|L+Bu6M=(afLjtkya#yZ175|z$pU~>2#^Z_pCZ7o z1c6UNcv2B3?; zX%qdxCXQpdKRz=#b*q0P%b&o)5ZrNZt7$fiETSK_VaY=mb4GK`#~0K#~9^ zcY!`#Af+4h?UMR-gMKOmpuYeN5P*RKF!(tb`)oe0j2BH1l?=>y#S5pMqkx6i{*=V9JF%>N8`ewGhRE(|WohnD59R^$_36{4>S zDFlPC5|k?;SPsDo87!B{6*7eqmMdU|QZ84>6)Kd9wNfh90=y=TFQay-0__>=<4pk& zYDjgIhL-jQ9o>z32K)BgAH+HxamL{ZL~ozu)Qqe@a`FpH=oQRA8=L-m-1dam(Ix2V z?du;LdMO+ooBelr^_y4{|44tmgH^2hSzPFd;U^!1p>6d|o)(-01z{i&Kj@)z-yfWQ)V#3Uo!_U}q3u`(fOs`_f^ueFii1xBNUB z6MecwJN$CqV&vhc+)b(p4NzGGEgwWNs z@*lUV6LaduZH)4_g!cE<2G6#+hJrWd5(|p1Z;YJ7ifVHv+n49btR}dq?HHDjl{m$T z!jLZcGkb&XS2OG~u%&R$(X+Z`CWec%QKt>NGYvd5g20)PU(dOn^7%@6kQb}C(%=vr z{?RP(z~C9DPnL{q^@pVw@|Vx~@3v!9dCaBtbh2EdtoNHm4kGxp>i#ct)7p|$QJs+U z-a3qtcPvhihub?wnJqEt>zC@)2suY?%-96cYCm$Q8R%-8$PZYsx3~QOLMDf(piXMm zB=<63yQk1AdOz#-qsEDX>>c)EES%$owHKue;?B3)8aRd}m~_)>SL3h2(9X;|+2#7X z+#2)NpD%qJvCQ0a-uzZLmz*ms+l*N}w)3LRQ*6>|Ub-fyptY(keUxw+)jfwF5K{L9 z|Cl_w=`!l_o><384d&?)$6Nh(GAm=4p_;{qVn#hI8lqewW7~wUlyBM-4Z|)cZr?Rh z=xZ&Ol>4(CU85ea(CZ^aO@2N18K>ftl8>2MqetAR53_JA>Fal`^)1Y--Am~UDa4th zKfCYpcXky$XSFDWBMIl(q=Mxj$iMBX=|j9P)^fDmF(5(5$|?Cx}DKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q z?YG}tx;sY@GzMmsY`7r$P+F_YLz)(e}% zyakqFB<6|x9R#TdoP{R$>o7y(-`$$p0NxJ6?2B8tH)4^yF(WhqGZlM3=9Ibs$%U1w zWzcss*_c0=v_+^bfb`kBFsI`d;ElwiU%frgRB%qBjn@!0U2zZehBn|{%uNIKBA7n= zzE`nnwTP85{g;8AkYxA68>#muXa!G>xH22D1I*SiD~7C?7Za+9y7j1SHiuSkKK*^O zsZ==KO(Ua#?YUpXl{ViynyT#Hzk=}5X$e04O@fsMQjb}EMuPWFO0e&8(2N(29$@Vd zn1h8Yd>6z(*p^E{c(L0Lg=wVdupg!z@WG;E0k|4a%s7Up5C0c)55XVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~tSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Y zu$JOl0b83zu$JMvy<#oH^Wl>aWL*?aDwnS0iEAwC?DK@aT)GHRLhnz2WCvf3Ba;o=aY7 z2{Asu5MEjGOY4O#Ggz@@J;q*0`kd2n8I3BeNuMmYZf{}pg=jTdTCrIIYuW~luKecn z+E-pHY%ohj@uS0%^ z&(OxwPFPD$+#~`H?fMvi9geVLci(`K?Kj|w{rZ9JgthFHV+=6vMbK~0)Ea<&WY-NC zy-PnZft_k2tfeQ*SuC=nUj4H%SQ&Y$gbH4#2sT0cU0SdFs=*W*4hKGpuR1{)mV;Qf5pw4? zfiQgy0w3fC*w&Bj#{&=7033qFR*<*61B4f9K%CQvxEn&bsWJ{&winp;FP!KBj=(P6 z4Z_n4L7cS;ao2)ax?Tm|I1pH|uLpDSRVghkA_UtFFuZ0b2#>!8;>-_0ELjQSD-DRd z4im;599VHDZYtnWZGAB25W-e(2VrzEh|etsv2YoP#VbIZ{aFkwPrzJ#JvCvA*mXS& z`}Q^v9(W4GiSs}#s7BaN!WA2bniM$0J(#;MR>uIJ^uvgD3GS^%*ikdW6-!VFUU?JV zZc2)4cMsX@j z5HQ^e3BUzOdm}yC-xA%SY``k$rbfk z;CHqifhU*jfGM@DkYCecD9vl*qr58l6x<8URB=&%{!Cu3RO*MrKZ4VO}V6R0a zZw3Eg^0iKWM1dcTYZ0>N899=r6?+adUiBKPciJw}L$=1f4cs^bio&cr9baLF>6#BM z(F}EXe-`F=f_@`A7+Q&|QaZ??Txp_dB#lg!NH=t3$G8&06MFhwR=Iu*Im0s_b2B@| znW>X}sy~m#EW)&6E&!*0%}8UAS)wjt+A(io#wGI@Z2S+Ms1Cxl%YVE800007ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 zcmVjJBgitF5mAp-i>4+KS_oR{|13AP->1TD4=w)g|)JHOx|a2Wk1Va z!k)vP$UcQ#mdj%wNQoaJ!w>jv_6&JPyutpQps?s5dmDQ>`%?Bvj>o<%kYG!YW6H-z zu`g$@mp`;qDR!51QaS}|ZToSuAGcJ7$2HF0z`ln4t!#Yg46>;vGG9N9{V@9z#}6v* zfP?}r6b{*-C*)(S>NECI_E~{QYzN5SXRmVnP<=gzP+_Sp(Aza_hKlZ{C1D&l*(7IKXxQC1Z9#6wx}YrGcn~g%;icdw>T0Rf^w0{ z$_wn1J+C0@!jCV<%Go5LA45e{5gY9PvZp8uM$=1}XDI+9m7!A95L>q>>oe0$nC->i zeexUIvq%Uk<-$>DiDb?!In)lAmtuMWxvWlk`2>4lNuhSsjAf2*2tjT`y;@d}($o)S zn(+W&hJ1p0xy@oxP%AM15->wPLp{H!k)BdBD$toBpJh+crWdsNV)qsHaqLg2_s|Ih z`8E9z{E3sA!}5aKu?T!#enD(wLw?IT?k-yWVHZ8Akz4k5(TZJN^zZgm&zM28sfTD2BYJ|Fde3Xzh;;S` z=GXTnY4Xc)8nYoz6&vF;P7{xRF-{|2Xs5>a5)@BrnQ}I(_x7Cgpx#5&Td^4Q9_FnQ zX5so*;#8-J8#c$OlA&JyPp$LKUhC~-e~Ij!L%uSMu!-VZG7Hx-L{m2DVR2i=GR(_% zCVD!4N`I)&Q5S`?P&fQZ=4#Dgt_v2-DzkT}K(9gF0L(owe-Id$Rc2qZVLqI_M_DyO z9@LC#U28_LU{;wGZ&))}0R2P4MhajKCd^K#D+JJ&JIXZ_p#@+7J9A&P<0kdRujtQ_ zOy>3=C$kgi6$0pW06KaLz!21oOryKM3ZUOWqppndxfH}QpgjEJ`j7Tzn5bk6K&@RA?vl##y z$?V~1E(!wB5rH`>3nc&@)|#<1dN2cMzzm=PGhQ|Yppne(C-Vlt450IXc`J4R0W@I7 zd1e5uW6juvO%ni(WX7BsKx3MLngO7rHO;^R5I~0^nE^9^E_eYLgiR9&KnJ)pBbfno zSVnW$0R+&6jOOsZ82}nJ126+c|%svPo;TeUku<2G7%?$oft zyaO;tVo}(W)VsTUhq^XmFi#2z%-W9a{7mXn{uzivYQ_d6b7VJG{77naW(vHt-uhnY zVN#d!JTqVh(7r-lhtXVU6o})aZbDt_;&wJVGl2FKYFBFpU-#9U)z#(A%=IVnqytR$SY-sO( z($oNE09{D^@OuYPz&w~?9>Fl5`g9u&ecFGhqX=^#fmR=we0CJw+5xna*@oHnkahk+ z9aWeE3v|An+O5%?4fA&$Fgu~H_YmqR!yIU!bFCk4!#pAj%(lI(A5n)n@Id#M)O9Yx zJU9oKy{sRAIV3=5>(s8n{8ryJ!;ho}%pn6hZKTKbqk=&m=f*UnK$zW3YQP*)pw$O* zIfLA^!-bmBl6%d_n$#tP8Zd_(XdA*z*WH|E_yILwjtI~;jK#v-6jMl^?<%Y%`gvpwv&cFb$||^v4D&V=aNy?NGo620jL3VZnA%s zH~I|qPzB~e(;p;b^gJr7Ure#7?8%F0m4vzzPy^^(q4q1OdthF}Fi*RmVZN1OwTsAP zn9CZP`FazX3^kG(KodIZ=Kty8DLTy--UKfa1$6XugS zk%6v$Kmxt6U!YMx0JQ)0qX*{CXwZZk$vEROidEc7=J-1;peNat!vS<3P-FT5po>iE z!l3R+<`#x|+_hw!HjQGV=8!q|76y8L7N8gP3$%0kfush|u0uU^?dKBaeRSBUpOZ0c z62;D&Mdn2}N}xHRFTRI?zRv=>=AjHgH}`2k4WK=#AHB)UFrR-J87GgX*x5fL^W2#d z=(%K8-oZfMO=i{aWRDg=FX}UubM4eotRDcn;OR#{3q=*?3mE3_oJ-~prjhxh%PgQT zyn)Qozaq0@o&|LEgS{Ind4Swsr;b`u185hZPOBLL<`d2%^Yp1?oL)=jnLi;Zo0ZDliTtQ^b5SmfIMe{T==zZkbvn$KTQGlbG8w}s@M3TZnde;1Am46P3juKb zl9GU&3F=q`>j!`?SyH#r@O59%@aMX^rx}Nxe<>NqpUp5=lX1ojGDIR*-D^SDuvCKF z?3$xG(gVUsBERef_YjPFl^rU9EtD{pt z0CXwpN7BN3!8>hajGaTVk-wl=9rxmfWtIhC{mheHgStLi^+Nz12a?4r(fz)?3A%at zMlvQmL<2-R)-@G1wJ0^zQK%mR=r4d{Y3fHp){nWXUL#|CqXl(+v+qDh>FkF9`eWrW zfr^D%LNfOcTNvtx0JXR35J0~Jpi2#P3Q&80w+nqNfc}&G0A~*)lGHKv=^FE+b(37|)zL;KLF>oiGfb(?&1 zV3XRu!Sw>@quKiab%g6jun#oZ%!>V#A%+lNc?q>6+VvyAn=kf_6z^(TZUa4Eelh{{ zqFX-#dY(EV@7l$NE&kv9u9BR8&Ojd#ZGJ6l8_BW}^r?DIS_rU2(XaGOK z225E@kH5Opf+CgD^{y29jD4gHbGf{1MD6ggQ&%>UG4WyPh5q_tb`{@_34B?xfSO*| zZv8!)q;^o-bz`MuxXk*G^}(6)ACb@=Lfs`Hxoh>`Y0NE8QRQ!*p|SH@{r8=%RKd4p z+#Ty^-0kb=-H-O`nAA3_6>2z(D=~Tbs(n8LHxD0`R0_ATFqp-SdY3(bZ3;VUM?J=O zKCNsxsgt@|&nKMC=*+ZqmLHhX1KHbAJs{nGVMs6~TiF%Q)P@>!koa$%oS zjXa=!5>P`vC-a}ln!uH1ooeI&v?=?v7?1n~P(wZ~0>xWxd_Aw;+}9#eULM7M8&E?Y zC-ZLhi3RoM92SXUb-5i-Lmt5_rfjE{6y^+24`y$1lywLyHO!)Boa7438K4#iLe?rh z2O~YGSgFUBH?og*6=r9rme=peP~ah`(8Zt7V)j5!V0KPFf_mebo3z95U8(up$-+EA^9dTRLq>Yl)YMBuch9%=e5B`Vnb>o zt03=kq;k2TgGe4|lGne&zJa~h(UGutjP_zr?a7~#b)@15XNA>Dj(m=gg2Q5V4-$)D|Q9}R#002ovPDHLkV1o7DH3k3x literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 zcmV-m2cP(fP)x~L`~4d)Rspd&<9kFh{hn*KP1LP0~$;u(LfAu zp%fx&qLBcRHx$G|3q(bv@+b;o0*D|jwD-Q9uQR(l*ST}s+uPgQ-MeFwZ#GS?b332? z&Tk$&_miXn3IGq)AmQ)3sisq{raD4(k*bHvpCe-TdWq^NRTEVM)i9xbgQ&ccnUVx* zEY%vS%gDcSg=!tuIK8$Th2_((_h^+7;R|G{n06&O2#6%LK`a}n?h_fL18btz<@lFG za}xS}u?#DBMB> zw^b($1Z)`9G?eP95EKi&$eOy@K%h;ryrR3la%;>|o*>CgB(s>dDcNOXg}CK9SPmD? zmr-s{0wRmxUnbDrYfRvnZ@d z6johZ2sMX{YkGSKWd}m|@V7`Degt-43=2M?+jR%8{(H$&MLLmS;-|JxnX2pnz;el1jsvqQz}pGSF<`mqEXRQ5sC4#BbwnB_4` zc5bFE-Gb#JV3tox9fp-vVEN{(tOCpRse`S+@)?%pz+zVJXSooTrNCUg`R6`hxwb{) zC@{O6MKY8tfZ5@!yy=p5Y|#+myRL=^{tc(6YgAnkg3I(Cd!r5l;|;l-MQ8B`;*SCE z{u)uP^C$lOPM z5d~UhKhRRmvv{LIa^|oavk1$QiEApSrP@~Jjbg`<*dW4TO?4qG%a%sTPUFz(QtW5( zM)lA+5)0TvH~aBaOAs|}?u2FO;yc-CZ1gNM1dAxJ?%m?YsGR`}-xk2*dxC}r5j$d* zE!#Vtbo69h>V4V`BL%_&$} z+oJAo@jQ^Tk`;%xw-4G>hhb&)B?##U+(6Fi7nno`C<|#PVA%$Y{}N-?(Gc$1%tr4Pc}}hm~yY#fTOe!@v9s-ik$dX~|ygArPhByaXn8 zpI^FUjNWMsTFKTP3X7m?UK)3m zp6rI^_zxRYrx6_QmhoWoDR`fp4R7gu6;gdO)!KexaoO2D88F9x#TM1(9Bn7g;|?|o z)~$n&Lh#hCP6_LOPD>a)NmhW})LADx2kq=X7}7wYRj-0?dXr&bHaRWCfSqvzFa=sn z-8^gSyn-RmH=BZ{AJZ~!8n5621GbUJV7Qvs%JNv&$%Q17s_X%s-41vAPfIR>;x0Wlqr5?09S>x#%Qkt>?(&XjFRY}*L6BeQ3 z<6XEBh^S7>AbwGm@XP{RkeEKj6@_o%oV?hDuUpUJ+r#JZO?!IUc;r0R?>mi)*ZpQ) z#((dn=A#i_&EQn|hd)N$#A*fjBFuiHcYvo?@y1 z5|fV=a^a~d!c-%ZbMNqkMKiSzM{Yq=7_c&1H!mXk60Uv32dV;vMg&-kQ)Q{+PFtwc zj|-uQ;b^gts??J*9VxxOro}W~Q9j4Em|zSRv)(WSO9$F$s=Ydu%Q+5DOid~lwk&we zY%W(Z@ofdwPHncEZzZgmqS|!gTj3wQq9rxQy+^eNYKr1mj&?tm@wkO*9@UtnRMG>c aR{jt9+;fr}hV%pg00001^@s67{VYS000c7NklQEG_j zup^)eW&WUIApqy$=APz8jE@awGp)!bsTjDbrJO`$x^ZR^dr;>)LW>{ zs70vpsD38v)19rI=GNk1b(0?Js9~rjsQsu*K;@SD40RB-3^gKU-MYC7G!Bw{fZsqp zih4iIi;Hr_xZ033Iu{sQxLS=}yBXgLMn40d++>aQ0#%8D1EbGZp7+ z5=mK?t31BkVYbGOxE9`i748x`YgCMwL$qMsChbSGSE1`p{nSmadR zcQ#R)(?!~dmtD0+D2!K zR9%!Xp1oOJzm(vbLvT^$IKp@+W2=-}qTzTgVtQ!#Y7Gxz}stUIm<1;oBQ^Sh2X{F4ibaOOx;5ZGSNK z0maF^@(UtV$=p6DXLgRURwF95C=|U8?osGhgOED*b z7woJ_PWXBD>V-NjQAm{~T%sjyJ{5tn2f{G%?J!KRSrrGvQ1(^`YLA5B!~eycY(e5_ z*%aa{at13SxC(=7JT7$IQF~R3sy`Nn%EMv!$-8ZEAryB*yB1k&stni)=)8-ODo41g zkJu~roIgAih94tb=YsL%iH5@^b~kU9M-=aqgXIrbtxMpFy5mekFm#edF9z7RQ6V}R zBIhbXs~pMzt0VWy1Fi$^fh+1xxLDoK09&5&MJl(q#THjPm(0=z2H2Yfm^a&E)V+a5 zbi>08u;bJsDRUKR9(INSc7XyuWv(JsD+BB*0hS)FO&l&7MdViuur@-<-EHw>kHRGY zqoT}3fDv2-m{NhBG8X}+rgOEZ;amh*DqN?jEfQdqxdj08`Sr=C-KmT)qU1 z+9Cl)a1mgXxhQiHVB}l`m;-RpmKy?0*|yl?FXvJkFxuu!fKlcmz$kN(a}i*saM3nr z0!;a~_%Xqy24IxA2rz<+08=B-Q|2PT)O4;EaxP^6qixOv7-cRh?*T?zZU`{nIM-at zTKYWr9rJ=tppQ9I#Z#mLgINVB!pO-^FOcvFw6NhV0gztuO?g ztoA*C-52Q-Z-P#xB4HAY3KQVd%dz1S4PA3vHp0aa=zAO?FCt zC_GaTyVBg2F!bBr3U@Zy2iJgIAt>1sf$JWA9kh{;L+P*HfUBX1Zy{4MgNbDfBV_ly z!y#+753arsZUt@366jIC0klaC@ckuk!qu=pAyf7&QmiBUT^L1&tOHzsK)4n|pmrVT zs2($4=?s~VejTFHbFdDOwG;_58LkIj1Fh@{glkO#F1>a==ymJS$z;gdedT1zPx4Kj ztjS`y_C}%af-RtpehdQDt3a<=W5C4$)9W@QAse;WUry$WYmr51ml9lkeunUrE`-3e zmq1SgSOPNEE-Mf+AGJ$g0M;3@w!$Ej;hMh=v=I+Lpz^n%Pg^MgwyqOkNyu2c^of)C z1~ALor3}}+RiF*K4+4{(1%1j3pif1>sv0r^mTZ?5Jd-It!tfPfiG_p$AY*Vfak%FG z4z#;wLtw&E&?}w+eKG^=#jF7HQzr8rV0mY<1YAJ_uGz~$E13p?F^fPSzXSn$8UcI$ z8er9{5w5iv0qf8%70zV71T1IBB1N}R5Kp%NO0=5wJalZt8;xYp;b{1K) zHY>2wW-`Sl{=NpR%iu3(u6l&)rc%%cSA#aV7WCowfbFR4wcc{LQZv~o1u_`}EJA3>ki`?9CKYTA!rhO)if*zRdd}Kn zEPfYbhoVE~!FI_2YbC5qAj1kq;xP6%J8+?2PAs?`V3}nyFVD#sV3+uP`pi}{$l9U^ zSz}_M9f7RgnnRhaoIJgT8us!1aB&4!*vYF07Hp&}L zCRlop0oK4DL@ISz{2_BPlezc;xj2|I z23RlDNpi9LgTG_#(w%cMaS)%N`e>~1&a3<{Xy}>?WbF>OOLuO+j&hc^YohQ$4F&ze z+hwnro1puQjnKm;vFG~o>`kCeUIlkA-2tI?WBKCFLMBY=J{hpSsQ=PDtU$=duS_hq zHpymHt^uuV1q@uc4bFb{MdG*|VoW@15Osrqt2@8ll0qO=j*uOXn{M0UJX#SUztui9FN4)K3{9!y8PC-AHHvpVTU;x|-7P+taAtyglk#rjlH2 z5Gq8ik}BPaGiM{#Woyg;*&N9R2{J0V+WGB69cEtH7F?U~Kbi6ksi*`CFXsi931q7Y zGO82?whBhN%w1iDetv%~wM*Y;E^)@Vl?VDj-f*RX>{;o_=$fU!&KAXbuadYZ46Zbg z&6jMF=49$uL^73y;;N5jaHYv)BTyfh&`qVLYn?`o6BCA_z-0niZz=qPG!vonK3MW_ zo$V96zM!+kJRs{P-5-rQVse0VBH*n6A58)4uc&gfHMa{gIhV2fGf{st>E8sKyP-$8zp~wJX^A*@DI&-;8>gANXZj zU)R+Y)PB?=)a|Kj>8NXEu^S_h^7R`~Q&7*Kn!xyvzVv&^>?^iu;S~R2e-2fJx-oUb cX)(b1KSk$MOV07*qoM6N<$f&6$jw%VRuvdN2+38CZWny1cRtlsl+0_KtW)EU14Ei(F!UtWuj4IK+3{sK@>rh zs1Z;=(DD&U6+tlyL?UnHVN^&g6QhFi2#HS+*qz;(>63G(`|jRtW|nz$Pv7qTovP!^ zP_jES{mr@O-02w%!^a?^1ZP!_KmQiz0L~jZ=W@Qt`8wzOoclQsAS<5YdH;a(4bGLE zk8s}1If(PSIgVi!XE!5kA?~z*sobvNyohr;=Q_@h2@$6Flyej3J)D-6YfheRGl`HEcPk|~huT_2-U?PfL=4BPV)f1o!%rQ!NMt_MYw-5bUSwQ9Z&zC>u zOrl~UJglJNa%f50Ok}?WB{on`Ci`p^Y!xBA?m@rcJXLxtrE0FhRF3d*ir>yzO|BD$ z3V}HpFcCh6bTzY}Nt_(W%QYd3NG)jJ4<`F<1Od) zfQblTdC&h2lCz`>y?>|9o2CdvC8qZeIZt%jN;B7Hdn2l*k4M4MFEtq`q_#5?}c$b$pf_3y{Y!cRDafZBEj-*OD|gz#PBDeu3QoueOesLzB+O zxjf2wvf6Wwz>@AiOo2mO4=TkAV+g~%_n&R;)l#!cBxjuoD$aS-`IIJv7cdX%2{WT7 zOm%5rs(wqyPE^k5SIpUZ!&Lq4<~%{*>_Hu$2|~Xa;iX*tz8~G6O3uFOS?+)tWtdi| zV2b#;zRN!m@H&jd=!$7YY6_}|=!IU@=SjvGDFtL;aCtw06U;-v^0%k0FOyESt z1Wv$={b_H&8FiRV?MrzoHWd>%v6KTRU;-v^Miiz+@q`(BoT!+<37CKhoKb)|8!+RG z6BQFU^@fRW;s8!mOf2QViKQGk0TVER6EG1`#;Nm39Do^PoT!+<37AD!%oJe86(=et zZ~|sLzU>V-qYiU6V8$0GmU7_K8|Fd0B?+9Un1BhKAz#V~Fk^`mJtlCX#{^8^M8!me z8Yg;8-~>!e<-iG;h*0B1kBKm}hItVGY6WnjVpgnTTAC$rqQ^v)4KvOtpY|sIj@WYg zyw##ZZ5AC2IKNC;^hwg9BPk0wLStlmBr;E|$5GoAo$&Ui_;S9WY62n3)i49|T%C#i017z3J=$RF|KyZWnci*@lW4 z=AKhNN6+m`Q!V3Ye68|8y@%=am>YD0nG99M)NWc20%)gwO!96j7muR}Fr&54SxKP2 zP30S~lt=a*qDlbu3+Av57=9v&vr<6g0&`!8E2fq>I|EJGKs}t|{h7+KT@)LfIV-3K zK)r_fr2?}FFyn*MYoLC>oV-J~eavL2ho4a4^r{E-8m2hi>~hA?_vIG4a*KT;2eyl1 zh_hUvUJpNCFwBvRq5BI*srSle>c6%n`#VNsyC|MGa{(P&08p=C9+WUw9Hl<1o9T4M zdD=_C0F7#o8A_bRR?sFNmU0R6tW`ElnF8p53IdHo#S9(JoZCz}fHwJ6F<&?qrpVqE zte|m%89JQD+XwaPU#%#lVs-@-OL);|MdfINd6!XwP2h(eyafTUsoRkA%&@fe?9m@jw-v(yTTiV2(*fthQH9}SqmsRPVnwwbV$1E(_lkmo&S zF-truCU914_$jpqjr(>Ha4HkM4YMT>m~NosUu&UZ>zirfHo%N6PPs9^_o$WqPA0#5 z%tG>qFCL+b*0s?sZ;Sht0nE7Kl>OVXy=gjWxxK;OJ3yGd7-pZf7JYNcZo2*1SF`u6 zHJyRRxGw9mDlOiXqVMsNe#WX`fC`vrtjSQ%KmLcl(lC>ZOQzG^%iql2w-f_K@r?OE zwCICifM#L-HJyc7Gm>Ern?+Sk3&|Khmu4(~3qa$(m6Ub^U0E5RHq49za|XklN#?kP zl;EstdW?(_4D>kwjWy2f!LM)y?F94kyU3`W!6+AyId-89v}sXJpuic^NLL7GJItl~ zsiuB98AI-(#Mnm|=A-R6&2fwJ0JVSY#Q>&3$zFh|@;#%0qeF=j5Ajq@4i0tIIW z&}sk$&fGwoJpe&u-JeGLi^r?dO`m=y(QO{@h zQqAC7$rvz&5+mo3IqE?h=a~6m>%r5Quapvzq;{y~p zJpyXOBgD9VrW7@#p6l7O?o3feml(DtSL>D^R) zZUY%T2b0-vBAFN7VB;M88!~HuOXi4KcI6aRQ&h|XQ0A?m%j2=l1f0cGP}h(oVfJ`N zz#PpmFC*ieab)zJK<4?^k=g%OjPnkANzbAbmGZHoVRk*mTfm75s_cWVa`l*f$B@xu z5E*?&@seIo#*Y~1rBm!7sF9~~u6Wrj5oICUOuz}CS)jdNIznfzCA(stJ(7$c^e5wN z?lt>eYgbA!kvAR7zYSD&*r1$b|(@;9dcZ^67R0 zXAXJKa|5Sdmj!g578Nwt6d$sXuc&MWezA0Whd`94$h{{?1IwXP4)Tx4obDK%xoFZ_Z zjjHJ_P@R_e5blG@yEjnaJb`l;s%Lb2&=8$&Ct-fV`E^4CUs)=jTk!I}2d&n!f@)bm z@ z_4Dc86+3l2*p|~;o-Sb~oXb_RuLmoifDU^&Te$*FevycC0*nE3Xws8gsWp|Rj2>SM zns)qcYj?^2sd8?N!_w~4v+f-HCF|a$TNZDoNl$I1Uq87euoNgKb6&r26TNrfkUa@o zfdiFA@p{K&mH3b8i!lcoz)V{n8Q@g(vR4ns4r6w;K z>1~ecQR0-<^J|Ndg5fvVUM9g;lbu-){#ghGw(fg>L zh)T5Ljb%lWE;V9L!;Cqk>AV1(rULYF07ZBJbGb9qbSoLAd;in9{)95YqX$J43-dY7YU*k~vrM25 zxh5_IqO0LYZW%oxQ5HOzmk4x{atE*vipUk}sh88$b2tn?!ujEHn`tQLe&vo}nMb&{ zio`xzZ&GG6&ZyN3jnaQy#iVqXE9VT(3tWY$n-)uWDQ|tc{`?fq2F`oQ{;d3aWPg4Hp-(iE{ry>MIPWL> iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 000000000000..89c2725b70f1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000000..f2e259c7c939 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Base.lproj/Main.storyboard b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 000000000000..ca2ca3396824 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Info.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Info.plist new file mode 100644 index 000000000000..6783ca935f1d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Info.plist @@ -0,0 +1,53 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + google_maps_flutter_example + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSLocationWhenInUseUsageDescription + This app needs your location to test the location feature of the Google Maps plugin. + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Runner-Bridging-Header.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000000..ba04211afd0a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1,5 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GeneratedPluginRegistrant.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/ExtractIconFromDataTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/ExtractIconFromDataTests.m new file mode 100644 index 000000000000..4d7da98cac59 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/ExtractIconFromDataTests.m @@ -0,0 +1,352 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; + +#import +#import + +@interface ExtractIconFromDataTests : XCTestCase +- (UIImage *)createOnePixelImage; +@end + +@implementation ExtractIconFromDataTests + +- (void)testExtractIconFromDataAssetAuto { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testExtractIconFromDataAssetAutoWithScale { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:10 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 10); + XCTAssertEqual(resultImage.size.width, 0.1); + XCTAssertEqual(resultImage.size.height, 0.1); +} + +- (void)testExtractIconFromDataAssetAutoAndSizeWithSameAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + XCTAssertEqual(testImage.scale, 1.0); + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + const CGFloat width = 15.0; + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(testImage.scale, 1.0); + + // As image has same aspect ratio as the original image, + // only image scale has been changed to match the target size. + CGFloat targetScale = testImage.scale * (testImage.size.width / width); + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(resultImage.scale, targetScale, accuracy); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, width); +} + +- (void)testExtractIconFromDataAssetAutoAndSizeWithDifferentAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + const CGFloat width = 15.0; + const CGFloat height = 45.0; + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:@(height)]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, screenScale); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, height); +} + +- (void)testExtractIconFromDataAssetNoScaling { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingNone + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testExtractIconFromDataBytesAuto { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testExtractIconFromDataBytesAutoWithScaling { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:10 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 10); + XCTAssertEqual(resultImage.size.width, 0.1); + XCTAssertEqual(resultImage.size.height, 0.1); +} + +- (void)testExtractIconFromDataBytesAutoAndSizeWithSameAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + const CGFloat width = 15.0; + const CGFloat height = 15.0; + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:@(height)]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(testImage.scale, 1.0); + + // As image has same aspect ratio as the original image, + // only image scale has been changed to match the target size. + CGFloat targetScale = testImage.scale * (testImage.size.width / width); + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(resultImage.scale, targetScale, accuracy); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, height); +} + +- (void)testExtractIconFromDataBytesAutoAndSizeWithDifferentAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + const CGFloat width = 15.0; + const CGFloat height = 45.0; + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:@(height)]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, screenScale); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, height); +} + +- (void)testExtractIconFromDataBytesNoScaling { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingNone + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testIsScalableWithScaleFactorFromSize100x100to10x100 { + CGSize originalSize = CGSizeMake(100.0, 100.0); + CGSize targetSize = CGSizeMake(10.0, 100.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize100x100to10x10 { + CGSize originalSize = CGSizeMake(100.0, 100.0); + CGSize targetSize = CGSizeMake(10.0, 10.0); + XCTAssertTrue(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize233x200to23x20 { + CGSize originalSize = CGSizeMake(233.0, 200.0); + CGSize targetSize = CGSizeMake(23.0, 20.0); + XCTAssertTrue(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize233x200to22x20 { + CGSize originalSize = CGSizeMake(233.0, 200.0); + CGSize targetSize = CGSizeMake(22.0, 20.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize200x233to20x23 { + CGSize originalSize = CGSizeMake(200.0, 233.0); + CGSize targetSize = CGSizeMake(20.0, 23.0); + XCTAssertTrue(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize200x233to20x22 { + CGSize originalSize = CGSizeMake(200.0, 233.0); + CGSize targetSize = CGSizeMake(20.0, 22.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize1024x768to500x250 { + CGSize originalSize = CGSizeMake(1024.0, 768.0); + CGSize targetSize = CGSizeMake(500.0, 250.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (UIImage *)createOnePixelImage { + CGSize size = CGSizeMake(1, 1); + UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat]; + format.scale = 1.0; + format.opaque = YES; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size + format:format]; + UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { + [UIColor.whiteColor setFill]; + [context fillRect:CGRectMake(0, 0, size.width, size.height)]; + }]; + return image; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMClusterManagersControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMClusterManagersControllerTests.m new file mode 100644 index 000000000000..f9baaa10184b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMClusterManagersControllerTests.m @@ -0,0 +1,145 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import +#import "PartiallyMockedMapView.h" + +@interface FGMClusterManagersControllerTests : XCTestCase +@end + +@implementation FGMClusterManagersControllerTests + +- (void)testClustering { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + CGRect frame = CGRectMake(0, 0, 100, 100); + + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + id handler = OCMClassMock([FGMMapsCallbackApi class]); + + FGMClusterManagersController *clusterManagersController = + [[FGMClusterManagersController alloc] initWithMapView:mapView callbackHandler:handler]; + + FLTMarkersController *markersController = + [[FLTMarkersController alloc] initWithMapView:mapView + callbackHandler:handler + clusterManagersController:clusterManagersController + registrar:registrar]; + + // Add cluster managers. + NSString *clusterManagerId = @"cm"; + FGMPlatformClusterManager *clusterManagerToAdd = + [FGMPlatformClusterManager makeWithIdentifier:clusterManagerId]; + [clusterManagersController addClusterManagers:@[ clusterManagerToAdd ]]; + + // Verify that cluster managers are available + GMUClusterManager *clusterManager = + [clusterManagersController clusterManagerWithIdentifier:clusterManagerId]; + XCTAssertNotNil(clusterManager, @"Cluster Manager should not be nil"); + + // Add markers + NSString *markerId1 = @"m1"; + NSString *markerId2 = @"m2"; + + FGMPlatformPoint *zeroPoint = [FGMPlatformPoint makeWithX:0 y:0]; + FGMPlatformLatLng *zeroLatLng = [FGMPlatformLatLng makeWithLatitude:0 longitude:0]; + FGMPlatformBitmap *bitmap = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + FGMPlatformInfoWindow *infoWindow = [FGMPlatformInfoWindow makeWithTitle:@"Info" + snippet:NULL + anchor:zeroPoint]; + FGMPlatformMarker *marker1 = [FGMPlatformMarker makeWithAlpha:1 + anchor:zeroPoint + consumeTapEvents:NO + draggable:NO + flat:NO + icon:bitmap + infoWindow:infoWindow + position:zeroLatLng + rotation:0 + visible:YES + zIndex:1 + markerId:markerId1 + clusterManagerId:clusterManagerId]; + FGMPlatformMarker *marker2 = [FGMPlatformMarker makeWithAlpha:1 + anchor:zeroPoint + consumeTapEvents:NO + draggable:NO + flat:NO + icon:bitmap + infoWindow:infoWindow + position:zeroLatLng + rotation:0 + visible:YES + zIndex:1 + markerId:markerId2 + clusterManagerId:clusterManagerId]; + + [markersController addMarkers:@[ marker1, marker2 ]]; + + FlutterError *error = nil; + + // Invoke clustering + [clusterManagersController invokeClusteringForEachClusterManager]; + + // Verify that the markers were added to the cluster manager + NSArray *clusters1 = + [clusterManagersController clustersWithIdentifier:clusterManagerId error:&error]; + XCTAssertNil(error, @"Error should be nil"); + for (FGMPlatformCluster *cluster in clusters1) { + NSString *cmId = cluster.clusterManagerId; + XCTAssertNotNil(cmId, @"Cluster Manager Identifier should not be nil"); + if ([cmId isEqualToString:clusterManagerId]) { + NSArray *markerIds = cluster.markerIds; + XCTAssertEqual(markerIds.count, 2, @"Cluster should contain two marker"); + XCTAssertTrue([markerIds containsObject:markerId1], @"Cluster should contain markerId1"); + XCTAssertTrue([markerIds containsObject:markerId2], @"Cluster should contain markerId2"); + return; + } + } + + [markersController removeMarkersWithIdentifiers:@[ markerId2 ]]; + + // Verify that the marker2 is removed from the clusterManager + NSArray *clusters2 = + [clusterManagersController clustersWithIdentifier:clusterManagerId error:&error]; + XCTAssertNil(error, @"Error should be nil"); + + for (FGMPlatformCluster *cluster in clusters2) { + NSString *cmId = cluster.clusterManagerId; + XCTAssertNotNil(cmId, @"Cluster Manager ID should not be nil"); + if ([cmId isEqualToString:clusterManagerId]) { + NSArray *markerIds = cluster.markerIds; + XCTAssertEqual(markerIds.count, 1, @"Cluster should contain one marker"); + XCTAssertTrue([markerIds containsObject:markerId1], @"Cluster should contain markerId1"); + return; + } + } + + [markersController removeMarkersWithIdentifiers:@[ markerId1 ]]; + + // Verify that all markers are removed from clusterManager + NSArray *clusters3 = + [clusterManagersController clustersWithIdentifier:clusterManagerId error:&error]; + XCTAssertNil(error, @"Error should be nil"); + XCTAssertEqual(clusters3.count, 0, @"Cluster Manager should not contain any clusters"); + + // Remove cluster manager + [clusterManagersController removeClusterManagersWithIdentifiers:@[ clusterManagerId ]]; + + // Verify that the cluster manager is removed + clusterManager = [clusterManagersController clusterManagerWithIdentifier:clusterManagerId]; + XCTAssertNil(clusterManager, @"Cluster Manager should be nil"); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMConversionsUtilsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMConversionsUtilsTests.m new file mode 100644 index 000000000000..ea39943cf571 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMConversionsUtilsTests.m @@ -0,0 +1,429 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +@interface FGMConversionUtilsTests : XCTestCase +@end + +@implementation FGMConversionUtilsTests + +- (void)testGetValueOrNilWithValue { + NSString *key = @"key"; + NSString *value = @"value"; + NSDictionary *dict = @{key : value}; + + XCTAssertEqual(FGMGetValueOrNilFromDict(dict, key), value); +} + +- (void)testGetValueOrNilWithNoEntry { + NSString *key = @"key"; + NSDictionary *dict = @{}; + + XCTAssertNil(FGMGetValueOrNilFromDict(dict, key)); +} + +- (void)testGetValueOrNilWithNSNull { + NSString *key = @"key"; + NSDictionary *dict = @{key : [NSNull null]}; + + XCTAssertNil(FGMGetValueOrNilFromDict(dict, key)); +} + +- (void)testColorFromPlatformColor { + double platformRed = 1 / 255.0; + double platformGreen = 2 / 255.0; + double platformBlue = 3 / 255.0; + double platformAlpha = 4 / 255.0; + UIColor *color = FGMGetColorForPigeonColor([FGMPlatformColor makeWithRed:platformRed + green:platformGreen + blue:platformBlue + alpha:platformAlpha]); + CGFloat red, green, blue, alpha; + BOOL success = [color getRed:&red green:&green blue:&blue alpha:&alpha]; + XCTAssertTrue(success); + const CGFloat accuracy = 0.0001; + XCTAssertEqualWithAccuracy(red, platformRed, accuracy); + XCTAssertEqualWithAccuracy(green, platformGreen, accuracy); + XCTAssertEqualWithAccuracy(blue, platformBlue, accuracy); + XCTAssertEqualWithAccuracy(alpha, platformAlpha, accuracy); +} + +- (void)testPlatformColorFromColor { + double red = 1 / 255.0; + double green = 2 / 255.0; + double blue = 3 / 255.0; + double alpha = 4 / 255.0; + UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; + FGMPlatformColor *platformColor = FGMGetPigeonColorForColor(color); + const CGFloat accuracy = 0.0001; + XCTAssertEqualWithAccuracy(red, platformColor.red, accuracy); + XCTAssertEqualWithAccuracy(green, platformColor.green, accuracy); + XCTAssertEqualWithAccuracy(blue, platformColor.blue, accuracy); + XCTAssertEqualWithAccuracy(alpha, platformColor.alpha, accuracy); +} + +- (void)testPointsFromLatLongs { + NSArray *latlongs = @[ + [FGMPlatformLatLng makeWithLatitude:1 longitude:2], [FGMPlatformLatLng makeWithLatitude:3 + longitude:4] + ]; + NSArray *locations = FGMGetPointsForPigeonLatLngs(latlongs); + XCTAssertEqual(locations.count, 2); + XCTAssertEqual(locations[0].coordinate.latitude, 1); + XCTAssertEqual(locations[0].coordinate.longitude, 2); + XCTAssertEqual(locations[1].coordinate.latitude, 3); + XCTAssertEqual(locations[1].coordinate.longitude, 4); +} + +- (void)testHolesFromPointsArray { + NSArray *> *pointsArray = @[ + @[ + [FGMPlatformLatLng makeWithLatitude:1 longitude:2], [FGMPlatformLatLng makeWithLatitude:3 + longitude:4] + ], + @[ + [FGMPlatformLatLng makeWithLatitude:5 longitude:6], [FGMPlatformLatLng makeWithLatitude:7 + longitude:8] + ] + ]; + NSArray *> *holes = FGMGetHolesForPigeonLatLngArrays(pointsArray); + XCTAssertEqual(holes.count, 2); + XCTAssertEqual(holes[0][0].coordinate.latitude, 1); + XCTAssertEqual(holes[0][0].coordinate.longitude, 2); + XCTAssertEqual(holes[0][1].coordinate.latitude, 3); + XCTAssertEqual(holes[0][1].coordinate.longitude, 4); + XCTAssertEqual(holes[1][0].coordinate.latitude, 5); + XCTAssertEqual(holes[1][0].coordinate.longitude, 6); + XCTAssertEqual(holes[1][1].coordinate.latitude, 7); + XCTAssertEqual(holes[1][1].coordinate.longitude, 8); +} + +- (void)testGetPigeonCameraPositionForPosition { + GMSCameraPosition *position = + [[GMSCameraPosition alloc] initWithTarget:CLLocationCoordinate2DMake(1, 2) + zoom:2.0 + bearing:3.0 + viewingAngle:75.0]; + FGMPlatformCameraPosition *pigeonPosition = FGMGetPigeonCameraPositionForPosition(position); + XCTAssertEqualWithAccuracy(pigeonPosition.target.latitude, position.target.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.target.longitude, position.target.longitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.zoom, position.zoom, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.bearing, position.bearing, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.tilt, position.viewingAngle, DBL_EPSILON); +} + +- (void)testPigeonPointForGCPoint { + CGPoint point = CGPointMake(10, 20); + FGMPlatformPoint *pigeonPoint = FGMGetPigeonPointForCGPoint(point); + XCTAssertEqualWithAccuracy(pigeonPoint.x, point.x, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPoint.y, point.y, DBL_EPSILON); +} + +- (void)testPigeonLatLngBoundsForCoordinateBounds { + GMSCoordinateBounds *bounds = + [[GMSCoordinateBounds alloc] initWithCoordinate:CLLocationCoordinate2DMake(10, 20) + coordinate:CLLocationCoordinate2DMake(30, 40)]; + FGMPlatformLatLngBounds *pigeonBounds = FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds); + XCTAssertEqualWithAccuracy(pigeonBounds.southwest.latitude, bounds.southWest.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonBounds.southwest.longitude, bounds.southWest.longitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonBounds.northeast.latitude, bounds.northEast.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonBounds.northeast.longitude, bounds.northEast.longitude, + DBL_EPSILON); +} + +- (void)testGetCameraPostionForPigeonCameraPosition { + FGMPlatformCameraPosition *pigeonCameraPosition = [FGMPlatformCameraPosition + makeWithBearing:1.0 + target:[FGMPlatformLatLng makeWithLatitude:2.0 longitude:3.0] + tilt:4.0 + zoom:5.0]; + + GMSCameraPosition *cameraPosition = + FGMGetCameraPositionForPigeonCameraPosition(pigeonCameraPosition); + + XCTAssertEqualWithAccuracy(cameraPosition.target.latitude, pigeonCameraPosition.target.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.target.longitude, pigeonCameraPosition.target.longitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.zoom, pigeonCameraPosition.zoom, DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.bearing, pigeonCameraPosition.bearing, DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.viewingAngle, pigeonCameraPosition.tilt, DBL_EPSILON); +} + +- (void)testCGPointForPigeonPoint { + FGMPlatformPoint *pigeonPoint = [FGMPlatformPoint makeWithX:1.0 y:2.0]; + + CGPoint point = FGMGetCGPointForPigeonPoint(pigeonPoint); + + XCTAssertEqualWithAccuracy(pigeonPoint.x, point.x, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPoint.y, point.y, DBL_EPSILON); +} + +- (void)testCoordinateBoundsFromLatLongs { + FGMPlatformLatLngBounds *pigeonBounds = [FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng makeWithLatitude:3 longitude:4] + southwest:[FGMPlatformLatLng makeWithLatitude:1 longitude:2]]; + + GMSCoordinateBounds *bounds = FGMGetCoordinateBoundsForPigeonLatLngBounds(pigeonBounds); + + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(bounds.southWest.latitude, 1, accuracy); + XCTAssertEqualWithAccuracy(bounds.southWest.longitude, 2, accuracy); + XCTAssertEqualWithAccuracy(bounds.northEast.latitude, 3, accuracy); + XCTAssertEqualWithAccuracy(bounds.northEast.longitude, 4, accuracy); +} + +- (void)testMapViewTypeFromPigeonType { + XCTAssertEqual(kGMSTypeNormal, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeNormal)); + XCTAssertEqual(kGMSTypeSatellite, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeSatellite)); + XCTAssertEqual(kGMSTypeTerrain, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeTerrain)); + XCTAssertEqual(kGMSTypeHybrid, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeHybrid)); + XCTAssertEqual(kGMSTypeNone, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeNone)); +} + +- (void)testCameraUpdateFromNewCameraPosition { + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMPlatformCameraUpdateNewCameraPosition *newPositionUpdate = + [FGMPlatformCameraUpdateNewCameraPosition + makeWithCameraPosition:[FGMPlatformCameraPosition + makeWithBearing:4 + target:[FGMPlatformLatLng makeWithLatitude:1 + longitude:2] + tilt:5 + zoom:3]]; + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:newPositionUpdate]); + [[classMockCameraUpdate expect] + setCamera:FGMGetCameraPositionForPigeonCameraPosition(newPositionUpdate.cameraPosition)]; + [classMockCameraUpdate stopMocking]; +} + +// TODO(cyanglaz): Fix the test for cameraUpdateFromArray with the "NewLatlng" key. +// 2 approaches have been tried and neither worked for the tests. +// +// 1. Use OCMock to vefiry that [GMSCameraUpdate setTarget:] is triggered with the correct value. +// This class method conflicts with certain category method in OCMock, causing OCMock not able to +// disambigious them. +// +// 2. Directly verify the GMSCameraUpdate object returned by the method. +// The GMSCameraUpdate object returned from the method doesn't have any accessors to the "target" +// property. It can be used to update the "camera" property in GMSMapView. However, [GMSMapView +// moveCamera:] doesn't update the camera immediately. Thus the GMSCameraUpdate object cannot be +// verified. +// +// The code in below test uses the 2nd approach. +- (void)skip_testCameraUpdateFromNewLatLong { + const CGFloat lat = 1; + const CGFloat lng = 2; + FGMPlatformCameraUpdateNewLatLng *platformUpdate = [FGMPlatformCameraUpdateNewLatLng + makeWithLatLng:[FGMPlatformLatLng makeWithLatitude:lat longitude:lng]]; + + GMSCameraUpdate *update = FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init]; + options.frame = CGRectZero; + options.camera = [GMSCameraPosition cameraWithTarget:CLLocationCoordinate2DMake(5, 6) zoom:1]; + GMSMapView *mapView = [[GMSMapView alloc] initWithOptions:options]; + [mapView moveCamera:update]; + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(mapView.camera.target.latitude, lat, + accuracy); // mapView.camera.target.latitude is still 5. + XCTAssertEqualWithAccuracy(mapView.camera.target.longitude, lng, + accuracy); // mapView.camera.target.longitude is still 6. +} + +- (void)testCameraUpdateFromNewLatLngBounds { + FGMPlatformLatLngBounds *pigeonBounds = [FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng makeWithLatitude:1 longitude:2] + southwest:[FGMPlatformLatLng makeWithLatitude:3 longitude:4]]; + GMSCoordinateBounds *bounds = FGMGetCoordinateBoundsForPigeonLatLngBounds(pigeonBounds); + + const CGFloat padding = 20; + FGMPlatformCameraUpdateNewLatLngBounds *platformUpdate = [FGMPlatformCameraUpdateNewLatLngBounds + makeWithBounds:FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds) + padding:padding]; + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] fitBounds:bounds withPadding:padding]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromNewLatLngZoom { + const CGFloat lat = 1; + const CGFloat lng = 2; + const CGFloat zoom = 3; + FGMPlatformCameraUpdateNewLatLngZoom *platformUpdate = [FGMPlatformCameraUpdateNewLatLngZoom + makeWithLatLng:[FGMPlatformLatLng makeWithLatitude:lat longitude:lng] + zoom:zoom]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] setTarget:CLLocationCoordinate2DMake(lat, lng) zoom:zoom]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromScrollBy { + const CGFloat x = 1; + const CGFloat y = 2; + FGMPlatformCameraUpdateScrollBy *platformUpdate = [FGMPlatformCameraUpdateScrollBy makeWithDx:x + dy:y]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] scrollByX:x Y:y]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomBy { + const CGFloat zoom = 1; + FGMPlatformCameraUpdateZoomBy *platformUpdateNoPoint = + [FGMPlatformCameraUpdateZoomBy makeWithAmount:zoom focus:nil]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdateNoPoint]); + + [[classMockCameraUpdate expect] zoomBy:zoom]; + + const CGFloat x = 2; + const CGFloat y = 3; + FGMPlatformCameraUpdateZoomBy *platformUpdate = + [FGMPlatformCameraUpdateZoomBy makeWithAmount:zoom focus:[FGMPlatformPoint makeWithX:x y:y]]; + + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomBy:zoom atPoint:CGPointMake(x, y)]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomIn { + FGMPlatformCameraUpdateZoom *platformUpdate = [FGMPlatformCameraUpdateZoom makeWithOut:NO]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomIn]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomOut { + FGMPlatformCameraUpdateZoom *platformUpdate = [FGMPlatformCameraUpdateZoom makeWithOut:YES]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomOut]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomTo { + const CGFloat zoom = 1; + FGMPlatformCameraUpdateZoomTo *platformUpdate = [FGMPlatformCameraUpdateZoomTo makeWithZoom:zoom]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomTo:zoom]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testStrokeStylesFromPatterns { + NSArray *patterns = @[ + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeGap length:@(1)], + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeDash length:@(1)] + ]; + UIColor *strokeColor = UIColor.redColor; + + NSArray *patternStrokeStyle = + FGMGetStrokeStylesFromPatterns(patterns, strokeColor); + + XCTAssertEqual(patternStrokeStyle.count, 2); + + // None of the parameters of `patternStrokeStyle` is observable, so we limit to testing + // the length of this output array. +} + +- (void)testLengthsFromPatterns { + const CGFloat gapLength = 10; + const CGFloat dashLength = 6.4; + NSArray *patterns = @[ + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeGap length:@(gapLength)], + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeDash length:@(dashLength)] + ]; + + NSArray *spanLengths = FGMGetSpanLengthsFromPatterns(patterns); + + XCTAssertEqual(spanLengths.count, 2); + + NSNumber *firstSpanLength = spanLengths[0]; + NSNumber *secondSpanLength = spanLengths[1]; + + XCTAssertEqual(firstSpanLength.doubleValue, gapLength); + XCTAssertEqual(secondSpanLength.doubleValue, dashLength); +} + +- (void)testWeightedDataFromPlatformWeightedData { + CGFloat intensity1 = 3.0; + CGFloat intensity2 = 6.0; + NSArray *data = @[ + [FGMPlatformWeightedLatLng makeWithPoint:[FGMPlatformLatLng makeWithLatitude:10 longitude:20] + weight:intensity1], + [FGMPlatformWeightedLatLng makeWithPoint:[FGMPlatformLatLng makeWithLatitude:30 longitude:40] + weight:intensity2], + ]; + + NSArray *weightedData = FGMGetWeightedDataForPigeonWeightedData(data); + XCTAssertEqual([weightedData[0] intensity], intensity1); + XCTAssertEqual([weightedData[1] intensity], intensity2); +} + +- (void)testGradientFromPlatformGradient { + CGFloat startPoint = 0.6; + CGFloat platformRed = 0.1; + CGFloat platformGreen = 0.2; + CGFloat platformBlue = 0.3; + CGFloat platformAlpha = 0.4; + NSInteger colorMapSize = 200; + FGMPlatformHeatmapGradient *platformGradient = + [FGMPlatformHeatmapGradient makeWithColors:@[ [FGMPlatformColor makeWithRed:platformRed + green:platformGreen + blue:platformBlue + alpha:platformAlpha] ] + startPoints:@[ @(startPoint) ] + colorMapSize:colorMapSize]; + + GMUGradient *gradient = FGMGetGradientForPigeonHeatmapGradient(platformGradient); + CGFloat red, green, blue, alpha; + [[gradient colors][0] getRed:&red green:&green blue:&blue alpha:&alpha]; + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(red, platformRed, accuracy); + XCTAssertEqualWithAccuracy(green, platformGreen, accuracy); + XCTAssertEqualWithAccuracy(blue, platformBlue, accuracy); + XCTAssertEqualWithAccuracy(alpha, platformAlpha, accuracy); + XCTAssertEqualWithAccuracy([[gradient startPoints][0] doubleValue], startPoint, accuracy); + XCTAssertEqual([gradient mapSize], colorMapSize); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m new file mode 100644 index 000000000000..2b0134d3ef9b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m @@ -0,0 +1,118 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; +@import GoogleMapsUtils; + +#import "PartiallyMockedMapView.h" + +@interface PropertyOrderValidatingHeatmap : GMUHeatmapTileLayer { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsHeatmapControllerTests : XCTestCase +@end + +@implementation GoogleMapsHeatmapControllerTests + +- (void)testUpdateHeatmapSetsVisibilityLast { + PropertyOrderValidatingHeatmap *heatmap = [[PropertyOrderValidatingHeatmap alloc] init]; + FGMPlatformHeatmapGradient *gradient = [FGMPlatformHeatmapGradient makeWithColors:@[ + [FGMPlatformColor makeWithRed:0 green:0 blue:0 alpha:0], + [FGMPlatformColor makeWithRed:1.0 green:1.0 blue:1.0 alpha:1.0], + ] + startPoints:@[ @(0), @(1) ] + colorMapSize:256]; + [FLTGoogleMapHeatmapController + updateHeatmap:heatmap + fromPlatformHeatmap:[FGMPlatformHeatmap + makeWithHeatmapId:@"heatmap" + data:@[ + [FGMPlatformWeightedLatLng + makeWithPoint:[FGMPlatformLatLng + makeWithLatitude:5.0 + longitude:5.0] + weight:0.5], + [FGMPlatformWeightedLatLng + makeWithPoint:[FGMPlatformLatLng + makeWithLatitude:10.0 + longitude:10.0] + weight:0.75], + ] + gradient:gradient + opacity:0.5 + radius:1 + minimumZoomIntensity:1 + maximumZoomIntensity:2] + withMapView:[GoogleMapsHeatmapControllerTests mapView]]; + XCTAssertTrue(heatmap.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingHeatmap + +- (void)setWeightedData:(NSArray *)weightedData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.weightedData = weightedData; +} + +- (void)setRadius:(NSUInteger)radius { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.radius = radius; +} + +- (void)setGradient:(GMUGradient *)gradient { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.gradient = gradient; +} + +- (void)setMinimumZoomIntensity:(NSUInteger)minimumZoomIntensity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.minimumZoomIntensity = minimumZoomIntensity; +} + +- (void)setMaximumZoomIntensity:(NSUInteger)maximumZoomIntensity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.maximumZoomIntensity = maximumZoomIntensity; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setTileSize:(NSInteger)tileSize { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tileSize = tileSize; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setFadeIn:(BOOL)fadeIn { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fadeIn = fadeIn; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTTileProviderControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTTileProviderControllerTests.m new file mode 100644 index 000000000000..3c7f43b3c206 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTTileProviderControllerTests.m @@ -0,0 +1,36 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import XCTest; +@import GoogleMaps; +@import google_maps_flutter_ios; + +#import + +@interface FLTTileProviderControllerTests : XCTestCase +@end + +@implementation FLTTileProviderControllerTests + +- (void)testCallChannelOnPlatformThread { + id handler = OCMClassMock([FGMMapsCallbackApi class]); + FLTTileProviderController *controller = + [[FLTTileProviderController alloc] initWithTileOverlayIdentifier:@"foo" + callbackHandler:handler]; + XCTAssertNotNil(controller); + XCTestExpectation *expectation = [self expectationWithDescription:@"invokeMethod"]; + OCMStub([handler tileWithOverlayIdentifier:[OCMArg any] + location:[OCMArg any] + zoom:0 + completion:[OCMArg any]]) + .andDo(^(NSInvocation *invocation) { + XCTAssertTrue([[NSThread currentThread] isMainThread]); + [expectation fulfill]; + }); + id receiver = OCMProtocolMock(@protocol(GMSTileReceiver)); + [controller requestTileForX:0 y:0 zoom:0 receiver:receiver]; + [self waitForExpectations:@[ expectation ] timeout:10.0]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m new file mode 100644 index 000000000000..7514a70704f5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m @@ -0,0 +1,104 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import "PartiallyMockedMapView.h" + +/// A GMSCircle that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingCircle : GMSCircle { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsCircleControllerTests : XCTestCase +@end + +@implementation GoogleMapsCircleControllerTests + +- (void)testUpdateCircleSetsVisibilityLast { + PropertyOrderValidatingCircle *circle = [[PropertyOrderValidatingCircle alloc] init]; + [FLTGoogleMapCircleController + updateCircle:circle + fromPlatformCircle:[FGMPlatformCircle + makeWithConsumeTapEvents:NO + fillColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + strokeColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + visible:YES + strokeWidth:0 + zIndex:0 + center:[FGMPlatformLatLng makeWithLatitude:0 + longitude:0] + radius:10 + circleId:@"circle"] + withMapView:[GoogleMapsCircleControllerTests mapView]]; + XCTAssertTrue(circle.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingCircle +- (void)setPosition:(CLLocationCoordinate2D)position { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.position = position; +} + +- (void)setRadius:(CLLocationDistance)radius { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.radius = radius; +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeWidth = strokeWidth; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeColor = strokeColor; +} + +- (void)setFillColor:(UIColor *)fillColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fillColor = fillColor; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m new file mode 100644 index 000000000000..9169d6064956 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -0,0 +1,281 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +/// A GMSGroundOverlay that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingGroundOverlay : GMSGroundOverlay { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsGroundOverlayControllerTests : XCTestCase +@end + +@implementation GoogleMapsGroundOverlayControllerTests + +/// Returns GoogleMapGroundOverlayController object instantiated with position and a mocked map +/// instance. +/// +/// @return An object of FLTGoogleMapGroundOverlayController ++ (FGMGroundOverlayController *)groundOverlayControllerWithPositionWithMockedMap { + NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"widegamut" + ofType:@"png" + inDirectory:@"assets"]; + UIImage *wideGamutImage = [UIImage imageWithContentsOfFile:imagePath]; + GMSGroundOverlay *groundOverlay = + [GMSGroundOverlay groundOverlayWithPosition:CLLocationCoordinate2DMake(52.4816, 3.1791) + icon:wideGamutImage + zoomLevel:14.0]; + + GMSMapView *mapView = [GoogleMapsGroundOverlayControllerTests mapView]; + + return [[FGMGroundOverlayController alloc] initWithGroundOverlay:groundOverlay + identifier:@"id_1" + mapView:mapView + isCreatedWithBounds:NO]; +} + +/// Returns GoogleMapGroundOverlayController object instantiated with bounds and a mocked map +/// instance. +/// +/// @return An object of FLTGoogleMapGroundOverlayController ++ (FGMGroundOverlayController *)groundOverlayControllerWithBoundsWithMockedMap { + NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"widegamut" + ofType:@"png" + inDirectory:@"assets"]; + UIImage *wideGamutImage = [UIImage imageWithContentsOfFile:imagePath]; + GMSGroundOverlay *groundOverlay = [GMSGroundOverlay + groundOverlayWithBounds:[[GMSCoordinateBounds alloc] + initWithCoordinate:CLLocationCoordinate2DMake(10, 20) + coordinate:CLLocationCoordinate2DMake(30, 40)] + icon:wideGamutImage]; + + GMSMapView *mapView = [GoogleMapsGroundOverlayControllerTests mapView]; + + return [[FGMGroundOverlayController alloc] initWithGroundOverlay:groundOverlay + identifier:@"id_1" + mapView:mapView + isCreatedWithBounds:YES]; +} + +- (void)testUpdatingGroundOverlayWithPosition { + FGMGroundOverlayController *groundOverlayController = + [GoogleMapsGroundOverlayControllerTests groundOverlayControllerWithPositionWithMockedMap]; + + FGMPlatformLatLng *position = [FGMPlatformLatLng makeWithLatitude:52.4816 longitude:3.1791]; + + FGMPlatformBitmap *bitmap = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + + FGMPlatformGroundOverlay *platformGroundOverlay = + [FGMPlatformGroundOverlay makeWithGroundOverlayId:@"id_1" + image:bitmap + position:position + bounds:nil + anchor:[FGMPlatformPoint makeWithX:0.5 y:0.5] + transparency:0.5 + bearing:65.0 + zIndex:2.0 + visible:true + clickable:true + zoomLevel:@14.0]; + + [groundOverlayController updateFromPlatformGroundOverlay:platformGroundOverlay + registrar:mockRegistrar + screenScale:1.0]; + + XCTAssertNotNil(groundOverlayController.groundOverlay.icon); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.position.latitude, + position.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.position.longitude, + position.longitude, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.opacity, platformGroundOverlay.transparency); + XCTAssertEqual(groundOverlayController.groundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.zIndex, platformGroundOverlay.zIndex); + + FGMPlatformGroundOverlay *convertedPlatformGroundOverlay = + FGMGetPigeonGroundOverlay(groundOverlayController.groundOverlay, @"id_1", NO, @14.0); + XCTAssertEqualObjects(convertedPlatformGroundOverlay.groundOverlayId, @"id_1"); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.position.latitude, position.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.position.longitude, position.longitude, + DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.zoomLevel.doubleValue, 14.0); + XCTAssertEqual(convertedPlatformGroundOverlay.transparency, platformGroundOverlay.transparency); + XCTAssertEqual(convertedPlatformGroundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.zIndex, platformGroundOverlay.zIndex); +} + +- (void)testUpdatingGroundOverlayWithBounds { + FGMGroundOverlayController *groundOverlayController = + [GoogleMapsGroundOverlayControllerTests groundOverlayControllerWithBoundsWithMockedMap]; + + FGMPlatformLatLngBounds *bounds = [FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng makeWithLatitude:54.4816 longitude:5.1791] + southwest:[FGMPlatformLatLng makeWithLatitude:52.4816 longitude:3.1791]]; + + FGMPlatformBitmap *bitmap = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + + FGMPlatformGroundOverlay *platformGroundOverlay = + [FGMPlatformGroundOverlay makeWithGroundOverlayId:@"id_1" + image:bitmap + position:nil + bounds:bounds + anchor:[FGMPlatformPoint makeWithX:0.5 y:0.5] + transparency:0.5 + bearing:65.0 + zIndex:2.0 + visible:true + clickable:true + zoomLevel:nil]; + + [groundOverlayController updateFromPlatformGroundOverlay:platformGroundOverlay + registrar:mockRegistrar + screenScale:1.0]; + + XCTAssertNotNil(groundOverlayController.groundOverlay.icon); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.northEast.latitude, + bounds.northeast.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.northEast.longitude, + bounds.northeast.longitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.southWest.latitude, + bounds.southwest.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.southWest.longitude, + bounds.southwest.longitude, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.opacity, platformGroundOverlay.transparency); + XCTAssertEqual(groundOverlayController.groundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.zIndex, platformGroundOverlay.zIndex); + + FGMPlatformGroundOverlay *convertedPlatformGroundOverlay = + FGMGetPigeonGroundOverlay(groundOverlayController.groundOverlay, @"id_1", YES, nil); + XCTAssertEqualObjects(convertedPlatformGroundOverlay.groundOverlayId, @"id_1"); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.northeast.latitude, + bounds.northeast.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.northeast.longitude, + bounds.northeast.longitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.southwest.latitude, + bounds.southwest.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.southwest.longitude, + bounds.southwest.longitude, DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.transparency, platformGroundOverlay.transparency); + XCTAssertEqual(convertedPlatformGroundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.zIndex, platformGroundOverlay.zIndex); +} + +- (void)testUpdateGroundOverlaySetsVisibilityLast { + PropertyOrderValidatingGroundOverlay *groundOverlay = + [[PropertyOrderValidatingGroundOverlay alloc] init]; + [FGMGroundOverlayController + updateGroundOverlay:groundOverlay + fromPlatformGroundOverlay: + [FGMPlatformGroundOverlay + makeWithGroundOverlayId:@"groundOverlay" + image:[FGMPlatformBitmap + makeWithBitmap:[FGMPlatformBitmapDefaultMarker + makeWithHue:@0]] + position:[FGMPlatformLatLng makeWithLatitude:0 longitude:0] + bounds:[FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng + makeWithLatitude:54.4816 + longitude:5.1791] + southwest:[FGMPlatformLatLng + makeWithLatitude:52.4816 + longitude:3.1791]] + anchor:[FGMPlatformPoint makeWithX:0.5 y:0.5] + transparency:0.5 + bearing:65.0 + zIndex:2.0 + visible:YES + clickable:YES + zoomLevel:nil] + withMapView:[GoogleMapsGroundOverlayControllerTests mapView] + registrar:nil + screenScale:1.0 + usingBounds:YES]; + XCTAssertTrue(groundOverlay.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingGroundOverlay + +- (void)setPosition:(CLLocationCoordinate2D)position { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.position = position; +} + +- (void)setAnchor:(CGPoint)anchor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.anchor = anchor; +} + +- (void)setIcon:(UIImage *)icon { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.icon = icon; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setBearing:(CLLocationDirection)bearing { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.bearing = bearing; +} + +- (void)setBounds:(GMSCoordinateBounds *)bounds { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.bounds = bounds; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m new file mode 100644 index 000000000000..bac3fb2cc84e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -0,0 +1,361 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import + +#import "PartiallyMockedMapView.h" + +/// A GMSMarker that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingMarker : GMSMarker { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsMarkerControllerTests : XCTestCase +@end + +@implementation GoogleMapsMarkerControllerTests + +/// Returns a simple map view for use with marker controllers. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +/// Returns a FLTMarkersController instance instantiated with the given map view. +/// +/// The mapView should outlive the controller, as the controller keeps a weak reference to it. +- (FLTMarkersController *)markersControllerWithMapView:(GMSMapView *)mapView { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + return [[FLTMarkersController alloc] initWithMapView:mapView + callbackHandler:[[FGMMapsCallbackApi alloc] init] + clusterManagersController:nil + registrar:mockRegistrar]; +} + +- (FGMPlatformBitmap *)placeholderBitmap { + return [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:@0]]; +} + +- (void)testSetsMarkerNumericProperties { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + double anchorX = 3.14; + double anchorY = 2.718; + double alpha = 0.4; + double rotation = 90.0; + double zIndex = 3.0; + double latitutde = 10.0; + double longitude = 20.0; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:alpha + anchor:[FGMPlatformPoint makeWithX:anchorX y:anchorY] + consumeTapEvents:YES + draggable:YES + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:latitutde + longitude:longitude] + rotation:rotation + visible:YES + zIndex:zIndex + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + const double delta = 0.0001; + XCTAssertEqualWithAccuracy(marker.opacity, alpha, delta); + XCTAssertEqualWithAccuracy(marker.rotation, rotation, delta); + XCTAssertEqualWithAccuracy(marker.zIndex, zIndex, delta); + XCTAssertEqualWithAccuracy(marker.groundAnchor.x, anchorX, delta); + XCTAssertEqualWithAccuracy(marker.groundAnchor.y, anchorY, delta); + XCTAssertEqualWithAccuracy(marker.position.latitude, latitutde, delta); + XCTAssertEqualWithAccuracy(marker.position.longitude, longitude, delta); +} + +// Boolean properties are tested individually to ensure they aren't accidentally cross-assigned from +// another property. +- (void)testSetsDraggable { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:NO + draggable:YES + flat:NO + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0.0 longitude:0.0] + rotation:0 + visible:NO + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + XCTAssertTrue(marker.draggable); +} + +// Boolean properties are tested individually to ensure they aren't accidentally cross-assigned from +// another property. +- (void)testSetsFlat { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:NO + draggable:NO + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0.0 longitude:0.0] + rotation:0 + visible:NO + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + XCTAssertTrue(marker.flat); +} + +// Boolean properties are tested individually to ensure they aren't accidentally cross-assigned from +// another property. +- (void)testSetsVisible { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:NO + draggable:NO + flat:NO + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0.0 longitude:0.0] + rotation:0 + visible:YES + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + // Visibility is controlled by being set to a map. + XCTAssertNotNil(marker.map); +} + +- (void)testSetsMarkerInfoWindowProperties { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + NSString *title = @"info title"; + NSString *snippet = @"info snippet"; + double anchorX = 3.14; + double anchorY = 2.718; + [controller + addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:YES + draggable:YES + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:title + snippet:snippet + anchor:[FGMPlatformPoint makeWithX:anchorX + y:anchorY]] + position:[FGMPlatformLatLng makeWithLatitude:0 longitude:0] + rotation:0 + visible:YES + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + const double delta = 0.0001; + XCTAssertEqualWithAccuracy(marker.infoWindowAnchor.x, anchorX, delta); + XCTAssertEqualWithAccuracy(marker.infoWindowAnchor.y, anchorY, delta); + XCTAssertEqual(marker.title, title); + XCTAssertEqual(marker.snippet, snippet); +} + +- (void)testUpdateMarkerSetsVisibilityLast { + PropertyOrderValidatingMarker *marker = [[PropertyOrderValidatingMarker alloc] init]; + [FLTGoogleMapMarkerController + updateMarker:marker + fromPlatformMarker:[FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:YES + draggable:YES + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint + makeWithX:0 + y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0 + longitude:0] + rotation:0 + visible:YES + zIndex:0 + markerId:@"marker" + clusterManagerId:nil] + withMapView:[GoogleMapsMarkerControllerTests mapView] + registrar:nil + screenScale:1 + usingOpacityForVisibility:NO]; + XCTAssertTrue(marker.hasSetMap); +} + +@end + +@implementation PropertyOrderValidatingMarker + +- (void)setPosition:(CLLocationCoordinate2D)position { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.position = position; +} + +- (void)setSnippet:(NSString *)snippet { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.snippet = snippet; +} + +- (void)setIcon:(UIImage *)icon { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.icon = icon; +} + +- (void)setIconView:(UIView *)iconView { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.iconView = iconView; +} + +- (void)setTracksViewChanges:(BOOL)tracksViewChanges { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tracksViewChanges = tracksViewChanges; +} + +- (void)setTracksInfoWindowChanges:(BOOL)tracksInfoWindowChanges { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tracksInfoWindowChanges = tracksInfoWindowChanges; +} + +- (void)setGroundAnchor:(CGPoint)groundAnchor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.groundAnchor = groundAnchor; +} + +- (void)setInfoWindowAnchor:(CGPoint)infoWindowAnchor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.infoWindowAnchor = infoWindowAnchor; +} + +- (void)setAppearAnimation:(GMSMarkerAnimation)appearAnimation { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.appearAnimation = appearAnimation; +} + +- (void)setDraggable:(BOOL)draggable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.draggable = draggable; +} + +- (void)setFlat:(BOOL)flat { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.flat = flat; +} + +- (void)setRotation:(CLLocationDegrees)rotation { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.rotation = rotation; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setPanoramaView:(GMSPanoramaView *)panoramaView { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.panoramaView = panoramaView; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setUserData:(id)userData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.userData = userData; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m new file mode 100644 index 000000000000..2cb386e0fc55 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m @@ -0,0 +1,112 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +/// A GMSPolygon that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingPolygon : GMSPolygon { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsPolygonControllerTests : XCTestCase +@end + +@implementation GoogleMapsPolygonControllerTests + +- (void)testUpdatePolygonSetsVisibilityLast { + PropertyOrderValidatingPolygon *polygon = [[PropertyOrderValidatingPolygon alloc] init]; + [FLTGoogleMapPolygonController + updatePolygon:polygon + fromPlatformPolygon:[FGMPlatformPolygon + makeWithConsumeTapEvents:NO + fillColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + geodesic:NO + holes:@[] + strokeColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + strokeWidth:0 + visible:YES + zIndex:0 + points:@[] + polygonId:@"polygon"] + withMapView:[GoogleMapsPolygonControllerTests mapView]]; + XCTAssertTrue(polygon.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingPolygon +- (void)setPath:(GMSPath *)path { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.path = path; +} + +- (void)setHoles:(NSArray *)holes { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.holes = holes; +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeWidth = strokeWidth; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeColor = strokeColor; +} + +- (void)setFillColor:(UIColor *)fillColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fillColor = fillColor; +} + +- (void)setGeodesic:(BOOL)geodesic { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.geodesic = geodesic; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setUserData:(id)userData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.userData = userData; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m new file mode 100644 index 000000000000..19ca6e84a266 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m @@ -0,0 +1,181 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +/// A GMSPolyline that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingPolyline : GMSPolyline { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsPolylineControllerTests : XCTestCase +@end + +@implementation GoogleMapsPolylineControllerTests + +/// Returns GoogleMapPolylineController object instantiated with a mocked map instance +/// +/// @return An object of FLTGoogleMapPolylineController +- (FLTGoogleMapPolylineController *)polylineControllerWithMockedMap { + FGMPlatformPolyline *polyline = [FGMPlatformPolyline + makeWithPolylineId:@"polyline_id_0" + consumesTapEvents:NO + color:[FGMPlatformColor makeWithRed:0 green:0 blue:0 alpha:0] + geodesic:NO + jointType:FGMPlatformJointTypeRound + patterns:@[] + points:[GoogleMapsPolylineControllerTests polylinePoints] + visible:NO + width:1 + zIndex:0]; + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSCameraPosition *camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + mapViewOptions.camera = camera; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + GMSMutablePath *path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(polyline.points)); + + FLTGoogleMapPolylineController *polylineControllerWithMockedMap = + [[FLTGoogleMapPolylineController alloc] initWithPath:path + identifier:polyline.polylineId + mapView:mapView]; + + return polylineControllerWithMockedMap; +} + +- (void)testPatternsSetSpans { + FLTGoogleMapPolylineController *polylineController = [self polylineControllerWithMockedMap]; + + XCTAssertNil(polylineController.polyline.spans); + + [polylineController + updateFromPlatformPolyline:[FGMPlatformPolyline + makeWithPolylineId:@"polyline_id_0" + consumesTapEvents:NO + color:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + geodesic:NO + jointType:FGMPlatformJointTypeRound + patterns:@[ + [FGMPlatformPatternItem + makeWithType:FGMPlatformPatternItemTypeDot + length:@(10)], + [FGMPlatformPatternItem + makeWithType:FGMPlatformPatternItemTypeDash + length:@(10)] + ] + points:[GoogleMapsPolylineControllerTests + polylinePoints] + visible:YES + width:1 + zIndex:0]]; + + // `GMSStyleSpan` doesn't implement `isEqual` so cannot be compared by value at present. + XCTAssertNotNil(polylineController.polyline.spans); +} + +- (void)testUpdatePolylineSetsVisibilityLast { + PropertyOrderValidatingPolyline *polyline = [[PropertyOrderValidatingPolyline alloc] init]; + [FLTGoogleMapPolylineController + updatePolyline:polyline + fromPlatformPolyline:[FGMPlatformPolyline + makeWithPolylineId:@"polyline" + consumesTapEvents:NO + color:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + geodesic:NO + jointType:FGMPlatformJointTypeRound + patterns:@[] + points:[GoogleMapsPolylineControllerTests polylinePoints] + visible:YES + width:1 + zIndex:0] + withMapView:[GoogleMapsPolylineControllerTests mapView]]; + XCTAssertTrue(polyline.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +/// Returns a set of points to use for tests that need a valid but arbitrary line. ++ (NSArray *)polylinePoints { + return @[ + [FGMPlatformLatLng makeWithLatitude:52.4816 longitude:-3.1791], + [FGMPlatformLatLng makeWithLatitude:54.043 longitude:-2.9925], + [FGMPlatformLatLng makeWithLatitude:54.1396 longitude:-4.2739], + [FGMPlatformLatLng makeWithLatitude:53.4153 longitude:-4.0829], + ]; +} + +@end + +@implementation PropertyOrderValidatingPolyline + +- (void)setPath:(GMSPath *)path { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.path = path; +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeWidth = strokeWidth; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeColor = strokeColor; +} + +- (void)setGeodesic:(BOOL)geodesic { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.geodesic = geodesic; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setUserData:(id)userData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.userData = userData; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.m new file mode 100644 index 000000000000..ecbef7b3924e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.m @@ -0,0 +1,212 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "FGMCATransactionWrapper.h" +#import "PartiallyMockedMapView.h" + +@interface FLTGoogleMapFactory (Test) +@property(strong, nonatomic, readonly) id sharedMapServices; +@end + +@interface GoogleMapsTests : XCTestCase +@end + +@interface FLTTileProviderController (Testing) +- (UIImage *)handleResultTile:(nullable UIImage *)tileImage; +@end + +@implementation GoogleMapsTests + +- (void)testPlugin { + FLTGoogleMapsPlugin *plugin = [[FLTGoogleMapsPlugin alloc] init]; + XCTAssertNotNil(plugin); +} + +- (void)testFrameObserver { + id registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init]; + options.frame = frame; + options.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:options]; + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + for (NSInteger i = 0; i < 10; ++i) { + [controller view]; + } + XCTAssertEqual(mapView.frameObserverCount, 1); + + mapView.frame = frame; + XCTAssertEqual(mapView.frameObserverCount, 0); +} + +- (void)testMapsServiceSync { + id registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + FLTGoogleMapFactory *factory1 = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + XCTAssertNotNil(factory1.sharedMapServices); + FLTGoogleMapFactory *factory2 = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + // Test pointer equality, should be same retained singleton +[GMSServices sharedServices] object. + // Retaining the opaque object should be enough to avoid multiple internal initializations, + // but don't test the internals of the GoogleMaps API. Assume that it does what is documented. + // https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_services#a436e03c32b1c0be74e072310a7158831 + XCTAssertEqual(factory1.sharedMapServices, factory2.sharedMapServices); +} + +- (void)testHandleResultTileDownsamplesWideGamutImages { + FLTTileProviderController *controller = [[FLTTileProviderController alloc] init]; + + NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"widegamut" + ofType:@"png" + inDirectory:@"assets"]; + UIImage *wideGamutImage = [UIImage imageWithContentsOfFile:imagePath]; + + XCTAssertNotNil(wideGamutImage, @"The image should be loaded."); + + UIImage *downsampledImage = [controller handleResultTile:wideGamutImage]; + + CGImageRef imageRef = downsampledImage.CGImage; + size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); + + // non wide gamut images use 8 bit format + XCTAssertEqual(bitsPerComponent, 8); + XCTAssertEqual(CGImageGetAlphaInfo(imageRef), kCGImageAlphaPremultipliedLast); +} + +- (void)testAnimateCameraWithUpdate { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + + // Init camera with zero zoom. + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + id mapViewMock = OCMPartialMock(mapView); + id mockTransactionWrapper = OCMProtocolMock(@protocol(FGMCATransactionProtocol)); + controller.callHandler.transactionWrapper = mockTransactionWrapper; + + FGMPlatformCameraUpdateZoomTo *zoomTo = [FGMPlatformCameraUpdateZoomTo makeWithZoom:10.0]; + FGMPlatformCameraUpdate *cameraUpdate = [FGMPlatformCameraUpdate makeWithCameraUpdate:zoomTo]; + FlutterError *error = nil; + + OCMReject([mockTransactionWrapper begin]); + OCMReject([mockTransactionWrapper commit]); + OCMExpect([mapViewMock animateWithCameraUpdate:[OCMArg any]]); + [controller.callHandler animateCameraWithUpdate:cameraUpdate duration:nil error:&error]; + OCMVerifyAll(mapViewMock); + OCMVerifyAll(mockTransactionWrapper); +} + +- (void)testAnimateCameraWithUpdateAndDuration { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + + // Init camera with zero zoom. + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + id mapViewMock = OCMPartialMock(mapView); + id mockTransactionWrapper = OCMProtocolMock(@protocol(FGMCATransactionProtocol)); + controller.callHandler.transactionWrapper = mockTransactionWrapper; + + FGMPlatformCameraUpdateZoomTo *zoomTo = [FGMPlatformCameraUpdateZoomTo makeWithZoom:10.0]; + FGMPlatformCameraUpdate *cameraUpdate = [FGMPlatformCameraUpdate makeWithCameraUpdate:zoomTo]; + FlutterError *error = nil; + + NSNumber *durationMilliseconds = @100; + OCMExpect([mockTransactionWrapper begin]); + OCMExpect( + [mockTransactionWrapper setAnimationDuration:[durationMilliseconds doubleValue] / 1000]); + OCMExpect([mockTransactionWrapper commit]); + OCMExpect([mapViewMock animateWithCameraUpdate:[OCMArg any]]); + [controller.callHandler animateCameraWithUpdate:cameraUpdate + duration:durationMilliseconds + error:&error]; + OCMVerifyAll(mapViewMock); + OCMVerifyAll(mockTransactionWrapper); +} + +- (void)testInspectorAPICameraPosition { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + + // Init camera with specific position. + GMSCameraPosition *initialCameraPosition = [[GMSCameraPosition alloc] initWithLatitude:37.7749 + longitude:-122.4194 + zoom:10]; + mapViewOptions.camera = initialCameraPosition; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + FGMMapInspector *inspector = [[FGMMapInspector alloc] initWithMapController:controller + messenger:registrar.messenger + pigeonSuffix:@"0"]; + + FlutterError *error = nil; + FGMPlatformCameraPosition *cameraPosition = [inspector cameraPosition:&error]; + + XCTAssertEqual(cameraPosition.target.latitude, initialCameraPosition.target.latitude); + XCTAssertEqual(cameraPosition.target.longitude, initialCameraPosition.target.longitude); + XCTAssertEqual(cameraPosition.zoom, initialCameraPosition.zoom); +} + +/// Creates an empty creation paramaters object for tests where the values don't matter, just that +/// there's a valid object to pass in. +- (FGMPlatformMapViewCreationParams *)emptyCreationParameters { + return [FGMPlatformMapViewCreationParams + makeWithInitialCameraPosition:[FGMPlatformCameraPosition + makeWithBearing:0.0 + target:[FGMPlatformLatLng makeWithLatitude:0.0 + longitude:0.0] + tilt:0.0 + zoom:0.0] + mapConfiguration:[[FGMPlatformMapConfiguration alloc] init] + initialCircles:@[] + initialMarkers:@[] + initialPolygons:@[] + initialPolylines:@[] + initialHeatmaps:@[] + initialTileOverlays:@[] + initialClusterManagers:@[] + initialGroundOverlays:@[]]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m new file mode 100644 index 000000000000..e7b1118a8d56 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m @@ -0,0 +1,73 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import "PartiallyMockedMapView.h" + +/// A GMSTileOverlay that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingTileLayer : GMSTileLayer +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsTileOverlayControllerTests : XCTestCase +@end + +@implementation GoogleMapsTileOverlayControllerTests + +- (void)testUpdateTileOverlaySetsVisibilityLast { + PropertyOrderValidatingTileLayer *tileLayer = [[PropertyOrderValidatingTileLayer alloc] init]; + [FLTGoogleMapTileOverlayController + updateTileLayer:tileLayer + fromPlatformTileOverlay:[FGMPlatformTileOverlay makeWithTileOverlayId:@"overlay" + fadeIn:NO + transparency:0.5 + zIndex:0 + visible:YES + tileSize:1] + withMapView:[GoogleMapsTileOverlayControllerTests mapView]]; + XCTAssertTrue(tileLayer.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingTileLayer + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setTileSize:(NSInteger)tileSize { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tileSize = tileSize; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setFadeIn:(BOOL)fadeIn { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fadeIn = fadeIn; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/Info.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/Info.plist new file mode 100644 index 000000000000..64d65ca49577 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/PartiallyMockedMapView.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/PartiallyMockedMapView.h new file mode 100644 index 000000000000..9a04ae84ab24 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/PartiallyMockedMapView.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import GoogleMaps; + +/** + * Defines a map view used for testing key-value observing. + */ +@interface PartiallyMockedMapView : GMSMapView + +/** + * The number of times that the `frame` KVO has been added. + */ +@property(nonatomic, assign, readonly) NSInteger frameObserverCount; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/PartiallyMockedMapView.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/PartiallyMockedMapView.m new file mode 100644 index 000000000000..47d48d2e07fc --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/PartiallyMockedMapView.m @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "PartiallyMockedMapView.h" + +@interface PartiallyMockedMapView () + +@property(nonatomic, assign) NSInteger frameObserverCount; + +@end + +@implementation PartiallyMockedMapView + +- (void)addObserver:(NSObject *)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + [super addObserver:observer forKeyPath:keyPath options:options context:context]; + + if ([keyPath isEqualToString:@"frame"]) { + ++self.frameObserverCount; + } +} + +- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { + [super removeObserver:observer forKeyPath:keyPath]; + + if ([keyPath isEqualToString:@"frame"]) { + --self.frameObserverCount; + } +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/assets/widegamut.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/assets/widegamut.png new file mode 100644 index 0000000000000000000000000000000000000000..32f032bae3de42c8c7ba9529d2d18ad41e81bede GIT binary patch literal 3025 zcma)84Lp-;8-MnNW=cq#befNPEo?LS*qV>od`25nQR-ORux1~&Vd3PXb2NR9e4SF1 zUI|5tljKb&Ig&Sr)O%1AIh9T)r5vZyInPk^R&VdK-@W_VbzlGgb^WjVe(v8gSgXDD zkS0g~0Q7u)7(w97(+nLg@LM{N6AS>5SOJ~R64Jftl4yyHE#+|e41ru4&DqMb2LP+g zSarjy%PgZS%<`b0DXO`PO-UK_u1;iJOq8{eCovdN&OWehjws0z7ZhW-4mZ9e;Cns6?V*M&7MVqvVupjMA^GyR*6)pVV|pSXR; zVRl(Wb?H$X%;0sqC&fyh|=Z175x1^u*wK=}>MUr;jPX5W7?Z5OD z-dvY=#dJ8ZjbpeBy^|G~3P;>aesg25+g@AQx^NbLAJnFm;XB{3x@q+1BOC)#j1FyB zeNO&(+q{#nuZl!Z7vzhi*9kp69x&%aNA}t9D$#;dR))U$baa%61wP@GCeK^1m@r?)w z0G5Nc4uF6d05H&kfFA&20w5-B0Puq>dT$3o>;Nd}Hv`A|9RdJ89g_skn#TtmAbM)1 z@g$r1SXPuoA(2N(q*&4lydBmmfWsAtH69!o2Q7lW=in8=W^8Z`IDI0{5uD~oeM02` zplhfZ5a2)o8UWyNg5VHENPs_uD-q#2nnZY|NUA{rR3!y8MSKMZs}x0xxhL^Kh602}A zH`gS3|4h}X5Jb#m63eG$fdUDd6@nd}Nca>C6dMrmzQPZ1N{)0ACK7!TDOUvXKa=qt zQXafj$|nTz<&sz#mk)+pe5Qo|UBLUEfRd>iHIz^dXLPKlFRo4`>ZHUEoHGrY0)%`D zFx&ax0H#d92lr$$gWYt3*}hrvlP#n$_%cBppXVi$h$gp6%8|+W8vQQj?;0>$hepa| z2Pp!vT)`1@`MwNSkO?mk@F;W!ZH2v)lan*e%gN5plR;pE}rNMw*4h-8u@gG%@a zI#bUKGf%>e6@e6Px=vbR??|8-_Lf5 z{3Y61&<|-TbQzzckjR21l4#d2-8YlsKR`^AQ3;wibJm+Wbq!2l*#NAlULt5%a@>`%;{;9ls6{t}6ES%b=Ajj-# zN|LW}yIQJT@a%`^cG#BV;)I$tck&QvEY*wS(QelwCbp^0r@pC+?r*J4F`7SCk^ZbW z?AS!Z<95@9yPpn4SfiU_>d1_N{g~qLyW88U(gVvb7^}NEVMrf1DrtT1()0=|bgq0y z_XL z)bcSxRkr0LTZ$WjR=J=eer=ik?cnRL#KR?Cxx3i&LWgmOiT6j>nw>nw)P-}<7aKUr zcFYDfE|t;fo*#v7QqKh$np(m&l#P+gR>3ThUg?~&-}P~z!~NT6q6%jUMwk?Kcz}?` z$Ov7S0m5RCxF%k$57rl@h(k9$oNEd78si}KN$aqI#E2GDJXSZ|@@XC(Qyu=otSfQ{ zEF*;mi!>>@tx58r&C!N_G`#HqW|%=wu|a43G1h4cDm&nk7@>3MQC6)E`uPd18oyJR zx@PtD@SA4>QuRY}+Zz!(mDF2kW2a>ih%pB=6YYF^QAsVaWv;Mzbrbi}@qel!FavtU z|EP*D8QWaA^3}@$GN*v2cZMw(;%;FV99+;@IYDsw+xmVg~tx zG-QLSJdPU}J$uAG%7?(NB_`~7U>YlcF8OoC8aI{_#eQfh-_W^?hTBS=*yz~TTl#G1 zVtq*>g8sVRslb_b$h%*sp!DsCt=L`VZGh zK1vkBztVLn>ic`-)I{)rr2c!;MTzylA}^-j`!n*@QBG0lc~nMP3{$)Mg41IC1l<0& zEp0^|3FnJpylMqK_rZd-{3FNU&(jD0swcGj zXFe?@IjB|s5XSwH91~Rn4(if6;(!1>mm(P@{t!zN`+jeE0n&$20{m#tE`c81lrTi* z`(aJ`aV|?TTu7kF^D{EyKPr{2#|E-SR+88yS_TNu?u=yN!LM}Ee2T2waCv~a)$+*0 z4+$_hI{!Zwc3%gWJcF!nWum^$X&Bs5#2U8Wx3VlTUMN&0#dlnV<-vo55Tk@MLwRR} zcN{w{Pk-m~Q9wV3+Ncj8Y*agViu7hdfdl#%%dN b>|umk_w!q81@)IS|E7FBS2Ip|gs1%tSx05K literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.m new file mode 100644 index 000000000000..cb7fbc196b40 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/GoogleMapsUITests.m @@ -0,0 +1,288 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import CoreLocation; +@import XCTest; +@import os.log; + +static const NSTimeInterval kWaitTime = 60; + +// TODO(bparrishMines): Remove once https://github.com/flutter/flutter/issues/154641 is fixed. +static const BOOL skipFor154641 = YES; + +@interface GoogleMapsUITests : XCTestCase +@property(nonatomic, strong) XCUIApplication *app; +@end + +@implementation GoogleMapsUITests + +- (void)setUp { + self.continueAfterFailure = NO; + + self.app = [[XCUIApplication alloc] init]; + [self.app launch]; + + [self + addUIInterruptionMonitorWithDescription:@"Permission popups" + handler:^BOOL(XCUIElement *_Nonnull interruptingElement) { + if (@available(iOS 14, *)) { + XCUIElement *locationPermission = + interruptingElement.buttons[@"Allow While Using App"]; + if (![locationPermission + waitForExistenceWithTimeout:kWaitTime]) { + XCTFail(@"Failed due to not able to find " + @"locationPermission button"); + } + [locationPermission tap]; + + } else { + XCUIElement *allow = + interruptingElement.buttons[@"Allow"]; + if (![allow waitForExistenceWithTimeout:kWaitTime]) { + XCTFail(@"Failed due to not able to find Allow button"); + } + [allow tap]; + } + return YES; + }]; +} + +- (void)testUserInterface { + XCTSkipIf(skipFor154641); + + XCUIApplication *app = self.app; + XCUIElement *userInteface = app.staticTexts[@"User interface"]; + if (![userInteface waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find User interface"); + } + [userInteface tap]; + + XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; + if (![platformView waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find platform view"); + } + + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button + // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app + // instead. + XCUICoordinate *coordinate = [app coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; + [coordinate tap]; + XCUIElement *compass = app.buttons[@"disable compass"]; + if (![compass waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find disable compass button"); + } + + [self forceTap:compass]; +} + +- (void)testMapCoordinatesPage { + XCTSkipIf(skipFor154641); + + XCUIApplication *app = self.app; + XCUIElement *mapCoordinates = app.staticTexts[@"Map coordinates"]; + if (![mapCoordinates waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'Map coordinates''"); + } + [mapCoordinates tap]; + + XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; + if (![platformView waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find platform view"); + } + + XCUIElement *titleBar = app.otherElements[@"Map coordinates"]; + if (![titleBar waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find title bar"); + } + + NSPredicate *visibleRegionPredicate = + [NSPredicate predicateWithFormat:@"label BEGINSWITH 'VisibleRegion'"]; + XCUIElement *visibleRegionText = + [app.staticTexts elementMatchingPredicate:visibleRegionPredicate]; + if (![visibleRegionText waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find Visible Region label'"); + } + + // Validate visible region does not change when scrolled under safe areas. + // https://github.com/flutter/flutter/issues/107913 + + // Example -33.79495661816674, 151.313996873796 + CLLocationCoordinate2D originalNortheast; + // Example -33.90900557679571, 151.10800322145224 + CLLocationCoordinate2D originalSouthwest; + [self validateVisibleRegion:visibleRegionText.label + northeast:&originalNortheast + southwest:&originalSouthwest]; + XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude); + XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude); + + XCTAssertLessThan(originalNortheast.latitude, 0); + XCTAssertLessThan(originalSouthwest.latitude, 0); + XCTAssertGreaterThan(originalNortheast.longitude, 0); + XCTAssertGreaterThan(originalSouthwest.longitude, 0); + + // Drag the map upward to under the title bar. + [platformView pressForDuration:0 thenDragToElement:titleBar]; + + CLLocationCoordinate2D draggedNortheast; + CLLocationCoordinate2D draggedSouthwest; + [self validateVisibleRegion:visibleRegionText.label + northeast:&draggedNortheast + southwest:&draggedSouthwest]; + XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude); + XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude); + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); +} + +- (void)validateVisibleRegion:(NSString *)label + northeast:(CLLocationCoordinate2D *)northeast + southwest:(CLLocationCoordinate2D *)southwest { + // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, + // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" + NSScanner *scan = [NSScanner scannerWithString:label]; + + // northeast + [scan scanString:@"VisibleRegion:\nnortheast: LatLng(" intoString:NULL]; + double northeastLatitude; + [scan scanDouble:&northeastLatitude]; + [scan scanString:@", " intoString:NULL]; + XCTAssertNotEqual(northeastLatitude, 0); + double northeastLongitude; + [scan scanDouble:&northeastLongitude]; + XCTAssertNotEqual(northeastLongitude, 0); + + [scan scanString:@"),\nsouthwest: LatLng(" intoString:NULL]; + double southwestLatitude; + [scan scanDouble:&southwestLatitude]; + XCTAssertNotEqual(southwestLatitude, 0); + [scan scanString:@", " intoString:NULL]; + double southwestLongitude; + [scan scanDouble:&southwestLongitude]; + XCTAssertNotEqual(southwestLongitude, 0); + *northeast = CLLocationCoordinate2DMake(northeastLatitude, northeastLongitude); + *southwest = CLLocationCoordinate2DMake(southwestLatitude, southwestLongitude); +} + +- (void)testMapClickPage { + XCTSkipIf(skipFor154641); + + XCUIApplication *app = self.app; + XCUIElement *mapClick = app.staticTexts[@"Map click"]; + if (![mapClick waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'Map click''"); + } + [mapClick tap]; + + XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; + if (![platformView waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find platform view"); + } + + [platformView tap]; + + XCUIElement *tapped = app.staticTexts[@"Tapped"]; + if (![tapped waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'tapped''"); + } + + [platformView pressForDuration:5.0]; + + XCUIElement *longPressed = app.staticTexts[@"Long pressed"]; + if (![longPressed waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'longPressed''"); + } +} + +- (void)forceTap:(XCUIElement *)button { + // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the + // button if that is the case. It is likely similar to + // https://github.com/flutter/flutter/issues/113377. + if (button.isHittable) { + [button tap]; + return; + } + XCUICoordinate *coordinate = [button coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; + [coordinate tap]; +} + +- (void)testMarkerDraggingCallbacks { + XCTSkipIf(skipFor154641); + + XCUIApplication *application = [[XCUIApplication alloc] init]; + [application launch]; + XCUIElement *placeMarkerButton = application.staticTexts[@"Place marker"]; + if (![placeMarkerButton waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the Place marker button."); + } + [placeMarkerButton tap]; + + XCUIElement *Add = application.buttons[@"Add"]; + if (![Add waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the Add button."); + } + [Add tap]; + + XCUIElement *marker = application.buttons[@"marker_id_1"]; + if (![marker waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the marker."); + } + [marker tap]; + + XCUIElement *toggleDraggable = application.buttons[@"toggle draggable"]; + if (![toggleDraggable waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the toggle draggable."); + } + [toggleDraggable tap]; + + // Drag marker to center + [marker pressForDuration:5 thenDragToElement:application]; + + NSPredicate *predicateDragStart = + [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragStart"]; + NSPredicate *predicateDrag = + [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDrag called"]; + NSPredicate *predicateDragEnd = + [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragEnd"]; + + XCUIElement *dragStart = [application.staticTexts matchingPredicate:predicateDragStart].element; + if (![dragStart waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the _onMarkerDragStart."); + } + XCTAssertTrue(dragStart.exists); + + XCUIElement *drag = [application.staticTexts matchingPredicate:predicateDrag].element; + if (![drag waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the _onMarkerDrag."); + } + XCTAssertTrue(drag.exists); + + XCUIElement *dragEnd = [application.staticTexts matchingPredicate:predicateDragEnd].element; + if (![dragEnd waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the _onMarkerDragEnd."); + } + XCTAssertTrue(dragEnd.exists); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/Info.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/Info.plist new file mode 100644 index 000000000000..64d65ca49577 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/animate_camera.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/animate_camera.dart new file mode 100644 index 000000000000..a7c515c36928 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/animate_camera.dart @@ -0,0 +1,204 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class AnimateCameraPage extends GoogleMapExampleAppPage { + const AnimateCameraPage({Key? key}) + : super(const Icon(Icons.map), 'Camera control, animated', key: key); + + @override + Widget build(BuildContext context) { + return const AnimateCamera(); + } +} + +class AnimateCamera extends StatefulWidget { + const AnimateCamera({super.key}); + @override + State createState() => AnimateCameraState(); +} + +// Animation duration for a animation configuration. +const int _durationSeconds = 10; + +class AnimateCameraState extends State { + ExampleGoogleMapController? mapController; + Duration? _cameraUpdateAnimationDuration; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + mapController = controller; + } + + void _toggleAnimationDuration() { + setState(() { + _cameraUpdateAnimationDuration = _cameraUpdateAnimationDuration != null + ? null + : const Duration(seconds: _durationSeconds); + }); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(0.0, 0.0), + ), + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newCameraPosition( + const CameraPosition( + bearing: 270.0, + target: LatLng(51.5160895, -0.1294527), + tilt: 30.0, + zoom: 17.0, + ), + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newCameraPosition'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newLatLng( + const LatLng(56.1725505, 10.1850512), + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newLatLng'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newLatLngBounds( + LatLngBounds( + southwest: const LatLng(-38.483935, 113.248673), + northeast: const LatLng(-8.982446, 153.823821), + ), + 10.0, + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newLatLngBounds'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newLatLngZoom( + const LatLng(37.4231613, -122.087159), + 11.0, + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newLatLngZoom'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.scrollBy(150.0, -225.0), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('scrollBy'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomBy(-0.5, const Offset(30.0, 20.0)), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomBy with focus'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomBy(-0.5), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomBy'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomIn(), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomIn'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomOut(), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomOut'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomTo(16.0), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomTo'), + ), + ], + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('With 10 second duration', textAlign: TextAlign.right), + const SizedBox(width: 5), + Switch( + value: _cameraUpdateAnimationDuration != null, + onChanged: (bool value) { + _toggleAnimationDuration(); + }, + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/clustering.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/clustering.dart new file mode 100644 index 000000000000..5757717c215b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/clustering.dart @@ -0,0 +1,288 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +/// Page for demonstrating marker clustering support. +class ClusteringPage extends GoogleMapExampleAppPage { + /// Default Constructor. + const ClusteringPage({Key? key}) + : super(const Icon(Icons.place), 'Manage clustering', key: key); + + @override + Widget build(BuildContext context) { + return const ClusteringBody(); + } +} + +/// Body of the clustering page. +class ClusteringBody extends StatefulWidget { + /// Default Constructor. + const ClusteringBody({super.key}); + + @override + State createState() => ClusteringBodyState(); +} + +/// State of the clustering page. +class ClusteringBodyState extends State { + /// Default Constructor. + ClusteringBodyState(); + + /// Starting point from where markers are added. + static const LatLng center = LatLng(-33.86, 151.1547171); + + /// Marker offset factor for randomizing marker placing. + static const double _markerOffsetFactor = 0.05; + + /// Offset for longitude when placing markers to different cluster managers. + static const double _clusterManagerLongitudeOffset = 0.1; + + /// Maximum amount of cluster managers. + static const int _clusterManagerMaxCount = 3; + + /// Amount of markers to be added to the cluster manager at once. + static const int _markersToAddToClusterManagerCount = 10; + + /// Fully visible alpha value. + static const double _fullyVisibleAlpha = 1.0; + + /// Half visible alpha value. + static const double _halfVisibleAlpha = 0.5; + + /// Google map controller. + ExampleGoogleMapController? controller; + + /// Map of clusterManagers with identifier as the key. + Map clusterManagers = + {}; + + /// Map of markers with identifier as the key. + Map markers = {}; + + /// Id of the currently selected marker. + MarkerId? selectedMarker; + + /// Counter for added cluster manager ids. + int _clusterManagerIdCounter = 1; + + /// Counter for added markers ids. + int _markerIdCounter = 1; + + /// Cluster that was tapped most recently. + Cluster? lastCluster; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onMarkerTapped(MarkerId markerId) { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + final MarkerId? previousMarkerId = selectedMarker; + if (previousMarkerId != null && markers.containsKey(previousMarkerId)) { + final Marker resetOld = markers[previousMarkerId]!.copyWith( + iconParam: BitmapDescriptor.defaultMarker, + ); + markers[previousMarkerId] = resetOld; + } + selectedMarker = markerId; + final Marker newMarker = tappedMarker.copyWith( + iconParam: BitmapDescriptor.defaultMarkerWithHue( + BitmapDescriptor.hueGreen, + ), + ); + markers[markerId] = newMarker; + }); + } + } + + void _addClusterManager() { + if (clusterManagers.length == _clusterManagerMaxCount) { + return; + } + + final clusterManagerIdVal = 'cluster_manager_id_$_clusterManagerIdCounter'; + _clusterManagerIdCounter++; + final clusterManagerId = ClusterManagerId(clusterManagerIdVal); + + final clusterManager = ClusterManager( + clusterManagerId: clusterManagerId, + onClusterTap: (Cluster cluster) => setState(() { + lastCluster = cluster; + }), + ); + + setState(() { + clusterManagers[clusterManagerId] = clusterManager; + }); + _addMarkersToCluster(clusterManager); + } + + void _removeClusterManager(ClusterManager clusterManager) { + setState(() { + // Remove markers managed by cluster manager to be removed. + markers.removeWhere( + (MarkerId key, Marker marker) => + marker.clusterManagerId == clusterManager.clusterManagerId, + ); + // Remove cluster manager. + clusterManagers.remove(clusterManager.clusterManagerId); + }); + } + + void _addMarkersToCluster(ClusterManager clusterManager) { + for (var i = 0; i < _markersToAddToClusterManagerCount; i++) { + final markerIdVal = + '${clusterManager.clusterManagerId.value}_marker_id_$_markerIdCounter'; + _markerIdCounter++; + final markerId = MarkerId(markerIdVal); + + final int clusterManagerIndex = clusterManagers.values.toList().indexOf( + clusterManager, + ); + + // Add additional offset to longitude for each cluster manager to space + // out markers in different cluster managers. + final double clusterManagerLongitudeOffset = + clusterManagerIndex * _clusterManagerLongitudeOffset; + + final marker = Marker( + clusterManagerId: clusterManager.clusterManagerId, + markerId: markerId, + position: LatLng( + center.latitude + _getRandomOffset(), + center.longitude + _getRandomOffset() + clusterManagerLongitudeOffset, + ), + infoWindow: InfoWindow(title: markerIdVal, snippet: '*'), + onTap: () => _onMarkerTapped(markerId), + ); + markers[markerId] = marker; + } + setState(() {}); + } + + double _getRandomOffset() { + return (Random().nextDouble() - 0.5) * _markerOffsetFactor; + } + + void _remove(MarkerId markerId) { + setState(() { + if (markers.containsKey(markerId)) { + markers.remove(markerId); + } + }); + } + + void _changeMarkersAlpha() { + for (final MarkerId markerId in markers.keys) { + final Marker marker = markers[markerId]!; + final double current = marker.alpha; + markers[markerId] = marker.copyWith( + alphaParam: current == _fullyVisibleAlpha + ? _halfVisibleAlpha + : _fullyVisibleAlpha, + ); + } + setState(() {}); + } + + @override + Widget build(BuildContext context) { + final MarkerId? selectedId = selectedMarker; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox( + height: 300.0, + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(-33.852, 151.25), + zoom: 11.0, + ), + markers: Set.of(markers.values), + clusterManagers: Set.of(clusterManagers.values), + ), + ), + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: clusterManagers.length >= _clusterManagerMaxCount + ? null + : () => _addClusterManager(), + child: const Text('Add cluster manager'), + ), + TextButton( + onPressed: clusterManagers.isEmpty + ? null + : () => + _removeClusterManager(clusterManagers.values.last), + child: const Text('Remove cluster manager'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + for (final MapEntry + clusterEntry + in clusterManagers.entries) + TextButton( + onPressed: () => _addMarkersToCluster(clusterEntry.value), + child: Text('Add markers to ${clusterEntry.key.value}'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: selectedId == null + ? null + : () { + _remove(selectedId); + setState(() { + selectedMarker = null; + }); + }, + child: const Text('Remove selected marker'), + ), + TextButton( + onPressed: markers.isEmpty + ? null + : () => _changeMarkersAlpha(), + child: const Text('Change all markers alpha'), + ), + ], + ), + if (lastCluster != null) + Padding( + padding: const EdgeInsets.all(10), + child: Text( + 'Cluster with ${lastCluster!.count} markers clicked at ${lastCluster!.position}', + ), + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/custom_marker_icon.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/custom_marker_icon.dart new file mode 100644 index 000000000000..548146c6206c --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/custom_marker_icon.dart @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +/// Returns a generated png image in [ByteData] format with the requested size. +Future createCustomMarkerIconImage({required Size size}) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final painter = _MarkerPainter(); + + painter.paint(canvas, size); + + final ui.Image image = await recorder.endRecording().toImage( + size.width.floor(), + size.height.floor(), + ); + + final ByteData? bytes = await image.toByteData( + format: ui.ImageByteFormat.png, + ); + return bytes!; +} + +class _MarkerPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Rect rect = Offset.zero & size; + const gradient = RadialGradient( + colors: [Colors.yellow, Colors.red], + stops: [0.4, 1.0], + ); + + // Draw radial gradient + canvas.drawRect(rect, Paint()..shader = gradient.createShader(rect)); + + // Draw diagonal black line + canvas.drawLine( + Offset.zero, + Offset(size.width, size.height), + Paint() + ..color = Colors.black + ..strokeWidth = 1, + ); + } + + @override + bool shouldRepaint(_MarkerPainter oldDelegate) => false; + @override + bool shouldRebuildSemantics(_MarkerPainter oldDelegate) => false; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/example_google_map.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/example_google_map.dart new file mode 100644 index 000000000000..152f83c16f38 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/example_google_map.dart @@ -0,0 +1,676 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +// This is a pared down version of the Dart code from the app-facing package, +// to allow running the same examples for package-local testing. +// TODO(stuartmorgan): Consider extracting this to a shared package. See also +// https://github.com/flutter/flutter/issues/46716. + +/// Controller for a single ExampleGoogleMap instance running on the host platform. +class ExampleGoogleMapController { + ExampleGoogleMapController._(this._googleMapState, {required this.mapId}) { + _connectStreams(mapId); + } + + /// The mapId for this controller + final int mapId; + + /// Initialize control of a [ExampleGoogleMap] with [id]. + /// + /// Mainly for internal use when instantiating a [ExampleGoogleMapController] passed + /// in [ExampleGoogleMap.onMapCreated] callback. + static Future _init( + int id, + CameraPosition initialCameraPosition, + _ExampleGoogleMapState googleMapState, + ) async { + await GoogleMapsFlutterPlatform.instance.init(id); + return ExampleGoogleMapController._(googleMapState, mapId: id); + } + + final _ExampleGoogleMapState _googleMapState; + + void _connectStreams(int mapId) { + if (_googleMapState.widget.onCameraMoveStarted != null) { + GoogleMapsFlutterPlatform.instance + .onCameraMoveStarted(mapId: mapId) + .listen((_) => _googleMapState.widget.onCameraMoveStarted!()); + } + if (_googleMapState.widget.onCameraMove != null) { + GoogleMapsFlutterPlatform.instance + .onCameraMove(mapId: mapId) + .listen( + (CameraMoveEvent e) => + _googleMapState.widget.onCameraMove!(e.value), + ); + } + if (_googleMapState.widget.onCameraIdle != null) { + GoogleMapsFlutterPlatform.instance + .onCameraIdle(mapId: mapId) + .listen((_) => _googleMapState.widget.onCameraIdle!()); + } + GoogleMapsFlutterPlatform.instance + .onMarkerTap(mapId: mapId) + .listen((MarkerTapEvent e) => _googleMapState.onMarkerTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onMarkerDragStart(mapId: mapId) + .listen( + (MarkerDragStartEvent e) => + _googleMapState.onMarkerDragStart(e.value, e.position), + ); + GoogleMapsFlutterPlatform.instance + .onMarkerDrag(mapId: mapId) + .listen( + (MarkerDragEvent e) => + _googleMapState.onMarkerDrag(e.value, e.position), + ); + GoogleMapsFlutterPlatform.instance + .onMarkerDragEnd(mapId: mapId) + .listen( + (MarkerDragEndEvent e) => + _googleMapState.onMarkerDragEnd(e.value, e.position), + ); + GoogleMapsFlutterPlatform.instance + .onInfoWindowTap(mapId: mapId) + .listen( + (InfoWindowTapEvent e) => _googleMapState.onInfoWindowTap(e.value), + ); + GoogleMapsFlutterPlatform.instance + .onPolylineTap(mapId: mapId) + .listen((PolylineTapEvent e) => _googleMapState.onPolylineTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onPolygonTap(mapId: mapId) + .listen((PolygonTapEvent e) => _googleMapState.onPolygonTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onCircleTap(mapId: mapId) + .listen((CircleTapEvent e) => _googleMapState.onCircleTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onGroundOverlayTap(mapId: mapId) + .listen( + (GroundOverlayTapEvent e) => + _googleMapState.onGroundOverlayTap(e.value), + ); + GoogleMapsFlutterPlatform.instance + .onTap(mapId: mapId) + .listen((MapTapEvent e) => _googleMapState.onTap(e.position)); + GoogleMapsFlutterPlatform.instance + .onLongPress(mapId: mapId) + .listen( + (MapLongPressEvent e) => _googleMapState.onLongPress(e.position), + ); + GoogleMapsFlutterPlatform.instance + .onClusterTap(mapId: mapId) + .listen((ClusterTapEvent e) => _googleMapState.onClusterTap(e.value)); + } + + /// Updates configuration options of the map user interface. + Future _updateMapConfiguration(MapConfiguration update) { + return GoogleMapsFlutterPlatform.instance.updateMapConfiguration( + update, + mapId: mapId, + ); + } + + /// Updates marker configuration. + Future _updateMarkers(MarkerUpdates markerUpdates) { + return GoogleMapsFlutterPlatform.instance.updateMarkers( + markerUpdates, + mapId: mapId, + ); + } + + /// Updates cluster manager configuration. + Future _updateClusterManagers( + ClusterManagerUpdates clusterManagerUpdates, + ) { + return GoogleMapsFlutterPlatform.instance.updateClusterManagers( + clusterManagerUpdates, + mapId: mapId, + ); + } + + /// Updates ground overlay configuration. + Future _updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, + ) { + return GoogleMapsFlutterPlatform.instance.updateGroundOverlays( + groundOverlayUpdates, + mapId: mapId, + ); + } + + /// Updates polygon configuration. + Future _updatePolygons(PolygonUpdates polygonUpdates) { + return GoogleMapsFlutterPlatform.instance.updatePolygons( + polygonUpdates, + mapId: mapId, + ); + } + + /// Updates polyline configuration. + Future _updatePolylines(PolylineUpdates polylineUpdates) { + return GoogleMapsFlutterPlatform.instance.updatePolylines( + polylineUpdates, + mapId: mapId, + ); + } + + /// Updates circle configuration. + Future _updateCircles(CircleUpdates circleUpdates) { + return GoogleMapsFlutterPlatform.instance.updateCircles( + circleUpdates, + mapId: mapId, + ); + } + + /// Updates tile overlays configuration. + Future _updateTileOverlays(Set newTileOverlays) { + return GoogleMapsFlutterPlatform.instance.updateTileOverlays( + newTileOverlays: newTileOverlays, + mapId: mapId, + ); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. + Future clearTileCache(TileOverlayId tileOverlayId) async { + return GoogleMapsFlutterPlatform.instance.clearTileCache( + tileOverlayId, + mapId: mapId, + ); + } + + /// Starts an animated change of the map camera position. + Future animateCamera(CameraUpdate cameraUpdate, {Duration? duration}) { + return GoogleMapsFlutterPlatform.instance.animateCameraWithConfiguration( + cameraUpdate, + CameraUpdateAnimationConfiguration(duration: duration), + mapId: mapId, + ); + } + + /// Changes the map camera position. + Future moveCamera(CameraUpdate cameraUpdate) { + return GoogleMapsFlutterPlatform.instance.moveCamera( + cameraUpdate, + mapId: mapId, + ); + } + + /// Return [LatLngBounds] defining the region that is visible in a map. + Future getVisibleRegion() { + return GoogleMapsFlutterPlatform.instance.getVisibleRegion(mapId: mapId); + } + + /// Return [ScreenCoordinate] of the [LatLng] in the current map view. + Future getScreenCoordinate(LatLng latLng) { + return GoogleMapsFlutterPlatform.instance.getScreenCoordinate( + latLng, + mapId: mapId, + ); + } + + /// Returns [LatLng] corresponding to the [ScreenCoordinate] in the current map view. + Future getLatLng(ScreenCoordinate screenCoordinate) { + return GoogleMapsFlutterPlatform.instance.getLatLng( + screenCoordinate, + mapId: mapId, + ); + } + + /// Programmatically show the Info Window for a [Marker]. + Future showMarkerInfoWindow(MarkerId markerId) { + return GoogleMapsFlutterPlatform.instance.showMarkerInfoWindow( + markerId, + mapId: mapId, + ); + } + + /// Programmatically hide the Info Window for a [Marker]. + Future hideMarkerInfoWindow(MarkerId markerId) { + return GoogleMapsFlutterPlatform.instance.hideMarkerInfoWindow( + markerId, + mapId: mapId, + ); + } + + /// Returns `true` when the [InfoWindow] is showing, `false` otherwise. + Future isMarkerInfoWindowShown(MarkerId markerId) { + return GoogleMapsFlutterPlatform.instance.isMarkerInfoWindowShown( + markerId, + mapId: mapId, + ); + } + + /// Returns the current zoom level of the map + Future getZoomLevel() { + return GoogleMapsFlutterPlatform.instance.getZoomLevel(mapId: mapId); + } + + /// Returns the image bytes of the map + Future takeSnapshot() { + return GoogleMapsFlutterPlatform.instance.takeSnapshot(mapId: mapId); + } + + /// Returns the last style error, if any. + Future getStyleError() { + return GoogleMapsFlutterPlatform.instance.getStyleError(mapId: mapId); + } + + /// Disposes of the platform resources + void dispose() { + GoogleMapsFlutterPlatform.instance.dispose(mapId: mapId); + } +} + +// The next map ID to create. +int _nextMapCreationId = 0; + +/// A widget which displays a map with data obtained from the Google Maps service. +class ExampleGoogleMap extends StatefulWidget { + /// Creates a widget displaying data from Google Maps services. + /// + /// [AssertionError] will be thrown if [initialCameraPosition] is null; + const ExampleGoogleMap({ + super.key, + required this.initialCameraPosition, + this.onMapCreated, + this.gestureRecognizers = const >{}, + this.compassEnabled = true, + this.cameraTargetBounds = CameraTargetBounds.unbounded, + this.mapType = MapType.normal, + this.minMaxZoomPreference = MinMaxZoomPreference.unbounded, + this.rotateGesturesEnabled = true, + this.scrollGesturesEnabled = true, + this.zoomControlsEnabled = true, + this.zoomGesturesEnabled = true, + this.tiltGesturesEnabled = true, + this.myLocationEnabled = false, + this.myLocationButtonEnabled = true, + this.layoutDirection, + + /// If no padding is specified default padding will be 0. + this.padding = EdgeInsets.zero, + this.indoorViewEnabled = false, + this.trafficEnabled = false, + this.buildingsEnabled = true, + this.markers = const {}, + this.polygons = const {}, + this.polylines = const {}, + this.circles = const {}, + this.clusterManagers = const {}, + this.onCameraMoveStarted, + this.tileOverlays = const {}, + this.groundOverlays = const {}, + this.onCameraMove, + this.onCameraIdle, + this.onTap, + this.onLongPress, + this.mapId, + this.style, + }); + + /// Callback method for when the map is ready to be used. + /// + /// Used to receive a [ExampleGoogleMapController] for this [ExampleGoogleMap]. + final void Function(ExampleGoogleMapController controller)? onMapCreated; + + /// The initial position of the map's camera. + final CameraPosition initialCameraPosition; + + /// True if the map should show a compass when rotated. + final bool compassEnabled; + + /// Geographical bounding box for the camera target. + final CameraTargetBounds cameraTargetBounds; + + /// Type of map tiles to be rendered. + final MapType mapType; + + /// The layout direction to use for the embedded view. + final TextDirection? layoutDirection; + + /// Preferred bounds for the camera zoom level. + /// + /// Actual bounds depend on map data and device. + final MinMaxZoomPreference minMaxZoomPreference; + + /// True if the map view should respond to rotate gestures. + final bool rotateGesturesEnabled; + + /// True if the map view should respond to scroll gestures. + final bool scrollGesturesEnabled; + + /// True if the map view should show zoom controls. This includes two buttons + /// to zoom in and zoom out. The default value is to show zoom controls. + final bool zoomControlsEnabled; + + /// True if the map view should respond to zoom gestures. + final bool zoomGesturesEnabled; + + /// True if the map view should respond to tilt gestures. + final bool tiltGesturesEnabled; + + /// Padding to be set on map. + final EdgeInsets padding; + + /// Markers to be placed on the map. + final Set markers; + + /// Polygons to be placed on the map. + final Set polygons; + + /// Polylines to be placed on the map. + final Set polylines; + + /// Circles to be placed on the map. + final Set circles; + + /// Tile overlays to be placed on the map. + final Set tileOverlays; + + /// Cluster Managers to be placed for the map. + final Set clusterManagers; + + /// Ground overlays to be initialized for the map. + final Set groundOverlays; + + /// Called when the camera starts moving. + final VoidCallback? onCameraMoveStarted; + + /// Called repeatedly as the camera continues to move after an + /// onCameraMoveStarted call. + final CameraPositionCallback? onCameraMove; + + /// Called when camera movement has ended, there are no pending + /// animations and the user has stopped interacting with the map. + final VoidCallback? onCameraIdle; + + /// Called every time a [ExampleGoogleMap] is tapped. + final ArgumentCallback? onTap; + + /// Called every time a [ExampleGoogleMap] is long pressed. + final ArgumentCallback? onLongPress; + + /// True if a "My Location" layer should be shown on the map. + final bool myLocationEnabled; + + /// Enables or disables the my-location button. + final bool myLocationButtonEnabled; + + /// Enables or disables the indoor view from the map + final bool indoorViewEnabled; + + /// Enables or disables the traffic layer of the map + final bool trafficEnabled; + + /// Enables or disables showing 3D buildings where available + final bool buildingsEnabled; + + /// Which gestures should be consumed by the map. + final Set> gestureRecognizers; + + /// Identifier that's associated with a specific cloud-based map style. + /// + /// See https://developers.google.com/maps/documentation/get-map-id + /// for more details. + final String? mapId; + + /// The locally configured style for the map. + final String? style; + + /// Creates a [State] for this [ExampleGoogleMap]. + @override + State createState() => _ExampleGoogleMapState(); +} + +class _ExampleGoogleMapState extends State { + final int _mapId = _nextMapCreationId++; + + final Completer _controller = + Completer(); + + Map _markers = {}; + Map _polygons = {}; + Map _polylines = {}; + Map _circles = {}; + Map _clusterManagers = + {}; + Map _groundOverlays = + {}; + late MapConfiguration _mapConfiguration; + + @override + Widget build(BuildContext context) { + return GoogleMapsFlutterPlatform.instance.buildViewWithConfiguration( + _mapId, + onPlatformViewCreated, + widgetConfiguration: MapWidgetConfiguration( + textDirection: + widget.layoutDirection ?? + Directionality.maybeOf(context) ?? + TextDirection.ltr, + initialCameraPosition: widget.initialCameraPosition, + gestureRecognizers: widget.gestureRecognizers, + ), + mapObjects: MapObjects( + markers: widget.markers, + polygons: widget.polygons, + polylines: widget.polylines, + circles: widget.circles, + clusterManagers: widget.clusterManagers, + groundOverlays: widget.groundOverlays, + ), + mapConfiguration: _mapConfiguration, + ); + } + + @override + void initState() { + super.initState(); + _mapConfiguration = _configurationFromMapWidget(widget); + _clusterManagers = keyByClusterManagerId(widget.clusterManagers); + _markers = keyByMarkerId(widget.markers); + _polygons = keyByPolygonId(widget.polygons); + _polylines = keyByPolylineId(widget.polylines); + _circles = keyByCircleId(widget.circles); + _groundOverlays = keyByGroundOverlayId(widget.groundOverlays); + } + + @override + void dispose() { + _controller.future.then( + (ExampleGoogleMapController controller) => controller.dispose(), + ); + super.dispose(); + } + + @override + void didUpdateWidget(ExampleGoogleMap oldWidget) { + super.didUpdateWidget(oldWidget); + _updateOptions(); + _updateClusterManagers(); + _updateMarkers(); + _updatePolygons(); + _updatePolylines(); + _updateCircles(); + _updateTileOverlays(); + _updateGroundOverlays(); + } + + Future _updateOptions() async { + final MapConfiguration newConfig = _configurationFromMapWidget(widget); + final MapConfiguration updates = newConfig.diffFrom(_mapConfiguration); + if (updates.isEmpty) { + return; + } + final ExampleGoogleMapController controller = await _controller.future; + unawaited(controller._updateMapConfiguration(updates)); + _mapConfiguration = newConfig; + } + + Future _updateMarkers() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateMarkers( + MarkerUpdates.from(_markers.values.toSet(), widget.markers), + ), + ); + _markers = keyByMarkerId(widget.markers); + } + + Future _updateClusterManagers() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateClusterManagers( + ClusterManagerUpdates.from( + _clusterManagers.values.toSet(), + widget.clusterManagers, + ), + ), + ); + _clusterManagers = keyByClusterManagerId(widget.clusterManagers); + } + + Future _updateGroundOverlays() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateGroundOverlays( + GroundOverlayUpdates.from( + _groundOverlays.values.toSet(), + widget.groundOverlays, + ), + ), + ); + _groundOverlays = keyByGroundOverlayId(widget.groundOverlays); + } + + Future _updatePolygons() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updatePolygons( + PolygonUpdates.from(_polygons.values.toSet(), widget.polygons), + ), + ); + _polygons = keyByPolygonId(widget.polygons); + } + + Future _updatePolylines() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updatePolylines( + PolylineUpdates.from(_polylines.values.toSet(), widget.polylines), + ), + ); + _polylines = keyByPolylineId(widget.polylines); + } + + Future _updateCircles() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateCircles( + CircleUpdates.from(_circles.values.toSet(), widget.circles), + ), + ); + _circles = keyByCircleId(widget.circles); + } + + Future _updateTileOverlays() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited(controller._updateTileOverlays(widget.tileOverlays)); + } + + Future onPlatformViewCreated(int id) async { + final ExampleGoogleMapController controller = + await ExampleGoogleMapController._init( + id, + widget.initialCameraPosition, + this, + ); + _controller.complete(controller); + unawaited(_updateTileOverlays()); + widget.onMapCreated?.call(controller); + } + + void onMarkerTap(MarkerId markerId) { + _markers[markerId]!.onTap?.call(); + } + + void onMarkerDragStart(MarkerId markerId, LatLng position) { + _markers[markerId]!.onDragStart?.call(position); + } + + void onMarkerDrag(MarkerId markerId, LatLng position) { + _markers[markerId]!.onDrag?.call(position); + } + + void onMarkerDragEnd(MarkerId markerId, LatLng position) { + _markers[markerId]!.onDragEnd?.call(position); + } + + void onPolygonTap(PolygonId polygonId) { + _polygons[polygonId]!.onTap?.call(); + } + + void onPolylineTap(PolylineId polylineId) { + _polylines[polylineId]!.onTap?.call(); + } + + void onCircleTap(CircleId circleId) { + _circles[circleId]!.onTap?.call(); + } + + void onGroundOverlayTap(GroundOverlayId groundOverlayId) { + _groundOverlays[groundOverlayId]!.onTap?.call(); + } + + void onInfoWindowTap(MarkerId markerId) { + _markers[markerId]!.infoWindow.onTap?.call(); + } + + void onTap(LatLng position) { + widget.onTap?.call(position); + } + + void onLongPress(LatLng position) { + widget.onLongPress?.call(position); + } + + void onClusterTap(Cluster cluster) { + final ClusterManager? clusterManager = + _clusterManagers[cluster.clusterManagerId]; + clusterManager?.onClusterTap?.call(cluster); + } +} + +/// Builds a [MapConfiguration] from the given [map]. +MapConfiguration _configurationFromMapWidget(ExampleGoogleMap map) { + return MapConfiguration( + compassEnabled: map.compassEnabled, + cameraTargetBounds: map.cameraTargetBounds, + mapType: map.mapType, + minMaxZoomPreference: map.minMaxZoomPreference, + rotateGesturesEnabled: map.rotateGesturesEnabled, + scrollGesturesEnabled: map.scrollGesturesEnabled, + tiltGesturesEnabled: map.tiltGesturesEnabled, + trackCameraPosition: map.onCameraMove != null, + zoomControlsEnabled: map.zoomControlsEnabled, + zoomGesturesEnabled: map.zoomGesturesEnabled, + myLocationEnabled: map.myLocationEnabled, + myLocationButtonEnabled: map.myLocationButtonEnabled, + padding: map.padding, + indoorViewEnabled: map.indoorViewEnabled, + trafficEnabled: map.trafficEnabled, + buildingsEnabled: map.buildingsEnabled, + mapId: map.mapId, + style: map.style, + ); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/ground_overlay.dart new file mode 100644 index 000000000000..d8f474eb7d5e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/ground_overlay.dart @@ -0,0 +1,311 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +enum _GroundOverlayPlacing { position, bounds } + +class GroundOverlayPage extends GoogleMapExampleAppPage { + const GroundOverlayPage({Key? key}) + : super(const Icon(Icons.map), 'Ground overlay', key: key); + + @override + Widget build(BuildContext context) { + return const GroundOverlayBody(); + } +} + +class GroundOverlayBody extends StatefulWidget { + const GroundOverlayBody({super.key}); + + @override + State createState() => GroundOverlayBodyState(); +} + +class GroundOverlayBodyState extends State { + GroundOverlayBodyState(); + + ExampleGoogleMapController? controller; + GroundOverlay? _groundOverlay; + + final LatLng _mapCenter = const LatLng(37.422026, -122.085329); + + _GroundOverlayPlacing _placingType = _GroundOverlayPlacing.bounds; + + // Positions for demonstranting placing ground overlays with position, and + // changing positions. + final LatLng _groundOverlayPos1 = const LatLng(37.422026, -122.085329); + final LatLng _groundOverlayPos2 = const LatLng(37.42, -122.08); + late LatLng _currentGroundOverlayPos; + + // Bounds for demonstranting placing ground overlays with bounds, and + // changing bounds. + final LatLngBounds _groundOverlayBounds1 = LatLngBounds( + southwest: const LatLng(37.42, -122.09), + northeast: const LatLng(37.423, -122.084), + ); + final LatLngBounds _groundOverlayBounds2 = LatLngBounds( + southwest: const LatLng(37.421, -122.091), + northeast: const LatLng(37.424, -122.08), + ); + late LatLngBounds _currentGroundOverlayBounds; + + Offset _anchor = const Offset(0.5, 0.5); + + // Index to be used as identifier for the ground overlay. + // If position is changed to bounds and vice versa, the ground overlay will + // be removed and added again with the new type. Also anchor can be given only + // when the ground overlay is created with position and cannot be changed + // after the ground overlay is created. + int _groundOverlayIndex = 0; + + @override + void initState() { + _currentGroundOverlayPos = _groundOverlayPos1; + _currentGroundOverlayBounds = _groundOverlayBounds1; + super.initState(); + } + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + void _removeGroundOverlay() { + setState(() { + _groundOverlay = null; + }); + } + + Future _addGroundOverlay() async { + final AssetMapBitmap assetMapBitmap = await AssetMapBitmap.create( + createLocalImageConfiguration(context), + 'assets/red_square.png', + bitmapScaling: MapBitmapScaling.none, + ); + + _groundOverlayIndex += 1; + + final id = GroundOverlayId('ground_overlay_$_groundOverlayIndex'); + + final GroundOverlay groundOverlay = switch (_placingType) { + _GroundOverlayPlacing.position => GroundOverlay.fromPosition( + groundOverlayId: id, + image: assetMapBitmap, + position: _currentGroundOverlayPos, + anchor: _anchor, + onTap: () { + _onGroundOverlayTapped(); + }, + zoomLevel: 14.0, + ), + _GroundOverlayPlacing.bounds => GroundOverlay.fromBounds( + groundOverlayId: id, + image: assetMapBitmap, + bounds: _currentGroundOverlayBounds, + anchor: _anchor, + onTap: () { + _onGroundOverlayTapped(); + }, + ), + }; + + setState(() { + _groundOverlay = groundOverlay; + }); + } + + void _onGroundOverlayTapped() { + _changePosition(); + } + + void _setBearing() { + assert(_groundOverlay != null); + setState(() { + // Adjusts the bearing by 10 degrees, wrapping around at 360 degrees. + // 10 is the increment, 350 degrees of the full circle -10. + _groundOverlay = _groundOverlay!.copyWith( + bearingParam: _groundOverlay!.bearing >= 350 + ? 0 + : _groundOverlay!.bearing + 10, + ); + }); + } + + void _changeTransparency() { + assert(_groundOverlay != null); + setState(() { + final transparency = _groundOverlay!.transparency == 0.0 ? 0.5 : 0.0; + _groundOverlay = _groundOverlay!.copyWith( + transparencyParam: transparency, + ); + }); + } + + Future _changePosition() async { + assert(_groundOverlay != null); + assert(_placingType == _GroundOverlayPlacing.position); + setState(() { + _currentGroundOverlayPos = _currentGroundOverlayPos == _groundOverlayPos1 + ? _groundOverlayPos2 + : _groundOverlayPos1; + }); + + // Re-add the ground overlay to apply the new position, as the position + // cannot be changed after the ground overlay is created on all platforms. + await _addGroundOverlay(); + } + + Future _changeBounds() async { + assert(_groundOverlay != null); + assert(_placingType == _GroundOverlayPlacing.bounds); + setState(() { + _currentGroundOverlayBounds = + _currentGroundOverlayBounds == _groundOverlayBounds1 + ? _groundOverlayBounds2 + : _groundOverlayBounds1; + }); + + // Re-add the ground overlay to apply the new position, as the position + // cannot be changed after the ground overlay is created on all platforms. + await _addGroundOverlay(); + } + + void _toggleVisible() { + assert(_groundOverlay != null); + setState(() { + _groundOverlay = _groundOverlay!.copyWith( + visibleParam: !_groundOverlay!.visible, + ); + }); + } + + void _changeZIndex() { + assert(_groundOverlay != null); + final int current = _groundOverlay!.zIndex; + final int zIndex = current == 12 ? 0 : current + 1; + setState(() { + _groundOverlay = _groundOverlay!.copyWith(zIndexParam: zIndex); + }); + } + + Future _changeType() async { + setState(() { + _placingType = _placingType == _GroundOverlayPlacing.position + ? _GroundOverlayPlacing.bounds + : _GroundOverlayPlacing.position; + }); + + // Re-add the ground overlay to apply the new position, as the position + // cannot be changed after the ground overlay is created on all platforms. + await _addGroundOverlay(); + } + + Future _changeAnchor() async { + assert(_groundOverlay != null); + setState(() { + _anchor = _groundOverlay!.anchor == const Offset(0.5, 0.5) + ? const Offset(1.0, 1.0) + : const Offset(0.5, 0.5); + }); + + // Re-add the ground overlay to apply the new anchor, as anchor cannot be + // changed after the ground overlay is created. + await _addGroundOverlay(); + } + + @override + Widget build(BuildContext context) { + final overlays = { + if (_groundOverlay != null) _groundOverlay!, + }; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: ExampleGoogleMap( + initialCameraPosition: CameraPosition( + target: _mapCenter, + zoom: 14.0, + ), + groundOverlays: overlays, + onMapCreated: _onMapCreated, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: _groundOverlay == null ? _addGroundOverlay : null, + child: const Text('Add'), + ), + TextButton( + onPressed: _groundOverlay != null ? _removeGroundOverlay : null, + child: const Text('Remove'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: _groundOverlay == null + ? null + : () => _changeTransparency(), + child: const Text('change transparency'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _setBearing(), + child: const Text('change bearing'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _toggleVisible(), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _changeZIndex(), + child: const Text('change zIndex'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _changeAnchor(), + child: const Text('change anchor'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _changeType(), + child: Text( + _placingType == _GroundOverlayPlacing.position + ? 'use bounds' + : 'use position', + ), + ), + TextButton( + onPressed: + _placingType != _GroundOverlayPlacing.position || + _groundOverlay == null + ? null + : () => _changePosition(), + child: const Text('change position'), + ), + TextButton( + onPressed: + _placingType != _GroundOverlayPlacing.bounds || + _groundOverlay == null + ? null + : () => _changeBounds(), + child: const Text('change bounds'), + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/lite_mode.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/lite_mode.dart new file mode 100644 index 000000000000..e6359e19acc2 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/lite_mode.dart @@ -0,0 +1,46 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class LiteModePage extends GoogleMapExampleAppPage { + const LiteModePage({Key? key}) + : super(const Icon(Icons.map), 'Lite mode', key: key); + + @override + Widget build(BuildContext context) { + return const _LiteModeBody(); + } +} + +class _LiteModeBody extends StatelessWidget { + const _LiteModeBody(); + + @override + Widget build(BuildContext context) { + return const Card( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 30.0), + child: Center( + child: SizedBox( + width: 300.0, + height: 300.0, + child: ExampleGoogleMap(initialCameraPosition: _kInitialPosition), + ), + ), + ), + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/main.dart new file mode 100644 index 000000000000..605e4e3a57ec --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/main.dart @@ -0,0 +1,53 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'animate_camera.dart'; +import 'clustering.dart'; +import 'ground_overlay.dart'; +import 'lite_mode.dart'; +import 'map_click.dart'; +import 'map_coordinates.dart'; +import 'map_map_id.dart'; +import 'map_ui.dart'; +import 'maps_demo.dart'; +import 'marker_icons.dart'; +import 'move_camera.dart'; +import 'padding.dart'; +import 'page.dart'; +import 'place_circle.dart'; +import 'place_marker.dart'; +import 'place_polygon.dart'; +import 'place_polyline.dart'; +import 'scrolling_map.dart'; +import 'snapshot.dart'; +import 'tile_overlay.dart'; + +void main() { + runApp( + const MaterialApp( + home: MapsDemo([ + MapUiPage(), + MapCoordinatesPage(), + MapClickPage(), + AnimateCameraPage(), + MoveCameraPage(), + PlaceMarkerPage(), + MarkerIconsPage(), + ScrollingMapPage(), + PlacePolylinePage(), + PlacePolygonPage(), + PlaceCirclePage(), + PaddingPage(), + SnapshotPage(), + LiteModePage(), + TileOverlayPage(), + GroundOverlayPage(), + ClusteringPage(), + MapIdPage(), + ]), + ), + ); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_click.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_click.dart new file mode 100644 index 000000000000..4d45e961d63e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_click.dart @@ -0,0 +1,105 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class MapClickPage extends GoogleMapExampleAppPage { + const MapClickPage({Key? key}) + : super(const Icon(Icons.mouse), 'Map click', key: key); + + @override + Widget build(BuildContext context) { + return const _MapClickBody(); + } +} + +class _MapClickBody extends StatefulWidget { + const _MapClickBody(); + + @override + State createState() => _MapClickBodyState(); +} + +class _MapClickBodyState extends State<_MapClickBody> { + _MapClickBodyState(); + + ExampleGoogleMapController? mapController; + LatLng? _lastTap; + LatLng? _lastLongPress; + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + onTap: (LatLng pos) { + setState(() { + _lastTap = pos; + }); + }, + onLongPress: (LatLng pos) { + setState(() { + _lastLongPress = pos; + }); + }, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + ]; + + if (mapController != null) { + final lastTap = 'Tap:\n${_lastTap ?? ""}\n'; + final lastLongPress = 'Long press:\n${_lastLongPress ?? ""}'; + columnChildren.add( + Center(child: Text(lastTap, textAlign: TextAlign.center)), + ); + columnChildren.add( + Center( + child: Text( + _lastTap != null ? 'Tapped' : '', + textAlign: TextAlign.center, + ), + ), + ); + columnChildren.add( + Center(child: Text(lastLongPress, textAlign: TextAlign.center)), + ); + columnChildren.add( + Center( + child: Text( + _lastLongPress != null ? 'Long pressed' : '', + textAlign: TextAlign.center, + ), + ), + ); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + Future onMapCreated(ExampleGoogleMapController controller) async { + setState(() { + mapController = controller; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_coordinates.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_coordinates.dart new file mode 100644 index 000000000000..3a93b0db93b7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_coordinates.dart @@ -0,0 +1,105 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class MapCoordinatesPage extends GoogleMapExampleAppPage { + const MapCoordinatesPage({Key? key}) + : super(const Icon(Icons.map), 'Map coordinates', key: key); + + @override + Widget build(BuildContext context) { + return const _MapCoordinatesBody(); + } +} + +class _MapCoordinatesBody extends StatefulWidget { + const _MapCoordinatesBody(); + + @override + State createState() => _MapCoordinatesBodyState(); +} + +class _MapCoordinatesBodyState extends State<_MapCoordinatesBody> { + _MapCoordinatesBodyState(); + + ExampleGoogleMapController? mapController; + LatLngBounds _visibleRegion = LatLngBounds( + southwest: const LatLng(0, 0), + northeast: const LatLng(0, 0), + ); + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + onCameraIdle: + _updateVisibleRegion, // https://github.com/flutter/flutter/issues/54758 + ); + + return NotificationListener( + onNotification: (ScrollNotification scrollState) { + _updateVisibleRegion(); + return true; + }, + child: Stack( + children: [ + ListView( + children: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: googleMap, + ), + ), + ), + // Add a block at the bottom of this list to allow validation that the visible region of the map + // does not change when scrolled under the safe view on iOS. + // https://github.com/flutter/flutter/issues/107913 + const SizedBox(width: 300, height: 1000), + ], + ), + if (mapController != null) + Center( + child: Text( + 'VisibleRegion:' + '\nnortheast: ${_visibleRegion.northeast},' + '\nsouthwest: ${_visibleRegion.southwest}', + ), + ), + ], + ), + ); + } + + Future onMapCreated(ExampleGoogleMapController controller) async { + final LatLngBounds visibleRegion = await controller.getVisibleRegion(); + setState(() { + mapController = controller; + _visibleRegion = visibleRegion; + }); + } + + Future _updateVisibleRegion() async { + final LatLngBounds visibleRegion = await mapController!.getVisibleRegion(); + setState(() { + _visibleRegion = visibleRegion; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_map_id.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_map_id.dart new file mode 100644 index 000000000000..c62152f149d0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_map_id.dart @@ -0,0 +1,100 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class MapIdPage extends GoogleMapExampleAppPage { + const MapIdPage({Key? key}) + : super(const Icon(Icons.map), 'Cloud-based maps styling', key: key); + + @override + Widget build(BuildContext context) { + return const MapIdBody(); + } +} + +class MapIdBody extends StatefulWidget { + const MapIdBody({super.key}); + + @override + State createState() => MapIdBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +class MapIdBodyState extends State { + ExampleGoogleMapController? controller; + + Key _key = const Key('mapId#'); + String? _mapId; + final TextEditingController _mapIdController = TextEditingController(); + + void _setMapId() { + setState(() { + _mapId = _mapIdController.text; + + // Change key to initialize new map instance for new mapId. + _key = Key(_mapId ?? 'mapId#'); + }); + } + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + key: _key, + mapId: _mapId, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: TextField( + controller: _mapIdController, + decoration: const InputDecoration(hintText: 'Map Id'), + ), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: ElevatedButton( + onPressed: () => _setMapId(), + child: const Text('Press to use specified map Id'), + ), + ), + ]; + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + @override + void dispose() { + _mapIdController.dispose(); + super.dispose(); + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_ui.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_ui.dart new file mode 100644 index 000000000000..46fa320ad3a0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/map_ui.dart @@ -0,0 +1,341 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart' show rootBundle; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +final LatLngBounds sydneyBounds = LatLngBounds( + southwest: const LatLng(-34.022631, 150.620685), + northeast: const LatLng(-33.571835, 151.325952), +); + +class MapUiPage extends GoogleMapExampleAppPage { + const MapUiPage({Key? key}) + : super(const Icon(Icons.map), 'User interface', key: key); + + @override + Widget build(BuildContext context) { + return const MapUiBody(); + } +} + +class MapUiBody extends StatefulWidget { + const MapUiBody({super.key}); + + @override + State createState() => MapUiBodyState(); +} + +class MapUiBodyState extends State { + MapUiBodyState(); + + static const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, + ); + + CameraPosition _position = _kInitialPosition; + bool _isMapCreated = false; + final bool _isMoving = false; + bool _compassEnabled = true; + CameraTargetBounds _cameraTargetBounds = CameraTargetBounds.unbounded; + MinMaxZoomPreference _minMaxZoomPreference = MinMaxZoomPreference.unbounded; + MapType _mapType = MapType.normal; + bool _rotateGesturesEnabled = true; + bool _scrollGesturesEnabled = true; + bool _tiltGesturesEnabled = true; + bool _zoomControlsEnabled = false; + bool _zoomGesturesEnabled = true; + bool _indoorViewEnabled = true; + bool _myLocationEnabled = true; + bool _myTrafficEnabled = false; + bool _myLocationButtonEnabled = true; + late ExampleGoogleMapController _controller; + bool _nightMode = false; + String _mapStyle = ''; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + Widget _compassToggler() { + return TextButton( + child: Text('${_compassEnabled ? 'disable' : 'enable'} compass'), + onPressed: () { + setState(() { + _compassEnabled = !_compassEnabled; + }); + }, + ); + } + + Widget _latLngBoundsToggler() { + return TextButton( + child: Text( + _cameraTargetBounds.bounds == null + ? 'bound camera target' + : 'release camera target', + ), + onPressed: () { + setState(() { + _cameraTargetBounds = _cameraTargetBounds.bounds == null + ? CameraTargetBounds(sydneyBounds) + : CameraTargetBounds.unbounded; + }); + }, + ); + } + + Widget _zoomBoundsToggler() { + return TextButton( + child: Text( + _minMaxZoomPreference.minZoom == null ? 'bound zoom' : 'release zoom', + ), + onPressed: () { + setState(() { + _minMaxZoomPreference = _minMaxZoomPreference.minZoom == null + ? const MinMaxZoomPreference(12.0, 16.0) + : MinMaxZoomPreference.unbounded; + }); + }, + ); + } + + Widget _mapTypeCycler() { + final MapType nextType = + MapType.values[(_mapType.index + 1) % MapType.values.length]; + return TextButton( + child: Text('change map type to $nextType'), + onPressed: () { + setState(() { + _mapType = nextType; + }); + }, + ); + } + + Widget _rotateToggler() { + return TextButton( + child: Text('${_rotateGesturesEnabled ? 'disable' : 'enable'} rotate'), + onPressed: () { + setState(() { + _rotateGesturesEnabled = !_rotateGesturesEnabled; + }); + }, + ); + } + + Widget _scrollToggler() { + return TextButton( + child: Text('${_scrollGesturesEnabled ? 'disable' : 'enable'} scroll'), + onPressed: () { + setState(() { + _scrollGesturesEnabled = !_scrollGesturesEnabled; + }); + }, + ); + } + + Widget _tiltToggler() { + return TextButton( + child: Text('${_tiltGesturesEnabled ? 'disable' : 'enable'} tilt'), + onPressed: () { + setState(() { + _tiltGesturesEnabled = !_tiltGesturesEnabled; + }); + }, + ); + } + + Widget _zoomToggler() { + return TextButton( + child: Text('${_zoomGesturesEnabled ? 'disable' : 'enable'} zoom'), + onPressed: () { + setState(() { + _zoomGesturesEnabled = !_zoomGesturesEnabled; + }); + }, + ); + } + + Widget _zoomControlsToggler() { + return TextButton( + child: Text( + '${_zoomControlsEnabled ? 'disable' : 'enable'} zoom controls', + ), + onPressed: () { + setState(() { + _zoomControlsEnabled = !_zoomControlsEnabled; + }); + }, + ); + } + + Widget _indoorViewToggler() { + return TextButton( + child: Text('${_indoorViewEnabled ? 'disable' : 'enable'} indoor'), + onPressed: () { + setState(() { + _indoorViewEnabled = !_indoorViewEnabled; + }); + }, + ); + } + + Widget _myLocationToggler() { + return TextButton( + child: Text( + '${_myLocationEnabled ? 'disable' : 'enable'} my location marker', + ), + onPressed: () { + setState(() { + _myLocationEnabled = !_myLocationEnabled; + }); + }, + ); + } + + Widget _myLocationButtonToggler() { + return TextButton( + child: Text( + '${_myLocationButtonEnabled ? 'disable' : 'enable'} my location button', + ), + onPressed: () { + setState(() { + _myLocationButtonEnabled = !_myLocationButtonEnabled; + }); + }, + ); + } + + Widget _myTrafficToggler() { + return TextButton( + child: Text('${_myTrafficEnabled ? 'disable' : 'enable'} my traffic'), + onPressed: () { + setState(() { + _myTrafficEnabled = !_myTrafficEnabled; + }); + }, + ); + } + + Future _getFileData(String path) async { + return rootBundle.loadString(path); + } + + Widget _nightModeToggler() { + return TextButton( + child: Text('${_nightMode ? 'disable' : 'enable'} night mode'), + onPressed: () async { + _nightMode = !_nightMode; + final String style = _nightMode + ? await _getFileData('assets/night_mode.json') + : ''; + setState(() { + _mapStyle = style; + }); + }, + ); + } + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + compassEnabled: _compassEnabled, + cameraTargetBounds: _cameraTargetBounds, + minMaxZoomPreference: _minMaxZoomPreference, + mapType: _mapType, + style: _mapStyle, + rotateGesturesEnabled: _rotateGesturesEnabled, + scrollGesturesEnabled: _scrollGesturesEnabled, + tiltGesturesEnabled: _tiltGesturesEnabled, + zoomGesturesEnabled: _zoomGesturesEnabled, + zoomControlsEnabled: _zoomControlsEnabled, + indoorViewEnabled: _indoorViewEnabled, + myLocationEnabled: _myLocationEnabled, + myLocationButtonEnabled: _myLocationButtonEnabled, + trafficEnabled: _myTrafficEnabled, + onCameraMove: _updateCameraPosition, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + ]; + + if (_isMapCreated) { + columnChildren.add( + Expanded( + child: ListView( + children: [ + Text('camera bearing: ${_position.bearing}'), + Text( + 'camera target: ${_position.target.latitude.toStringAsFixed(4)},' + '${_position.target.longitude.toStringAsFixed(4)}', + ), + Text('camera zoom: ${_position.zoom}'), + Text('camera tilt: ${_position.tilt}'), + Text(_isMoving ? '(Camera moving)' : '(Camera idle)'), + _compassToggler(), + _latLngBoundsToggler(), + _mapTypeCycler(), + _zoomBoundsToggler(), + _rotateToggler(), + _scrollToggler(), + _tiltToggler(), + _zoomToggler(), + _zoomControlsToggler(), + _indoorViewToggler(), + _myLocationToggler(), + _myLocationButtonToggler(), + _myTrafficToggler(), + _nightModeToggler(), + ], + ), + ), + ); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + void _updateCameraPosition(CameraPosition position) { + setState(() { + _position = position; + }); + } + + void onMapCreated(ExampleGoogleMapController controller) { + setState(() { + _controller = controller; + _isMapCreated = true; + }); + // Log any style errors to the console for debugging. + _controller.getStyleError().then((String? error) { + if (error != null) { + debugPrint(error); + } + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/maps_demo.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/maps_demo.dart new file mode 100644 index 000000000000..6d21ab3b91e9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/maps_demo.dart @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'page.dart'; + +/// MapsDemo is the Main Application. +class MapsDemo extends StatelessWidget { + /// Default Constructor + const MapsDemo(this.pages, {super.key}); + + /// The list of demo pages. + final List pages; + + void _pushPage(BuildContext context, GoogleMapExampleAppPage page) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + appBar: AppBar(title: Text(page.title)), + body: page, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('GoogleMaps examples')), + body: ListView.builder( + itemCount: pages.length, + itemBuilder: (_, int index) => ListTile( + leading: pages[index].leading, + title: Text(pages[index].title), + onTap: () => _pushPage(context, pages[index]), + ), + ), + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/marker_icons.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/marker_icons.dart new file mode 100644 index 000000000000..2959c7c0dcf0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/marker_icons.dart @@ -0,0 +1,355 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs +// ignore_for_file: unawaited_futures + +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'custom_marker_icon.dart'; +import 'example_google_map.dart'; +import 'page.dart'; + +class MarkerIconsPage extends GoogleMapExampleAppPage { + const MarkerIconsPage({Key? key}) + : super(const Icon(Icons.image), 'Marker icons', key: key); + + @override + Widget build(BuildContext context) { + return const MarkerIconsBody(); + } +} + +class MarkerIconsBody extends StatefulWidget { + const MarkerIconsBody({super.key}); + + @override + State createState() => MarkerIconsBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +enum _MarkerSizeOption { original, width30, height40, size30x60, size120x60 } + +class MarkerIconsBodyState extends State { + final Size _markerAssetImageSize = const Size(48, 48); + _MarkerSizeOption _currentSizeOption = _MarkerSizeOption.original; + Set _markers = {}; + bool _scalingEnabled = true; + bool _mipMapsEnabled = true; + ExampleGoogleMapController? controller; + AssetMapBitmap? _markerIconAsset; + BytesMapBitmap? _markerIconBytes; + final int _markersAmountPerType = 15; + bool get _customSizeEnabled => + _currentSizeOption != _MarkerSizeOption.original; + + @override + Widget build(BuildContext context) { + _createCustomMarkerIconImages(context); + final Size referenceSize = _getMarkerReferenceSize(); + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Column( + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + markers: _markers, + onMapCreated: _onMapCreated, + ), + ), + ), + TextButton( + onPressed: () => _toggleScaling(context), + child: Text( + _scalingEnabled + ? 'Disable auto scaling' + : 'Enable auto scaling', + ), + ), + if (_scalingEnabled) ...[ + Container( + width: referenceSize.width, + height: referenceSize.height, + decoration: BoxDecoration(border: Border.all()), + ), + Text( + 'Reference box with size of ${referenceSize.width} x ${referenceSize.height} in logical pixels.', + ), + const SizedBox(height: 10), + Image.asset( + 'assets/red_square.png', + scale: _mipMapsEnabled ? null : 1.0, + ), + const Text('Asset image rendered with flutter'), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Marker size:'), + const SizedBox(width: 10), + DropdownButton<_MarkerSizeOption>( + value: _currentSizeOption, + onChanged: (_MarkerSizeOption? newValue) { + if (newValue != null) { + setState(() { + _currentSizeOption = newValue; + _updateMarkerImages(context); + }); + } + }, + items: _MarkerSizeOption.values.map(( + _MarkerSizeOption option, + ) { + return DropdownMenuItem<_MarkerSizeOption>( + value: option, + child: Text(_getMarkerSizeOptionName(option)), + ); + }).toList(), + ), + ], + ), + ], + TextButton( + onPressed: () => _toggleMipMaps(context), + child: Text( + _mipMapsEnabled ? 'Disable mipmaps' : 'Enable mipmaps', + ), + ), + ], + ), + ], + ); + } + + String _getMarkerSizeOptionName(_MarkerSizeOption option) { + switch (option) { + case _MarkerSizeOption.original: + return 'Original'; + case _MarkerSizeOption.width30: + return 'Width 30'; + case _MarkerSizeOption.height40: + return 'Height 40'; + case _MarkerSizeOption.size30x60: + return '30x60'; + case _MarkerSizeOption.size120x60: + return '120x60'; + } + } + + (double? width, double? height) _getCurrentMarkerSize() { + if (_scalingEnabled) { + switch (_currentSizeOption) { + case _MarkerSizeOption.width30: + return (30, null); + case _MarkerSizeOption.height40: + return (null, 40); + case _MarkerSizeOption.size30x60: + return (30, 60); + case _MarkerSizeOption.size120x60: + return (120, 60); + case _MarkerSizeOption.original: + return (_markerAssetImageSize.width, _markerAssetImageSize.height); + } + } else { + return (_markerAssetImageSize.width, _markerAssetImageSize.height); + } + } + + // Helper method to calculate reference size for custom marker size. + Size _getMarkerReferenceSize() { + final (double? width, double? height) = _getCurrentMarkerSize(); + + // Calculates reference size using _markerAssetImageSize aspect ration: + + if (width != null && height != null) { + return Size(width, height); + } else if (width != null) { + return Size( + width, + width * _markerAssetImageSize.height / _markerAssetImageSize.width, + ); + } else if (height != null) { + return Size( + height * _markerAssetImageSize.width / _markerAssetImageSize.height, + height, + ); + } else { + return _markerAssetImageSize; + } + } + + void _toggleMipMaps(BuildContext context) { + _mipMapsEnabled = !_mipMapsEnabled; + _updateMarkerImages(context); + } + + void _toggleScaling(BuildContext context) { + _scalingEnabled = !_scalingEnabled; + _updateMarkerImages(context); + } + + void _updateMarkerImages(BuildContext context) { + _updateMarkerAssetImage(context); + _updateMarkerBytesImage(context); + _updateMarkers(); + } + + Marker _createAssetMarker(int index) { + final position = LatLng( + _kMapCenter.latitude - (index * 0.5), + _kMapCenter.longitude - 1, + ); + + return Marker( + markerId: MarkerId('marker_asset_$index'), + position: position, + icon: _markerIconAsset!, + ); + } + + Marker _createBytesMarker(int index) { + final position = LatLng( + _kMapCenter.latitude - (index * 0.5), + _kMapCenter.longitude + 1, + ); + + return Marker( + markerId: MarkerId('marker_bytes_$index'), + position: position, + icon: _markerIconBytes!, + ); + } + + void _updateMarkers() { + final markers = {}; + for (var i = 0; i < _markersAmountPerType; i++) { + if (_markerIconAsset != null) { + markers.add(_createAssetMarker(i)); + } + if (_markerIconBytes != null) { + markers.add(_createBytesMarker(i)); + } + } + setState(() { + _markers = markers; + }); + } + + Future _updateMarkerAssetImage(BuildContext context) async { + // Width and height are used only for custom size. + final ( + double? width, + double? height, + ) = _scalingEnabled && _customSizeEnabled + ? _getCurrentMarkerSize() + : (null, null); + + AssetMapBitmap assetMapBitmap; + if (_mipMapsEnabled) { + final ImageConfiguration imageConfiguration = + createLocalImageConfiguration(context); + + assetMapBitmap = await AssetMapBitmap.create( + imageConfiguration, + 'assets/red_square.png', + width: width, + height: height, + bitmapScaling: _scalingEnabled + ? MapBitmapScaling.auto + : MapBitmapScaling.none, + ); + } else { + // Uses hardcoded asset path + // This bypasses the asset resolving logic and allows to load the asset + // with precise path. + assetMapBitmap = AssetMapBitmap( + 'assets/red_square.png', + width: width, + height: height, + bitmapScaling: _scalingEnabled + ? MapBitmapScaling.auto + : MapBitmapScaling.none, + ); + } + + _updateAssetBitmap(assetMapBitmap); + } + + Future _updateMarkerBytesImage(BuildContext context) async { + final double? devicePixelRatio = MediaQuery.maybeDevicePixelRatioOf( + context, + ); + + final Size bitmapLogicalSize = _getMarkerReferenceSize(); + final double? imagePixelRatio = _scalingEnabled ? devicePixelRatio : null; + + // Create canvasSize with physical marker size + final canvasSize = Size( + bitmapLogicalSize.width * (imagePixelRatio ?? 1.0), + bitmapLogicalSize.height * (imagePixelRatio ?? 1.0), + ); + + final ByteData bytes = await createCustomMarkerIconImage(size: canvasSize); + + // Width and height are used only for custom size. + final ( + double? width, + double? height, + ) = _scalingEnabled && _customSizeEnabled + ? _getCurrentMarkerSize() + : (null, null); + + final bitmap = BytesMapBitmap( + bytes.buffer.asUint8List(), + imagePixelRatio: imagePixelRatio, + width: width, + height: height, + bitmapScaling: _scalingEnabled + ? MapBitmapScaling.auto + : MapBitmapScaling.none, + ); + + _updateBytesBitmap(bitmap); + } + + void _updateAssetBitmap(AssetMapBitmap bitmap) { + _markerIconAsset = bitmap; + _updateMarkers(); + } + + void _updateBytesBitmap(BytesMapBitmap bitmap) { + _markerIconBytes = bitmap; + _updateMarkers(); + } + + void _createCustomMarkerIconImages(BuildContext context) { + if (_markerIconAsset == null) { + _updateMarkerAssetImage(context); + } + + if (_markerIconBytes == null) { + _updateMarkerBytesImage(context); + } + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/move_camera.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/move_camera.dart new file mode 100644 index 000000000000..bc6fcdea2651 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/move_camera.dart @@ -0,0 +1,161 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class MoveCameraPage extends GoogleMapExampleAppPage { + const MoveCameraPage({Key? key}) + : super(const Icon(Icons.map), 'Camera control', key: key); + + @override + Widget build(BuildContext context) { + return const MoveCamera(); + } +} + +class MoveCamera extends StatefulWidget { + const MoveCamera({super.key}); + @override + State createState() => MoveCameraState(); +} + +class MoveCameraState extends State { + ExampleGoogleMapController? mapController; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + mapController = controller; + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(0.0, 0.0), + ), + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newCameraPosition( + const CameraPosition( + bearing: 270.0, + target: LatLng(51.5160895, -0.1294527), + tilt: 30.0, + zoom: 17.0, + ), + ), + ); + }, + child: const Text('newCameraPosition'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newLatLng( + const LatLng(56.1725505, 10.1850512), + ), + ); + }, + child: const Text('newLatLng'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newLatLngBounds( + LatLngBounds( + southwest: const LatLng(-38.483935, 113.248673), + northeast: const LatLng(-8.982446, 153.823821), + ), + 10.0, + ), + ); + }, + child: const Text('newLatLngBounds'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newLatLngZoom( + const LatLng(37.4231613, -122.087159), + 11.0, + ), + ); + }, + child: const Text('newLatLngZoom'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.scrollBy(150.0, -225.0), + ); + }, + child: const Text('scrollBy'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.zoomBy(-0.5, const Offset(30.0, 20.0)), + ); + }, + child: const Text('zoomBy with focus'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomBy(-0.5)); + }, + child: const Text('zoomBy'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomIn()); + }, + child: const Text('zoomIn'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomOut()); + }, + child: const Text('zoomOut'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomTo(16.0)); + }, + child: const Text('zoomTo'), + ), + ], + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/padding.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/padding.dart new file mode 100644 index 000000000000..beb39b305f58 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/padding.dart @@ -0,0 +1,169 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PaddingPage extends GoogleMapExampleAppPage { + const PaddingPage({Key? key}) + : super(const Icon(Icons.map), 'Add padding to the map', key: key); + + @override + Widget build(BuildContext context) { + return const MarkerIconsBody(); + } +} + +class MarkerIconsBody extends StatefulWidget { + const MarkerIconsBody({super.key}); + + @override + State createState() => MarkerIconsBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +class MarkerIconsBodyState extends State { + ExampleGoogleMapController? controller; + + EdgeInsets _padding = EdgeInsets.zero; + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + padding: _padding, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + const Padding( + padding: EdgeInsets.only(top: 20), + child: Center( + child: Text( + 'Enter Padding Below', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + ), + ]; + + columnChildren.addAll([_paddingInput(), _buttons()]); + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } + + final TextEditingController _topController = TextEditingController(); + final TextEditingController _bottomController = TextEditingController(); + final TextEditingController _leftController = TextEditingController(); + final TextEditingController _rightController = TextEditingController(); + + Widget _paddingInput() { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Flexible( + flex: 2, + child: TextField( + controller: _topController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Top'), + ), + ), + const Spacer(), + Flexible( + flex: 2, + child: TextField( + controller: _bottomController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Bottom'), + ), + ), + const Spacer(), + Flexible( + flex: 2, + child: TextField( + controller: _leftController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Left'), + ), + ), + const Spacer(), + Flexible( + flex: 2, + child: TextField( + controller: _rightController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Right'), + ), + ), + ], + ), + ); + } + + Widget _buttons() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + child: const Text('Set Padding'), + onPressed: () { + setState(() { + _padding = EdgeInsets.fromLTRB( + double.tryParse(_leftController.value.text) ?? 0, + double.tryParse(_topController.value.text) ?? 0, + double.tryParse(_rightController.value.text) ?? 0, + double.tryParse(_bottomController.value.text) ?? 0, + ); + }); + }, + ), + TextButton( + child: const Text('Reset Padding'), + onPressed: () { + setState(() { + _topController.clear(); + _bottomController.clear(); + _leftController.clear(); + _rightController.clear(); + _padding = EdgeInsets.zero; + }); + }, + ), + ], + ), + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/page.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/page.dart new file mode 100644 index 000000000000..2793b9d10edb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/page.dart @@ -0,0 +1,14 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; + +abstract class GoogleMapExampleAppPage extends StatelessWidget { + const GoogleMapExampleAppPage(this.leading, this.title, {super.key}); + + final Widget leading; + final String title; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_circle.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_circle.dart new file mode 100644 index 000000000000..88c84c79e124 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_circle.dart @@ -0,0 +1,227 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PlaceCirclePage extends GoogleMapExampleAppPage { + const PlaceCirclePage({Key? key}) + : super(const Icon(Icons.linear_scale), 'Place circle', key: key); + + @override + Widget build(BuildContext context) { + return const PlaceCircleBody(); + } +} + +class PlaceCircleBody extends StatefulWidget { + const PlaceCircleBody({super.key}); + + @override + State createState() => PlaceCircleBodyState(); +} + +class PlaceCircleBodyState extends State { + PlaceCircleBodyState(); + + ExampleGoogleMapController? controller; + Map circles = {}; + int _circleIdCounter = 1; + CircleId? selectedCircle; + + // Values when toggling circle color + int fillColorsIndex = 0; + int strokeColorsIndex = 0; + List colors = [ + Colors.purple, + Colors.red, + Colors.green, + Colors.pink, + ]; + + // Values when toggling circle stroke width + int widthsIndex = 0; + List widths = [10, 20, 5]; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onCircleTapped(CircleId circleId) { + setState(() { + selectedCircle = circleId; + }); + } + + void _remove(CircleId circleId) { + setState(() { + if (circles.containsKey(circleId)) { + circles.remove(circleId); + } + if (circleId == selectedCircle) { + selectedCircle = null; + } + }); + } + + void _add() { + final int circleCount = circles.length; + + if (circleCount == 12) { + return; + } + + final circleIdVal = 'circle_id_$_circleIdCounter'; + _circleIdCounter++; + final circleId = CircleId(circleIdVal); + + final circle = Circle( + circleId: circleId, + consumeTapEvents: true, + strokeColor: Colors.orange, + fillColor: Colors.green, + strokeWidth: 5, + center: _createCenter(), + radius: 50000, + onTap: () { + _onCircleTapped(circleId); + }, + ); + + setState(() { + circles[circleId] = circle; + }); + } + + void _toggleVisible(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith(visibleParam: !circle.visible); + }); + } + + void _changeFillColor(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith( + fillColorParam: colors[++fillColorsIndex % colors.length], + ); + }); + } + + void _changeStrokeColor(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith( + strokeColorParam: colors[++strokeColorsIndex % colors.length], + ); + }); + } + + void _changeStrokeWidth(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith( + strokeWidthParam: widths[++widthsIndex % widths.length], + ); + }); + } + + @override + Widget build(BuildContext context) { + final CircleId? selectedId = selectedCircle; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(52.4478, -3.5402), + zoom: 7.0, + ), + circles: Set.of(circles.values), + onMapCreated: _onMapCreated, + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + TextButton(onPressed: _add, child: const Text('add')), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), + child: const Text('remove'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeStrokeWidth(selectedId), + child: const Text('change stroke width'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeStrokeColor(selectedId), + child: const Text('change stroke color'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeFillColor(selectedId), + child: const Text('change fill color'), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ); + } + + LatLng _createCenter() { + final double offset = _circleIdCounter.ceilToDouble(); + return _createLatLng(51.4816 + offset * 0.2, -3.1791); + } + + LatLng _createLatLng(double lat, double lng) { + return LatLng(lat, lng); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_marker.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_marker.dart new file mode 100644 index 000000000000..926c2db2e426 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_marker.dart @@ -0,0 +1,417 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:async'; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'custom_marker_icon.dart'; +import 'example_google_map.dart'; +import 'page.dart'; + +class PlaceMarkerPage extends GoogleMapExampleAppPage { + const PlaceMarkerPage({Key? key}) + : super(const Icon(Icons.place), 'Place marker', key: key); + + @override + Widget build(BuildContext context) { + return const PlaceMarkerBody(); + } +} + +class PlaceMarkerBody extends StatefulWidget { + const PlaceMarkerBody({super.key}); + + @override + State createState() => PlaceMarkerBodyState(); +} + +typedef MarkerUpdateAction = Marker Function(Marker marker); + +class PlaceMarkerBodyState extends State { + PlaceMarkerBodyState(); + static const LatLng center = LatLng(-33.86711, 151.1947171); + + ExampleGoogleMapController? controller; + Map markers = {}; + MarkerId? selectedMarker; + int _markerIdCounter = 1; + LatLng? markerPosition; + // A helper text for Xcode UITests. + String _onDragXcodeUITestHelperText = ''; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onMarkerTapped(MarkerId markerId) { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + final MarkerId? previousMarkerId = selectedMarker; + if (previousMarkerId != null && markers.containsKey(previousMarkerId)) { + final Marker resetOld = markers[previousMarkerId]!.copyWith( + iconParam: BitmapDescriptor.defaultMarker, + ); + markers[previousMarkerId] = resetOld; + } + selectedMarker = markerId; + final Marker newMarker = tappedMarker.copyWith( + iconParam: BitmapDescriptor.defaultMarkerWithHue( + BitmapDescriptor.hueGreen, + ), + ); + markers[markerId] = newMarker; + + markerPosition = null; + }); + } + } + + Future _onMarkerDrag(MarkerId markerId, LatLng newPosition) async { + setState(() { + markerPosition = newPosition; + if (!_onDragXcodeUITestHelperText.contains('\n_onMarkerDrag called')) { + // _onMarkerDrag can be called multiple times during a single drag. + // Only log _onMarkerDrag once per dragging action to reduce noises in UI. + _onDragXcodeUITestHelperText += '\n_onMarkerDrag called'; + } + }); + } + + Future _onMarkerDragStart(MarkerId markerId, LatLng newPosition) async { + setState(() { + _onDragXcodeUITestHelperText += '\n_onMarkerDragStart'; + }); + } + + Future _onMarkerDragEnd(MarkerId markerId, LatLng newPosition) async { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + _onDragXcodeUITestHelperText += '\n_onMarkerDragEnd'; + markerPosition = null; + }); + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + actions: [ + TextButton( + child: const Text('OK'), + onPressed: () { + _onDragXcodeUITestHelperText = ''; + Navigator.of(context).pop(); + }, + ), + ], + content: Padding( + padding: const EdgeInsets.symmetric(vertical: 66), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('iOS delegate called: \n $_onDragXcodeUITestHelperText'), + Text('Old position: ${tappedMarker.position}'), + Text('New position: $newPosition'), + ], + ), + ), + ); + }, + ); + } + } + + void _add() { + final int markerCount = markers.length; + + if (markerCount == 12) { + return; + } + + final markerIdVal = 'marker_id_$_markerIdCounter'; + _markerIdCounter++; + final markerId = MarkerId(markerIdVal); + + final marker = Marker( + markerId: markerId, + position: LatLng( + center.latitude + sin(_markerIdCounter * pi / 6.0) / 20.0, + center.longitude + cos(_markerIdCounter * pi / 6.0) / 20.0, + ), + infoWindow: InfoWindow(title: markerIdVal, snippet: '*'), + onTap: () => _onMarkerTapped(markerId), + onDragStart: (LatLng position) => _onMarkerDragStart(markerId, position), + onDragEnd: (LatLng position) => _onMarkerDragEnd(markerId, position), + onDrag: (LatLng position) => _onMarkerDrag(markerId, position), + ); + + setState(() { + markers[markerId] = marker; + }); + } + + void _remove(MarkerId markerId) { + setState(() { + if (markers.containsKey(markerId)) { + markers.remove(markerId); + } + }); + } + + void _changePosition(MarkerId markerId) { + final Marker marker = markers[markerId]!; + final LatLng current = marker.position; + final offset = Offset( + center.latitude - current.latitude, + center.longitude - current.longitude, + ); + setState(() { + markers[markerId] = marker.copyWith( + positionParam: LatLng( + center.latitude + offset.dy, + center.longitude + offset.dx, + ), + ); + }); + } + + void _changeAnchor(MarkerId markerId) { + final Marker marker = markers[markerId]!; + final Offset currentAnchor = marker.anchor; + final newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); + setState(() { + markers[markerId] = marker.copyWith(anchorParam: newAnchor); + }); + } + + Future _changeInfoAnchor(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final Offset currentAnchor = marker.infoWindow.anchor; + final newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); + setState(() { + markers[markerId] = marker.copyWith( + infoWindowParam: marker.infoWindow.copyWith(anchorParam: newAnchor), + ); + }); + } + + Future _toggleDraggable(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(draggableParam: !marker.draggable); + }); + } + + Future _toggleFlat(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(flatParam: !marker.flat); + }); + } + + Future _changeInfo(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final newSnippet = '${marker.infoWindow.snippet!}*'; + setState(() { + markers[markerId] = marker.copyWith( + infoWindowParam: marker.infoWindow.copyWith(snippetParam: newSnippet), + ); + }); + } + + Future _changeAlpha(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final double current = marker.alpha; + setState(() { + markers[markerId] = marker.copyWith( + alphaParam: current < 0.1 ? 1.0 : current * 0.75, + ); + }); + } + + Future _changeRotation(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final double current = marker.rotation; + setState(() { + markers[markerId] = marker.copyWith( + rotationParam: current == 330.0 ? 0.0 : current + 30.0, + ); + }); + } + + Future _toggleVisible(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(visibleParam: !marker.visible); + }); + } + + Future _changeZIndex(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final int current = marker.zIndexInt; + setState(() { + markers[markerId] = marker.copyWith( + zIndexIntParam: current == 12 ? 0 : current + 1, + ); + }); + } + + void _setMarkerIcon(MarkerId markerId, BitmapDescriptor assetIcon) { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(iconParam: assetIcon); + }); + } + + Future _getMarkerIcon(BuildContext context) async { + const canvasSize = Size(48, 48); + final ByteData bytes = await createCustomMarkerIconImage(size: canvasSize); + return BytesMapBitmap(bytes.buffer.asUint8List()); + } + + @override + Widget build(BuildContext context) { + final MarkerId? selectedId = selectedMarker; + return Stack( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, + ), + markers: Set.of(markers.values), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton(onPressed: _add, child: const Text('Add')), + TextButton( + onPressed: selectedId == null + ? null + : () => _remove(selectedId), + child: const Text('Remove'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: selectedId == null + ? null + : () => _changeInfo(selectedId), + child: const Text('change info'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeInfoAnchor(selectedId), + child: const Text('change info anchor'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeAlpha(selectedId), + child: const Text('change alpha'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeAnchor(selectedId), + child: const Text('change anchor'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _toggleDraggable(selectedId), + child: const Text('toggle draggable'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _toggleFlat(selectedId), + child: const Text('toggle flat'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changePosition(selectedId), + child: const Text('change position'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeRotation(selectedId), + child: const Text('change rotation'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeZIndex(selectedId), + child: const Text('change zIndex'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () { + _getMarkerIcon(context).then((BitmapDescriptor icon) { + _setMarkerIcon(selectedId, icon); + }); + }, + child: const Text('set marker icon'), + ), + ], + ), + ], + ), + Visibility( + visible: markerPosition != null, + child: Container( + color: Colors.white70, + height: 30, + padding: const EdgeInsets.only(left: 12, right: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + if (markerPosition == null) + Container() + else + Expanded(child: Text('lat: ${markerPosition!.latitude}')), + if (markerPosition == null) + Container() + else + Expanded(child: Text('lng: ${markerPosition!.longitude}')), + ], + ), + ), + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_polygon.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_polygon.dart new file mode 100644 index 000000000000..ff9eac82210c --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_polygon.dart @@ -0,0 +1,298 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PlacePolygonPage extends GoogleMapExampleAppPage { + const PlacePolygonPage({Key? key}) + : super(const Icon(Icons.linear_scale), 'Place polygon', key: key); + + @override + Widget build(BuildContext context) { + return const PlacePolygonBody(); + } +} + +class PlacePolygonBody extends StatefulWidget { + const PlacePolygonBody({super.key}); + + @override + State createState() => PlacePolygonBodyState(); +} + +class PlacePolygonBodyState extends State { + PlacePolygonBodyState(); + + ExampleGoogleMapController? controller; + Map polygons = {}; + Map polygonOffsets = {}; + int _polygonIdCounter = 0; + PolygonId? selectedPolygon; + + // Values when toggling polygon color + int strokeColorsIndex = 0; + int fillColorsIndex = 0; + List colors = [ + Colors.purple, + Colors.red, + Colors.green, + Colors.pink, + ]; + + // Values when toggling polygon width + int widthsIndex = 0; + List widths = [10, 20, 5]; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onPolygonTapped(PolygonId polygonId) { + setState(() { + selectedPolygon = polygonId; + }); + } + + void _remove(PolygonId polygonId) { + setState(() { + if (polygons.containsKey(polygonId)) { + polygons.remove(polygonId); + } + selectedPolygon = null; + }); + } + + void _add() { + final int polygonCount = polygons.length; + + if (polygonCount == 12) { + return; + } + + final polygonIdVal = 'polygon_id_$_polygonIdCounter'; + final polygonId = PolygonId(polygonIdVal); + + final polygon = Polygon( + polygonId: polygonId, + consumeTapEvents: true, + strokeColor: Colors.orange, + strokeWidth: 5, + fillColor: Colors.green, + points: _createPoints(), + onTap: () { + _onPolygonTapped(polygonId); + }, + ); + + setState(() { + polygons[polygonId] = polygon; + polygonOffsets[polygonId] = _polygonIdCounter.ceilToDouble(); + // increment _polygonIdCounter to have unique polygon id each time + _polygonIdCounter++; + }); + } + + void _toggleGeodesic(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith(geodesicParam: !polygon.geodesic); + }); + } + + void _toggleVisible(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith(visibleParam: !polygon.visible); + }); + } + + void _changeStrokeColor(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + strokeColorParam: colors[++strokeColorsIndex % colors.length], + ); + }); + } + + void _changeFillColor(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + fillColorParam: colors[++fillColorsIndex % colors.length], + ); + }); + } + + void _changeWidth(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + strokeWidthParam: widths[++widthsIndex % widths.length], + ); + }); + } + + void _addHoles(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + holesParam: _createHoles(polygonId), + ); + }); + } + + void _removeHoles(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith(holesParam: >[]); + }); + } + + @override + Widget build(BuildContext context) { + final PolygonId? selectedId = selectedPolygon; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(52.4478, -3.5402), + zoom: 7.0, + ), + polygons: Set.of(polygons.values), + onMapCreated: _onMapCreated, + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + TextButton(onPressed: _add, child: const Text('add')), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), + child: const Text('remove'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleGeodesic(selectedId), + child: const Text('toggle geodesic'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: (selectedId == null) + ? null + : (polygons[selectedId]!.holes.isNotEmpty + ? null + : () => _addHoles(selectedId)), + child: const Text('add holes'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : (polygons[selectedId]!.holes.isEmpty + ? null + : () => _removeHoles(selectedId)), + child: const Text('remove holes'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeWidth(selectedId), + child: const Text('change stroke width'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeStrokeColor(selectedId), + child: const Text('change stroke color'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeFillColor(selectedId), + child: const Text('change fill color'), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ); + } + + List _createPoints() { + final points = []; + final double offset = _polygonIdCounter.ceilToDouble(); + points.add(_createLatLng(51.2395 + offset, -3.4314)); + points.add(_createLatLng(53.5234 + offset, -3.5314)); + points.add(_createLatLng(52.4351 + offset, -4.5235)); + points.add(_createLatLng(52.1231 + offset, -5.0829)); + return points; + } + + List> _createHoles(PolygonId polygonId) { + final holes = >[]; + final double offset = polygonOffsets[polygonId]!; + + final hole1 = []; + hole1.add(_createLatLng(51.8395 + offset, -3.8814)); + hole1.add(_createLatLng(52.0234 + offset, -3.9914)); + hole1.add(_createLatLng(52.1351 + offset, -4.4435)); + hole1.add(_createLatLng(52.0231 + offset, -4.5829)); + holes.add(hole1); + + final hole2 = []; + hole2.add(_createLatLng(52.2395 + offset, -3.6814)); + hole2.add(_createLatLng(52.4234 + offset, -3.7914)); + hole2.add(_createLatLng(52.5351 + offset, -4.2435)); + hole2.add(_createLatLng(52.4231 + offset, -4.3829)); + holes.add(hole2); + + return holes; + } + + LatLng _createLatLng(double lat, double lng) { + return LatLng(lat, lng); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_polyline.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_polyline.dart new file mode 100644 index 000000000000..f749cac5f268 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/place_polyline.dart @@ -0,0 +1,322 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PlacePolylinePage extends GoogleMapExampleAppPage { + const PlacePolylinePage({Key? key}) + : super(const Icon(Icons.linear_scale), 'Place polyline', key: key); + + @override + Widget build(BuildContext context) { + return const PlacePolylineBody(); + } +} + +class PlacePolylineBody extends StatefulWidget { + const PlacePolylineBody({super.key}); + + @override + State createState() => PlacePolylineBodyState(); +} + +class PlacePolylineBodyState extends State { + PlacePolylineBodyState(); + + ExampleGoogleMapController? controller; + Map polylines = {}; + int _polylineIdCounter = 0; + PolylineId? selectedPolyline; + + // Values when toggling polyline color + int colorsIndex = 0; + List colors = [ + Colors.purple, + Colors.red, + Colors.green, + Colors.pink, + ]; + + // Values when toggling polyline width + int widthsIndex = 0; + List widths = [10, 20, 5]; + + int jointTypesIndex = 0; + List jointTypes = [ + JointType.mitered, + JointType.bevel, + JointType.round, + ]; + + // Values when toggling polyline end cap type + int endCapsIndex = 0; + List endCaps = [Cap.buttCap, Cap.squareCap, Cap.roundCap]; + + // Values when toggling polyline start cap type + int startCapsIndex = 0; + List startCaps = [Cap.buttCap, Cap.squareCap, Cap.roundCap]; + + // Values when toggling polyline pattern + int patternsIndex = 0; + List> patterns = >[ + [], + [ + PatternItem.dash(30.0), + PatternItem.gap(20.0), + PatternItem.dot, + PatternItem.gap(20.0), + ], + [PatternItem.dash(30.0), PatternItem.gap(20.0)], + [PatternItem.dot, PatternItem.gap(10.0)], + ]; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onPolylineTapped(PolylineId polylineId) { + setState(() { + selectedPolyline = polylineId; + }); + } + + void _remove(PolylineId polylineId) { + setState(() { + if (polylines.containsKey(polylineId)) { + polylines.remove(polylineId); + } + selectedPolyline = null; + }); + } + + void _add() { + final int polylineCount = polylines.length; + + if (polylineCount == 12) { + return; + } + + final polylineIdVal = 'polyline_id_$_polylineIdCounter'; + _polylineIdCounter++; + final polylineId = PolylineId(polylineIdVal); + + final polyline = Polyline( + polylineId: polylineId, + consumeTapEvents: true, + color: Colors.orange, + width: 5, + points: _createPoints(), + onTap: () { + _onPolylineTapped(polylineId); + }, + ); + + setState(() { + polylines[polylineId] = polyline; + }); + } + + void _toggleGeodesic(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + geodesicParam: !polyline.geodesic, + ); + }); + } + + void _toggleVisible(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + visibleParam: !polyline.visible, + ); + }); + } + + void _changeColor(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + colorParam: colors[++colorsIndex % colors.length], + ); + }); + } + + void _changeWidth(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + widthParam: widths[++widthsIndex % widths.length], + ); + }); + } + + void _changeJointType(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + jointTypeParam: jointTypes[++jointTypesIndex % jointTypes.length], + ); + }); + } + + void _changeEndCap(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + endCapParam: endCaps[++endCapsIndex % endCaps.length], + ); + }); + } + + void _changeStartCap(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + startCapParam: startCaps[++startCapsIndex % startCaps.length], + ); + }); + } + + void _changePattern(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + patternsParam: patterns[++patternsIndex % patterns.length], + ); + }); + } + + @override + Widget build(BuildContext context) { + final bool isIOS = !kIsWeb && defaultTargetPlatform == TargetPlatform.iOS; + + final PolylineId? selectedId = selectedPolyline; + + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(53.1721, -3.5402), + zoom: 7.0, + ), + polylines: Set.of(polylines.values), + onMapCreated: _onMapCreated, + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + TextButton(onPressed: _add, child: const Text('add')), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), + child: const Text('remove'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleGeodesic(selectedId), + child: const Text('toggle geodesic'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeWidth(selectedId), + child: const Text('change width'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeColor(selectedId), + child: const Text('change color'), + ), + TextButton( + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeStartCap(selectedId), + child: const Text('change start cap [Android only]'), + ), + TextButton( + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeEndCap(selectedId), + child: const Text('change end cap [Android only]'), + ), + TextButton( + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeJointType(selectedId), + child: const Text('change joint type [Android only]'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changePattern(selectedId), + child: const Text('change pattern'), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ); + } + + List _createPoints() { + final points = []; + final double offset = _polylineIdCounter.ceilToDouble(); + points.add(_createLatLng(51.4816 + offset, -3.1791)); + points.add(_createLatLng(53.0430 + offset, -2.9925)); + points.add(_createLatLng(53.1396 + offset, -4.2739)); + points.add(_createLatLng(52.4153 + offset, -4.0829)); + return points; + } + + LatLng _createLatLng(double lat, double lng) { + return LatLng(lat, lng); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/scrolling_map.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/scrolling_map.dart new file mode 100644 index 000000000000..57d8cd6d9ff4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/scrolling_map.dart @@ -0,0 +1,112 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const LatLng _center = LatLng(32.080664, 34.9563837); + +class ScrollingMapPage extends GoogleMapExampleAppPage { + const ScrollingMapPage({Key? key}) + : super(const Icon(Icons.map), 'Scrolling map', key: key); + + @override + Widget build(BuildContext context) { + return const ScrollingMapBody(); + } +} + +class ScrollingMapBody extends StatelessWidget { + const ScrollingMapBody({super.key}); + + @override + Widget build(BuildContext context) { + return ListView( + children: [ + Card( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 30.0), + child: Column( + children: [ + const Padding( + padding: EdgeInsets.only(bottom: 12.0), + child: Text('This map consumes all touch events.'), + ), + Center( + child: SizedBox( + width: 300.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: _center, + zoom: 11.0, + ), + gestureRecognizers: // + >{ + Factory( + () => EagerGestureRecognizer(), + ), + }, + ), + ), + ), + ], + ), + ), + ), + Card( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 30.0), + child: Column( + children: [ + const Text("This map doesn't consume the vertical drags."), + const Padding( + padding: EdgeInsets.only(bottom: 12.0), + child: Text( + 'It still gets other gestures (e.g scale or tap).', + ), + ), + Center( + child: SizedBox( + width: 300.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: _center, + zoom: 11.0, + ), + markers: { + Marker( + markerId: const MarkerId('test_marker_id'), + position: LatLng(_center.latitude, _center.longitude), + infoWindow: const InfoWindow( + title: 'An interesting location', + snippet: '*', + ), + ), + }, + gestureRecognizers: + >{ + Factory( + () => ScaleGestureRecognizer(), + ), + }, + ), + ), + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/snapshot.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/snapshot.dart new file mode 100644 index 000000000000..8fa4d67b6422 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/snapshot.dart @@ -0,0 +1,81 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class SnapshotPage extends GoogleMapExampleAppPage { + const SnapshotPage({Key? key}) + : super( + const Icon(Icons.camera_alt), + 'Take a snapshot of the map', + key: key, + ); + + @override + Widget build(BuildContext context) { + return _SnapshotBody(); + } +} + +class _SnapshotBody extends StatefulWidget { + @override + _SnapshotBodyState createState() => _SnapshotBodyState(); +} + +class _SnapshotBodyState extends State<_SnapshotBody> { + ExampleGoogleMapController? _mapController; + Uint8List? _imageBytes; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox( + height: 180, + child: ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + ), + ), + TextButton( + child: const Text('Take a snapshot'), + onPressed: () async { + final Uint8List? imageBytes = await _mapController + ?.takeSnapshot(); + setState(() { + _imageBytes = imageBytes; + }); + }, + ), + Container( + decoration: BoxDecoration(color: Colors.blueGrey[50]), + height: 180, + child: _imageBytes != null ? Image.memory(_imageBytes!) : null, + ), + ], + ), + ); + } + + // ignore: use_setters_to_change_properties + void onMapCreated(ExampleGoogleMapController controller) { + _mapController = controller; + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/tile_overlay.dart new file mode 100644 index 000000000000..bcce3b5f387b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/lib/tile_overlay.dart @@ -0,0 +1,147 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class TileOverlayPage extends GoogleMapExampleAppPage { + const TileOverlayPage({Key? key}) + : super(const Icon(Icons.map), 'Tile overlay', key: key); + + @override + Widget build(BuildContext context) { + return const TileOverlayBody(); + } +} + +class TileOverlayBody extends StatefulWidget { + const TileOverlayBody({super.key}); + + @override + State createState() => TileOverlayBodyState(); +} + +class TileOverlayBodyState extends State { + TileOverlayBodyState(); + + ExampleGoogleMapController? controller; + TileOverlay? _tileOverlay; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _removeTileOverlay() { + setState(() { + _tileOverlay = null; + }); + } + + void _addTileOverlay() { + final tileOverlay = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + ); + setState(() { + _tileOverlay = tileOverlay; + }); + } + + void _clearTileCache() { + if (_tileOverlay != null && controller != null) { + controller!.clearTileCache(_tileOverlay!.tileOverlayId); + } + } + + @override + Widget build(BuildContext context) { + final overlays = {if (_tileOverlay != null) _tileOverlay!}; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(59.935460, 30.325177), + zoom: 7.0, + ), + tileOverlays: overlays, + onMapCreated: _onMapCreated, + ), + ), + ), + TextButton( + onPressed: _addTileOverlay, + child: const Text('Add tile overlay'), + ), + TextButton( + onPressed: _removeTileOverlay, + child: const Text('Remove tile overlay'), + ), + TextButton( + onPressed: _clearTileCache, + child: const Text('Clear tile cache'), + ), + ], + ); + } +} + +class _DebugTileProvider implements TileProvider { + _DebugTileProvider() { + boxPaint.isAntiAlias = true; + boxPaint.color = Colors.blue; + boxPaint.strokeWidth = 2.0; + boxPaint.style = PaintingStyle.stroke; + } + + static const int width = 100; + static const int height = 100; + static final Paint boxPaint = Paint(); + static const TextStyle textStyle = TextStyle(color: Colors.red, fontSize: 20); + + @override + Future getTile(int x, int y, int? zoom) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final textSpan = TextSpan(text: '$x,$y', style: textStyle); + final textPainter = TextPainter( + text: textSpan, + textDirection: TextDirection.ltr, + ); + textPainter.layout(maxWidth: width.toDouble()); + textPainter.paint(canvas, Offset.zero); + canvas.drawRect( + Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), + boxPaint, + ); + final ui.Picture picture = recorder.endRecording(); + final Uint8List byteData = await picture + .toImage(width, height) + .then( + (ui.Image image) => image.toByteData(format: ui.ImageByteFormat.png), + ) + .then((ByteData? byteData) => byteData!.buffer.asUint8List()); + return Tile(width, height, byteData); + } +} 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 new file mode 100644 index 000000000000..d439bbf8cd46 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/pubspec.yaml @@ -0,0 +1,33 @@ +name: google_maps_flutter_example +description: Demonstrates how to use the google_maps_flutter plugin. +publish_to: none + +environment: + sdk: ^3.9.0 + flutter: ">=3.35.0" + +dependencies: + cupertino_icons: ^1.0.5 + flutter: + sdk: flutter + flutter_plugin_android_lifecycle: ^2.0.1 + google_maps_flutter_ios_sdk9: + # When depending on this package from a real application you should use: + # google_maps_flutter_ios_sdk9: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # 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.13.0 + +dev_dependencies: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + stream_transform: ^2.0.0 + +flutter: + uses-material-design: true + assets: + - assets/ diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/example_google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/example_google_map_test.dart new file mode 100644 index 000000000000..261fc473e8bb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/example_google_map_test.dart @@ -0,0 +1,176 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_example/example_google_map.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'fake_google_maps_flutter_platform.dart'; + +Widget _mapWithObjects({ + Set circles = const {}, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set tileOverlays = const {}, +}) { + return Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + circles: circles, + markers: markers, + polygons: polygons, + polylines: polylines, + tileOverlays: tileOverlays, + ), + ); +} + +void main() { + late FakeGoogleMapsFlutterPlatform platform; + + setUp(() { + platform = FakeGoogleMapsFlutterPlatform(); + GoogleMapsFlutterPlatform.instance = platform; + }); + + testWidgets('circle updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const c1 = Circle(circleId: CircleId('circle_1')); + const c2 = Circle(circleId: CircleId('circle_2')); + const c3 = Circle(circleId: CircleId('circle_3'), radius: 1); + const c3updated = Circle(circleId: CircleId('circle_3'), radius: 10); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(circles: {c1, c2})); + await tester.pumpWidget(_mapWithObjects(circles: {c1, c3})); + await tester.pumpWidget(_mapWithObjects(circles: {c1, c3updated})); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.circleUpdates.length, 3); + + expect(map.circleUpdates[0].circlesToChange.isEmpty, true); + expect(map.circleUpdates[0].circlesToAdd, {c1, c2}); + expect(map.circleUpdates[0].circleIdsToRemove.isEmpty, true); + + expect(map.circleUpdates[1].circlesToChange.isEmpty, true); + expect(map.circleUpdates[1].circlesToAdd, {c3}); + expect(map.circleUpdates[1].circleIdsToRemove, {c2.circleId}); + + expect(map.circleUpdates[2].circlesToChange, {c3updated}); + expect(map.circleUpdates[2].circlesToAdd.isEmpty, true); + expect(map.circleUpdates[2].circleIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); + + testWidgets('marker updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const m1 = Marker(markerId: MarkerId('marker_1')); + const m2 = Marker(markerId: MarkerId('marker_2')); + const m3 = Marker(markerId: MarkerId('marker_3')); + const m3updated = Marker(markerId: MarkerId('marker_3'), draggable: true); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(markers: {m1, m2})); + await tester.pumpWidget(_mapWithObjects(markers: {m1, m3})); + await tester.pumpWidget(_mapWithObjects(markers: {m1, m3updated})); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.markerUpdates.length, 3); + + expect(map.markerUpdates[0].markersToChange.isEmpty, true); + expect(map.markerUpdates[0].markersToAdd, {m1, m2}); + expect(map.markerUpdates[0].markerIdsToRemove.isEmpty, true); + + expect(map.markerUpdates[1].markersToChange.isEmpty, true); + expect(map.markerUpdates[1].markersToAdd, {m3}); + expect(map.markerUpdates[1].markerIdsToRemove, {m2.markerId}); + + expect(map.markerUpdates[2].markersToChange, {m3updated}); + expect(map.markerUpdates[2].markersToAdd.isEmpty, true); + expect(map.markerUpdates[2].markerIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); + + testWidgets('polygon updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const p1 = Polygon(polygonId: PolygonId('polygon_1')); + const p2 = Polygon(polygonId: PolygonId('polygon_2')); + const p3 = Polygon(polygonId: PolygonId('polygon_3'), strokeWidth: 1); + const p3updated = Polygon( + polygonId: PolygonId('polygon_3'), + strokeWidth: 2, + ); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(polygons: {p1, p2})); + await tester.pumpWidget(_mapWithObjects(polygons: {p1, p3})); + await tester.pumpWidget( + _mapWithObjects(polygons: {p1, p3updated}), + ); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.polygonUpdates.length, 3); + + expect(map.polygonUpdates[0].polygonsToChange.isEmpty, true); + expect(map.polygonUpdates[0].polygonsToAdd, {p1, p2}); + expect(map.polygonUpdates[0].polygonIdsToRemove.isEmpty, true); + + expect(map.polygonUpdates[1].polygonsToChange.isEmpty, true); + expect(map.polygonUpdates[1].polygonsToAdd, {p3}); + expect(map.polygonUpdates[1].polygonIdsToRemove, {p2.polygonId}); + + expect(map.polygonUpdates[2].polygonsToChange, {p3updated}); + expect(map.polygonUpdates[2].polygonsToAdd.isEmpty, true); + expect(map.polygonUpdates[2].polygonIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); + + testWidgets('polyline updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const p1 = Polyline(polylineId: PolylineId('polyline_1')); + const p2 = Polyline(polylineId: PolylineId('polyline_2')); + const p3 = Polyline(polylineId: PolylineId('polyline_3'), width: 1); + const p3updated = Polyline(polylineId: PolylineId('polyline_3'), width: 2); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(polylines: {p1, p2})); + await tester.pumpWidget(_mapWithObjects(polylines: {p1, p3})); + await tester.pumpWidget( + _mapWithObjects(polylines: {p1, p3updated}), + ); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.polylineUpdates.length, 3); + + expect(map.polylineUpdates[0].polylinesToChange.isEmpty, true); + expect(map.polylineUpdates[0].polylinesToAdd, {p1, p2}); + expect(map.polylineUpdates[0].polylineIdsToRemove.isEmpty, true); + + expect(map.polylineUpdates[1].polylinesToChange.isEmpty, true); + expect(map.polylineUpdates[1].polylinesToAdd, {p3}); + expect(map.polylineUpdates[1].polylineIdsToRemove, { + p2.polylineId, + }); + + expect(map.polylineUpdates[2].polylinesToChange, {p3updated}); + expect(map.polylineUpdates[2].polylinesToAdd.isEmpty, true); + expect(map.polylineUpdates[2].polylineIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); +} 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 new file mode 100644 index 000000000000..899a7709c548 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test/fake_google_maps_flutter_platform.dart @@ -0,0 +1,350 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:stream_transform/stream_transform.dart'; + +// A dummy implementation of the platform interface for tests. +class FakeGoogleMapsFlutterPlatform extends GoogleMapsFlutterPlatform { + FakeGoogleMapsFlutterPlatform(); + + /// The IDs passed to each call to buildView, in call order. + List createdIds = []; + + /// A map of creation IDs to fake map instances. + Map mapInstances = + {}; + + PlatformMapStateRecorder get lastCreatedMap => mapInstances[createdIds.last]!; + + /// Whether to add a small delay to async calls to simulate more realistic + /// async behavior (simulating the platform channel calls most + /// implementations will do). + /// + /// When true, requires tests to `pumpAndSettle` at the end of the test + /// to avoid exceptions. + bool simulatePlatformDelay = false; + + /// Whether `dispose` has been called. + bool disposed = false; + + /// Stream controller to inject events for testing. + final StreamController> mapEventStreamController = + StreamController>.broadcast(); + + @override + Future init(int mapId) async {} + + @override + Future updateMapConfiguration( + MapConfiguration update, { + required int mapId, + }) async { + mapInstances[mapId]?.mapConfiguration = update; + await _fakeDelay(); + } + + @override + Future updateMarkers( + MarkerUpdates markerUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.markerUpdates.add(markerUpdates); + await _fakeDelay(); + } + + @override + Future updatePolygons( + PolygonUpdates polygonUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.polygonUpdates.add(polygonUpdates); + await _fakeDelay(); + } + + @override + Future updatePolylines( + PolylineUpdates polylineUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.polylineUpdates.add(polylineUpdates); + await _fakeDelay(); + } + + @override + Future updateCircles( + CircleUpdates circleUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.circleUpdates.add(circleUpdates); + await _fakeDelay(); + } + + @override + Future updateTileOverlays({ + required Set newTileOverlays, + required int mapId, + }) async { + mapInstances[mapId]?.tileOverlaySets.add(newTileOverlays); + await _fakeDelay(); + } + + @override + Future updateClusterManagers( + ClusterManagerUpdates clusterManagerUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.clusterManagerUpdates.add(clusterManagerUpdates); + await _fakeDelay(); + } + + @override + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.groundOverlayUpdates.add(groundOverlayUpdates); + await _fakeDelay(); + } + + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + required int mapId, + }) async {} + + @override + Future animateCamera( + CameraUpdate cameraUpdate, { + required int mapId, + }) async {} + + @override + Future animateCameraWithConfiguration( + CameraUpdate cameraUpdate, + CameraUpdateAnimationConfiguration configuration, { + required int mapId, + }) async {} + + @override + Future moveCamera( + CameraUpdate cameraUpdate, { + required int mapId, + }) async {} + + @override + Future setMapStyle(String? mapStyle, {required int mapId}) async {} + + @override + Future getVisibleRegion({required int mapId}) async { + return LatLngBounds( + southwest: const LatLng(0, 0), + northeast: const LatLng(0, 0), + ); + } + + @override + Future getScreenCoordinate( + LatLng latLng, { + required int mapId, + }) async { + return const ScreenCoordinate(x: 0, y: 0); + } + + @override + Future getLatLng( + ScreenCoordinate screenCoordinate, { + required int mapId, + }) async { + return const LatLng(0, 0); + } + + @override + Future showMarkerInfoWindow( + MarkerId markerId, { + required int mapId, + }) async {} + + @override + Future hideMarkerInfoWindow( + MarkerId markerId, { + required int mapId, + }) async {} + + @override + Future isMarkerInfoWindowShown( + MarkerId markerId, { + required int mapId, + }) async { + return false; + } + + @override + Future getZoomLevel({required int mapId}) async { + return 0.0; + } + + @override + Future takeSnapshot({required int mapId}) async { + return null; + } + + @override + Stream onCameraMoveStarted({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCameraMove({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCameraIdle({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onInfoWindowTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDragStart({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDrag({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDragEnd({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onPolylineTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onPolygonTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCircleTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onLongPress({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onClusterTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onGroundOverlayTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + void dispose({required int mapId}) { + disposed = true; + } + + @override + Widget buildViewWithConfiguration( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required MapWidgetConfiguration widgetConfiguration, + MapObjects mapObjects = const MapObjects(), + MapConfiguration mapConfiguration = const MapConfiguration(), + }) { + final PlatformMapStateRecorder? instance = mapInstances[creationId]; + if (instance == null) { + createdIds.add(creationId); + mapInstances[creationId] = PlatformMapStateRecorder( + widgetConfiguration: widgetConfiguration, + mapConfiguration: mapConfiguration, + mapObjects: mapObjects, + ); + onPlatformViewCreated(creationId); + } + return Container(); + } + + Future _fakeDelay() async { + if (!simulatePlatformDelay) { + return; + } + return Future.delayed(const Duration(microseconds: 1)); + } +} + +/// A fake implementation of a native map, which stores all the updates it is +/// sent for inspection in tests. +class PlatformMapStateRecorder { + PlatformMapStateRecorder({ + required this.widgetConfiguration, + this.mapObjects = const MapObjects(), + this.mapConfiguration = const MapConfiguration(), + }) { + clusterManagerUpdates.add( + ClusterManagerUpdates.from( + const {}, + mapObjects.clusterManagers, + ), + ); + groundOverlayUpdates.add( + GroundOverlayUpdates.from( + const {}, + mapObjects.groundOverlays, + ), + ); + markerUpdates.add(MarkerUpdates.from(const {}, mapObjects.markers)); + polygonUpdates.add( + PolygonUpdates.from(const {}, mapObjects.polygons), + ); + polylineUpdates.add( + PolylineUpdates.from(const {}, mapObjects.polylines), + ); + circleUpdates.add(CircleUpdates.from(const {}, mapObjects.circles)); + tileOverlaySets.add(mapObjects.tileOverlays); + } + + MapWidgetConfiguration widgetConfiguration; + MapObjects mapObjects; + MapConfiguration mapConfiguration; + + final List markerUpdates = []; + final List polygonUpdates = []; + final List polylineUpdates = []; + final List circleUpdates = []; + final List> tileOverlaySets = >[]; + final List clusterManagerUpdates = + []; + final List groundOverlayUpdates = + []; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test_driver/integration_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test_driver/integration_test.dart new file mode 100644 index 000000000000..fb3dec00bee9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/test_driver/integration_test.dart @@ -0,0 +1,7 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9.podspec b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9.podspec new file mode 100644 index 000000000000..7f45f35b59e8 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9.podspec @@ -0,0 +1,37 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'google_maps_flutter_ios_sdk9' + s.version = '0.0.1' + s.summary = 'Google Maps for Flutter' + s.description = <<-DESC +A Flutter plugin that provides a Google Maps widget. +Downloaded by pub (not CocoaPods). + DESC + s.homepage = 'https://github.com/flutter/packages' + s.license = { :type => 'BSD', :file => '../LICENSE' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :http => 'https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios_sdk9' } + s.documentation_url = 'https://pub.dev/packages/google_maps_flutter_ios_sdk9' + s.source_files = 'google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/**/*.{h,m}' + s.public_header_files = 'google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/**/*.h' + s.dependency 'Flutter' + s.dependency 'GoogleMaps', '~> 9.0' + # Google-Maps-iOS-Utils 6.0 and 6.1.0 support GoogleMaps 9.x. The next release + # was 6.1.3, which switched to GoogleMaps 10.x without a major version change. + s.dependency 'Google-Maps-iOS-Utils', '>= 6.0', '<= 6.1.0' + s.static_framework = true + s.platform = :ios, '15.0' + # "Google-Maps-iOS-Utils" is static and contains Swift classes. + # Find the Swift runtime when these plugins are built as libraries without `use_frameworks!` + s.swift_version = '5.9' + s.xcconfig = { + 'LIBRARY_SEARCH_PATHS' => '$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', + 'LD_RUNPATH_SEARCH_PATHS' => '$(inherited) /usr/lib/swift', + # To handle the difference in framework names between CocoaPods and Swift Package Manager. + 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) FGM_USING_COCOAPODS=1', + } + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.resource_bundles = {'google_maps_flutter_ios_sdk9_privacy' => ['google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy']} +end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift new file mode 100644 index 000000000000..6df0b1cc1ba5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift @@ -0,0 +1,44 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import PackageDescription + +let package = Package( + name: "google_maps_flutter_ios_sdk9", + platforms: [ + .iOS(.v15) + ], + products: [ + .library(name: "google-maps-flutter-ios-sdk9", type: .static, targets: ["google_maps_flutter_ios_sdk9"]) + ], + dependencies: [ + .package(url: "https://github.com/googlemaps/ios-maps-sdk", "9.0.0"..<"10.0.0"), + // 6.1.3+ requires SDK 10. + .package(url: "https://github.com/googlemaps/google-maps-ios-utils", "6.0.0"..<"6.1.3"), + ], + targets: [ + .target( + name: "google_maps_flutter_ios_sdk9", + dependencies: [ + .product( + name: "GoogleMapsUtils", + package: "google-maps-ios-utils" + ), + .product( + name: "GoogleMaps", + package: "ios-maps-sdk" + ), + ], + resources: [ + .process("Resources") + ], + cSettings: [ + .headerSearchPath("include/google_maps_flutter_ios_sdk9") + ] + ) + ] +) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m new file mode 100644 index 000000000000..5fb79de8b17a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMCATransactionWrapper.h" + +@import QuartzCore; + +@implementation FGMCATransactionWrapper + +- (void)begin { + [CATransaction begin]; +} + +- (void)commit { + [CATransaction commit]; +} + +- (void)setAnimationDuration:(CFTimeInterval)duration { + [CATransaction setAnimationDuration:duration]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m new file mode 100644 index 000000000000..04c3f04c9285 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m @@ -0,0 +1,128 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMClusterManagersController.h" + +#import "FGMConversionUtils.h" +#import "FGMMarkerUserData.h" + +@interface FGMClusterManagersController () + +/// A dictionary mapping unique cluster manager identifiers to their corresponding cluster managers. +@property(strong, nonatomic) + NSMutableDictionary *clusterManagerIdentifierToManagers; + +/// The callback handler interface for calls to Flutter. +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; + +/// The current map instance on which the cluster managers are operating. +@property(strong, nonatomic) GMSMapView *mapView; + +@end + +@implementation FGMClusterManagersController +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _clusterManagerIdentifierToManagers = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)addClusterManagers:(NSArray *)clusterManagersToAdd { + for (FGMPlatformClusterManager *clusterManager in clusterManagersToAdd) { + NSString *identifier = clusterManager.identifier; + [self addClusterManager:identifier]; + } +} + +- (void)addClusterManager:(NSString *)identifier { + id algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init]; + id iconGenerator = [[GMUDefaultClusterIconGenerator alloc] init]; + id renderer = + [[GMUDefaultClusterRenderer alloc] initWithMapView:self.mapView + clusterIconGenerator:iconGenerator]; + self.clusterManagerIdentifierToManagers[identifier] = + [[GMUClusterManager alloc] initWithMap:self.mapView algorithm:algorithm renderer:renderer]; + ; +} + +- (void)removeClusterManagersWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + GMUClusterManager *clusterManager = + [self.clusterManagerIdentifierToManagers objectForKey:identifier]; + if (!clusterManager) { + continue; + } + [clusterManager clearItems]; + [self.clusterManagerIdentifierToManagers removeObjectForKey:identifier]; + } +} + +- (nullable GMUClusterManager *)clusterManagerWithIdentifier:(NSString *)identifier { + return [self.clusterManagerIdentifierToManagers objectForKey:identifier]; +} + +- (void)invokeClusteringForEachClusterManager { + for (GMUClusterManager *clusterManager in [self.clusterManagerIdentifierToManagers allValues]) { + [clusterManager cluster]; + } +} + +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMUClusterManager *clusterManager = + [self.clusterManagerIdentifierToManagers objectForKey:identifier]; + + if (!clusterManager) { + *error = [FlutterError + errorWithCode:@"Invalid clusterManagerId" + message:@"getClusters called with invalid clusterManagerId" + details:[NSString stringWithFormat:@"clusterManagerId was: '%@'", identifier]]; + return nil; + } + + // Ref: + // https://github.com/googlemaps/google-maps-ios-utils/blob/0e7ed81f1bbd9d29e4529c40ae39b0791b0a0eb8/src/Clustering/GMUClusterManager.m#L94. + NSUInteger integralZoom = (NSUInteger)floorf(_mapView.camera.zoom + 0.5f); + NSArray> *clusters = [clusterManager.algorithm clustersAtZoom:integralZoom]; + NSMutableArray *response = + [[NSMutableArray alloc] initWithCapacity:clusters.count]; + for (id cluster in clusters) { + FGMPlatformCluster *platFormCluster = FGMGetPigeonCluster(cluster, identifier); + [response addObject:platFormCluster]; + } + return response; +} + +- (void)didTapCluster:(GMUStaticCluster *)cluster { + NSString *clusterManagerId = [self clusterManagerIdentifierForCluster:cluster]; + if (!clusterManagerId) { + return; + } + FGMPlatformCluster *platFormCluster = FGMGetPigeonCluster(cluster, clusterManagerId); + [self.callbackHandler didTapCluster:platFormCluster + completion:^(FlutterError *_Nullable _){ + }]; +} + +#pragma mark - Private methods + +/// Returns the cluster manager identifier for given cluster. +/// +/// @return The cluster manager identifier if found; otherwise, nil. +- (nullable NSString *)clusterManagerIdentifierForCluster:(GMUStaticCluster *)cluster { + if ([cluster.items.firstObject isKindOfClass:[GMSMarker class]]) { + GMSMarker *firstMarker = (GMSMarker *)cluster.items.firstObject; + return FGMGetClusterManagerIdentifierFromMarker(firstMarker); + } + + return nil; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m new file mode 100644 index 000000000000..876ec0d1e4aa --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m @@ -0,0 +1,288 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMConversionUtils.h" + +#import "FGMMarkerUserData.h" + +/// Returns dict[key], or nil if dict[key] is NSNull. +id FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key) { + id value = dict[key]; + return value == [NSNull null] ? nil : value; +} + +CGPoint FGMGetCGPointForPigeonPoint(FGMPlatformPoint *point) { + return CGPointMake(point.x, point.y); +} + +FGMPlatformPoint *FGMGetPigeonPointForCGPoint(CGPoint point) { + return [FGMPlatformPoint makeWithX:point.x y:point.y]; +} + +CLLocationCoordinate2D FGMGetCoordinateForPigeonLatLng(FGMPlatformLatLng *latLng) { + return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude); +} + +FGMPlatformLatLng *FGMGetPigeonLatLngForCoordinate(CLLocationCoordinate2D coord) { + return [FGMPlatformLatLng makeWithLatitude:coord.latitude longitude:coord.longitude]; +} + +GMSCoordinateBounds *FGMGetCoordinateBoundsForPigeonLatLngBounds(FGMPlatformLatLngBounds *bounds) { + return [[GMSCoordinateBounds alloc] + initWithCoordinate:FGMGetCoordinateForPigeonLatLng(bounds.northeast) + coordinate:FGMGetCoordinateForPigeonLatLng(bounds.southwest)]; +} + +FGMPlatformLatLngBounds *FGMGetPigeonLatLngBoundsForCoordinateBounds(GMSCoordinateBounds *bounds) { + return + [FGMPlatformLatLngBounds makeWithNortheast:FGMGetPigeonLatLngForCoordinate(bounds.northEast) + southwest:FGMGetPigeonLatLngForCoordinate(bounds.southWest)]; +} + +FGMPlatformCameraPosition *FGMGetPigeonCameraPositionForPosition(GMSCameraPosition *position) { + return [FGMPlatformCameraPosition makeWithBearing:position.bearing + target:FGMGetPigeonLatLngForCoordinate(position.target) + tilt:position.viewingAngle + zoom:position.zoom]; +} + +GMSCameraPosition *FGMGetCameraPositionForPigeonCameraPosition( + FGMPlatformCameraPosition *position) { + return [GMSCameraPosition cameraWithTarget:FGMGetCoordinateForPigeonLatLng(position.target) + zoom:position.zoom + bearing:position.bearing + viewingAngle:position.tilt]; +} + +NSArray *FGMGetPointsForPigeonLatLngs(NSArray *pigeonPoints) { + NSMutableArray *points = [[NSMutableArray alloc] initWithCapacity:pigeonPoints.count]; + for (FGMPlatformLatLng *point in pigeonPoints) { + [points addObject:[[CLLocation alloc] initWithLatitude:point.latitude + longitude:point.longitude]]; + } + return points; +} + +NSArray *> *FGMGetHolesForPigeonLatLngArrays( + NSArray *> *pigeonHolePoints) { + NSMutableArray *> *holes = + [[NSMutableArray alloc] initWithCapacity:pigeonHolePoints.count]; + for (NSArray *holePoints in pigeonHolePoints) { + [holes addObject:FGMGetPointsForPigeonLatLngs(holePoints)]; + } + return holes; +} + +GMSMutablePath *FGMGetPathFromPoints(NSArray *points) { + GMSMutablePath *path = [GMSMutablePath path]; + for (CLLocation *location in points) { + [path addCoordinate:location.coordinate]; + } + return path; +} + +GMSMapViewType FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapType type) { + switch (type) { + case FGMPlatformMapTypeNone: + return kGMSTypeNone; + case FGMPlatformMapTypeNormal: + return kGMSTypeNormal; + case FGMPlatformMapTypeSatellite: + return kGMSTypeSatellite; + case FGMPlatformMapTypeTerrain: + return kGMSTypeTerrain; + case FGMPlatformMapTypeHybrid: + return kGMSTypeHybrid; + } +} + +FGMPlatformCluster *FGMGetPigeonCluster(GMUStaticCluster *cluster, + NSString *clusterManagerIdentifier) { + NSMutableArray *markerIDs = [[NSMutableArray alloc] initWithCapacity:cluster.items.count]; + GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] init]; + + for (GMSMarker *marker in cluster.items) { + [markerIDs addObject:FGMGetMarkerIdentifierFromMarker(marker)]; + bounds = [bounds includingCoordinate:marker.position]; + } + + return [FGMPlatformCluster + makeWithClusterManagerId:clusterManagerIdentifier + position:FGMGetPigeonLatLngForCoordinate(cluster.position) + bounds:FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds) + markerIds:markerIDs]; +} + +FGMPlatformGroundOverlay *FGMGetPigeonGroundOverlay(GMSGroundOverlay *groundOverlay, + NSString *overlayId, BOOL isCreatedWithBounds, + NSNumber *zoomLevel) { + // Image is mandatory field on FGMPlatformGroundOverlay (and it should be kept + // non-nullable), therefore image must be set for the object. The image is + // description either contains set of bytes, or path to asset. This info is + // converted to format google maps uses (BitmapDescription), and the original + // data is not stored on native code. Therefore placeholder image is used for + // the image field. + FGMPlatformBitmap *placeholderImage = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + if (isCreatedWithBounds) { + return [FGMPlatformGroundOverlay + makeWithGroundOverlayId:overlayId + image:placeholderImage + position:nil + bounds:[FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng + makeWithLatitude:groundOverlay.bounds + .northEast.latitude + longitude:groundOverlay.bounds + .northEast.longitude] + southwest:[FGMPlatformLatLng + makeWithLatitude:groundOverlay.bounds + .southWest.latitude + longitude:groundOverlay.bounds + .southWest + .longitude]] + anchor:[FGMPlatformPoint makeWithX:groundOverlay.anchor.x + y:groundOverlay.anchor.y] + transparency:1.0f - groundOverlay.opacity + bearing:groundOverlay.bearing + zIndex:groundOverlay.zIndex + visible:groundOverlay.map != nil + clickable:groundOverlay.isTappable + zoomLevel:zoomLevel]; + } else { + return [FGMPlatformGroundOverlay + makeWithGroundOverlayId:overlayId + image:placeholderImage + position:[FGMPlatformLatLng + makeWithLatitude:groundOverlay.position.latitude + longitude:groundOverlay.position.longitude] + bounds:nil + anchor:[FGMPlatformPoint makeWithX:groundOverlay.anchor.x + y:groundOverlay.anchor.y] + transparency:1.0f - groundOverlay.opacity + bearing:groundOverlay.bearing + zIndex:groundOverlay.zIndex + visible:groundOverlay.map != nil + clickable:groundOverlay.isTappable + zoomLevel:zoomLevel]; + } +} + +GMUGradient *FGMGetGradientForPigeonHeatmapGradient(FGMPlatformHeatmapGradient *gradient) { + NSMutableArray *colors = [[NSMutableArray alloc] initWithCapacity:gradient.colors.count]; + for (FGMPlatformColor *color in gradient.colors) { + [colors addObject:FGMGetColorForPigeonColor(color)]; + } + return [[GMUGradient alloc] initWithColors:colors + startPoints:gradient.startPoints + colorMapSize:gradient.colorMapSize]; +} + +FGMPlatformHeatmapGradient *FGMGetPigeonHeatmapGradientForGradient(GMUGradient *gradient) { + NSMutableArray *colors = [[NSMutableArray alloc] initWithCapacity:gradient.colors.count]; + for (UIColor *color in gradient.colors) { + [colors addObject:FGMGetPigeonColorForColor(color)]; + } + return [FGMPlatformHeatmapGradient makeWithColors:colors + startPoints:gradient.startPoints + colorMapSize:gradient.mapSize]; +} + +NSArray *FGMGetWeightedDataForPigeonWeightedData( + NSArray *weightedLatLngs) { + NSMutableArray *weightedData = [[NSMutableArray alloc] initWithCapacity:weightedLatLngs.count]; + for (FGMPlatformWeightedLatLng *weightedLatLng in weightedLatLngs) { + [weightedData + addObject:[[GMUWeightedLatLng alloc] + initWithCoordinate:FGMGetCoordinateForPigeonLatLng(weightedLatLng.point) + intensity:weightedLatLng.weight]]; + } + return weightedData; +} + +NSArray *FGMGetPigeonWeightedDataForWeightedData( + NSArray *weightedLatLngs) { + NSMutableArray *weightedData = [[NSMutableArray alloc] initWithCapacity:weightedLatLngs.count]; + for (GMUWeightedLatLng *weightedLatLng in weightedLatLngs) { + GMSMapPoint point = {weightedLatLng.point.x, weightedLatLng.point.y}; + [weightedData addObject:[FGMPlatformWeightedLatLng + makeWithPoint:FGMGetPigeonLatLngForCoordinate(GMSUnproject(point)) + weight:weightedLatLng.intensity]]; + } + return weightedData; +} + +GMSCameraUpdate *FGMGetCameraUpdateForPigeonCameraUpdate(FGMPlatformCameraUpdate *cameraUpdate) { + // See note in messages.dart for why this is so loosely typed. + id update = cameraUpdate.cameraUpdate; + if ([update isKindOfClass:[FGMPlatformCameraUpdateNewCameraPosition class]]) { + return [GMSCameraUpdate + setCamera:FGMGetCameraPositionForPigeonCameraPosition( + ((FGMPlatformCameraUpdateNewCameraPosition *)update).cameraPosition)]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateNewLatLng class]]) { + return [GMSCameraUpdate setTarget:FGMGetCoordinateForPigeonLatLng( + ((FGMPlatformCameraUpdateNewLatLng *)update).latLng)]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateNewLatLngBounds class]]) { + FGMPlatformCameraUpdateNewLatLngBounds *typedUpdate = + (FGMPlatformCameraUpdateNewLatLngBounds *)update; + return + [GMSCameraUpdate fitBounds:FGMGetCoordinateBoundsForPigeonLatLngBounds(typedUpdate.bounds) + withPadding:typedUpdate.padding]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateNewLatLngZoom class]]) { + FGMPlatformCameraUpdateNewLatLngZoom *typedUpdate = + (FGMPlatformCameraUpdateNewLatLngZoom *)update; + return [GMSCameraUpdate setTarget:FGMGetCoordinateForPigeonLatLng(typedUpdate.latLng) + zoom:typedUpdate.zoom]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateScrollBy class]]) { + FGMPlatformCameraUpdateScrollBy *typedUpdate = (FGMPlatformCameraUpdateScrollBy *)update; + return [GMSCameraUpdate scrollByX:typedUpdate.dx Y:typedUpdate.dy]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateZoomBy class]]) { + FGMPlatformCameraUpdateZoomBy *typedUpdate = (FGMPlatformCameraUpdateZoomBy *)update; + if (typedUpdate.focus) { + return [GMSCameraUpdate zoomBy:typedUpdate.amount + atPoint:FGMGetCGPointForPigeonPoint(typedUpdate.focus)]; + } else { + return [GMSCameraUpdate zoomBy:typedUpdate.amount]; + } + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateZoom class]]) { + if (((FGMPlatformCameraUpdateZoom *)update).out) { + return [GMSCameraUpdate zoomOut]; + } else { + return [GMSCameraUpdate zoomIn]; + } + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateZoomTo class]]) { + return [GMSCameraUpdate zoomTo:((FGMPlatformCameraUpdateZoomTo *)update).zoom]; + } + return nil; +} + +UIColor *FGMGetColorForPigeonColor(FGMPlatformColor *color) { + return [UIColor colorWithRed:color.red green:color.green blue:color.blue alpha:color.alpha]; +} + +FGMPlatformColor *FGMGetPigeonColorForColor(UIColor *color) { + double red, green, blue, alpha; + [color getRed:&red green:&green blue:&blue alpha:&alpha]; + return [FGMPlatformColor makeWithRed:red green:green blue:blue alpha:alpha]; +} + +NSArray *FGMGetStrokeStylesFromPatterns( + NSArray *patterns, UIColor *strokeColor) { + NSMutableArray *strokeStyles = [[NSMutableArray alloc] initWithCapacity:[patterns count]]; + for (FGMPlatformPatternItem *pattern in patterns) { + UIColor *color = + pattern.type == FGMPlatformPatternItemTypeGap ? UIColor.clearColor : strokeColor; + [strokeStyles addObject:[GMSStrokeStyle solidColor:color]]; + } + return strokeStyles; +} + +NSArray *FGMGetSpanLengthsFromPatterns(NSArray *patterns) { + NSMutableArray *lengths = [[NSMutableArray alloc] initWithCapacity:[patterns count]]; + for (FGMPlatformPatternItem *pattern in patterns) { + NSNumber *length = pattern.length ?: @0; + [lengths addObject:length]; + } + return lengths; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m new file mode 100644 index 000000000000..624f43032c53 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m @@ -0,0 +1,211 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMGroundOverlayController.h" +#import "FGMGroundOverlayController_Test.h" + +#import "FGMConversionUtils.h" +#import "FGMImageUtils.h" + +@interface FGMGroundOverlayController () + +/// The GMSMapView to which the ground overlays are added. +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FGMGroundOverlayController + +- (instancetype)initWithGroundOverlay:(GMSGroundOverlay *)groundOverlay + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView + isCreatedWithBounds:(BOOL)isCreatedWithBounds { + self = [super init]; + if (self) { + _groundOverlay = groundOverlay; + _mapView = mapView; + _groundOverlay.userData = @[ identifier ]; + _createdWithBounds = isCreatedWithBounds; + } + return self; +} + +- (void)removeGroundOverlay { + self.groundOverlay.map = nil; +} + +- (void)updateFromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)groundOverlay + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale { + [FGMGroundOverlayController updateGroundOverlay:self.groundOverlay + fromPlatformGroundOverlay:groundOverlay + withMapView:self.mapView + registrar:registrar + screenScale:screenScale + usingBounds:self.createdWithBounds]; +} + ++ (void)updateGroundOverlay:(GMSGroundOverlay *)groundOverlay + fromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)platformGroundOverlay + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingBounds:(BOOL)useBounds { + groundOverlay.tappable = platformGroundOverlay.clickable; + groundOverlay.zIndex = (int)platformGroundOverlay.zIndex; + groundOverlay.anchor = + CGPointMake(platformGroundOverlay.anchor.x, platformGroundOverlay.anchor.y); + UIImage *image = FGMIconFromBitmap(platformGroundOverlay.image, registrar, screenScale); + groundOverlay.icon = image; + groundOverlay.bearing = platformGroundOverlay.bearing; + groundOverlay.opacity = 1.0 - platformGroundOverlay.transparency; + if (useBounds) { + groundOverlay.bounds = [[GMSCoordinateBounds alloc] + initWithCoordinate:CLLocationCoordinate2DMake( + platformGroundOverlay.bounds.northeast.latitude, + platformGroundOverlay.bounds.northeast.longitude) + coordinate:CLLocationCoordinate2DMake( + platformGroundOverlay.bounds.southwest.latitude, + platformGroundOverlay.bounds.southwest.longitude)]; + } else { + groundOverlay.position = CLLocationCoordinate2DMake(platformGroundOverlay.position.latitude, + platformGroundOverlay.position.longitude); + } + + // This must be done last, to avoid visual flickers of default property values. + groundOverlay.map = platformGroundOverlay.visible ? mapView : nil; +} + +@end + +@interface FLTGroundOverlaysController () + +/// A map from ground overlay id to the controller that manages it. +@property(strong, nonatomic) NSMutableDictionary + *groundOverlayControllerByIdentifier; + +/// A callback api for the map interactions. +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; + +/// Flutter Plugin Registrar used to load images. +@property(weak, nonatomic) NSObject *registrar; + +/// The map view used to generate the controllers. +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGroundOverlaysController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _groundOverlayControllerByIdentifier = [[NSMutableDictionary alloc] init]; + _registrar = registrar; + } + return self; +} + +- (void)addGroundOverlays:(NSArray *)groundOverlaysToAdd { + for (FGMPlatformGroundOverlay *groundOverlay in groundOverlaysToAdd) { + NSString *identifier = groundOverlay.groundOverlayId; + GMSGroundOverlay *gmsOverlay; + BOOL isCreatedWithBounds = NO; + if (groundOverlay.position == nil) { + isCreatedWithBounds = YES; + NSAssert(groundOverlay.bounds != nil, + @"If ground overlay is initialized without position, bounds are required"); + gmsOverlay = [GMSGroundOverlay + groundOverlayWithBounds: + [[GMSCoordinateBounds alloc] + initWithCoordinate:CLLocationCoordinate2DMake( + groundOverlay.bounds.northeast.latitude, + groundOverlay.bounds.northeast.longitude) + coordinate:CLLocationCoordinate2DMake( + groundOverlay.bounds.southwest.latitude, + groundOverlay.bounds.southwest.longitude)] + icon:FGMIconFromBitmap(groundOverlay.image, self.registrar, + [self getScreenScale])]; + } else { + NSAssert(groundOverlay.zoomLevel != nil, + @"If ground overlay is initialized with position, zoomLevel is required"); + gmsOverlay = [GMSGroundOverlay + groundOverlayWithPosition:CLLocationCoordinate2DMake(groundOverlay.position.latitude, + groundOverlay.position.longitude) + icon:FGMIconFromBitmap(groundOverlay.image, self.registrar, + [self getScreenScale]) + zoomLevel:[groundOverlay.zoomLevel doubleValue]]; + } + FGMGroundOverlayController *controller = + [[FGMGroundOverlayController alloc] initWithGroundOverlay:gmsOverlay + identifier:identifier + mapView:self.mapView + isCreatedWithBounds:isCreatedWithBounds]; + controller.zoomLevel = groundOverlay.zoomLevel; + [controller updateFromPlatformGroundOverlay:groundOverlay + registrar:self.registrar + screenScale:[self getScreenScale]]; + self.groundOverlayControllerByIdentifier[identifier] = controller; + } +} + +- (void)changeGroundOverlays:(NSArray *)groundOverlaysToChange { + for (FGMPlatformGroundOverlay *groundOverlay in groundOverlaysToChange) { + NSString *identifier = groundOverlay.groundOverlayId; + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + [controller updateFromPlatformGroundOverlay:groundOverlay + registrar:self.registrar + screenScale:[self getScreenScale]]; + } +} + +- (void)removeGroundOverlaysWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + if (!controller) { + continue; + } + [controller removeGroundOverlay]; + [self.groundOverlayControllerByIdentifier removeObjectForKey:identifier]; + } +} + +- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier { + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapGroundOverlayWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (bool)hasGroundOverlaysWithIdentifier:(NSString *)identifier { + return self.groundOverlayControllerByIdentifier[identifier] != nil; +} + +- (CGFloat)getScreenScale { + // TODO(jokerttu): This method is called on marker creation, which, for initial markers, is done + // before the view is added to the view hierarchy. This means that the traitCollection values may + // not be matching the right display where the map is finally shown. The solution should be + // revisited after the proper way to fetch the display scale is resolved for platform views. This + // should be done under the context of the following issue: + // https://github.com/flutter/flutter/issues/125496. + return self.mapView.traitCollection.displayScale; +} + +- (nullable FGMPlatformGroundOverlay *)groundOverlayWithIdentifier:(NSString *)identifier { + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + if (!controller) { + return nil; + } + return FGMGetPigeonGroundOverlay(controller.groundOverlay, identifier, + controller.isCreatedWithBounds, controller.zoomLevel); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m new file mode 100644 index 000000000000..7bd5192c2377 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m @@ -0,0 +1,235 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMImageUtils.h" + +@import Foundation; + +/// This method is deprecated within the context of `BitmapDescriptor.fromBytes` handling in the +/// flutter google_maps_flutter_platform_interface package which has been replaced by 'bytes' +/// message handling. It will be removed when the deprecated image bitmap description type +/// 'fromBytes' is removed from the platform interface. +static UIImage *scaledImage(UIImage *image, double scale); + +/// Creates a scaled version of the provided UIImage based on a specified scale factor. If the +/// scale factor differs from the image's current scale by more than a small epsilon-delta (to +/// account for minor floating-point inaccuracies), a new UIImage object is created with the +/// specified scale. Otherwise, the original image is returned. +/// +/// @param image The UIImage to scale. +/// @param scale The factor by which to scale the image. +/// @return UIImage Returns the scaled UIImage. +static UIImage *scaledImageWithScale(UIImage *image, CGFloat scale); + +/// Scales an input UIImage to a specified size. If the aspect ratio of the input image +/// closely matches the target size, indicated by a small epsilon-delta, the image's scale +/// property is updated instead of resizing the image. If the aspect ratios differ beyond this +/// threshold, the method redraws the image at the target size. +/// +/// @param image The UIImage to scale. +/// @param size The target CGSize to scale the image to. +/// @return UIImage Returns the scaled UIImage. +static UIImage *scaledImageWithSize(UIImage *image, CGSize size); + +/// Scales an input UIImage to a specified width and height preserving aspect ratio if both +/// widht and height are not given.. +/// +/// @param image The UIImage to scale. +/// @param width The target width to scale the image to. +/// @param height The target height to scale the image to. +/// @param screenScale The current screen scale. +/// @return UIImage Returns the scaled UIImage. +static UIImage *scaledImageWithWidthHeight(UIImage *image, NSNumber *width, NSNumber *height, + CGFloat screenScale); + +UIImage *FGMIconFromBitmap(FGMPlatformBitmap *platformBitmap, + NSObject *registrar, CGFloat screenScale) { + assert(screenScale > 0 && "Screen scale must be greater than 0"); + // See comment in messages.dart for why this is so loosely typed. See also + // https://github.com/flutter/flutter/issues/117819. + id bitmap = platformBitmap.bitmap; + UIImage *image; + if ([bitmap isKindOfClass:[FGMPlatformBitmapDefaultMarker class]]) { + FGMPlatformBitmapDefaultMarker *bitmapDefaultMarker = bitmap; + CGFloat hue = bitmapDefaultMarker.hue.doubleValue; + image = [GMSMarker markerImageWithColor:[UIColor colorWithHue:hue / 360.0 + saturation:1.0 + brightness:0.7 + alpha:1.0]]; + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapAsset class]]) { + // Deprecated: This message handling for 'fromAsset' has been replaced by 'asset'. + // Refer to the flutter google_maps_flutter_platform_interface package for details. + FGMPlatformBitmapAsset *bitmapAsset = bitmap; + if (bitmapAsset.pkg) { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAsset.name + fromPackage:bitmapAsset.pkg]]; + } else { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAsset.name]]; + } + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapAssetImage class]]) { + // Deprecated: This message handling for 'fromAssetImage' has been replaced by 'asset'. + // Refer to the flutter google_maps_flutter_platform_interface package for details. + FGMPlatformBitmapAssetImage *bitmapAssetImage = bitmap; + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAssetImage.name]]; + image = scaledImage(image, bitmapAssetImage.scale); + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapBytes class]]) { + // Deprecated: This message handling for 'fromBytes' has been replaced by 'bytes'. + // Refer to the flutter google_maps_flutter_platform_interface package for details. + FGMPlatformBitmapBytes *bitmapBytes = bitmap; + @try { + CGFloat mainScreenScale = [[UIScreen mainScreen] scale]; + image = [UIImage imageWithData:bitmapBytes.byteData.data scale:mainScreenScale]; + } @catch (NSException *exception) { + @throw [NSException exceptionWithName:@"InvalidByteDescriptor" + reason:@"Unable to interpret bytes as a valid image." + userInfo:nil]; + } + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapAssetMap class]]) { + FGMPlatformBitmapAssetMap *bitmapAssetMap = bitmap; + + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAssetMap.assetName]]; + + if (bitmapAssetMap.bitmapScaling == FGMPlatformMapBitmapScalingAuto) { + NSNumber *width = bitmapAssetMap.width; + NSNumber *height = bitmapAssetMap.height; + if (width || height) { + image = scaledImageWithScale(image, screenScale); + image = scaledImageWithWidthHeight(image, width, height, screenScale); + } else { + image = scaledImageWithScale(image, bitmapAssetMap.imagePixelRatio); + } + } + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapBytesMap class]]) { + FGMPlatformBitmapBytesMap *bitmapBytesMap = bitmap; + FlutterStandardTypedData *bytes = bitmapBytesMap.byteData; + + @try { + image = [UIImage imageWithData:bytes.data scale:screenScale]; + if (bitmapBytesMap.bitmapScaling == FGMPlatformMapBitmapScalingAuto) { + NSNumber *width = bitmapBytesMap.width; + NSNumber *height = bitmapBytesMap.height; + + if (width || height) { + // Before scaling the image, image must be in screenScale. + image = scaledImageWithScale(image, screenScale); + image = scaledImageWithWidthHeight(image, width, height, screenScale); + } else { + image = scaledImageWithScale(image, bitmapBytesMap.imagePixelRatio); + } + } else { + // No scaling, load image from bytes without scale parameter. + image = [UIImage imageWithData:bytes.data]; + } + } @catch (NSException *exception) { + @throw [NSException exceptionWithName:@"InvalidByteDescriptor" + reason:@"Unable to interpret bytes as a valid image." + userInfo:nil]; + } + } + + return image; +} + +UIImage *scaledImage(UIImage *image, double scale) { + if (fabs(scale - 1) > 1e-3) { + return [UIImage imageWithCGImage:[image CGImage] + scale:(image.scale * scale) + orientation:(image.imageOrientation)]; + } + return image; +} + +UIImage *scaledImageWithScale(UIImage *image, CGFloat scale) { + if (fabs(scale - image.scale) > DBL_EPSILON) { + return [UIImage imageWithCGImage:[image CGImage] + scale:scale + orientation:(image.imageOrientation)]; + } + return image; +} + +UIImage *scaledImageWithSize(UIImage *image, CGSize size) { + CGFloat originalPixelWidth = image.size.width * image.scale; + CGFloat originalPixelHeight = image.size.height * image.scale; + + // Return original image if either original image size or target size is so small that + // image cannot be resized or displayed. + if (originalPixelWidth <= 0 || originalPixelHeight <= 0 || size.width <= 0 || size.height <= 0) { + return image; + } + + // Check if the image's size, accounting for scale, matches the target size. + if (fabs(originalPixelWidth - size.width) <= DBL_EPSILON && + fabs(originalPixelHeight - size.height) <= DBL_EPSILON) { + // No need for resizing, return the original image + return image; + } + + // Check if the aspect ratios are approximately equal. + CGSize originalPixelSize = CGSizeMake(originalPixelWidth, originalPixelHeight); + if (FGMIsScalableWithScaleFactorFromSize(originalPixelSize, size)) { + // Scaled image has close to same aspect ratio, + // updating image scale instead of resizing image. + CGFloat factor = originalPixelWidth / size.width; + return scaledImageWithScale(image, image.scale * factor); + } else { + // Aspect ratios differ significantly, resize the image. + UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat]; + format.scale = 1.0; + format.opaque = NO; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size + format:format]; + UIImage *newImage = + [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { + [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; + }]; + + // Return image with proper scaling. + return scaledImageWithScale(newImage, image.scale); + } +} + +UIImage *scaledImageWithWidthHeight(UIImage *image, NSNumber *width, NSNumber *height, + CGFloat screenScale) { + if ((width == nil) && (height == nil)) { + return image; + } + + CGFloat targetWidth = width == nil ? image.size.width : width.doubleValue; + CGFloat targetHeight = height == nil ? image.size.height : height.doubleValue; + + if ((width != nil) && (height == nil)) { + // Calculate height based on aspect ratio if only width is provided. + double aspectRatio = image.size.height / image.size.width; + targetHeight = round(targetWidth * aspectRatio); + } else if ((width == nil) && (height != nil)) { + // Calculate width based on aspect ratio if only height is provided. + double aspectRatio = image.size.width / image.size.height; + targetWidth = round(targetHeight * aspectRatio); + } + + CGSize targetSize = + CGSizeMake(round(targetWidth * screenScale), round(targetHeight * screenScale)); + return scaledImageWithSize(image, targetSize); +} + +BOOL FGMIsScalableWithScaleFactorFromSize(CGSize originalSize, CGSize targetSize) { + // Select the scaling factor based on the longer side to have good precision. + CGFloat scaleFactor = (originalSize.width > originalSize.height) + ? (targetSize.width / originalSize.width) + : (targetSize.height / originalSize.height); + + // Calculate the scaled dimensions. + CGFloat scaledWidth = originalSize.width * scaleFactor; + CGFloat scaledHeight = originalSize.height * scaleFactor; + + // Check if the scaled dimensions are within a one-pixel + // threshold of the target dimensions. + BOOL widthWithinThreshold = fabs(scaledWidth - targetSize.width) <= 1.0; + BOOL heightWithinThreshold = fabs(scaledHeight - targetSize.height) <= 1.0; + + // The image is considered scalable with scale factor + // if both dimensions are within the threshold. + return widthWithinThreshold && heightWithinThreshold; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m new file mode 100644 index 000000000000..22b100e34102 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMMarkerUserData.h" + +@implementation FGMMarkerUserData + +@end + +void FGMSetIdentifiersToMarkerUserData(NSString *markerIdentifier, + NSString *_Nullable clusterManagerIdentifier, + GMSMarker *marker) { + FGMMarkerUserData *userData = [[FGMMarkerUserData alloc] init]; + userData.markerIdentifier = markerIdentifier; + userData.clusterManagerIdentifier = clusterManagerIdentifier; + marker.userData = userData; +}; + +NSString *_Nullable FGMGetMarkerIdentifierFromMarker(GMSMarker *marker) { + if ([marker.userData isKindOfClass:[FGMMarkerUserData class]]) { + FGMMarkerUserData *userData = (FGMMarkerUserData *)marker.userData; + return userData.markerIdentifier; + } + return nil; +}; + +NSString *_Nullable FGMGetClusterManagerIdentifierFromMarker(GMSMarker *marker) { + if ([marker.userData isKindOfClass:[FGMMarkerUserData class]]) { + FGMMarkerUserData *userData = (FGMMarkerUserData *)marker.userData; + return userData.clusterManagerIdentifier; + } + return nil; +}; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m new file mode 100644 index 000000000000..91c93933308d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m @@ -0,0 +1,140 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapHeatmapController.h" +#import "FLTGoogleMapHeatmapController_Test.h" + +@import GoogleMapsUtils; + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapHeatmapController () + +/// The heatmap tile layer this controller handles. +@property(nonatomic, strong) GMUHeatmapTileLayer *heatmapTileLayer; + +/// The GMSMapView to which the heatmaps are added. +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapHeatmapController +- (instancetype)initWithHeatmap:(FGMPlatformHeatmap *)heatmap + tileLayer:(GMUHeatmapTileLayer *)heatmapTileLayer + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _heatmapTileLayer = heatmapTileLayer; + _mapView = mapView; + + [FLTGoogleMapHeatmapController updateHeatmap:_heatmapTileLayer + fromPlatformHeatmap:heatmap + withMapView:_mapView]; + } + return self; +} + +- (void)removeHeatmap { + _heatmapTileLayer.map = nil; +} + +- (void)clearTileCache { + [_heatmapTileLayer clearTileCache]; +} + +- (void)updateFromPlatformHeatmap:(FGMPlatformHeatmap *)platformHeatmap { + [FLTGoogleMapHeatmapController updateHeatmap:_heatmapTileLayer + fromPlatformHeatmap:platformHeatmap + withMapView:_mapView]; +} + ++ (void)updateHeatmap:(GMUHeatmapTileLayer *)heatmapTileLayer + fromPlatformHeatmap:(FGMPlatformHeatmap *)platformHeatmap + withMapView:(GMSMapView *)mapView { + heatmapTileLayer.weightedData = FGMGetWeightedDataForPigeonWeightedData(platformHeatmap.data); + if (platformHeatmap.gradient) { + heatmapTileLayer.gradient = FGMGetGradientForPigeonHeatmapGradient(platformHeatmap.gradient); + } + heatmapTileLayer.opacity = platformHeatmap.opacity; + heatmapTileLayer.radius = platformHeatmap.radius; + heatmapTileLayer.minimumZoomIntensity = platformHeatmap.minimumZoomIntensity; + heatmapTileLayer.maximumZoomIntensity = platformHeatmap.maximumZoomIntensity; + + // The map must be set each time for options to update. + // This must be done last, to avoid visual flickers of default property values. + heatmapTileLayer.map = mapView; +} +@end + +@interface FLTHeatmapsController () + +/// A map from heatmapId to the controller that manages it. +@property(nonatomic, strong) + NSMutableDictionary *heatmapIdToController; + +/// The map view owned by GoogmeMapController. +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTHeatmapsController +- (instancetype)initWithMapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _mapView = mapView; + _heatmapIdToController = [NSMutableDictionary dictionary]; + } + return self; +} + +- (void)addHeatmaps:(NSArray *)heatmapsToAdd { + for (FGMPlatformHeatmap *heatmap in heatmapsToAdd) { + GMUHeatmapTileLayer *heatmapTileLayer = [[GMUHeatmapTileLayer alloc] init]; + FLTGoogleMapHeatmapController *controller = + [[FLTGoogleMapHeatmapController alloc] initWithHeatmap:heatmap + tileLayer:heatmapTileLayer + mapView:_mapView]; + _heatmapIdToController[heatmap.heatmapId] = controller; + } +} + +- (void)changeHeatmaps:(NSArray *)heatmapsToChange { + for (FGMPlatformHeatmap *heatmap in heatmapsToChange) { + FLTGoogleMapHeatmapController *controller = _heatmapIdToController[heatmap.heatmapId]; + + [controller updateFromPlatformHeatmap:heatmap]; + [controller clearTileCache]; + } +} + +- (void)removeHeatmapsWithIdentifiers:(NSArray *)identifiers { + for (NSString *heatmapId in identifiers) { + FLTGoogleMapHeatmapController *controller = _heatmapIdToController[heatmapId]; + if (!controller) { + continue; + } + [controller removeHeatmap]; + [_heatmapIdToController removeObjectForKey:heatmapId]; + } +} + +- (BOOL)hasHeatmapWithIdentifier:(NSString *)identifier { + return _heatmapIdToController[identifier] != nil; +} + +- (FGMPlatformHeatmap *)heatmapWithIdentifier:(NSString *)identifier { + GMUHeatmapTileLayer *heatmap = self.heatmapIdToController[identifier].heatmapTileLayer; + if (!heatmap) { + return nil; + } + return [FGMPlatformHeatmap + makeWithHeatmapId:identifier + data:FGMGetPigeonWeightedDataForWeightedData(heatmap.weightedData) + gradient:FGMGetPigeonHeatmapGradientForGradient(heatmap.gradient) + opacity:heatmap.opacity + radius:heatmap.radius + minimumZoomIntensity:heatmap.minimumZoomIntensity + maximumZoomIntensity:heatmap.maximumZoomIntensity]; +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m new file mode 100644 index 000000000000..c4cce14ed247 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m @@ -0,0 +1,199 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapTileOverlayController.h" +#import "FLTGoogleMapTileOverlayController_Test.h" + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapTileOverlayController () + +@property(strong, nonatomic) GMSTileLayer *layer; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapTileOverlayController + +- (instancetype)initWithTileOverlay:(FGMPlatformTileOverlay *)tileOverlay + tileLayer:(GMSTileLayer *)tileLayer + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _layer = tileLayer; + _mapView = mapView; + [FLTGoogleMapTileOverlayController updateTileLayer:tileLayer + fromPlatformTileOverlay:tileOverlay + withMapView:mapView]; + } + return self; +} + +- (void)removeTileOverlay { + self.layer.map = nil; +} + +- (void)clearTileCache { + [self.layer clearTileCache]; +} + +- (void)updateFromPlatformTileOverlay:(FGMPlatformTileOverlay *)overlay { + [FLTGoogleMapTileOverlayController updateTileLayer:self.layer + fromPlatformTileOverlay:overlay + withMapView:self.mapView]; +} + ++ (void)updateTileLayer:(GMSTileLayer *)tileLayer + fromPlatformTileOverlay:(FGMPlatformTileOverlay *)platformOverlay + withMapView:(GMSMapView *)mapView { + tileLayer.opacity = 1.0 - platformOverlay.transparency; + tileLayer.zIndex = (int)platformOverlay.zIndex; + tileLayer.fadeIn = platformOverlay.fadeIn; + tileLayer.tileSize = platformOverlay.tileSize; + + // This must be done last, to avoid visual flickers of default property values. + tileLayer.map = platformOverlay.visible ? mapView : nil; +} + +@end + +@interface FLTTileProviderController () + +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; + +@end + +@implementation FLTTileProviderController + +- (instancetype)initWithTileOverlayIdentifier:(NSString *)identifier + callbackHandler:(FGMMapsCallbackApi *)callbackHandler { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _tileOverlayIdentifier = identifier; + } + return self; +} + +#pragma mark - GMSTileLayer method + +- (UIImage *)handleResultTile:(nullable UIImage *)tile { + CGImageRef imageRef = tile.CGImage; + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + BOOL isFloat = bitmapInfo && kCGBitmapFloatComponents; + size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); + + // Engine use f16 pixel format for wide gamut images + // If it is wide gamut, we want to downsample it + if (isFloat & (bitsPerComponent == 16)) { + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = + CGBitmapContextCreate(nil, tile.size.width, tile.size.height, 8, 0, colorSpace, + (kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast)); + CGContextDrawImage(context, CGRectMake(0, 0, tile.size.width, tile.size.height), tile.CGImage); + CGImageRef image = CGBitmapContextCreateImage(context); + tile = [UIImage imageWithCGImage:image]; + + CGImageRelease(image); + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + } + return tile; +} + +- (void)requestTileForX:(NSUInteger)x + y:(NSUInteger)y + zoom:(NSUInteger)zoom + receiver:(id)receiver { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.callbackHandler + tileWithOverlayIdentifier:self.tileOverlayIdentifier + location:[FGMPlatformPoint makeWithX:x y:y] + zoom:zoom + completion:^(FGMPlatformTile *_Nullable tile, + FlutterError *_Nullable error) { + FlutterStandardTypedData *typedData = tile.data; + UIImage *tileImage = + typedData + ? [self handleResultTile:[UIImage imageWithData:typedData.data]] + : kGMSTileLayerNoTile; + if (error) { + NSLog(@"Can't get tile: errorCode = %@, errorMessage = %@, details = %@", + [error code], [error message], [error details]); + } + [receiver receiveTileWithX:x y:y zoom:zoom image:tileImage]; + }]; + }); +} + +@end + +@interface FLTTileOverlaysController () + +@property(strong, nonatomic) NSMutableDictionary + *tileOverlayIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTTileOverlaysController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _tileOverlayIdentifierToController = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd { + for (FGMPlatformTileOverlay *tileOverlay in tileOverlaysToAdd) { + NSString *identifier = tileOverlay.tileOverlayId; + FLTTileProviderController *tileProvider = + [[FLTTileProviderController alloc] initWithTileOverlayIdentifier:identifier + callbackHandler:self.callbackHandler]; + FLTGoogleMapTileOverlayController *controller = + [[FLTGoogleMapTileOverlayController alloc] initWithTileOverlay:tileOverlay + tileLayer:tileProvider + mapView:self.mapView]; + self.tileOverlayIdentifierToController[identifier] = controller; + } +} + +- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange { + for (FGMPlatformTileOverlay *tileOverlay in tileOverlaysToChange) { + NSString *identifier = tileOverlay.tileOverlayId; + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; + [controller updateFromPlatformTileOverlay:tileOverlay]; + } +} +- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; + if (!controller) { + continue; + } + [controller removeTileOverlay]; + [self.tileOverlayIdentifierToController removeObjectForKey:identifier]; + } +} + +- (void)clearTileCacheWithIdentifier:(NSString *)identifier { + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; + [controller clearTileCache]; +} + +- (nullable FLTGoogleMapTileOverlayController *)tileOverlayWithIdentifier:(NSString *)identifier { + return self.tileOverlayIdentifierToController[identifier]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m new file mode 100644 index 000000000000..86391b40892e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m @@ -0,0 +1,19 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapsPlugin.h" + +#pragma mark - GoogleMaps plugin implementation + +@implementation FLTGoogleMapsPlugin + ++ (void)registerWithRegistrar:(NSObject *)registrar { + FLTGoogleMapFactory *googleMapFactory = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + [registrar registerViewFactory:googleMapFactory + withId:@"plugins.flutter.dev/google_maps_ios" + gestureRecognizersBlockingPolicy: + FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m new file mode 100644 index 000000000000..d2d0130dc64a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m @@ -0,0 +1,130 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapCircleController.h" +#import "GoogleMapCircleController_Test.h" + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapCircleController () + +@property(nonatomic, strong) GMSCircle *circle; +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapCircleController + +- (instancetype)initCircleWithPlatformCircle:(FGMPlatformCircle *)circle + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _circle = [GMSCircle circleWithPosition:FGMGetCoordinateForPigeonLatLng(circle.center) + radius:circle.radius]; + _mapView = mapView; + _circle.userData = @[ circle.circleId ]; + [FLTGoogleMapCircleController updateCircle:_circle + fromPlatformCircle:circle + withMapView:mapView]; + } + return self; +} + +- (void)removeCircle { + self.circle.map = nil; +} + +- (void)updateFromPlatformCircle:(FGMPlatformCircle *)platformCircle { + [FLTGoogleMapCircleController updateCircle:self.circle + fromPlatformCircle:platformCircle + withMapView:self.mapView]; +} + ++ (void)updateCircle:(GMSCircle *)circle + fromPlatformCircle:(FGMPlatformCircle *)platformCircle + withMapView:(GMSMapView *)mapView { + circle.tappable = platformCircle.consumeTapEvents; + circle.zIndex = platformCircle.zIndex; + circle.position = FGMGetCoordinateForPigeonLatLng(platformCircle.center); + circle.radius = platformCircle.radius; + circle.strokeColor = FGMGetColorForPigeonColor(platformCircle.strokeColor); + circle.strokeWidth = platformCircle.strokeWidth; + circle.fillColor = FGMGetColorForPigeonColor(platformCircle.fillColor); + + // This must be done last, to avoid visual flickers of default property values. + circle.map = platformCircle.visible ? mapView : nil; +} + +@end + +@interface FLTCirclesController () + +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) GMSMapView *mapView; +@property(strong, nonatomic) NSMutableDictionary *circleIdToController; + +@end + +@implementation FLTCirclesController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _circleIdToController = [NSMutableDictionary dictionaryWithCapacity:1]; + } + return self; +} + +- (void)addCircles:(NSArray *)circlesToAdd { + for (FGMPlatformCircle *circle in circlesToAdd) { + FLTGoogleMapCircleController *controller = + [[FLTGoogleMapCircleController alloc] initCircleWithPlatformCircle:circle + mapView:self.mapView]; + self.circleIdToController[circle.circleId] = controller; + } +} + +- (void)changeCircles:(NSArray *)circlesToChange { + for (FGMPlatformCircle *circle in circlesToChange) { + FLTGoogleMapCircleController *controller = self.circleIdToController[circle.circleId]; + [controller updateFromPlatformCircle:circle]; + } +} + +- (void)removeCirclesWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapCircleController *controller = self.circleIdToController[identifier]; + if (!controller) { + continue; + } + [controller removeCircle]; + [self.circleIdToController removeObjectForKey:identifier]; + } +} + +- (bool)hasCircleWithIdentifier:(NSString *)identifier { + if (!identifier) { + return false; + } + return self.circleIdToController[identifier] != nil; +} + +- (void)didTapCircleWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapCircleController *controller = self.circleIdToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapCircleWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +@end 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.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.m new file mode 100644 index 000000000000..0537d48ba9ce --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.m @@ -0,0 +1,838 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import GoogleMapsUtils; + +#import "GoogleMapController.h" +#import "GoogleMapController_Test.h" + +#import "FGMConversionUtils.h" +#import "FGMGroundOverlayController.h" +#import "FGMMarkerUserData.h" +#import "FLTGoogleMapHeatmapController.h" +#import "FLTGoogleMapTileOverlayController.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +#pragma mark - Conversion of JSON-like values sent via platform channels. Forward declarations. + +@interface FLTGoogleMapFactory () + +@property(weak, nonatomic) NSObject *registrar; +@property(strong, nonatomic, readonly) id sharedMapServices; + +@end + +@implementation FLTGoogleMapFactory + +@synthesize sharedMapServices = _sharedMapServices; + +- (instancetype)initWithRegistrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _registrar = registrar; + } + return self; +} + +- (NSObject *)createArgsCodec { + return FGMGetGoogleMapsFlutterPigeonMessagesCodec(); +} + +- (NSObject *)createWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + arguments:(id _Nullable)args { + // Precache shared map services, if needed. + // Retain the shared map services singleton, don't use the result for anything. + (void)[self sharedMapServices]; + + return [[FLTGoogleMapController alloc] initWithFrame:frame + viewIdentifier:viewId + creationParameters:args + registrar:self.registrar]; +} + +- (id)sharedMapServices { + if (_sharedMapServices == nil) { + // Calling this prepares GMSServices on a background thread controlled + // by the GoogleMaps framework. + // Retain the singleton to cache the initialization work across all map views. + _sharedMapServices = [GMSServices sharedServices]; + } + return _sharedMapServices; +} + +@end + +#pragma mark - + +/// Private declarations of the FGMMapCallHandler. +@interface FGMMapCallHandler () +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix; + +/// The map controller this inspector corresponds to. +@property(nonatomic, weak) FLTGoogleMapController *controller; +/// The messenger this instance was registered with by Pigeon. +@property(nonatomic, copy) NSObject *messenger; +/// The suffix this instance was registered under with Pigeon. +@property(nonatomic, copy) NSString *pigeonSuffix; +@end + +#pragma mark - + +/// Private declarations of the FGMMapInspector. +@interface FGMMapInspector () + +/// The map controller this inspector corresponds to. +@property(nonatomic, weak) FLTGoogleMapController *controller; +/// The messenger this instance was registered with by Pigeon. +@property(nonatomic, copy) NSObject *messenger; +/// The suffix this instance was registered under with Pigeon. +@property(nonatomic, copy) NSString *pigeonSuffix; +@end + +#pragma mark - + +@interface FLTGoogleMapController () + +@property(nonatomic, strong) GMSMapView *mapView; +@property(nonatomic, strong) FGMMapsCallbackApi *dartCallbackHandler; +@property(nonatomic, assign) BOOL trackCameraPosition; +@property(nonatomic, weak) NSObject *registrar; +@property(nonatomic, strong) FGMClusterManagersController *clusterManagersController; +@property(nonatomic, strong) FLTMarkersController *markersController; +@property(nonatomic, strong) FLTPolygonsController *polygonsController; +@property(nonatomic, strong) FLTPolylinesController *polylinesController; +@property(nonatomic, strong) FLTCirclesController *circlesController; + +// The controller that handles heatmaps +@property(nonatomic, strong) FLTHeatmapsController *heatmapsController; +@property(nonatomic, strong) FLTTileOverlaysController *tileOverlaysController; +@property(nonatomic, strong) FLTGroundOverlaysController *groundOverlaysController; +// The resulting error message, if any, from the last attempt to set the map style. +// This is used to provide access to errors after the fact, since the map style is generally set at +// creation time and there's no mechanism to return non-fatal error details during platform view +// initialization. +@property(nonatomic, copy) NSString *styleError; +// The main Pigeon API implementation, separate to avoid lifetime extension. +@property(nonatomic, strong) FGMMapCallHandler *callHandler; +// The inspector API implementation, separate to avoid lifetime extension. +@property(nonatomic, strong) FGMMapInspector *inspector; + +@end + +@implementation FLTGoogleMapController + +- (instancetype)initWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *)registrar { + GMSCameraPosition *camera = + FGMGetCameraPositionForPigeonCameraPosition(creationParameters.initialCameraPosition); + + GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init]; + options.frame = frame; + options.camera = camera; + NSString *cloudMapId = creationParameters.mapConfiguration.mapId; + if (cloudMapId) { + options.mapID = [GMSMapID mapIDWithIdentifier:cloudMapId]; + } + + GMSMapView *mapView = [[GMSMapView alloc] initWithOptions:options]; + + return [self initWithMapView:mapView + viewIdentifier:viewId + creationParameters:creationParameters + registrar:registrar]; +} + +- (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *_Nonnull)registrar { + if (self = [super init]) { + _mapView = mapView; + + _mapView.accessibilityElementsHidden = NO; + // TODO(cyanglaz): avoid sending message to self in the middle of the init method. + // https://github.com/flutter/flutter/issues/104121 + [self interpretMapConfiguration:creationParameters.mapConfiguration]; + NSString *pigeonSuffix = [NSString stringWithFormat:@"%lld", viewId]; + _dartCallbackHandler = [[FGMMapsCallbackApi alloc] initWithBinaryMessenger:registrar.messenger + messageChannelSuffix:pigeonSuffix]; + _mapView.delegate = self; + _mapView.paddingAdjustmentBehavior = kGMSMapViewPaddingAdjustmentBehaviorNever; + _registrar = registrar; + _clusterManagersController = + [[FGMClusterManagersController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler]; + _markersController = [[FLTMarkersController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + clusterManagersController:_clusterManagersController + registrar:registrar]; + _polygonsController = [[FLTPolygonsController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _polylinesController = [[FLTPolylinesController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _circlesController = [[FLTCirclesController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _heatmapsController = [[FLTHeatmapsController alloc] initWithMapView:_mapView]; + _tileOverlaysController = + [[FLTTileOverlaysController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _groundOverlaysController = + [[FLTGroundOverlaysController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + [_clusterManagersController addClusterManagers:creationParameters.initialClusterManagers]; + [_markersController addMarkers:creationParameters.initialMarkers]; + [_polygonsController addPolygons:creationParameters.initialPolygons]; + [_polylinesController addPolylines:creationParameters.initialPolylines]; + [_circlesController addCircles:creationParameters.initialCircles]; + [_heatmapsController addHeatmaps:creationParameters.initialHeatmaps]; + [_tileOverlaysController addTileOverlays:creationParameters.initialTileOverlays]; + [_groundOverlaysController addGroundOverlays:creationParameters.initialGroundOverlays]; + + // Invoke clustering after markers are added. + [_clusterManagersController invokeClusteringForEachClusterManager]; + + [_mapView addObserver:self forKeyPath:@"frame" options:0 context:nil]; + + _callHandler = [[FGMMapCallHandler alloc] initWithMapController:self + messenger:registrar.messenger + pigeonSuffix:pigeonSuffix]; + SetUpFGMMapsApiWithSuffix(registrar.messenger, _callHandler, pigeonSuffix); + _inspector = [[FGMMapInspector alloc] initWithMapController:self + messenger:registrar.messenger + pigeonSuffix:pigeonSuffix]; + SetUpFGMMapsInspectorApiWithSuffix(registrar.messenger, _inspector, pigeonSuffix); + } + return self; +} + +- (void)dealloc { + // Unregister the API implementations so that they can be released; the registration created an + // owning reference. + SetUpFGMMapsApiWithSuffix(_callHandler.messenger, nil, _callHandler.pigeonSuffix); + SetUpFGMMapsInspectorApiWithSuffix(_inspector.messenger, nil, _inspector.pigeonSuffix); +} + +- (UIView *)view { + return self.mapView; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if (object == self.mapView && [keyPath isEqualToString:@"frame"]) { + CGRect bounds = self.mapView.bounds; + if (CGRectEqualToRect(bounds, CGRectZero)) { + // The workaround is to fix an issue that the camera location is not current when + // the size of the map is zero at initialization. + // So We only care about the size of the `self.mapView`, ignore the frame changes when the + // size is zero. + return; + } + // We only observe the frame for initial setup. + [self.mapView removeObserver:self forKeyPath:@"frame"]; + [self.mapView moveCamera:[GMSCameraUpdate setCamera:self.mapView.camera]]; + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +- (void)showAtOrigin:(CGPoint)origin { + CGRect frame = {origin, self.mapView.frame.size}; + self.mapView.frame = frame; + self.mapView.hidden = NO; +} + +- (void)hide { + self.mapView.hidden = YES; +} + +- (GMSCameraPosition *)cameraPosition { + if (self.trackCameraPosition) { + return self.mapView.camera; + } else { + return nil; + } +} + +- (void)setCamera:(GMSCameraPosition *)camera { + self.mapView.camera = camera; +} + +- (void)setCameraTargetBounds:(GMSCoordinateBounds *)bounds { + self.mapView.cameraTargetBounds = bounds; +} + +- (void)setCompassEnabled:(BOOL)enabled { + self.mapView.settings.compassButton = enabled; +} + +- (void)setIndoorEnabled:(BOOL)enabled { + self.mapView.indoorEnabled = enabled; +} + +- (void)setTrafficEnabled:(BOOL)enabled { + self.mapView.trafficEnabled = enabled; +} + +- (void)setBuildingsEnabled:(BOOL)enabled { + self.mapView.buildingsEnabled = enabled; +} + +- (void)setMapType:(GMSMapViewType)mapType { + self.mapView.mapType = mapType; +} + +- (void)setMinZoom:(float)minZoom maxZoom:(float)maxZoom { + [self.mapView setMinZoom:minZoom maxZoom:maxZoom]; +} + +- (void)setPaddingTop:(float)top left:(float)left bottom:(float)bottom right:(float)right { + self.mapView.padding = UIEdgeInsetsMake(top, left, bottom, right); +} + +- (void)setRotateGesturesEnabled:(BOOL)enabled { + self.mapView.settings.rotateGestures = enabled; +} + +- (void)setScrollGesturesEnabled:(BOOL)enabled { + self.mapView.settings.scrollGestures = enabled; +} + +- (void)setTiltGesturesEnabled:(BOOL)enabled { + self.mapView.settings.tiltGestures = enabled; +} + +- (void)setTrackCameraPosition:(BOOL)enabled { + _trackCameraPosition = enabled; +} + +- (void)setZoomGesturesEnabled:(BOOL)enabled { + self.mapView.settings.zoomGestures = enabled; +} + +- (void)setMyLocationEnabled:(BOOL)enabled { + self.mapView.myLocationEnabled = enabled; +} + +- (void)setMyLocationButtonEnabled:(BOOL)enabled { + self.mapView.settings.myLocationButton = enabled; +} + +/// Sets the map style, returing any error string as well as storing that error in `mapStyle` for +/// later access. +- (NSString *)setMapStyle:(NSString *)mapStyle { + NSString *errorString = nil; + if (mapStyle.length == 0) { + self.mapView.mapStyle = nil; + } else { + NSError *error; + GMSMapStyle *style = [GMSMapStyle styleWithJSONString:mapStyle error:&error]; + if (style) { + self.mapView.mapStyle = style; + } else { + errorString = [error localizedDescription]; + } + } + self.styleError = errorString; + return errorString; +} + +#pragma mark - GMSMapViewDelegate methods + +- (void)mapView:(GMSMapView *)mapView willMove:(BOOL)gesture { + [self.dartCallbackHandler didStartCameraMoveWithCompletion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position { + if (self.trackCameraPosition) { + [self.dartCallbackHandler + didMoveCameraToPosition:FGMGetPigeonCameraPositionForPosition(position) + completion:^(FlutterError *_Nullable _){ + }]; + } +} + +- (void)mapView:(GMSMapView *)mapView idleAtCameraPosition:(GMSCameraPosition *)position { + [self.dartCallbackHandler didIdleCameraWithCompletion:^(FlutterError *_Nullable _){ + }]; +} + +- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker { + if ([marker.userData isKindOfClass:[GMUStaticCluster class]]) { + GMUStaticCluster *cluster = marker.userData; + [self.clusterManagersController didTapCluster:cluster]; + // When NO is returned, the map will focus on the cluster. + return NO; + } + return + [self.markersController didTapMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker)]; +} + +- (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker { + [self.markersController + didEndDraggingMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker) + location:marker.position]; +} + +- (void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker { + [self.markersController + didStartDraggingMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker) + location:marker.position]; +} + +- (void)mapView:(GMSMapView *)mapView didDragMarker:(GMSMarker *)marker { + [self.markersController didDragMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker) + location:marker.position]; +} + +- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker { + [self.markersController + didTapInfoWindowOfMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker)]; +} +- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay { + NSString *overlayId = overlay.userData[0]; + if ([self.polylinesController hasPolylineWithIdentifier:overlayId]) { + [self.polylinesController didTapPolylineWithIdentifier:overlayId]; + } else if ([self.polygonsController hasPolygonWithIdentifier:overlayId]) { + [self.polygonsController didTapPolygonWithIdentifier:overlayId]; + } else if ([self.circlesController hasCircleWithIdentifier:overlayId]) { + [self.circlesController didTapCircleWithIdentifier:overlayId]; + } else if ([self.groundOverlaysController hasGroundOverlaysWithIdentifier:overlayId]) { + [self.groundOverlaysController didTapGroundOverlayWithIdentifier:overlayId]; + } +} + +- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { + [self.dartCallbackHandler didTapAtPosition:FGMGetPigeonLatLngForCoordinate(coordinate) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate { + [self.dartCallbackHandler didLongPressAtPosition:FGMGetPigeonLatLngForCoordinate(coordinate) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)interpretMapConfiguration:(FGMPlatformMapConfiguration *)config { + FGMPlatformCameraTargetBounds *cameraTargetBounds = config.cameraTargetBounds; + if (cameraTargetBounds) { + [self setCameraTargetBounds:cameraTargetBounds.bounds + ? FGMGetCoordinateBoundsForPigeonLatLngBounds( + cameraTargetBounds.bounds) + : nil]; + } + NSNumber *compassEnabled = config.compassEnabled; + if (compassEnabled != nil) { + [self setCompassEnabled:compassEnabled.boolValue]; + } + NSNumber *indoorEnabled = config.indoorViewEnabled; + if (indoorEnabled != nil) { + [self setIndoorEnabled:indoorEnabled.boolValue]; + } + NSNumber *trafficEnabled = config.trafficEnabled; + if (trafficEnabled != nil) { + [self setTrafficEnabled:trafficEnabled.boolValue]; + } + NSNumber *buildingsEnabled = config.buildingsEnabled; + if (buildingsEnabled != nil) { + [self setBuildingsEnabled:buildingsEnabled.boolValue]; + } + FGMPlatformMapTypeBox *mapType = config.mapType; + if (mapType) { + [self setMapType:FGMGetMapViewTypeForPigeonMapType(mapType.value)]; + } + FGMPlatformZoomRange *zoomData = config.minMaxZoomPreference; + if (zoomData) { + float minZoom = zoomData.min != nil ? zoomData.min.floatValue : kGMSMinZoomLevel; + float maxZoom = zoomData.max != nil ? zoomData.max.floatValue : kGMSMaxZoomLevel; + [self setMinZoom:minZoom maxZoom:maxZoom]; + } + FGMPlatformEdgeInsets *padding = config.padding; + if (padding) { + [self setPaddingTop:padding.top left:padding.left bottom:padding.bottom right:padding.right]; + } + + NSNumber *rotateGesturesEnabled = config.rotateGesturesEnabled; + if (rotateGesturesEnabled != nil) { + [self setRotateGesturesEnabled:rotateGesturesEnabled.boolValue]; + } + NSNumber *scrollGesturesEnabled = config.scrollGesturesEnabled; + if (scrollGesturesEnabled != nil) { + [self setScrollGesturesEnabled:scrollGesturesEnabled.boolValue]; + } + NSNumber *tiltGesturesEnabled = config.tiltGesturesEnabled; + if (tiltGesturesEnabled != nil) { + [self setTiltGesturesEnabled:tiltGesturesEnabled.boolValue]; + } + NSNumber *trackCameraPosition = config.trackCameraPosition; + if (trackCameraPosition != nil) { + [self setTrackCameraPosition:trackCameraPosition.boolValue]; + } + NSNumber *zoomGesturesEnabled = config.zoomGesturesEnabled; + if (zoomGesturesEnabled != nil) { + [self setZoomGesturesEnabled:zoomGesturesEnabled.boolValue]; + } + NSNumber *myLocationEnabled = config.myLocationEnabled; + if (myLocationEnabled != nil) { + [self setMyLocationEnabled:myLocationEnabled.boolValue]; + } + NSNumber *myLocationButtonEnabled = config.myLocationButtonEnabled; + if (myLocationButtonEnabled != nil) { + [self setMyLocationButtonEnabled:myLocationButtonEnabled.boolValue]; + } + NSString *style = config.style; + if (style) { + [self setMapStyle:style]; + } +} + +@end + +#pragma mark - + +/// Private declarations of the FGMMapCallHandler. +@implementation FGMMapCallHandler + +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix { + self = [super init]; + if (self) { + _controller = controller; + _messenger = messenger; + _pigeonSuffix = suffix; + _transactionWrapper = [[FGMCATransactionWrapper alloc] init]; + } + return self; +} + +- (void)waitForMapWithError:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + // No-op; this call just ensures synchronization with the platform thread. +} + +- (void)updateCirclesByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.circlesController addCircles:toAdd]; + [self.controller.circlesController changeCircles:toChange]; + [self.controller.circlesController removeCirclesWithIdentifiers:idsToRemove]; +} + +- (void)updateHeatmapsByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.heatmapsController addHeatmaps:toAdd]; + [self.controller.heatmapsController changeHeatmaps:toChange]; + [self.controller.heatmapsController removeHeatmapsWithIdentifiers:idsToRemove]; +} + +- (void)updateWithMapConfiguration:(nonnull FGMPlatformMapConfiguration *)configuration + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller interpretMapConfiguration:configuration]; +} + +- (void)updateMarkersByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.markersController addMarkers:toAdd]; + [self.controller.markersController changeMarkers:toChange]; + [self.controller.markersController removeMarkersWithIdentifiers:idsToRemove]; + + // Invoke clustering after markers are added. + [self.controller.clusterManagersController invokeClusteringForEachClusterManager]; +} + +- (void)updateClusterManagersByAdding:(nonnull NSArray *)toAdd + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.clusterManagersController addClusterManagers:toAdd]; + [self.controller.clusterManagersController removeClusterManagersWithIdentifiers:idsToRemove]; +} + +- (void)updatePolygonsByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.polygonsController addPolygons:toAdd]; + [self.controller.polygonsController changePolygons:toChange]; + [self.controller.polygonsController removePolygonWithIdentifiers:idsToRemove]; +} + +- (void)updatePolylinesByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.polylinesController addPolylines:toAdd]; + [self.controller.polylinesController changePolylines:toChange]; + [self.controller.polylinesController removePolylineWithIdentifiers:idsToRemove]; +} + +- (void)updateTileOverlaysByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.tileOverlaysController addTileOverlays:toAdd]; + [self.controller.tileOverlaysController changeTileOverlays:toChange]; + [self.controller.tileOverlaysController removeTileOverlayWithIdentifiers:idsToRemove]; +} + +- (void)updateGroundOverlaysByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.groundOverlaysController addGroundOverlays:toAdd]; + [self.controller.groundOverlaysController changeGroundOverlays:toChange]; + [self.controller.groundOverlaysController removeGroundOverlaysWithIdentifiers:idsToRemove]; +} + +- (nullable FGMPlatformLatLng *) + latLngForScreenCoordinate:(nonnull FGMPlatformPoint *)screenCoordinate + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + if (!self.controller.mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"getLatLng called prior to map initialization" + details:nil]; + return nil; + } + CGPoint point = FGMGetCGPointForPigeonPoint(screenCoordinate); + CLLocationCoordinate2D latlng = [self.controller.mapView.projection coordinateForPoint:point]; + return FGMGetPigeonLatLngForCoordinate(latlng); +} + +- (nullable FGMPlatformPoint *) + screenCoordinatesForLatLng:(nonnull FGMPlatformLatLng *)latLng + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + if (!self.controller.mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"getScreenCoordinate called prior to map initialization" + details:nil]; + return nil; + } + CLLocationCoordinate2D location = FGMGetCoordinateForPigeonLatLng(latLng); + CGPoint point = [self.controller.mapView.projection pointForCoordinate:location]; + return FGMGetPigeonPointForCGPoint(point); +} + +- (nullable FGMPlatformLatLngBounds *)visibleMapRegion: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + if (!self.controller.mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"getVisibleRegion called prior to map initialization" + details:nil]; + return nil; + } + GMSVisibleRegion visibleRegion = self.controller.mapView.projection.visibleRegion; + GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithRegion:visibleRegion]; + return FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds); +} + +- (void)moveCameraWithUpdate:(nonnull FGMPlatformCameraUpdate *)cameraUpdate + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSCameraUpdate *update = FGMGetCameraUpdateForPigeonCameraUpdate(cameraUpdate); + if (!update) { + *error = [FlutterError errorWithCode:@"Invalid update" + message:@"Unrecognized camera update" + details:nil]; + return; + } + [self.controller.mapView moveCamera:update]; +} + +- (void)animateCameraWithUpdate:(nonnull FGMPlatformCameraUpdate *)cameraUpdate + duration:(nullable NSNumber *)durationMilliseconds + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSCameraUpdate *update = FGMGetCameraUpdateForPigeonCameraUpdate(cameraUpdate); + if (!update) { + *error = [FlutterError errorWithCode:@"Invalid update" + message:@"Unrecognized camera update" + details:nil]; + return; + } + FGMCATransactionWrapper *transaction = + durationMilliseconds != nil ? self.transactionWrapper : nil; + [transaction begin]; + [transaction setAnimationDuration:[durationMilliseconds doubleValue] / 1000]; + [self.controller.mapView animateWithCameraUpdate:update]; + [transaction commit]; +} + +- (nullable NSNumber *)currentZoomLevel:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.camera.zoom); +} + +- (void)showInfoWindowForMarkerWithIdentifier:(nonnull NSString *)markerId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + [self.controller.markersController showMarkerInfoWindowWithIdentifier:markerId error:error]; +} + +- (void)hideInfoWindowForMarkerWithIdentifier:(nonnull NSString *)markerId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + [self.controller.markersController hideMarkerInfoWindowWithIdentifier:markerId error:error]; +} + +- (nullable NSNumber *) + isShowingInfoWindowForMarkerWithIdentifier:(nonnull NSString *)markerId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + return [self.controller.markersController isInfoWindowShownForMarkerWithIdentifier:markerId + error:error]; +} + +- (nullable NSString *)setStyle:(nonnull NSString *)style + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [self.controller setMapStyle:style]; +} + +- (nullable NSString *)lastStyleError:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return self.controller.styleError; +} + +- (void)clearTileCacheForOverlayWithIdentifier:(nonnull NSString *)tileOverlayId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + [self.controller.tileOverlaysController clearTileCacheWithIdentifier:tileOverlayId]; +} + +- (nullable FlutterStandardTypedData *)takeSnapshotWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSMapView *mapView = self.controller.mapView; + if (!mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"takeSnapshot called prior to map initialization" + details:nil]; + return nil; + } + UIGraphicsImageRenderer *renderer = + [[UIGraphicsImageRenderer alloc] initWithSize:mapView.bounds.size]; + // For some unknown reason mapView.layer::renderInContext API returns a blank image on iOS 17. + // So we have to use drawViewHierarchyInRect API. + UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *context) { + [mapView drawViewHierarchyInRect:mapView.bounds afterScreenUpdates:YES]; + }]; + NSData *imageData = UIImagePNGRepresentation(image); + return imageData ? [FlutterStandardTypedData typedDataWithBytes:imageData] : nil; +} + +@end + +#pragma mark - + +/// Private declarations of the FGMMapInspector. +@implementation FGMMapInspector + +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix { + self = [super init]; + if (self) { + _controller = controller; + _messenger = messenger; + _pigeonSuffix = suffix; + } + return self; +} + +- (nullable NSNumber *)areBuildingsEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.buildingsEnabled); +} + +- (nullable NSNumber *)areRotateGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.rotateGestures); +} + +- (nullable NSNumber *)areScrollGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.scrollGestures); +} + +- (nullable NSNumber *)areTiltGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.tiltGestures); +} + +- (nullable NSNumber *)areZoomGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.zoomGestures); +} + +- (nullable FGMPlatformTileLayer *) + tileOverlayWithIdentifier:(nonnull NSString *)tileOverlayId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSTileLayer *layer = + [self.controller.tileOverlaysController tileOverlayWithIdentifier:tileOverlayId].layer; + if (!layer) { + return nil; + } + return [FGMPlatformTileLayer makeWithVisible:(layer.map != nil) + fadeIn:layer.fadeIn + opacity:layer.opacity + zIndex:layer.zIndex]; +} + +- (nullable FGMPlatformHeatmap *) + heatmapWithIdentifier:(nonnull NSString *)heatmapId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [self.controller.heatmapsController heatmapWithIdentifier:heatmapId]; +} + +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)clusterManagerId + error:(FlutterError *_Nullable *_Nonnull)error { + return [self.controller.clusterManagersController clustersWithIdentifier:clusterManagerId + error:error]; +} + +- (nullable NSNumber *)isCompassEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.compassButton); +} + +- (nullable NSNumber *)isMyLocationButtonEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.myLocationButton); +} + +- (nullable NSNumber *)isTrafficEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.trafficEnabled); +} + +- (nullable FGMPlatformZoomRange *)zoomRange: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [FGMPlatformZoomRange makeWithMin:@(self.controller.mapView.minZoom) + max:@(self.controller.mapView.maxZoom)]; +} + +- (nullable FGMPlatformGroundOverlay *) + groundOverlayWithIdentifier:(NSString *)groundOverlayId + error:(FlutterError *_Nullable __autoreleasing *)error { + return [self.controller.groundOverlaysController groundOverlayWithIdentifier:groundOverlayId]; +} + +- (nullable FGMPlatformCameraPosition *)cameraPosition: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return FGMGetPigeonCameraPositionForPosition(self.controller.mapView.camera); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m new file mode 100644 index 000000000000..ed3aabd7fc10 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m @@ -0,0 +1,343 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapMarkerController.h" +#import "GoogleMapMarkerController_Test.h" + +#import "FGMConversionUtils.h" +#import "FGMImageUtils.h" +#import "FGMMarkerUserData.h" + +@interface FLTGoogleMapMarkerController () + +@property(strong, nonatomic, readwrite) GMSMarker *marker; +@property(weak, nonatomic) GMSMapView *mapView; +@property(assign, nonatomic, readwrite) BOOL consumeTapEvents; +/// The unique identifier for the cluster manager. +@property(copy, nonatomic, nullable) NSString *clusterManagerIdentifier; +/// The unique identifier for the marker. +@property(copy, nonatomic) NSString *markerIdentifier; + +@end + +@implementation FLTGoogleMapMarkerController + +- (instancetype)initWithMarker:(GMSMarker *)marker + markerIdentifier:(NSString *)markerIdentifier + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _marker = marker; + _markerIdentifier = [markerIdentifier copy]; + _mapView = mapView; + } + return self; +} + +- (void)showInfoWindow { + self.mapView.selectedMarker = self.marker; +} + +- (void)hideInfoWindow { + if (self.mapView.selectedMarker == self.marker) { + self.mapView.selectedMarker = nil; + } +} + +- (BOOL)isInfoWindowShown { + return self.mapView.selectedMarker == self.marker; +} + +- (void)removeMarker { + self.marker.map = nil; +} + +- (void)updateFromPlatformMarker:(FGMPlatformMarker *)platformMarker + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale { + self.clusterManagerIdentifier = platformMarker.clusterManagerId; + self.consumeTapEvents = platformMarker.consumeTapEvents; + + // Set the marker's user data with current identifiers. + FGMSetIdentifiersToMarkerUserData(self.markerIdentifier, self.clusterManagerIdentifier, + self.marker); + + // If marker belongs the cluster manager, visibility need to be controlled with the opacity + // as the cluster manager controls when marker is on the map and when not. + BOOL useOpacityForVisibility = self.clusterManagerIdentifier != nil; + [FLTGoogleMapMarkerController updateMarker:self.marker + fromPlatformMarker:platformMarker + withMapView:self.mapView + registrar:registrar + screenScale:screenScale + usingOpacityForVisibility:useOpacityForVisibility]; +} + ++ (void)updateMarker:(GMSMarker *)marker + fromPlatformMarker:(FGMPlatformMarker *)platformMarker + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingOpacityForVisibility:(BOOL)useOpacityForVisibility { + marker.groundAnchor = FGMGetCGPointForPigeonPoint(platformMarker.anchor); + marker.draggable = platformMarker.draggable; + UIImage *image = FGMIconFromBitmap(platformMarker.icon, registrar, screenScale); + marker.icon = image; + marker.flat = platformMarker.flat; + marker.position = FGMGetCoordinateForPigeonLatLng(platformMarker.position); + marker.rotation = platformMarker.rotation; + marker.zIndex = (int)platformMarker.zIndex; + FGMPlatformInfoWindow *infoWindow = platformMarker.infoWindow; + marker.infoWindowAnchor = FGMGetCGPointForPigeonPoint(infoWindow.anchor); + if (infoWindow.title) { + marker.title = infoWindow.title; + marker.snippet = infoWindow.snippet; + } + + // This must be done last, to avoid visual flickers of default property values. + if (useOpacityForVisibility) { + marker.opacity = platformMarker.visible ? platformMarker.alpha : 0.0f; + } else { + marker.opacity = platformMarker.alpha; + marker.map = platformMarker.visible ? mapView : nil; + } +} + +@end + +@interface FLTMarkersController () + +@property(strong, nonatomic, readwrite) NSMutableDictionary *markerIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +/// Controller for adding/removing/fetching cluster managers +@property(weak, nonatomic, nullable) FGMClusterManagersController *clusterManagersController; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTMarkersController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + clusterManagersController:(nullable FGMClusterManagersController *)clusterManagersController + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _clusterManagersController = clusterManagersController; + _markerIdentifierToController = [[NSMutableDictionary alloc] init]; + _registrar = registrar; + } + return self; +} + +- (void)addMarkers:(NSArray *)markersToAdd { + for (FGMPlatformMarker *marker in markersToAdd) { + [self addMarker:marker]; + } +} + +- (void)addMarker:(FGMPlatformMarker *)markerToAdd { + CLLocationCoordinate2D position = FGMGetCoordinateForPigeonLatLng(markerToAdd.position); + NSString *markerIdentifier = markerToAdd.markerId; + NSString *clusterManagerIdentifier = markerToAdd.clusterManagerId; + GMSMarker *marker = [GMSMarker markerWithPosition:position]; + FLTGoogleMapMarkerController *controller = + [[FLTGoogleMapMarkerController alloc] initWithMarker:marker + markerIdentifier:markerIdentifier + mapView:self.mapView]; + [controller updateFromPlatformMarker:markerToAdd + registrar:self.registrar + screenScale:[self getScreenScale]]; + if (clusterManagerIdentifier) { + GMUClusterManager *clusterManager = + [_clusterManagersController clusterManagerWithIdentifier:clusterManagerIdentifier]; + if ([marker conformsToProtocol:@protocol(GMUClusterItem)]) { + [clusterManager addItem:(id)marker]; + } + } + self.markerIdentifierToController[markerIdentifier] = controller; +} + +- (void)changeMarkers:(NSArray *)markersToChange { + for (FGMPlatformMarker *marker in markersToChange) { + [self changeMarker:marker]; + } +} + +- (void)changeMarker:(FGMPlatformMarker *)markerToChange { + NSString *markerIdentifier = markerToChange.markerId; + + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[markerIdentifier]; + if (!controller) { + return; + } + + NSString *clusterManagerIdentifier = markerToChange.clusterManagerId; + NSString *previousClusterManagerIdentifier = [controller clusterManagerIdentifier]; + [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]; + } + } +} + +- (void)removeMarkersWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + [self removeMarker:identifier]; + } +} + +- (void)removeMarker:(NSString *)identifier { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + NSString *clusterManagerIdentifier = [controller clusterManagerIdentifier]; + if (clusterManagerIdentifier) { + GMUClusterManager *clusterManager = + [_clusterManagersController clusterManagerWithIdentifier:clusterManagerIdentifier]; + [clusterManager removeItem:(id)controller.marker]; + } else { + [controller removeMarker]; + } + [self.markerIdentifierToController removeObjectForKey:identifier]; +} + +- (BOOL)didTapMarkerWithIdentifier:(NSString *)identifier { + if (!identifier) { + return NO; + } + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return NO; + } + [self.callbackHandler didTapMarkerWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; + return controller.consumeTapEvents; +} + +- (void)didStartDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + if (!identifier) { + return; + } + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler + didStartDragForMarkerWithIdentifier:identifier + atPosition:FGMGetPigeonLatLngForCoordinate(location) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)didDragMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + if (!identifier) { + return; + } + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didDragMarkerWithIdentifier:identifier + atPosition:FGMGetPigeonLatLngForCoordinate(location) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)didEndDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didEndDragForMarkerWithIdentifier:identifier + atPosition:FGMGetPigeonLatLngForCoordinate(location) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)identifier { + if (identifier && self.markerIdentifierToController[identifier]) { + [self.callbackHandler didTapInfoWindowOfMarkerWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; + } +} + +- (void)showMarkerInfoWindowWithIdentifier:(NSString *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (controller) { + [controller showInfoWindow]; + } else { + *error = [FlutterError errorWithCode:@"Invalid markerId" + message:@"showInfoWindow called with invalid markerId" + details:nil]; + } +} + +- (void)hideMarkerInfoWindowWithIdentifier:(NSString *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (controller) { + [controller hideInfoWindow]; + } else { + *error = [FlutterError errorWithCode:@"Invalid markerId" + message:@"hideInfoWindow called with invalid markerId" + details:nil]; + } +} + +- (nullable NSNumber *) + isInfoWindowShownForMarkerWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (controller) { + return @([controller isInfoWindowShown]); + } else { + *error = [FlutterError errorWithCode:@"Invalid markerId" + message:@"isInfoWindowShown called with invalid markerId" + details:nil]; + return nil; + } +} + +- (CGFloat)getScreenScale { + // TODO(jokerttu): This method is called on marker creation, which, for initial markers, is done + // before the view is added to the view hierarchy. This means that the traitCollection values may + // not be matching the right display where the map is finally shown. The solution should be + // revisited after the proper way to fetch the display scale is resolved for platform views. This + // should be done under the context of the following issue: + // https://github.com/flutter/flutter/issues/125496. + return self.mapView.traitCollection.displayScale; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m new file mode 100644 index 000000000000..12cbfeefecd7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m @@ -0,0 +1,146 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolygonController.h" +#import "GoogleMapPolygonController_Test.h" + +#import "FGMConversionUtils.h" + +/// Converts a list of holes represented as CLLocation lists to GMSMutablePath lists. +static NSArray *FMGPathHolesFromLocationHoles( + NSArray *> *locationHoles) { + NSMutableArray *pathHoles = + [NSMutableArray arrayWithCapacity:locationHoles.count]; + for (NSArray *hole in locationHoles) { + [pathHoles addObject:FGMGetPathFromPoints(hole)]; + } + return pathHoles; +} + +@interface FLTGoogleMapPolygonController () + +@property(strong, nonatomic) GMSPolygon *polygon; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapPolygonController + +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _polygon = [GMSPolygon polygonWithPath:path]; + _mapView = mapView; + _polygon.userData = @[ identifier ]; + } + return self; +} + +- (void)removePolygon { + self.polygon.map = nil; +} + +- (void)updateFromPlatformPolygon:(FGMPlatformPolygon *)polygon { + [FLTGoogleMapPolygonController updatePolygon:self.polygon + fromPlatformPolygon:polygon + withMapView:self.mapView]; +} + ++ (void)updatePolygon:(GMSPolygon *)polygon + fromPlatformPolygon:(FGMPlatformPolygon *)platformPolygon + withMapView:(GMSMapView *)mapView { + polygon.tappable = platformPolygon.consumesTapEvents; + polygon.zIndex = (int)platformPolygon.zIndex; + polygon.path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(platformPolygon.points)); + polygon.holes = + FMGPathHolesFromLocationHoles(FGMGetHolesForPigeonLatLngArrays(platformPolygon.holes)); + polygon.fillColor = FGMGetColorForPigeonColor(platformPolygon.fillColor); + polygon.strokeColor = FGMGetColorForPigeonColor(platformPolygon.strokeColor); + polygon.strokeWidth = platformPolygon.strokeWidth; + + // This must be done last, to avoid visual flickers of default property values. + polygon.map = platformPolygon.visible ? mapView : nil; +} + +@end + +@interface FLTPolygonsController () + +@property(strong, nonatomic) NSMutableDictionary *polygonIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTPolygonsController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _polygonIdentifierToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _registrar = registrar; + } + return self; +} + +- (void)addPolygons:(NSArray *)polygonsToAdd { + for (FGMPlatformPolygon *polygon in polygonsToAdd) { + GMSMutablePath *path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(polygon.points)); + NSString *identifier = polygon.polygonId; + FLTGoogleMapPolygonController *controller = + [[FLTGoogleMapPolygonController alloc] initWithPath:path + identifier:identifier + mapView:self.mapView]; + [controller updateFromPlatformPolygon:polygon]; + self.polygonIdentifierToController[identifier] = controller; + } +} + +- (void)changePolygons:(NSArray *)polygonsToChange { + for (FGMPlatformPolygon *polygon in polygonsToChange) { + NSString *identifier = polygon.polygonId; + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; + [controller updateFromPlatformPolygon:polygon]; + } +} + +- (void)removePolygonWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; + if (!controller) { + continue; + } + [controller removePolygon]; + [self.polygonIdentifierToController removeObjectForKey:identifier]; + } +} + +- (void)didTapPolygonWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapPolygonWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (bool)hasPolygonWithIdentifier:(NSString *)identifier { + if (!identifier) { + return false; + } + return self.polygonIdentifierToController[identifier] != nil; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m new file mode 100644 index 000000000000..63a7f7b7b0fc --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m @@ -0,0 +1,140 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolylineController.h" +#import "GoogleMapPolylineController_Test.h" + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapPolylineController () + +@property(strong, nonatomic) GMSPolyline *polyline; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapPolylineController + +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _polyline = [GMSPolyline polylineWithPath:path]; + _mapView = mapView; + _polyline.userData = @[ identifier ]; + } + return self; +} + +- (void)removePolyline { + self.polyline.map = nil; +} + +- (void)updateFromPlatformPolyline:(FGMPlatformPolyline *)polyline { + [FLTGoogleMapPolylineController updatePolyline:self.polyline + fromPlatformPolyline:polyline + withMapView:self.mapView]; +} + ++ (void)updatePolyline:(GMSPolyline *)polyline + fromPlatformPolyline:(FGMPlatformPolyline *)platformPolyline + withMapView:(GMSMapView *)mapView { + polyline.tappable = platformPolyline.consumesTapEvents; + polyline.zIndex = (int)platformPolyline.zIndex; + GMSMutablePath *path = + FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(platformPolyline.points)); + polyline.path = path; + UIColor *strokeColor = FGMGetColorForPigeonColor(platformPolyline.color); + polyline.strokeColor = strokeColor; + polyline.strokeWidth = platformPolyline.width; + polyline.geodesic = platformPolyline.geodesic; + polyline.spans = + GMSStyleSpans(path, FGMGetStrokeStylesFromPatterns(platformPolyline.patterns, strokeColor), + FGMGetSpanLengthsFromPatterns(platformPolyline.patterns), kGMSLengthRhumb); + + // This must be done last, to avoid visual flickers of default property values. + polyline.map = platformPolyline.visible ? mapView : nil; +} + +@end + +@interface FLTPolylinesController () + +@property(strong, nonatomic) NSMutableDictionary *polylineIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end +; + +@implementation FLTPolylinesController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _polylineIdentifierToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _registrar = registrar; + } + return self; +} + +- (void)addPolylines:(NSArray *)polylinesToAdd { + for (FGMPlatformPolyline *polyline in polylinesToAdd) { + GMSMutablePath *path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(polyline.points)); + NSString *identifier = polyline.polylineId; + FLTGoogleMapPolylineController *controller = + [[FLTGoogleMapPolylineController alloc] initWithPath:path + identifier:identifier + mapView:self.mapView]; + [controller updateFromPlatformPolyline:polyline]; + self.polylineIdentifierToController[identifier] = controller; + } +} + +- (void)changePolylines:(NSArray *)polylinesToChange { + for (FGMPlatformPolyline *polyline in polylinesToChange) { + NSString *identifier = polyline.polylineId; + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; + [controller updateFromPlatformPolyline:polyline]; + } +} + +- (void)removePolylineWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; + if (!controller) { + continue; + } + [controller removePolyline]; + [self.polylineIdentifierToController removeObjectForKey:identifier]; + } +} + +- (void)didTapPolylineWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapPolylineWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (bool)hasPolylineWithIdentifier:(NSString *)identifier { + if (!identifier) { + return false; + } + return self.polylineIdentifierToController[identifier] != nil; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 000000000000..7b4cbc597d31 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,123 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeCrashData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeDeviceID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypePerformanceData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeProductInteraction + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeUserID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryDiskSpace + NSPrivacyAccessedAPITypeReasons + + 85F4.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m new file mode 100644 index 000000000000..e833e2f24f42 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m @@ -0,0 +1,3446 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#import "google_maps_flutter_pigeon_messages.g.h" + +#if TARGET_OS_OSX +#import +#else +#import +#endif + +#if !__has_feature(objc_arc) +#error File requires ARC to be enabled. +#endif + +static NSArray *wrapResult(id result, FlutterError *error) { + if (error) { + return @[ + error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null] + ]; + } + return @[ result ?: [NSNull null] ]; +} + +static FlutterError *createConnectionError(NSString *channelName) { + return [FlutterError + errorWithCode:@"channel-error" + message:[NSString stringWithFormat:@"%@/%@/%@", + @"Unable to establish connection on channel: '", + channelName, @"'."] + details:@""]; +} + +static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { + id result = array[key]; + return (result == [NSNull null]) ? nil : result; +} + +/// Pigeon equivalent of MapType +@implementation FGMPlatformMapTypeBox +- (instancetype)initWithValue:(FGMPlatformMapType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +/// Join types for polyline joints. +@implementation FGMPlatformJointTypeBox +- (instancetype)initWithValue:(FGMPlatformJointType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +/// Enumeration of possible types for PatternItem. +@implementation FGMPlatformPatternItemTypeBox +- (instancetype)initWithValue:(FGMPlatformPatternItemType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +/// Pigeon equivalent of [MapBitmapScaling]. +@implementation FGMPlatformMapBitmapScalingBox +- (instancetype)initWithValue:(FGMPlatformMapBitmapScaling)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +@interface FGMPlatformCameraPosition () ++ (FGMPlatformCameraPosition *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraPosition *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdate () ++ (FGMPlatformCameraUpdate *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdate *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewCameraPosition () ++ (FGMPlatformCameraUpdateNewCameraPosition *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewCameraPosition *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewLatLng () ++ (FGMPlatformCameraUpdateNewLatLng *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewLatLng *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewLatLngBounds () ++ (FGMPlatformCameraUpdateNewLatLngBounds *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewLatLngBounds *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewLatLngZoom () ++ (FGMPlatformCameraUpdateNewLatLngZoom *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewLatLngZoom *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateScrollBy () ++ (FGMPlatformCameraUpdateScrollBy *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateScrollBy *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateZoomBy () ++ (FGMPlatformCameraUpdateZoomBy *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateZoomBy *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateZoom () ++ (FGMPlatformCameraUpdateZoom *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateZoom *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateZoomTo () ++ (FGMPlatformCameraUpdateZoomTo *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateZoomTo *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCircle () ++ (FGMPlatformCircle *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCircle *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformHeatmap () ++ (FGMPlatformHeatmap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformHeatmap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformHeatmapGradient () ++ (FGMPlatformHeatmapGradient *)fromList:(NSArray *)list; ++ (nullable FGMPlatformHeatmapGradient *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformWeightedLatLng () ++ (FGMPlatformWeightedLatLng *)fromList:(NSArray *)list; ++ (nullable FGMPlatformWeightedLatLng *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformInfoWindow () ++ (FGMPlatformInfoWindow *)fromList:(NSArray *)list; ++ (nullable FGMPlatformInfoWindow *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCluster () ++ (FGMPlatformCluster *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCluster *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformClusterManager () ++ (FGMPlatformClusterManager *)fromList:(NSArray *)list; ++ (nullable FGMPlatformClusterManager *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformMarker () ++ (FGMPlatformMarker *)fromList:(NSArray *)list; ++ (nullable FGMPlatformMarker *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPolygon () ++ (FGMPlatformPolygon *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPolygon *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPolyline () ++ (FGMPlatformPolyline *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPolyline *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPatternItem () ++ (FGMPlatformPatternItem *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPatternItem *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformTile () ++ (FGMPlatformTile *)fromList:(NSArray *)list; ++ (nullable FGMPlatformTile *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformTileOverlay () ++ (FGMPlatformTileOverlay *)fromList:(NSArray *)list; ++ (nullable FGMPlatformTileOverlay *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformEdgeInsets () ++ (FGMPlatformEdgeInsets *)fromList:(NSArray *)list; ++ (nullable FGMPlatformEdgeInsets *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformLatLng () ++ (FGMPlatformLatLng *)fromList:(NSArray *)list; ++ (nullable FGMPlatformLatLng *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformLatLngBounds () ++ (FGMPlatformLatLngBounds *)fromList:(NSArray *)list; ++ (nullable FGMPlatformLatLngBounds *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraTargetBounds () ++ (FGMPlatformCameraTargetBounds *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraTargetBounds *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformGroundOverlay () ++ (FGMPlatformGroundOverlay *)fromList:(NSArray *)list; ++ (nullable FGMPlatformGroundOverlay *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformMapViewCreationParams () ++ (FGMPlatformMapViewCreationParams *)fromList:(NSArray *)list; ++ (nullable FGMPlatformMapViewCreationParams *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformMapConfiguration () ++ (FGMPlatformMapConfiguration *)fromList:(NSArray *)list; ++ (nullable FGMPlatformMapConfiguration *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPoint () ++ (FGMPlatformPoint *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPoint *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformSize () ++ (FGMPlatformSize *)fromList:(NSArray *)list; ++ (nullable FGMPlatformSize *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformColor () ++ (FGMPlatformColor *)fromList:(NSArray *)list; ++ (nullable FGMPlatformColor *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformTileLayer () ++ (FGMPlatformTileLayer *)fromList:(NSArray *)list; ++ (nullable FGMPlatformTileLayer *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformZoomRange () ++ (FGMPlatformZoomRange *)fromList:(NSArray *)list; ++ (nullable FGMPlatformZoomRange *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmap () ++ (FGMPlatformBitmap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapDefaultMarker () ++ (FGMPlatformBitmapDefaultMarker *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapDefaultMarker *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapBytes () ++ (FGMPlatformBitmapBytes *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapBytes *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapAsset () ++ (FGMPlatformBitmapAsset *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapAsset *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapAssetImage () ++ (FGMPlatformBitmapAssetImage *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapAssetImage *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapAssetMap () ++ (FGMPlatformBitmapAssetMap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapAssetMap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapBytesMap () ++ (FGMPlatformBitmapBytesMap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapBytesMap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@implementation FGMPlatformCameraPosition ++ (instancetype)makeWithBearing:(double)bearing + target:(FGMPlatformLatLng *)target + tilt:(double)tilt + zoom:(double)zoom { + FGMPlatformCameraPosition *pigeonResult = [[FGMPlatformCameraPosition alloc] init]; + pigeonResult.bearing = bearing; + pigeonResult.target = target; + pigeonResult.tilt = tilt; + pigeonResult.zoom = zoom; + return pigeonResult; +} ++ (FGMPlatformCameraPosition *)fromList:(NSArray *)list { + FGMPlatformCameraPosition *pigeonResult = [[FGMPlatformCameraPosition alloc] init]; + pigeonResult.bearing = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.target = GetNullableObjectAtIndex(list, 1); + pigeonResult.tilt = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.zoom = [GetNullableObjectAtIndex(list, 3) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraPosition *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraPosition fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.bearing), + self.target ?: [NSNull null], + @(self.tilt), + @(self.zoom), + ]; +} +@end + +@implementation FGMPlatformCameraUpdate ++ (instancetype)makeWithCameraUpdate:(id)cameraUpdate { + FGMPlatformCameraUpdate *pigeonResult = [[FGMPlatformCameraUpdate alloc] init]; + pigeonResult.cameraUpdate = cameraUpdate; + return pigeonResult; +} ++ (FGMPlatformCameraUpdate *)fromList:(NSArray *)list { + FGMPlatformCameraUpdate *pigeonResult = [[FGMPlatformCameraUpdate alloc] init]; + pigeonResult.cameraUpdate = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdate *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdate fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.cameraUpdate ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewCameraPosition ++ (instancetype)makeWithCameraPosition:(FGMPlatformCameraPosition *)cameraPosition { + FGMPlatformCameraUpdateNewCameraPosition *pigeonResult = + [[FGMPlatformCameraUpdateNewCameraPosition alloc] init]; + pigeonResult.cameraPosition = cameraPosition; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewCameraPosition *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewCameraPosition *pigeonResult = + [[FGMPlatformCameraUpdateNewCameraPosition alloc] init]; + pigeonResult.cameraPosition = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewCameraPosition *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewCameraPosition fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.cameraPosition ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewLatLng ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng { + FGMPlatformCameraUpdateNewLatLng *pigeonResult = [[FGMPlatformCameraUpdateNewLatLng alloc] init]; + pigeonResult.latLng = latLng; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewLatLng *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewLatLng *pigeonResult = [[FGMPlatformCameraUpdateNewLatLng alloc] init]; + pigeonResult.latLng = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewLatLng *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewLatLng fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.latLng ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewLatLngBounds ++ (instancetype)makeWithBounds:(FGMPlatformLatLngBounds *)bounds padding:(double)padding { + FGMPlatformCameraUpdateNewLatLngBounds *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngBounds alloc] init]; + pigeonResult.bounds = bounds; + pigeonResult.padding = padding; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewLatLngBounds *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewLatLngBounds *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngBounds alloc] init]; + pigeonResult.bounds = GetNullableObjectAtIndex(list, 0); + pigeonResult.padding = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewLatLngBounds *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewLatLngBounds fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.bounds ?: [NSNull null], + @(self.padding), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewLatLngZoom ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng zoom:(double)zoom { + FGMPlatformCameraUpdateNewLatLngZoom *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngZoom alloc] init]; + pigeonResult.latLng = latLng; + pigeonResult.zoom = zoom; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewLatLngZoom *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewLatLngZoom *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngZoom alloc] init]; + pigeonResult.latLng = GetNullableObjectAtIndex(list, 0); + pigeonResult.zoom = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewLatLngZoom *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewLatLngZoom fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.latLng ?: [NSNull null], + @(self.zoom), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateScrollBy ++ (instancetype)makeWithDx:(double)dx dy:(double)dy { + FGMPlatformCameraUpdateScrollBy *pigeonResult = [[FGMPlatformCameraUpdateScrollBy alloc] init]; + pigeonResult.dx = dx; + pigeonResult.dy = dy; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateScrollBy *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateScrollBy *pigeonResult = [[FGMPlatformCameraUpdateScrollBy alloc] init]; + pigeonResult.dx = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.dy = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateScrollBy *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateScrollBy fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.dx), + @(self.dy), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateZoomBy ++ (instancetype)makeWithAmount:(double)amount focus:(nullable FGMPlatformPoint *)focus { + FGMPlatformCameraUpdateZoomBy *pigeonResult = [[FGMPlatformCameraUpdateZoomBy alloc] init]; + pigeonResult.amount = amount; + pigeonResult.focus = focus; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateZoomBy *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateZoomBy *pigeonResult = [[FGMPlatformCameraUpdateZoomBy alloc] init]; + pigeonResult.amount = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.focus = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateZoomBy *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateZoomBy fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.amount), + self.focus ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateZoom ++ (instancetype)makeWithOut:(BOOL)out { + FGMPlatformCameraUpdateZoom *pigeonResult = [[FGMPlatformCameraUpdateZoom alloc] init]; + pigeonResult.out = out; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateZoom *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateZoom *pigeonResult = [[FGMPlatformCameraUpdateZoom alloc] init]; + pigeonResult.out = [GetNullableObjectAtIndex(list, 0) boolValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateZoom *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateZoom fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.out), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateZoomTo ++ (instancetype)makeWithZoom:(double)zoom { + FGMPlatformCameraUpdateZoomTo *pigeonResult = [[FGMPlatformCameraUpdateZoomTo alloc] init]; + pigeonResult.zoom = zoom; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateZoomTo *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateZoomTo *pigeonResult = [[FGMPlatformCameraUpdateZoomTo alloc] init]; + pigeonResult.zoom = [GetNullableObjectAtIndex(list, 0) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateZoomTo *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateZoomTo fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.zoom), + ]; +} +@end + +@implementation FGMPlatformCircle ++ (instancetype)makeWithConsumeTapEvents:(BOOL)consumeTapEvents + fillColor:(FGMPlatformColor *)fillColor + strokeColor:(FGMPlatformColor *)strokeColor + visible:(BOOL)visible + strokeWidth:(NSInteger)strokeWidth + zIndex:(double)zIndex + center:(FGMPlatformLatLng *)center + radius:(double)radius + circleId:(NSString *)circleId { + FGMPlatformCircle *pigeonResult = [[FGMPlatformCircle alloc] init]; + pigeonResult.consumeTapEvents = consumeTapEvents; + pigeonResult.fillColor = fillColor; + pigeonResult.strokeColor = strokeColor; + pigeonResult.visible = visible; + pigeonResult.strokeWidth = strokeWidth; + pigeonResult.zIndex = zIndex; + pigeonResult.center = center; + pigeonResult.radius = radius; + pigeonResult.circleId = circleId; + return pigeonResult; +} ++ (FGMPlatformCircle *)fromList:(NSArray *)list { + FGMPlatformCircle *pigeonResult = [[FGMPlatformCircle alloc] init]; + pigeonResult.consumeTapEvents = [GetNullableObjectAtIndex(list, 0) boolValue]; + pigeonResult.fillColor = GetNullableObjectAtIndex(list, 1); + pigeonResult.strokeColor = GetNullableObjectAtIndex(list, 2); + pigeonResult.visible = [GetNullableObjectAtIndex(list, 3) boolValue]; + pigeonResult.strokeWidth = [GetNullableObjectAtIndex(list, 4) integerValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 5) doubleValue]; + pigeonResult.center = GetNullableObjectAtIndex(list, 6); + pigeonResult.radius = [GetNullableObjectAtIndex(list, 7) doubleValue]; + pigeonResult.circleId = GetNullableObjectAtIndex(list, 8); + return pigeonResult; +} ++ (nullable FGMPlatformCircle *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCircle fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.consumeTapEvents), + self.fillColor ?: [NSNull null], + self.strokeColor ?: [NSNull null], + @(self.visible), + @(self.strokeWidth), + @(self.zIndex), + self.center ?: [NSNull null], + @(self.radius), + self.circleId ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformHeatmap ++ (instancetype)makeWithHeatmapId:(NSString *)heatmapId + data:(NSArray *)data + gradient:(nullable FGMPlatformHeatmapGradient *)gradient + opacity:(double)opacity + radius:(NSInteger)radius + minimumZoomIntensity:(NSInteger)minimumZoomIntensity + maximumZoomIntensity:(NSInteger)maximumZoomIntensity { + FGMPlatformHeatmap *pigeonResult = [[FGMPlatformHeatmap alloc] init]; + pigeonResult.heatmapId = heatmapId; + pigeonResult.data = data; + pigeonResult.gradient = gradient; + pigeonResult.opacity = opacity; + pigeonResult.radius = radius; + pigeonResult.minimumZoomIntensity = minimumZoomIntensity; + pigeonResult.maximumZoomIntensity = maximumZoomIntensity; + return pigeonResult; +} ++ (FGMPlatformHeatmap *)fromList:(NSArray *)list { + FGMPlatformHeatmap *pigeonResult = [[FGMPlatformHeatmap alloc] init]; + pigeonResult.heatmapId = GetNullableObjectAtIndex(list, 0); + pigeonResult.data = GetNullableObjectAtIndex(list, 1); + pigeonResult.gradient = GetNullableObjectAtIndex(list, 2); + pigeonResult.opacity = [GetNullableObjectAtIndex(list, 3) doubleValue]; + pigeonResult.radius = [GetNullableObjectAtIndex(list, 4) integerValue]; + pigeonResult.minimumZoomIntensity = [GetNullableObjectAtIndex(list, 5) integerValue]; + pigeonResult.maximumZoomIntensity = [GetNullableObjectAtIndex(list, 6) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformHeatmap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformHeatmap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.heatmapId ?: [NSNull null], + self.data ?: [NSNull null], + self.gradient ?: [NSNull null], + @(self.opacity), + @(self.radius), + @(self.minimumZoomIntensity), + @(self.maximumZoomIntensity), + ]; +} +@end + +@implementation FGMPlatformHeatmapGradient ++ (instancetype)makeWithColors:(NSArray *)colors + startPoints:(NSArray *)startPoints + colorMapSize:(NSInteger)colorMapSize { + FGMPlatformHeatmapGradient *pigeonResult = [[FGMPlatformHeatmapGradient alloc] init]; + pigeonResult.colors = colors; + pigeonResult.startPoints = startPoints; + pigeonResult.colorMapSize = colorMapSize; + return pigeonResult; +} ++ (FGMPlatformHeatmapGradient *)fromList:(NSArray *)list { + FGMPlatformHeatmapGradient *pigeonResult = [[FGMPlatformHeatmapGradient alloc] init]; + pigeonResult.colors = GetNullableObjectAtIndex(list, 0); + pigeonResult.startPoints = GetNullableObjectAtIndex(list, 1); + pigeonResult.colorMapSize = [GetNullableObjectAtIndex(list, 2) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformHeatmapGradient *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformHeatmapGradient fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.colors ?: [NSNull null], + self.startPoints ?: [NSNull null], + @(self.colorMapSize), + ]; +} +@end + +@implementation FGMPlatformWeightedLatLng ++ (instancetype)makeWithPoint:(FGMPlatformLatLng *)point weight:(double)weight { + FGMPlatformWeightedLatLng *pigeonResult = [[FGMPlatformWeightedLatLng alloc] init]; + pigeonResult.point = point; + pigeonResult.weight = weight; + return pigeonResult; +} ++ (FGMPlatformWeightedLatLng *)fromList:(NSArray *)list { + FGMPlatformWeightedLatLng *pigeonResult = [[FGMPlatformWeightedLatLng alloc] init]; + pigeonResult.point = GetNullableObjectAtIndex(list, 0); + pigeonResult.weight = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformWeightedLatLng *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformWeightedLatLng fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.point ?: [NSNull null], + @(self.weight), + ]; +} +@end + +@implementation FGMPlatformInfoWindow ++ (instancetype)makeWithTitle:(nullable NSString *)title + snippet:(nullable NSString *)snippet + anchor:(FGMPlatformPoint *)anchor { + FGMPlatformInfoWindow *pigeonResult = [[FGMPlatformInfoWindow alloc] init]; + pigeonResult.title = title; + pigeonResult.snippet = snippet; + pigeonResult.anchor = anchor; + return pigeonResult; +} ++ (FGMPlatformInfoWindow *)fromList:(NSArray *)list { + FGMPlatformInfoWindow *pigeonResult = [[FGMPlatformInfoWindow alloc] init]; + pigeonResult.title = GetNullableObjectAtIndex(list, 0); + pigeonResult.snippet = GetNullableObjectAtIndex(list, 1); + pigeonResult.anchor = GetNullableObjectAtIndex(list, 2); + return pigeonResult; +} ++ (nullable FGMPlatformInfoWindow *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformInfoWindow fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.title ?: [NSNull null], + self.snippet ?: [NSNull null], + self.anchor ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCluster ++ (instancetype)makeWithClusterManagerId:(NSString *)clusterManagerId + position:(FGMPlatformLatLng *)position + bounds:(FGMPlatformLatLngBounds *)bounds + markerIds:(NSArray *)markerIds { + FGMPlatformCluster *pigeonResult = [[FGMPlatformCluster alloc] init]; + pigeonResult.clusterManagerId = clusterManagerId; + pigeonResult.position = position; + pigeonResult.bounds = bounds; + pigeonResult.markerIds = markerIds; + return pigeonResult; +} ++ (FGMPlatformCluster *)fromList:(NSArray *)list { + FGMPlatformCluster *pigeonResult = [[FGMPlatformCluster alloc] init]; + pigeonResult.clusterManagerId = GetNullableObjectAtIndex(list, 0); + pigeonResult.position = GetNullableObjectAtIndex(list, 1); + pigeonResult.bounds = GetNullableObjectAtIndex(list, 2); + pigeonResult.markerIds = GetNullableObjectAtIndex(list, 3); + return pigeonResult; +} ++ (nullable FGMPlatformCluster *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCluster fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.clusterManagerId ?: [NSNull null], + self.position ?: [NSNull null], + self.bounds ?: [NSNull null], + self.markerIds ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformClusterManager ++ (instancetype)makeWithIdentifier:(NSString *)identifier { + FGMPlatformClusterManager *pigeonResult = [[FGMPlatformClusterManager alloc] init]; + pigeonResult.identifier = identifier; + return pigeonResult; +} ++ (FGMPlatformClusterManager *)fromList:(NSArray *)list { + FGMPlatformClusterManager *pigeonResult = [[FGMPlatformClusterManager alloc] init]; + pigeonResult.identifier = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformClusterManager *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformClusterManager fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.identifier ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformMarker ++ (instancetype)makeWithAlpha:(double)alpha + anchor:(FGMPlatformPoint *)anchor + consumeTapEvents:(BOOL)consumeTapEvents + draggable:(BOOL)draggable + flat:(BOOL)flat + icon:(FGMPlatformBitmap *)icon + infoWindow:(FGMPlatformInfoWindow *)infoWindow + position:(FGMPlatformLatLng *)position + rotation:(double)rotation + visible:(BOOL)visible + zIndex:(NSInteger)zIndex + markerId:(NSString *)markerId + clusterManagerId:(nullable NSString *)clusterManagerId { + FGMPlatformMarker *pigeonResult = [[FGMPlatformMarker alloc] init]; + pigeonResult.alpha = alpha; + pigeonResult.anchor = anchor; + pigeonResult.consumeTapEvents = consumeTapEvents; + pigeonResult.draggable = draggable; + pigeonResult.flat = flat; + pigeonResult.icon = icon; + pigeonResult.infoWindow = infoWindow; + pigeonResult.position = position; + pigeonResult.rotation = rotation; + pigeonResult.visible = visible; + pigeonResult.zIndex = zIndex; + pigeonResult.markerId = markerId; + pigeonResult.clusterManagerId = clusterManagerId; + return pigeonResult; +} ++ (FGMPlatformMarker *)fromList:(NSArray *)list { + FGMPlatformMarker *pigeonResult = [[FGMPlatformMarker alloc] init]; + pigeonResult.alpha = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.anchor = GetNullableObjectAtIndex(list, 1); + pigeonResult.consumeTapEvents = [GetNullableObjectAtIndex(list, 2) boolValue]; + pigeonResult.draggable = [GetNullableObjectAtIndex(list, 3) boolValue]; + pigeonResult.flat = [GetNullableObjectAtIndex(list, 4) boolValue]; + pigeonResult.icon = GetNullableObjectAtIndex(list, 5); + pigeonResult.infoWindow = GetNullableObjectAtIndex(list, 6); + pigeonResult.position = GetNullableObjectAtIndex(list, 7); + pigeonResult.rotation = [GetNullableObjectAtIndex(list, 8) doubleValue]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 9) boolValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 10) integerValue]; + pigeonResult.markerId = GetNullableObjectAtIndex(list, 11); + pigeonResult.clusterManagerId = GetNullableObjectAtIndex(list, 12); + return pigeonResult; +} ++ (nullable FGMPlatformMarker *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformMarker fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.alpha), + self.anchor ?: [NSNull null], + @(self.consumeTapEvents), + @(self.draggable), + @(self.flat), + self.icon ?: [NSNull null], + self.infoWindow ?: [NSNull null], + self.position ?: [NSNull null], + @(self.rotation), + @(self.visible), + @(self.zIndex), + self.markerId ?: [NSNull null], + self.clusterManagerId ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformPolygon ++ (instancetype)makeWithPolygonId:(NSString *)polygonId + consumesTapEvents:(BOOL)consumesTapEvents + fillColor:(FGMPlatformColor *)fillColor + geodesic:(BOOL)geodesic + points:(NSArray *)points + holes:(NSArray *> *)holes + visible:(BOOL)visible + strokeColor:(FGMPlatformColor *)strokeColor + strokeWidth:(NSInteger)strokeWidth + zIndex:(NSInteger)zIndex { + FGMPlatformPolygon *pigeonResult = [[FGMPlatformPolygon alloc] init]; + pigeonResult.polygonId = polygonId; + pigeonResult.consumesTapEvents = consumesTapEvents; + pigeonResult.fillColor = fillColor; + pigeonResult.geodesic = geodesic; + pigeonResult.points = points; + pigeonResult.holes = holes; + pigeonResult.visible = visible; + pigeonResult.strokeColor = strokeColor; + pigeonResult.strokeWidth = strokeWidth; + pigeonResult.zIndex = zIndex; + return pigeonResult; +} ++ (FGMPlatformPolygon *)fromList:(NSArray *)list { + FGMPlatformPolygon *pigeonResult = [[FGMPlatformPolygon alloc] init]; + pigeonResult.polygonId = GetNullableObjectAtIndex(list, 0); + pigeonResult.consumesTapEvents = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.fillColor = GetNullableObjectAtIndex(list, 2); + pigeonResult.geodesic = [GetNullableObjectAtIndex(list, 3) boolValue]; + pigeonResult.points = GetNullableObjectAtIndex(list, 4); + pigeonResult.holes = GetNullableObjectAtIndex(list, 5); + pigeonResult.visible = [GetNullableObjectAtIndex(list, 6) boolValue]; + pigeonResult.strokeColor = GetNullableObjectAtIndex(list, 7); + pigeonResult.strokeWidth = [GetNullableObjectAtIndex(list, 8) integerValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 9) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformPolygon *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPolygon fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.polygonId ?: [NSNull null], + @(self.consumesTapEvents), + self.fillColor ?: [NSNull null], + @(self.geodesic), + self.points ?: [NSNull null], + self.holes ?: [NSNull null], + @(self.visible), + self.strokeColor ?: [NSNull null], + @(self.strokeWidth), + @(self.zIndex), + ]; +} +@end + +@implementation FGMPlatformPolyline ++ (instancetype)makeWithPolylineId:(NSString *)polylineId + consumesTapEvents:(BOOL)consumesTapEvents + color:(FGMPlatformColor *)color + geodesic:(BOOL)geodesic + jointType:(FGMPlatformJointType)jointType + patterns:(NSArray *)patterns + points:(NSArray *)points + visible:(BOOL)visible + width:(NSInteger)width + zIndex:(NSInteger)zIndex { + FGMPlatformPolyline *pigeonResult = [[FGMPlatformPolyline alloc] init]; + pigeonResult.polylineId = polylineId; + pigeonResult.consumesTapEvents = consumesTapEvents; + pigeonResult.color = color; + pigeonResult.geodesic = geodesic; + pigeonResult.jointType = jointType; + pigeonResult.patterns = patterns; + pigeonResult.points = points; + pigeonResult.visible = visible; + pigeonResult.width = width; + pigeonResult.zIndex = zIndex; + return pigeonResult; +} ++ (FGMPlatformPolyline *)fromList:(NSArray *)list { + FGMPlatformPolyline *pigeonResult = [[FGMPlatformPolyline alloc] init]; + pigeonResult.polylineId = GetNullableObjectAtIndex(list, 0); + pigeonResult.consumesTapEvents = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.color = GetNullableObjectAtIndex(list, 2); + pigeonResult.geodesic = [GetNullableObjectAtIndex(list, 3) boolValue]; + FGMPlatformJointTypeBox *boxedFGMPlatformJointType = GetNullableObjectAtIndex(list, 4); + pigeonResult.jointType = boxedFGMPlatformJointType.value; + pigeonResult.patterns = GetNullableObjectAtIndex(list, 5); + pigeonResult.points = GetNullableObjectAtIndex(list, 6); + pigeonResult.visible = [GetNullableObjectAtIndex(list, 7) boolValue]; + pigeonResult.width = [GetNullableObjectAtIndex(list, 8) integerValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 9) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformPolyline *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPolyline fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.polylineId ?: [NSNull null], + @(self.consumesTapEvents), + self.color ?: [NSNull null], + @(self.geodesic), + [[FGMPlatformJointTypeBox alloc] initWithValue:self.jointType], + self.patterns ?: [NSNull null], + self.points ?: [NSNull null], + @(self.visible), + @(self.width), + @(self.zIndex), + ]; +} +@end + +@implementation FGMPlatformPatternItem ++ (instancetype)makeWithType:(FGMPlatformPatternItemType)type length:(nullable NSNumber *)length { + FGMPlatformPatternItem *pigeonResult = [[FGMPlatformPatternItem alloc] init]; + pigeonResult.type = type; + pigeonResult.length = length; + return pigeonResult; +} ++ (FGMPlatformPatternItem *)fromList:(NSArray *)list { + FGMPlatformPatternItem *pigeonResult = [[FGMPlatformPatternItem alloc] init]; + FGMPlatformPatternItemTypeBox *boxedFGMPlatformPatternItemType = + GetNullableObjectAtIndex(list, 0); + pigeonResult.type = boxedFGMPlatformPatternItemType.value; + pigeonResult.length = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformPatternItem *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPatternItem fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + [[FGMPlatformPatternItemTypeBox alloc] initWithValue:self.type], + self.length ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformTile ++ (instancetype)makeWithWidth:(NSInteger)width + height:(NSInteger)height + data:(nullable FlutterStandardTypedData *)data { + FGMPlatformTile *pigeonResult = [[FGMPlatformTile alloc] init]; + pigeonResult.width = width; + pigeonResult.height = height; + pigeonResult.data = data; + return pigeonResult; +} ++ (FGMPlatformTile *)fromList:(NSArray *)list { + FGMPlatformTile *pigeonResult = [[FGMPlatformTile alloc] init]; + pigeonResult.width = [GetNullableObjectAtIndex(list, 0) integerValue]; + pigeonResult.height = [GetNullableObjectAtIndex(list, 1) integerValue]; + pigeonResult.data = GetNullableObjectAtIndex(list, 2); + return pigeonResult; +} ++ (nullable FGMPlatformTile *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformTile fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.width), + @(self.height), + self.data ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformTileOverlay ++ (instancetype)makeWithTileOverlayId:(NSString *)tileOverlayId + fadeIn:(BOOL)fadeIn + transparency:(double)transparency + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + tileSize:(NSInteger)tileSize { + FGMPlatformTileOverlay *pigeonResult = [[FGMPlatformTileOverlay alloc] init]; + pigeonResult.tileOverlayId = tileOverlayId; + pigeonResult.fadeIn = fadeIn; + pigeonResult.transparency = transparency; + pigeonResult.zIndex = zIndex; + pigeonResult.visible = visible; + pigeonResult.tileSize = tileSize; + return pigeonResult; +} ++ (FGMPlatformTileOverlay *)fromList:(NSArray *)list { + FGMPlatformTileOverlay *pigeonResult = [[FGMPlatformTileOverlay alloc] init]; + pigeonResult.tileOverlayId = GetNullableObjectAtIndex(list, 0); + pigeonResult.fadeIn = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.transparency = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 3) integerValue]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 4) boolValue]; + pigeonResult.tileSize = [GetNullableObjectAtIndex(list, 5) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformTileOverlay *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformTileOverlay fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.tileOverlayId ?: [NSNull null], + @(self.fadeIn), + @(self.transparency), + @(self.zIndex), + @(self.visible), + @(self.tileSize), + ]; +} +@end + +@implementation FGMPlatformEdgeInsets ++ (instancetype)makeWithTop:(double)top + bottom:(double)bottom + left:(double)left + right:(double)right { + FGMPlatformEdgeInsets *pigeonResult = [[FGMPlatformEdgeInsets alloc] init]; + pigeonResult.top = top; + pigeonResult.bottom = bottom; + pigeonResult.left = left; + pigeonResult.right = right; + return pigeonResult; +} ++ (FGMPlatformEdgeInsets *)fromList:(NSArray *)list { + FGMPlatformEdgeInsets *pigeonResult = [[FGMPlatformEdgeInsets alloc] init]; + pigeonResult.top = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.bottom = [GetNullableObjectAtIndex(list, 1) doubleValue]; + pigeonResult.left = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.right = [GetNullableObjectAtIndex(list, 3) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformEdgeInsets *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformEdgeInsets fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.top), + @(self.bottom), + @(self.left), + @(self.right), + ]; +} +@end + +@implementation FGMPlatformLatLng ++ (instancetype)makeWithLatitude:(double)latitude longitude:(double)longitude { + FGMPlatformLatLng *pigeonResult = [[FGMPlatformLatLng alloc] init]; + pigeonResult.latitude = latitude; + pigeonResult.longitude = longitude; + return pigeonResult; +} ++ (FGMPlatformLatLng *)fromList:(NSArray *)list { + FGMPlatformLatLng *pigeonResult = [[FGMPlatformLatLng alloc] init]; + pigeonResult.latitude = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.longitude = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformLatLng *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformLatLng fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.latitude), + @(self.longitude), + ]; +} +@end + +@implementation FGMPlatformLatLngBounds ++ (instancetype)makeWithNortheast:(FGMPlatformLatLng *)northeast + southwest:(FGMPlatformLatLng *)southwest { + FGMPlatformLatLngBounds *pigeonResult = [[FGMPlatformLatLngBounds alloc] init]; + pigeonResult.northeast = northeast; + pigeonResult.southwest = southwest; + return pigeonResult; +} ++ (FGMPlatformLatLngBounds *)fromList:(NSArray *)list { + FGMPlatformLatLngBounds *pigeonResult = [[FGMPlatformLatLngBounds alloc] init]; + pigeonResult.northeast = GetNullableObjectAtIndex(list, 0); + pigeonResult.southwest = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformLatLngBounds *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformLatLngBounds fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.northeast ?: [NSNull null], + self.southwest ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraTargetBounds ++ (instancetype)makeWithBounds:(nullable FGMPlatformLatLngBounds *)bounds { + FGMPlatformCameraTargetBounds *pigeonResult = [[FGMPlatformCameraTargetBounds alloc] init]; + pigeonResult.bounds = bounds; + return pigeonResult; +} ++ (FGMPlatformCameraTargetBounds *)fromList:(NSArray *)list { + FGMPlatformCameraTargetBounds *pigeonResult = [[FGMPlatformCameraTargetBounds alloc] init]; + pigeonResult.bounds = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraTargetBounds *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraTargetBounds fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.bounds ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformGroundOverlay ++ (instancetype)makeWithGroundOverlayId:(NSString *)groundOverlayId + image:(FGMPlatformBitmap *)image + position:(nullable FGMPlatformLatLng *)position + bounds:(nullable FGMPlatformLatLngBounds *)bounds + anchor:(nullable FGMPlatformPoint *)anchor + transparency:(double)transparency + bearing:(double)bearing + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + clickable:(BOOL)clickable + zoomLevel:(nullable NSNumber *)zoomLevel { + FGMPlatformGroundOverlay *pigeonResult = [[FGMPlatformGroundOverlay alloc] init]; + pigeonResult.groundOverlayId = groundOverlayId; + pigeonResult.image = image; + pigeonResult.position = position; + pigeonResult.bounds = bounds; + pigeonResult.anchor = anchor; + pigeonResult.transparency = transparency; + pigeonResult.bearing = bearing; + pigeonResult.zIndex = zIndex; + pigeonResult.visible = visible; + pigeonResult.clickable = clickable; + pigeonResult.zoomLevel = zoomLevel; + return pigeonResult; +} ++ (FGMPlatformGroundOverlay *)fromList:(NSArray *)list { + FGMPlatformGroundOverlay *pigeonResult = [[FGMPlatformGroundOverlay alloc] init]; + pigeonResult.groundOverlayId = GetNullableObjectAtIndex(list, 0); + pigeonResult.image = GetNullableObjectAtIndex(list, 1); + pigeonResult.position = GetNullableObjectAtIndex(list, 2); + pigeonResult.bounds = GetNullableObjectAtIndex(list, 3); + pigeonResult.anchor = GetNullableObjectAtIndex(list, 4); + pigeonResult.transparency = [GetNullableObjectAtIndex(list, 5) doubleValue]; + pigeonResult.bearing = [GetNullableObjectAtIndex(list, 6) doubleValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 7) integerValue]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 8) boolValue]; + pigeonResult.clickable = [GetNullableObjectAtIndex(list, 9) boolValue]; + pigeonResult.zoomLevel = GetNullableObjectAtIndex(list, 10); + return pigeonResult; +} ++ (nullable FGMPlatformGroundOverlay *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformGroundOverlay fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.groundOverlayId ?: [NSNull null], + self.image ?: [NSNull null], + self.position ?: [NSNull null], + self.bounds ?: [NSNull null], + self.anchor ?: [NSNull null], + @(self.transparency), + @(self.bearing), + @(self.zIndex), + @(self.visible), + @(self.clickable), + self.zoomLevel ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformMapViewCreationParams ++ (instancetype) + makeWithInitialCameraPosition:(FGMPlatformCameraPosition *)initialCameraPosition + mapConfiguration:(FGMPlatformMapConfiguration *)mapConfiguration + initialCircles:(NSArray *)initialCircles + initialMarkers:(NSArray *)initialMarkers + initialPolygons:(NSArray *)initialPolygons + initialPolylines:(NSArray *)initialPolylines + initialHeatmaps:(NSArray *)initialHeatmaps + initialTileOverlays:(NSArray *)initialTileOverlays + initialClusterManagers:(NSArray *)initialClusterManagers + initialGroundOverlays:(NSArray *)initialGroundOverlays { + FGMPlatformMapViewCreationParams *pigeonResult = [[FGMPlatformMapViewCreationParams alloc] init]; + pigeonResult.initialCameraPosition = initialCameraPosition; + pigeonResult.mapConfiguration = mapConfiguration; + pigeonResult.initialCircles = initialCircles; + pigeonResult.initialMarkers = initialMarkers; + pigeonResult.initialPolygons = initialPolygons; + pigeonResult.initialPolylines = initialPolylines; + pigeonResult.initialHeatmaps = initialHeatmaps; + pigeonResult.initialTileOverlays = initialTileOverlays; + pigeonResult.initialClusterManagers = initialClusterManagers; + pigeonResult.initialGroundOverlays = initialGroundOverlays; + return pigeonResult; +} ++ (FGMPlatformMapViewCreationParams *)fromList:(NSArray *)list { + FGMPlatformMapViewCreationParams *pigeonResult = [[FGMPlatformMapViewCreationParams alloc] init]; + pigeonResult.initialCameraPosition = GetNullableObjectAtIndex(list, 0); + pigeonResult.mapConfiguration = GetNullableObjectAtIndex(list, 1); + pigeonResult.initialCircles = GetNullableObjectAtIndex(list, 2); + pigeonResult.initialMarkers = GetNullableObjectAtIndex(list, 3); + pigeonResult.initialPolygons = GetNullableObjectAtIndex(list, 4); + pigeonResult.initialPolylines = GetNullableObjectAtIndex(list, 5); + pigeonResult.initialHeatmaps = GetNullableObjectAtIndex(list, 6); + pigeonResult.initialTileOverlays = GetNullableObjectAtIndex(list, 7); + pigeonResult.initialClusterManagers = GetNullableObjectAtIndex(list, 8); + pigeonResult.initialGroundOverlays = GetNullableObjectAtIndex(list, 9); + return pigeonResult; +} ++ (nullable FGMPlatformMapViewCreationParams *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformMapViewCreationParams fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.initialCameraPosition ?: [NSNull null], + self.mapConfiguration ?: [NSNull null], + self.initialCircles ?: [NSNull null], + self.initialMarkers ?: [NSNull null], + self.initialPolygons ?: [NSNull null], + self.initialPolylines ?: [NSNull null], + self.initialHeatmaps ?: [NSNull null], + self.initialTileOverlays ?: [NSNull null], + self.initialClusterManagers ?: [NSNull null], + self.initialGroundOverlays ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformMapConfiguration ++ (instancetype)makeWithCompassEnabled:(nullable NSNumber *)compassEnabled + cameraTargetBounds:(nullable FGMPlatformCameraTargetBounds *)cameraTargetBounds + mapType:(nullable FGMPlatformMapTypeBox *)mapType + minMaxZoomPreference:(nullable FGMPlatformZoomRange *)minMaxZoomPreference + rotateGesturesEnabled:(nullable NSNumber *)rotateGesturesEnabled + scrollGesturesEnabled:(nullable NSNumber *)scrollGesturesEnabled + tiltGesturesEnabled:(nullable NSNumber *)tiltGesturesEnabled + trackCameraPosition:(nullable NSNumber *)trackCameraPosition + zoomGesturesEnabled:(nullable NSNumber *)zoomGesturesEnabled + myLocationEnabled:(nullable NSNumber *)myLocationEnabled + myLocationButtonEnabled:(nullable NSNumber *)myLocationButtonEnabled + padding:(nullable FGMPlatformEdgeInsets *)padding + indoorViewEnabled:(nullable NSNumber *)indoorViewEnabled + trafficEnabled:(nullable NSNumber *)trafficEnabled + buildingsEnabled:(nullable NSNumber *)buildingsEnabled + mapId:(nullable NSString *)mapId + style:(nullable NSString *)style { + FGMPlatformMapConfiguration *pigeonResult = [[FGMPlatformMapConfiguration alloc] init]; + pigeonResult.compassEnabled = compassEnabled; + pigeonResult.cameraTargetBounds = cameraTargetBounds; + pigeonResult.mapType = mapType; + pigeonResult.minMaxZoomPreference = minMaxZoomPreference; + pigeonResult.rotateGesturesEnabled = rotateGesturesEnabled; + pigeonResult.scrollGesturesEnabled = scrollGesturesEnabled; + pigeonResult.tiltGesturesEnabled = tiltGesturesEnabled; + pigeonResult.trackCameraPosition = trackCameraPosition; + pigeonResult.zoomGesturesEnabled = zoomGesturesEnabled; + pigeonResult.myLocationEnabled = myLocationEnabled; + pigeonResult.myLocationButtonEnabled = myLocationButtonEnabled; + pigeonResult.padding = padding; + pigeonResult.indoorViewEnabled = indoorViewEnabled; + pigeonResult.trafficEnabled = trafficEnabled; + pigeonResult.buildingsEnabled = buildingsEnabled; + pigeonResult.mapId = mapId; + pigeonResult.style = style; + return pigeonResult; +} ++ (FGMPlatformMapConfiguration *)fromList:(NSArray *)list { + FGMPlatformMapConfiguration *pigeonResult = [[FGMPlatformMapConfiguration alloc] init]; + pigeonResult.compassEnabled = GetNullableObjectAtIndex(list, 0); + pigeonResult.cameraTargetBounds = GetNullableObjectAtIndex(list, 1); + pigeonResult.mapType = GetNullableObjectAtIndex(list, 2); + pigeonResult.minMaxZoomPreference = GetNullableObjectAtIndex(list, 3); + pigeonResult.rotateGesturesEnabled = GetNullableObjectAtIndex(list, 4); + pigeonResult.scrollGesturesEnabled = GetNullableObjectAtIndex(list, 5); + pigeonResult.tiltGesturesEnabled = GetNullableObjectAtIndex(list, 6); + pigeonResult.trackCameraPosition = GetNullableObjectAtIndex(list, 7); + pigeonResult.zoomGesturesEnabled = GetNullableObjectAtIndex(list, 8); + pigeonResult.myLocationEnabled = GetNullableObjectAtIndex(list, 9); + pigeonResult.myLocationButtonEnabled = GetNullableObjectAtIndex(list, 10); + pigeonResult.padding = GetNullableObjectAtIndex(list, 11); + pigeonResult.indoorViewEnabled = GetNullableObjectAtIndex(list, 12); + pigeonResult.trafficEnabled = GetNullableObjectAtIndex(list, 13); + pigeonResult.buildingsEnabled = GetNullableObjectAtIndex(list, 14); + pigeonResult.mapId = GetNullableObjectAtIndex(list, 15); + pigeonResult.style = GetNullableObjectAtIndex(list, 16); + return pigeonResult; +} ++ (nullable FGMPlatformMapConfiguration *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformMapConfiguration fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.compassEnabled ?: [NSNull null], + self.cameraTargetBounds ?: [NSNull null], + self.mapType ?: [NSNull null], + self.minMaxZoomPreference ?: [NSNull null], + self.rotateGesturesEnabled ?: [NSNull null], + self.scrollGesturesEnabled ?: [NSNull null], + self.tiltGesturesEnabled ?: [NSNull null], + self.trackCameraPosition ?: [NSNull null], + self.zoomGesturesEnabled ?: [NSNull null], + self.myLocationEnabled ?: [NSNull null], + self.myLocationButtonEnabled ?: [NSNull null], + self.padding ?: [NSNull null], + self.indoorViewEnabled ?: [NSNull null], + self.trafficEnabled ?: [NSNull null], + self.buildingsEnabled ?: [NSNull null], + self.mapId ?: [NSNull null], + self.style ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformPoint ++ (instancetype)makeWithX:(double)x y:(double)y { + FGMPlatformPoint *pigeonResult = [[FGMPlatformPoint alloc] init]; + pigeonResult.x = x; + pigeonResult.y = y; + return pigeonResult; +} ++ (FGMPlatformPoint *)fromList:(NSArray *)list { + FGMPlatformPoint *pigeonResult = [[FGMPlatformPoint alloc] init]; + pigeonResult.x = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.y = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformPoint *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPoint fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.x), + @(self.y), + ]; +} +@end + +@implementation FGMPlatformSize ++ (instancetype)makeWithWidth:(double)width height:(double)height { + FGMPlatformSize *pigeonResult = [[FGMPlatformSize alloc] init]; + pigeonResult.width = width; + pigeonResult.height = height; + return pigeonResult; +} ++ (FGMPlatformSize *)fromList:(NSArray *)list { + FGMPlatformSize *pigeonResult = [[FGMPlatformSize alloc] init]; + pigeonResult.width = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.height = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformSize *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformSize fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.width), + @(self.height), + ]; +} +@end + +@implementation FGMPlatformColor ++ (instancetype)makeWithRed:(double)red green:(double)green blue:(double)blue alpha:(double)alpha { + FGMPlatformColor *pigeonResult = [[FGMPlatformColor alloc] init]; + pigeonResult.red = red; + pigeonResult.green = green; + pigeonResult.blue = blue; + pigeonResult.alpha = alpha; + return pigeonResult; +} ++ (FGMPlatformColor *)fromList:(NSArray *)list { + FGMPlatformColor *pigeonResult = [[FGMPlatformColor alloc] init]; + pigeonResult.red = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.green = [GetNullableObjectAtIndex(list, 1) doubleValue]; + pigeonResult.blue = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.alpha = [GetNullableObjectAtIndex(list, 3) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformColor *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformColor fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.red), + @(self.green), + @(self.blue), + @(self.alpha), + ]; +} +@end + +@implementation FGMPlatformTileLayer ++ (instancetype)makeWithVisible:(BOOL)visible + fadeIn:(BOOL)fadeIn + opacity:(double)opacity + zIndex:(NSInteger)zIndex { + FGMPlatformTileLayer *pigeonResult = [[FGMPlatformTileLayer alloc] init]; + pigeonResult.visible = visible; + pigeonResult.fadeIn = fadeIn; + pigeonResult.opacity = opacity; + pigeonResult.zIndex = zIndex; + return pigeonResult; +} ++ (FGMPlatformTileLayer *)fromList:(NSArray *)list { + FGMPlatformTileLayer *pigeonResult = [[FGMPlatformTileLayer alloc] init]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 0) boolValue]; + pigeonResult.fadeIn = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.opacity = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 3) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformTileLayer *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformTileLayer fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.visible), + @(self.fadeIn), + @(self.opacity), + @(self.zIndex), + ]; +} +@end + +@implementation FGMPlatformZoomRange ++ (instancetype)makeWithMin:(nullable NSNumber *)min max:(nullable NSNumber *)max { + FGMPlatformZoomRange *pigeonResult = [[FGMPlatformZoomRange alloc] init]; + pigeonResult.min = min; + pigeonResult.max = max; + return pigeonResult; +} ++ (FGMPlatformZoomRange *)fromList:(NSArray *)list { + FGMPlatformZoomRange *pigeonResult = [[FGMPlatformZoomRange alloc] init]; + pigeonResult.min = GetNullableObjectAtIndex(list, 0); + pigeonResult.max = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformZoomRange *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformZoomRange fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.min ?: [NSNull null], + self.max ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmap ++ (instancetype)makeWithBitmap:(id)bitmap { + FGMPlatformBitmap *pigeonResult = [[FGMPlatformBitmap alloc] init]; + pigeonResult.bitmap = bitmap; + return pigeonResult; +} ++ (FGMPlatformBitmap *)fromList:(NSArray *)list { + FGMPlatformBitmap *pigeonResult = [[FGMPlatformBitmap alloc] init]; + pigeonResult.bitmap = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformBitmap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.bitmap ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapDefaultMarker ++ (instancetype)makeWithHue:(nullable NSNumber *)hue { + FGMPlatformBitmapDefaultMarker *pigeonResult = [[FGMPlatformBitmapDefaultMarker alloc] init]; + pigeonResult.hue = hue; + return pigeonResult; +} ++ (FGMPlatformBitmapDefaultMarker *)fromList:(NSArray *)list { + FGMPlatformBitmapDefaultMarker *pigeonResult = [[FGMPlatformBitmapDefaultMarker alloc] init]; + pigeonResult.hue = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapDefaultMarker *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapDefaultMarker fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.hue ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapBytes ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + size:(nullable FGMPlatformSize *)size { + FGMPlatformBitmapBytes *pigeonResult = [[FGMPlatformBitmapBytes alloc] init]; + pigeonResult.byteData = byteData; + pigeonResult.size = size; + return pigeonResult; +} ++ (FGMPlatformBitmapBytes *)fromList:(NSArray *)list { + FGMPlatformBitmapBytes *pigeonResult = [[FGMPlatformBitmapBytes alloc] init]; + pigeonResult.byteData = GetNullableObjectAtIndex(list, 0); + pigeonResult.size = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapBytes *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapBytes fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.byteData ?: [NSNull null], + self.size ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapAsset ++ (instancetype)makeWithName:(NSString *)name pkg:(nullable NSString *)pkg { + FGMPlatformBitmapAsset *pigeonResult = [[FGMPlatformBitmapAsset alloc] init]; + pigeonResult.name = name; + pigeonResult.pkg = pkg; + return pigeonResult; +} ++ (FGMPlatformBitmapAsset *)fromList:(NSArray *)list { + FGMPlatformBitmapAsset *pigeonResult = [[FGMPlatformBitmapAsset alloc] init]; + pigeonResult.name = GetNullableObjectAtIndex(list, 0); + pigeonResult.pkg = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapAsset *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapAsset fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.name ?: [NSNull null], + self.pkg ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapAssetImage ++ (instancetype)makeWithName:(NSString *)name + scale:(double)scale + size:(nullable FGMPlatformSize *)size { + FGMPlatformBitmapAssetImage *pigeonResult = [[FGMPlatformBitmapAssetImage alloc] init]; + pigeonResult.name = name; + pigeonResult.scale = scale; + pigeonResult.size = size; + return pigeonResult; +} ++ (FGMPlatformBitmapAssetImage *)fromList:(NSArray *)list { + FGMPlatformBitmapAssetImage *pigeonResult = [[FGMPlatformBitmapAssetImage alloc] init]; + pigeonResult.name = GetNullableObjectAtIndex(list, 0); + pigeonResult.scale = [GetNullableObjectAtIndex(list, 1) doubleValue]; + pigeonResult.size = GetNullableObjectAtIndex(list, 2); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapAssetImage *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapAssetImage fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.name ?: [NSNull null], + @(self.scale), + self.size ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapAssetMap ++ (instancetype)makeWithAssetName:(NSString *)assetName + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height { + FGMPlatformBitmapAssetMap *pigeonResult = [[FGMPlatformBitmapAssetMap alloc] init]; + pigeonResult.assetName = assetName; + pigeonResult.bitmapScaling = bitmapScaling; + pigeonResult.imagePixelRatio = imagePixelRatio; + pigeonResult.width = width; + pigeonResult.height = height; + return pigeonResult; +} ++ (FGMPlatformBitmapAssetMap *)fromList:(NSArray *)list { + FGMPlatformBitmapAssetMap *pigeonResult = [[FGMPlatformBitmapAssetMap alloc] init]; + pigeonResult.assetName = GetNullableObjectAtIndex(list, 0); + FGMPlatformMapBitmapScalingBox *boxedFGMPlatformMapBitmapScaling = + GetNullableObjectAtIndex(list, 1); + pigeonResult.bitmapScaling = boxedFGMPlatformMapBitmapScaling.value; + pigeonResult.imagePixelRatio = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.width = GetNullableObjectAtIndex(list, 3); + pigeonResult.height = GetNullableObjectAtIndex(list, 4); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapAssetMap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapAssetMap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.assetName ?: [NSNull null], + [[FGMPlatformMapBitmapScalingBox alloc] initWithValue:self.bitmapScaling], + @(self.imagePixelRatio), + self.width ?: [NSNull null], + self.height ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapBytesMap ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height { + FGMPlatformBitmapBytesMap *pigeonResult = [[FGMPlatformBitmapBytesMap alloc] init]; + pigeonResult.byteData = byteData; + pigeonResult.bitmapScaling = bitmapScaling; + pigeonResult.imagePixelRatio = imagePixelRatio; + pigeonResult.width = width; + pigeonResult.height = height; + return pigeonResult; +} ++ (FGMPlatformBitmapBytesMap *)fromList:(NSArray *)list { + FGMPlatformBitmapBytesMap *pigeonResult = [[FGMPlatformBitmapBytesMap alloc] init]; + pigeonResult.byteData = GetNullableObjectAtIndex(list, 0); + FGMPlatformMapBitmapScalingBox *boxedFGMPlatformMapBitmapScaling = + GetNullableObjectAtIndex(list, 1); + pigeonResult.bitmapScaling = boxedFGMPlatformMapBitmapScaling.value; + pigeonResult.imagePixelRatio = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.width = GetNullableObjectAtIndex(list, 3); + pigeonResult.height = GetNullableObjectAtIndex(list, 4); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapBytesMap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapBytesMap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.byteData ?: [NSNull null], + [[FGMPlatformMapBitmapScalingBox alloc] initWithValue:self.bitmapScaling], + @(self.imagePixelRatio), + self.width ?: [NSNull null], + self.height ?: [NSNull null], + ]; +} +@end + +@interface FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReader : FlutterStandardReader +@end +@implementation FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReader +- (nullable id)readValueOfType:(UInt8)type { + switch (type) { + case 129: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil + ? nil + : [[FGMPlatformMapTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; + } + case 130: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil + ? nil + : [[FGMPlatformJointTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; + } + case 131: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil ? nil + : [[FGMPlatformPatternItemTypeBox alloc] + initWithValue:[enumAsNumber integerValue]]; + } + case 132: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil ? nil + : [[FGMPlatformMapBitmapScalingBox alloc] + initWithValue:[enumAsNumber integerValue]]; + } + case 133: + return [FGMPlatformCameraPosition fromList:[self readValue]]; + case 134: + return [FGMPlatformCameraUpdate fromList:[self readValue]]; + case 135: + return [FGMPlatformCameraUpdateNewCameraPosition fromList:[self readValue]]; + case 136: + return [FGMPlatformCameraUpdateNewLatLng fromList:[self readValue]]; + case 137: + return [FGMPlatformCameraUpdateNewLatLngBounds fromList:[self readValue]]; + case 138: + return [FGMPlatformCameraUpdateNewLatLngZoom fromList:[self readValue]]; + case 139: + return [FGMPlatformCameraUpdateScrollBy fromList:[self readValue]]; + case 140: + return [FGMPlatformCameraUpdateZoomBy fromList:[self readValue]]; + case 141: + return [FGMPlatformCameraUpdateZoom fromList:[self readValue]]; + case 142: + return [FGMPlatformCameraUpdateZoomTo fromList:[self readValue]]; + case 143: + return [FGMPlatformCircle fromList:[self readValue]]; + case 144: + return [FGMPlatformHeatmap fromList:[self readValue]]; + case 145: + return [FGMPlatformHeatmapGradient fromList:[self readValue]]; + case 146: + return [FGMPlatformWeightedLatLng fromList:[self readValue]]; + case 147: + return [FGMPlatformInfoWindow fromList:[self readValue]]; + case 148: + return [FGMPlatformCluster fromList:[self readValue]]; + case 149: + return [FGMPlatformClusterManager fromList:[self readValue]]; + case 150: + return [FGMPlatformMarker fromList:[self readValue]]; + case 151: + return [FGMPlatformPolygon fromList:[self readValue]]; + case 152: + return [FGMPlatformPolyline fromList:[self readValue]]; + case 153: + return [FGMPlatformPatternItem fromList:[self readValue]]; + case 154: + return [FGMPlatformTile fromList:[self readValue]]; + case 155: + return [FGMPlatformTileOverlay fromList:[self readValue]]; + case 156: + return [FGMPlatformEdgeInsets fromList:[self readValue]]; + case 157: + return [FGMPlatformLatLng fromList:[self readValue]]; + case 158: + return [FGMPlatformLatLngBounds fromList:[self readValue]]; + case 159: + return [FGMPlatformCameraTargetBounds fromList:[self readValue]]; + case 160: + return [FGMPlatformGroundOverlay fromList:[self readValue]]; + case 161: + return [FGMPlatformMapViewCreationParams fromList:[self readValue]]; + case 162: + return [FGMPlatformMapConfiguration fromList:[self readValue]]; + case 163: + return [FGMPlatformPoint fromList:[self readValue]]; + case 164: + return [FGMPlatformSize fromList:[self readValue]]; + case 165: + return [FGMPlatformColor fromList:[self readValue]]; + case 166: + return [FGMPlatformTileLayer fromList:[self readValue]]; + case 167: + return [FGMPlatformZoomRange fromList:[self readValue]]; + case 168: + return [FGMPlatformBitmap fromList:[self readValue]]; + case 169: + return [FGMPlatformBitmapDefaultMarker fromList:[self readValue]]; + case 170: + return [FGMPlatformBitmapBytes fromList:[self readValue]]; + case 171: + return [FGMPlatformBitmapAsset fromList:[self readValue]]; + case 172: + return [FGMPlatformBitmapAssetImage fromList:[self readValue]]; + case 173: + return [FGMPlatformBitmapAssetMap fromList:[self readValue]]; + case 174: + return [FGMPlatformBitmapBytesMap fromList:[self readValue]]; + default: + return [super readValueOfType:type]; + } +} +@end + +@interface FGMGoogleMapsFlutterPigeonMessagesPigeonCodecWriter : FlutterStandardWriter +@end +@implementation FGMGoogleMapsFlutterPigeonMessagesPigeonCodecWriter +- (void)writeValue:(id)value { + if ([value isKindOfClass:[FGMPlatformMapTypeBox class]]) { + FGMPlatformMapTypeBox *box = (FGMPlatformMapTypeBox *)value; + [self writeByte:129]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformJointTypeBox class]]) { + FGMPlatformJointTypeBox *box = (FGMPlatformJointTypeBox *)value; + [self writeByte:130]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformPatternItemTypeBox class]]) { + FGMPlatformPatternItemTypeBox *box = (FGMPlatformPatternItemTypeBox *)value; + [self writeByte:131]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformMapBitmapScalingBox class]]) { + FGMPlatformMapBitmapScalingBox *box = (FGMPlatformMapBitmapScalingBox *)value; + [self writeByte:132]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformCameraPosition class]]) { + [self writeByte:133]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdate class]]) { + [self writeByte:134]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewCameraPosition class]]) { + [self writeByte:135]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewLatLng class]]) { + [self writeByte:136]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewLatLngBounds class]]) { + [self writeByte:137]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewLatLngZoom class]]) { + [self writeByte:138]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateScrollBy class]]) { + [self writeByte:139]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateZoomBy class]]) { + [self writeByte:140]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateZoom class]]) { + [self writeByte:141]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateZoomTo class]]) { + [self writeByte:142]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCircle class]]) { + [self writeByte:143]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformHeatmap class]]) { + [self writeByte:144]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformHeatmapGradient class]]) { + [self writeByte:145]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformWeightedLatLng class]]) { + [self writeByte:146]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformInfoWindow class]]) { + [self writeByte:147]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCluster class]]) { + [self writeByte:148]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformClusterManager class]]) { + [self writeByte:149]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformMarker class]]) { + [self writeByte:150]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPolygon class]]) { + [self writeByte:151]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPolyline class]]) { + [self writeByte:152]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPatternItem class]]) { + [self writeByte:153]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformTile class]]) { + [self writeByte:154]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformTileOverlay class]]) { + [self writeByte:155]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformEdgeInsets class]]) { + [self writeByte:156]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformLatLng class]]) { + [self writeByte:157]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformLatLngBounds class]]) { + [self writeByte:158]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraTargetBounds class]]) { + [self writeByte:159]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformGroundOverlay class]]) { + [self writeByte:160]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformMapViewCreationParams class]]) { + [self writeByte:161]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformMapConfiguration class]]) { + [self writeByte:162]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPoint class]]) { + [self writeByte:163]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformSize class]]) { + [self writeByte:164]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformColor class]]) { + [self writeByte:165]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformTileLayer class]]) { + [self writeByte:166]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformZoomRange class]]) { + [self writeByte:167]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmap class]]) { + [self writeByte:168]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapDefaultMarker class]]) { + [self writeByte:169]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapBytes class]]) { + [self writeByte:170]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapAsset class]]) { + [self writeByte:171]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapAssetImage class]]) { + [self writeByte:172]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapAssetMap class]]) { + [self writeByte:173]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapBytesMap class]]) { + [self writeByte:174]; + [self writeValue:[value toList]]; + } else { + [super writeValue:value]; + } +} +@end + +@interface FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter : FlutterStandardReaderWriter +@end +@implementation FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter +- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { + return [[FGMGoogleMapsFlutterPigeonMessagesPigeonCodecWriter alloc] initWithData:data]; +} +- (FlutterStandardReader *)readerWithData:(NSData *)data { + return [[FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReader alloc] initWithData:data]; +} +@end + +NSObject *FGMGetGoogleMapsFlutterPigeonMessagesCodec(void) { + static FlutterStandardMessageCodec *sSharedObject = nil; + static dispatch_once_t sPred = 0; + dispatch_once(&sPred, ^{ + FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter *readerWriter = + [[FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter alloc] init]; + sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; + }); + return sSharedObject; +} +void SetUpFGMMapsApi(id binaryMessenger, NSObject *api) { + SetUpFGMMapsApiWithSuffix(binaryMessenger, api, @""); +} + +void SetUpFGMMapsApiWithSuffix(id binaryMessenger, + NSObject *api, NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; + /// Returns once the map instance is available. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.waitForMap", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(waitForMapWithError:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(waitForMapWithError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + [api waitForMapWithError:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateMapConfiguration", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(updateWithMapConfiguration:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(updateWithMapConfiguration:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformMapConfiguration *arg_configuration = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api updateWithMapConfiguration:arg_configuration error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of circles on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateCircles", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateCirclesByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateCirclesByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateCirclesByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of heatmaps on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateHeatmaps", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateHeatmapsByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateHeatmapsByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateHeatmapsByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of custer managers for clusters on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateClusterManagers", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateClusterManagersByAdding:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateClusterManagersByAdding:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + [api updateClusterManagersByAdding:arg_toAdd removing:arg_idsToRemove error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of markers on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateMarkers", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateMarkersByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateMarkersByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateMarkersByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of polygonss on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updatePolygons", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updatePolygonsByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updatePolygonsByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updatePolygonsByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of polylines on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updatePolylines", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updatePolylinesByAdding: + changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updatePolylinesByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updatePolylinesByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of tile overlays on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateTileOverlays", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateTileOverlaysByAdding: + changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateTileOverlaysByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateTileOverlaysByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of ground overlays on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateGroundOverlays", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateGroundOverlaysByAdding: + changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateGroundOverlaysByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateGroundOverlaysByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the screen coordinate for the given map location. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.getScreenCoordinate", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(screenCoordinatesForLatLng:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(screenCoordinatesForLatLng:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformLatLng *arg_latLng = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformPoint *output = [api screenCoordinatesForLatLng:arg_latLng error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the map location for the given screen coordinate. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getLatLng", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(latLngForScreenCoordinate:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(latLngForScreenCoordinate:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformPoint *arg_screenCoordinate = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformLatLng *output = [api latLngForScreenCoordinate:arg_screenCoordinate + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the map region currently displayed on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.getVisibleRegion", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(visibleMapRegion:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(visibleMapRegion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FGMPlatformLatLngBounds *output = [api visibleMapRegion:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.moveCamera", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(moveCameraWithUpdate:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(moveCameraWithUpdate:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformCameraUpdate *arg_cameraUpdate = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api moveCameraWithUpdate:arg_cameraUpdate error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Moves the camera according to [cameraUpdate], animating the update using a + /// duration in milliseconds if provided. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.animateCamera", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(animateCameraWithUpdate:duration:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(animateCameraWithUpdate:duration:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformCameraUpdate *arg_cameraUpdate = GetNullableObjectAtIndex(args, 0); + NSNumber *arg_durationMilliseconds = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + [api animateCameraWithUpdate:arg_cameraUpdate + duration:arg_durationMilliseconds + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the current map zoom level. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getZoomLevel", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(currentZoomLevel:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(currentZoomLevel:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api currentZoomLevel:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Show the info window for the marker with the given ID. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.showInfoWindow", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(showInfoWindowForMarkerWithIdentifier:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(showInfoWindowForMarkerWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_markerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api showInfoWindowForMarkerWithIdentifier:arg_markerId error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Hide the info window for the marker with the given ID. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.hideInfoWindow", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(hideInfoWindowForMarkerWithIdentifier:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(hideInfoWindowForMarkerWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_markerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api hideInfoWindowForMarkerWithIdentifier:arg_markerId error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns true if the marker with the given ID is currently displaying its + /// info window. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.isInfoWindowShown", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(isShowingInfoWindowForMarkerWithIdentifier: + error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(isShowingInfoWindowForMarkerWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_markerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSNumber *output = [api isShowingInfoWindowForMarkerWithIdentifier:arg_markerId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Sets the style to the given map style string, where an empty string + /// indicates that the style should be cleared. + /// + /// If there was an error setting the style, such as an invalid style string, + /// returns the error message. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.setStyle", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(setStyle:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(setStyle:error:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_style = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSString *output = [api setStyle:arg_style error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns the error string from the last attempt to set the map style, if + /// any. + /// + /// This allows checking asynchronously for initial style failures, as there + /// is no way to return failures from map initialization. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.getLastStyleError", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(lastStyleError:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(lastStyleError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSString *output = [api lastStyleError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Clears the cache of tiles previously requseted from the tile provider. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.clearTileCache", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(clearTileCacheForOverlayWithIdentifier:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(clearTileCacheForOverlayWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_tileOverlayId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api clearTileCacheForOverlayWithIdentifier:arg_tileOverlayId error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Takes a snapshot of the map and returns its image data. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.takeSnapshot", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(takeSnapshotWithError:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(takeSnapshotWithError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FlutterStandardTypedData *output = [api takeSnapshotWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} +@interface FGMMapsCallbackApi () +@property(nonatomic, strong) NSObject *binaryMessenger; +@property(nonatomic, strong) NSString *messageChannelSuffix; +@end + +@implementation FGMMapsCallbackApi + +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger { + return [self initWithBinaryMessenger:binaryMessenger messageChannelSuffix:@""]; +} +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger + messageChannelSuffix:(nullable NSString *)messageChannelSuffix { + self = [self init]; + if (self) { + _binaryMessenger = binaryMessenger; + _messageChannelSuffix = [messageChannelSuffix length] == 0 + ? @"" + : [NSString stringWithFormat:@".%@", messageChannelSuffix]; + } + return self; +} +- (void)didStartCameraMoveWithCompletion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMoveStarted", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:nil + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didMoveCameraToPosition:(FGMPlatformCameraPosition *)arg_cameraPosition + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMove", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_cameraPosition ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didIdleCameraWithCompletion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraIdle", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:nil + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapAtPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didLongPressAtPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onLongPress", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapMarkerWithIdentifier:(NSString *)arg_markerId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didStartDragForMarkerWithIdentifier:(NSString *)arg_markerId + atPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null], arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didDragMarkerWithIdentifier:(NSString *)arg_markerId + atPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null], arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didEndDragForMarkerWithIdentifier:(NSString *)arg_markerId + atPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null], arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)arg_markerId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onInfoWindowTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapCircleWithIdentifier:(NSString *)arg_circleId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCircleTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_circleId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapCluster:(FGMPlatformCluster *)arg_cluster + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_cluster ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapPolygonWithIdentifier:(NSString *)arg_polygonId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolygonTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_polygonId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapPolylineWithIdentifier:(NSString *)arg_polylineId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolylineTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_polylineId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapGroundOverlayWithIdentifier:(NSString *)arg_groundOverlayId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onGroundOverlayTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_groundOverlayId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)tileWithOverlayIdentifier:(NSString *)arg_tileOverlayId + location:(FGMPlatformPoint *)arg_location + zoom:(NSInteger)arg_zoom + completion:(void (^)(FGMPlatformTile *_Nullable, + FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ + arg_tileOverlayId ?: [NSNull null], arg_location ?: [NSNull null], @(arg_zoom) + ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion(nil, [FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + FGMPlatformTile *output = reply[0] == [NSNull null] ? nil : reply[0]; + completion(output, nil); + } + } else { + completion(nil, createConnectionError(channelName)); + } + }]; +} +@end + +void SetUpFGMMapsPlatformViewApi(id binaryMessenger, + NSObject *api) { + SetUpFGMMapsPlatformViewApiWithSuffix(binaryMessenger, api, @""); +} + +void SetUpFGMMapsPlatformViewApiWithSuffix(id binaryMessenger, + NSObject *api, + NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsPlatformViewApi.createView", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(createViewType:error:)], + @"FGMMapsPlatformViewApi api (%@) doesn't respond to @selector(createViewType:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformMapViewCreationParams *arg_type = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api createViewType:arg_type error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} +void SetUpFGMMapsInspectorApi(id binaryMessenger, + NSObject *api) { + SetUpFGMMapsInspectorApiWithSuffix(binaryMessenger, api, @""); +} + +void SetUpFGMMapsInspectorApiWithSuffix(id binaryMessenger, + NSObject *api, + NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areBuildingsEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areBuildingsEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areBuildingsEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areBuildingsEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areRotateGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areRotateGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areRotateGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areRotateGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areScrollGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areScrollGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areScrollGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areScrollGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areTiltGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areTiltGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areTiltGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areTiltGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areZoomGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areZoomGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areZoomGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areZoomGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.isCompassEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(isCompassEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(isCompassEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isCompassEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.isMyLocationButtonEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(isMyLocationButtonEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(isMyLocationButtonEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isMyLocationButtonEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.isTrafficEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(isTrafficEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(isTrafficEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isTrafficEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getTileOverlayInfo", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(tileOverlayWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(tileOverlayWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_tileOverlayId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformTileLayer *output = [api tileOverlayWithIdentifier:arg_tileOverlayId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getGroundOverlayInfo", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(groundOverlayWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(groundOverlayWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_groundOverlayId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformGroundOverlay *output = [api groundOverlayWithIdentifier:arg_groundOverlayId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getHeatmapInfo", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(heatmapWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(heatmapWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_heatmapId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformHeatmap *output = [api heatmapWithIdentifier:arg_heatmapId error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getZoomRange", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(zoomRange:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(zoomRange:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FGMPlatformZoomRange *output = [api zoomRange:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getClusters", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(clustersWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(clustersWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_clusterManagerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSArray *output = [api clustersWithIdentifier:arg_clusterManagerId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getCameraPosition", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(cameraPosition:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(cameraPosition:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FGMPlatformCameraPosition *output = [api cameraPosition:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h new file mode 100644 index 000000000000..41df2dedd618 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Foundation; + +NS_ASSUME_NONNULL_BEGIN + +/// Protocol for CATransaction to allow mocking in tests. +@protocol FGMCATransactionProtocol +- (void)begin; +- (void)commit; +- (void)setAnimationDuration:(CFTimeInterval)duration; +@end + +/// Wrapper for CATransaction to allow mocking in tests. +@interface FGMCATransactionWrapper : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h new file mode 100644 index 000000000000..394f9e3d71e0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h @@ -0,0 +1,56 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "GoogleMapsUtilsTrampoline.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// A controller that manages all of the cluster managers on a map. +@interface FGMClusterManagersController : NSObject + +/// Initializes cluster manager controller. +/// +/// @param callbackHandler A callback handler. +/// @param mapView A map view that will be used to display clustered markers. +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler; + +/// Creates cluster managers and initializes them. +/// +/// @param clusterManagersToAdd Array of cluster managers to add. +- (void)addClusterManagers:(NSArray *)clusterManagersToAdd; + +/// Removes requested cluster managers from the controller. +/// +/// @param identifiers Array of cluster manager IDs to remove. +- (void)removeClusterManagersWithIdentifiers:(NSArray *)identifiers; + +/// Returns the cluster managers for the given identifier. +/// +/// @param identifier The identifier of the cluster manager. +/// @return A cluster manager if found; otherwise, nil. +- (nullable GMUClusterManager *)clusterManagerWithIdentifier:(NSString *)identifier; + +/// Returns an array of clusters managed by the cluster manager. +/// +/// @param identifier The identifier of the cluster manager whose clusters are to be retrieved. +/// @return An array of clusters. Returns `nil` only if `error` is populated. +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error; + +/// Called when a cluster marker is tapped on the map. +/// +/// @param cluster The cluster that was tapped on. +- (void)didTapCluster:(GMUStaticCluster *)cluster; + +/// Calls the cluster method of all the cluster managers. +- (void)invokeClusteringForEachClusterManager; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h new file mode 100644 index 000000000000..45c13797099b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h @@ -0,0 +1,97 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import Foundation; +@import GoogleMaps; + +#import "GoogleMapsUtilsTrampoline.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Returns dict[key], or nil if dict[key] is NSNull. +extern id _Nullable FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key); + +/// Creates a CGPoint from its Pigeon equivalent. +extern CGPoint FGMGetCGPointForPigeonPoint(FGMPlatformPoint *point); + +/// Converts a CGPoint to its Pigeon equivalent. +extern FGMPlatformPoint *FGMGetPigeonPointForCGPoint(CGPoint point); + +/// Creates a CLLocationCoordinate2D from its Pigeon representation. +extern CLLocationCoordinate2D FGMGetCoordinateForPigeonLatLng(FGMPlatformLatLng *latLng); + +/// Converts a CLLocationCoordinate2D to its Pigeon representation. +extern FGMPlatformLatLng *FGMGetPigeonLatLngForCoordinate(CLLocationCoordinate2D coord); + +/// Creates a GMSCoordinateBounds from its Pigeon representation. +extern GMSCoordinateBounds *FGMGetCoordinateBoundsForPigeonLatLngBounds( + FGMPlatformLatLngBounds *bounds); + +/// Converts a GMSCoordinateBounds to its Pigeon representation. +extern FGMPlatformLatLngBounds *FGMGetPigeonLatLngBoundsForCoordinateBounds( + GMSCoordinateBounds *bounds); + +/// Converts a GMSCameraPosition to its Pigeon representation. +extern FGMPlatformCameraPosition *FGMGetPigeonCameraPositionForPosition( + GMSCameraPosition *position); + +/// Creates a GMSCameraPosition from its Pigeon representation. +extern GMSCameraPosition *FGMGetCameraPositionForPigeonCameraPosition( + FGMPlatformCameraPosition *position); + +/// Creates a CLLocation array from its Pigeon equivalent. +extern NSArray *FGMGetPointsForPigeonLatLngs(NSArray *points); + +/// Creates a CLLocation arary array, representing a set of holes, from its Pigeon equivalent. +extern NSArray *> *FGMGetHolesForPigeonLatLngArrays( + NSArray *> *points); + +extern GMSMutablePath *FGMGetPathFromPoints(NSArray *points); + +/// Creates a GMSMapViewType from its Pigeon representation. +extern GMSMapViewType FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapType type); + +/// Converts a GMUStaticCluster to its Pigeon representation. +extern FGMPlatformCluster *FGMGetPigeonCluster(GMUStaticCluster *cluster, + NSString *clusterManagerIdentifier); + +/// Converts a GMSGroundOverlay to its Pigeon representation. +extern FGMPlatformGroundOverlay *FGMGetPigeonGroundOverlay(GMSGroundOverlay *groundOverlay, + NSString *overlayId, + BOOL isCreatedWithBounds, + NSNumber *_Nullable zoomLevel); + +extern GMUGradient *FGMGetGradientForPigeonHeatmapGradient(FGMPlatformHeatmapGradient *gradient); + +extern FGMPlatformHeatmapGradient *FGMGetPigeonHeatmapGradientForGradient(GMUGradient *gradient); + +/// Creates a GMUWeightedLatLng array from its Pigeon equivalent. +extern NSArray *FGMGetWeightedDataForPigeonWeightedData( + NSArray *weightedLatLngs); + +/// Converts a GMUWeightedLatLng array to its Pigeon equivalent. +extern NSArray *FGMGetPigeonWeightedDataForWeightedData( + NSArray *weightedLatLngs); + +/// Creates a GMSCameraUpdate from its Pigeon equivalent. +extern GMSCameraUpdate *_Nullable FGMGetCameraUpdateForPigeonCameraUpdate( + FGMPlatformCameraUpdate *update); + +/// Creates a UIColor from its Pigeon representation. +extern UIColor *FGMGetColorForPigeonColor(FGMPlatformColor *color); + +/// Converts a UIColor to its Pigeon representation. +extern FGMPlatformColor *FGMGetPigeonColorForColor(UIColor *color); + +/// Creates an array of GMSStrokeStyles using the given patterns and stroke color. +extern NSArray *FGMGetStrokeStylesFromPatterns( + NSArray *patterns, UIColor *strokeColor); + +/// Creates an array of span lengths using the given patterns. +extern NSArray *FGMGetSpanLengthsFromPatterns( + NSArray *patterns); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h new file mode 100644 index 000000000000..a5297f703b9e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h @@ -0,0 +1,64 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import CoreLocation; +@import Flutter; +@import Foundation; +@import GoogleMaps; +@import UIKit; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Controller of a single ground overlay on the map. +@interface FGMGroundOverlayController : NSObject + +/// The ground overlay this controller handles. +@property(strong, nonatomic) GMSGroundOverlay *groundOverlay; + +/// Whether ground overlay is created with bounds or position. +@property(nonatomic, assign, getter=isCreatedWithBounds) BOOL createdWithBounds; + +/// Zoom level when ground overlay is initialized with position. +@property(nonatomic, strong, nullable) NSNumber *zoomLevel; + +/// Initializes an instance of this class with a GMSGroundOverlay, a map view, and identifier. +- (instancetype)initWithGroundOverlay:(GMSGroundOverlay *)groundOverlay + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView + isCreatedWithBounds:(BOOL)isCreatedWithBounds; + +/// Removes this ground overlay from the map. +- (void)removeGroundOverlay; +@end + +/// Controller of multiple ground overlays on the map. +@interface FLTGroundOverlaysController : NSObject + +/// Initializes the controller with a GMSMapView, callback handler and registrar. +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; + +/// Adds ground overlays to the map. +- (void)addGroundOverlays:(NSArray *)groundOverlaysToAdd; + +/// Updates ground overlays on the map. +- (void)changeGroundOverlays:(NSArray *)groundOverlaysToChange; + +/// Removes ground overlays from the map. +- (void)removeGroundOverlaysWithIdentifiers:(NSArray *)identifiers; + +/// Called when a ground overlay is tapped on the map. +- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier; + +/// Returns true if a ground overlay with the given identifier exists on the map. +- (bool)hasGroundOverlaysWithIdentifier:(NSString *)identifier; + +/// Returns the ground overlay with the given identifier. +- (nullable FGMPlatformGroundOverlay *)groundOverlayWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h new file mode 100644 index 000000000000..87123539947d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h @@ -0,0 +1,29 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMGroundOverlayController.h" + +/// Internal APIs exposed for unit testing +@interface FGMGroundOverlayController (Test) + +/// Ground Overlay instance the controller is attached to +@property(strong, nonatomic) GMSGroundOverlay *groundOverlay; + +/// Function to update the gms ground overlay from platform ground overlay. +- (void)updateFromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)groundOverlay + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale; + +/// Updates the underlying GMSGroundOverlay with the properties from the given +/// FGMPlatformGroundOverlay. +/// +/// Setting the ground overlay to visible will set its map to the given mapView. ++ (void)updateGroundOverlay:(GMSGroundOverlay *)groundOverlay + fromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)groundOverlay + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingBounds:(BOOL)useBounds; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h new file mode 100644 index 000000000000..37a833d79d1e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Creates a UIImage from Pigeon bitmap. +UIImage *_Nullable FGMIconFromBitmap(FGMPlatformBitmap *platformBitmap, + NSObject *registrar, + CGFloat screenScale); +/// Returns a BOOL indicating whether image is considered scalable with the given scale factor from +/// size. +BOOL FGMIsScalableWithScaleFactorFromSize(CGSize originalSize, CGSize targetSize); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h new file mode 100644 index 000000000000..166241f3cb56 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import GoogleMaps; + +NS_ASSUME_NONNULL_BEGIN + +/// Defines user data object for markers. +@interface FGMMarkerUserData : NSObject + +/// The identifier of the marker. +@property(nonatomic, copy) NSString *markerIdentifier; + +/// The identifier of the cluster manager. +/// This property is set only if the marker is managed by a cluster manager. +@property(nonatomic, copy, nullable) NSString *clusterManagerIdentifier; + +@end + +/// Associates a marker identifier and optionally a cluster manager identifier with a marker's user +/// data. +extern void FGMSetIdentifiersToMarkerUserData(NSString *markerIdentifier, + NSString *_Nullable clusterManagerIdentifier, + GMSMarker *marker); + +/// Get the marker identifier from marker's user data. +/// +/// @return The marker identifier if found; otherwise, nil. +extern NSString *_Nullable FGMGetMarkerIdentifierFromMarker(GMSMarker *marker); + +/// Get the cluster manager identifier from marker's user data. +/// +/// @return The cluster manager identifier if found; otherwise, nil. +extern NSString *_Nullable FGMGetClusterManagerIdentifierFromMarker(GMSMarker *marker); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h new file mode 100644 index 000000000000..a9c306abe7c4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "GoogleMapsUtilsTrampoline.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Controller of a single Heatmap on the map. +@interface FLTGoogleMapHeatmapController : NSObject + +/// Initializes an instance of this class with a heatmap tile layer, a map view, and additional +/// configuration options. +/// +/// @param heatmap The heatmap data to display. +/// @param heatmapTileLayer The heatmap tile layer that will be used to display heatmap data on the +/// map. +/// @param mapView The map view where the heatmap layer will be overlaid. +/// +/// @return An initialized instance of this class, configured with the specified heatmap tile layer, +/// map view, and additional options. +- (instancetype)initWithHeatmap:(FGMPlatformHeatmap *)heatmap + tileLayer:(GMUHeatmapTileLayer *)heatmapTileLayer + mapView:(GMSMapView *)mapView; + +/// Removes this heatmap from the map. +- (void)removeHeatmap; + +/// Clears the tile cache in order to visually udpate this heatmap. +- (void)clearTileCache; +@end + +/// Controller of multiple Heatmaps on the map. +@interface FLTHeatmapsController : NSObject + +/// Initializes the controller with a GMSMapView. +- (instancetype)initWithMapView:(GMSMapView *)mapView; + +/// Adds heatmaps to the map. +- (void)addHeatmaps:(NSArray *)heatmapsToAdd; + +/// Updates heatmaps on the map. +- (void)changeHeatmaps:(NSArray *)heatmapsToChange; + +/// Removes heatmaps from the map. +- (void)removeHeatmapsWithIdentifiers:(NSArray *)identifiers; + +/// Returns true if a heatmap with the given identifier exists on the map. +- (BOOL)hasHeatmapWithIdentifier:(NSString *)identifier; + +/// Returns the heatmap with the given identifier. +- (nullable FGMPlatformHeatmap *)heatmapWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h new file mode 100644 index 000000000000..b00a48e3477f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapHeatmapController.h" + +/// Internal APIs exposed for unit testing +@interface FLTGoogleMapHeatmapController (Test) + +/// Updates the underlying GMUHeatmapTileLayer with the properties from the given platform heatmap. +/// +/// Setting the heatmap to visible will set its map to the given mapView. ++ (void)updateHeatmap:(GMUHeatmapTileLayer *)heatmapTileLayer + fromPlatformHeatmap:(FGMPlatformHeatmap *)platformHeatmap + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h new file mode 100644 index 000000000000..5c1b6e5418e8 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h @@ -0,0 +1,40 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTGoogleMapTileOverlayController : NSObject +/// The layer managed by this controller instance. +@property(readonly, nonatomic) GMSTileLayer *layer; + +- (instancetype)initWithTileOverlay:(FGMPlatformTileOverlay *)tileOverlay + tileLayer:(GMSTileLayer *)tileLayer + mapView:(GMSMapView *)mapView; +- (void)removeTileOverlay; +- (void)clearTileCache; +@end + +@interface FLTTileProviderController : GMSTileLayer +@property(copy, nonatomic, readonly) NSString *tileOverlayIdentifier; +- (instancetype)initWithTileOverlayIdentifier:(NSString *)identifier + callbackHandler:(FGMMapsCallbackApi *)callbackHandler; +@end + +@interface FLTTileOverlaysController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd; +- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange; +- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers; +- (void)clearTileCacheWithIdentifier:(NSString *)identifier; +- (nullable FLTGoogleMapTileOverlayController *)tileOverlayWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h new file mode 100644 index 000000000000..e753698cde45 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapTileOverlayController.h" + +/// Internal APIs exposed for unit testing +@interface FLTGoogleMapTileOverlayController (Test) + +/// Updates the underlying GMSTileLayer with the properties from the given FGMPlatformTileOverlay. +/// +/// Setting the tile overlay to visible will set its map to the given mapView. ++ (void)updateTileLayer:(GMSTileLayer *)tileLayer + fromPlatformTileOverlay:(FGMPlatformTileOverlay *)platformOverlay + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h new file mode 100644 index 000000000000..a5a1d05a4cbd --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMClusterManagersController.h" +#import "GoogleMapCircleController.h" +#import "GoogleMapController.h" +#import "GoogleMapMarkerController.h" +#import "GoogleMapPolygonController.h" +#import "GoogleMapPolylineController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTGoogleMapsPlugin : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h new file mode 100644 index 000000000000..0cb21d926f6a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h @@ -0,0 +1,30 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +// Defines circle controllable by Flutter. +@interface FLTGoogleMapCircleController : NSObject +- (instancetype)initCircleWithPlatformCircle:(FGMPlatformCircle *)circle + mapView:(GMSMapView *)mapView; +- (void)removeCircle; +@end + +@interface FLTCirclesController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addCircles:(NSArray *)circlesToAdd; +- (void)changeCircles:(NSArray *)circlesToChange; +- (void)removeCirclesWithIdentifiers:(NSArray *)identifiers; +- (void)didTapCircleWithIdentifier:(NSString *)identifier; +- (bool)hasCircleWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h new file mode 100644 index 000000000000..1c72d2060dc1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h @@ -0,0 +1,21 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapCircleController.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Private methods exposed for testing. +@interface FLTGoogleMapCircleController (Test) + +/// Updates the underlying GMSCircle with the properties from the given FGMPlatformCircle. +/// +/// Setting the circle to visible will set its map to the given mapView. ++ (void)updateCircle:(GMSCircle *)circle + fromPlatformCircle:(FGMPlatformCircle *)platformCircle + withMapView:(GMSMapView *)mapView; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h new file mode 100644 index 000000000000..e9ea39630ebf --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMCATransactionWrapper.h" +#import "FGMClusterManagersController.h" +#import "GoogleMapCircleController.h" +#import "GoogleMapMarkerController.h" +#import "GoogleMapPolygonController.h" +#import "GoogleMapPolylineController.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +// Defines map overlay controllable from Flutter. +@interface FLTGoogleMapController : NSObject +- (instancetype)initWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *)registrar; +- (void)showAtOrigin:(CGPoint)origin; +- (void)hide; +- (nullable GMSCameraPosition *)cameraPosition; +@end + +// Allows the engine to create new Google Map instances. +@interface FLTGoogleMapFactory : NSObject +- (instancetype)initWithRegistrar:(NSObject *)registrar; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h new file mode 100644 index 000000000000..219a1ac246e9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMCATransactionWrapper.h" +#import "GoogleMapController.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Implementation of the Pigeon maps API. +/// +/// This is a separate object from the maps controller because the Pigeon API registration keeps a +/// strong reference to the implementor, but as the FlutterPlatformView, the lifetime of the +/// FLTGoogleMapController instance is what needs to trigger Pigeon unregistration, so can't be +/// the target of the registration. +@interface FGMMapCallHandler : NSObject + +/// The transaction wrapper to use for camera animations. +@property(nonatomic, strong) id transactionWrapper; + +@end + +/// Implementation of the Pigeon maps inspector API. +/// +/// This is a separate object from the maps controller because the Pigeon API registration keeps a +/// strong reference to the implementor, but as the FlutterPlatformView, the lifetime of the +/// FLTGoogleMapController instance is what needs to trigger Pigeon unregistration, so can't be +/// the target of the registration. +@interface FGMMapInspector : NSObject + +/// Initializes a Pigeon API for inpector with a map controller. +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix; + +@end + +@interface FLTGoogleMapController (Test) + +/// Initializes a map controller with a concrete map view. +/// +/// @param mapView A map view that will be displayed by the controller +/// @param viewId A unique identifier for the controller. +/// @param creationParameters Parameters for initialising the map view. +/// @param registrar The plugin registrar passed from Flutter. +- (instancetype)initWithMapView:(GMSMapView *)mapView + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *)registrar; + +// The main Pigeon API implementation. +@property(nonatomic, strong, readonly) FGMMapCallHandler *callHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h new file mode 100644 index 000000000000..dcebcb1e2982 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMClusterManagersController.h" +#import "GoogleMapController.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +// Defines marker controllable by Flutter. +@interface FLTGoogleMapMarkerController : NSObject +@property(assign, nonatomic, readonly) BOOL consumeTapEvents; +- (instancetype)initWithMarker:(GMSMarker *)marker + markerIdentifier:(NSString *)markerIdentifier + mapView:(GMSMapView *)mapView; +- (void)showInfoWindow; +- (void)hideInfoWindow; +- (BOOL)isInfoWindowShown; +- (void)removeMarker; +@end + +@interface FLTMarkersController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + clusterManagersController:(nullable FGMClusterManagersController *)clusterManagersController + registrar:(NSObject *)registrar; +- (void)addMarkers:(NSArray *)markersToAdd; +- (void)changeMarkers:(NSArray *)markersToChange; +- (void)removeMarkersWithIdentifiers:(NSArray *)identifiers; +- (BOOL)didTapMarkerWithIdentifier:(NSString *)identifier; +- (void)didStartDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)coordinate; +- (void)didEndDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)coordinate; +- (void)didDragMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)coordinate; +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)identifier; +- (void)showMarkerInfoWindowWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error; +- (void)hideMarkerInfoWindowWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error; +/// Returns whether or not the info window for the marker with the given identifier is shown. +/// +/// If there is no such marker, returns nil and sets error. +- (nullable NSNumber *) + isInfoWindowShownForMarkerWithIdentifier:(NSString *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h new file mode 100644 index 000000000000..f6ff32e791e1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h @@ -0,0 +1,31 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapMarkerController.h" + +/// Methods exposed for unit testing. +@interface FLTGoogleMapMarkerController (Test) + +/// The underlying controlled GMSMarker. +@property(strong, nonatomic, readonly) GMSMarker *marker; + +/// Updates the underlying GMSMarker with the properties from the given FGMPlatformMarker. +/// +/// Setting the marker to visible will set its map to the given mapView. ++ (void)updateMarker:(GMSMarker *)marker + fromPlatformMarker:(FGMPlatformMarker *)platformMarker + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingOpacityForVisibility:(BOOL)useOpacityForVisibility; + +@end + +/// Methods exposed for unit testing. +@interface FLTMarkersController (Test) + +/// A mapping from marker identifiers to corresponding marker controllers. +@property(strong, nonatomic, readonly) NSMutableDictionary *markerIdentifierToController; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h new file mode 100644 index 000000000000..b26cf2416c5f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +// Defines polygon controllable by Flutter. +@interface FLTGoogleMapPolygonController : NSObject +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView; +- (void)removePolygon; +@end + +@interface FLTPolygonsController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addPolygons:(NSArray *)polygonsToAdd; +- (void)changePolygons:(NSArray *)polygonsToChange; +- (void)removePolygonWithIdentifiers:(NSArray *)identifiers; +- (void)didTapPolygonWithIdentifier:(NSString *)identifier; +- (bool)hasPolygonWithIdentifier:(NSString *)identifier; +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h new file mode 100644 index 000000000000..ab4cf60be224 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolygonController.h" + +/// Methods exposed for unit testing. +@interface FLTGoogleMapPolygonController (Test) + +/// Updates the underlying GMSPolygon with the properties from the given FGMPlatformPolygon. +/// +/// Setting the polygon to visible will set its map to the given mapView. ++ (void)updatePolygon:(GMSPolygon *)polygon + fromPlatformPolygon:(FGMPlatformPolygon *)polygon + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h new file mode 100644 index 000000000000..5505ec54019b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +// Defines polyline controllable by Flutter. +@interface FLTGoogleMapPolylineController : NSObject +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView; +- (void)removePolyline; +@end + +@interface FLTPolylinesController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addPolylines:(NSArray *)polylinesToAdd; +- (void)changePolylines:(NSArray *)polylinesToChange; +- (void)removePolylineWithIdentifiers:(NSArray *)identifiers; +- (void)didTapPolylineWithIdentifier:(NSString *)identifier; +- (bool)hasPolylineWithIdentifier:(NSString *)identifier; +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h new file mode 100644 index 000000000000..df9e31293951 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h @@ -0,0 +1,25 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolylineController.h" + +/// Internal APIs exposed for unit testing +@interface FLTGoogleMapPolylineController (Test) + +/// Polyline instance the controller is attached to +@property(strong, nonatomic) GMSPolyline *polyline; + +/// Updates the controller's polyline with the properties from the given FGMPlatformPolyline. +/// +/// Setting the polyline to visible will set its map to the controller's mapView. +- (void)updateFromPlatformPolyline:(FGMPlatformPolyline *)polyline; + +/// Updates the underlying GMSPolyline with the properties from the given FGMPlatformPolyline. +/// +/// Setting the polyline to visible will set its map to the given mapView. ++ (void)updatePolyline:(GMSPolyline *)polyline + fromPlatformPolyline:(FGMPlatformPolyline *)platformPolyline + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h new file mode 100644 index 000000000000..cf6399b5b39e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h @@ -0,0 +1,12 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// If Swift Package Manager is in use, Objective-C headers are available under the +// GoogleMapsUtilsObjC package. When using CocoaPods, the headers are provided by the +// GoogleMapsUtils package. +#ifdef FGM_USING_COCOAPODS +@import GoogleMapsUtils; +#else +@import GoogleMapsUtilsObjC; +#endif diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h new file mode 100644 index 000000000000..db11f425c37c --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h @@ -0,0 +1,940 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#import + +@protocol FlutterBinaryMessenger; +@protocol FlutterMessageCodec; +@class FlutterError; +@class FlutterStandardTypedData; + +NS_ASSUME_NONNULL_BEGIN + +/// Pigeon equivalent of MapType +typedef NS_ENUM(NSUInteger, FGMPlatformMapType) { + FGMPlatformMapTypeNone = 0, + FGMPlatformMapTypeNormal = 1, + FGMPlatformMapTypeSatellite = 2, + FGMPlatformMapTypeTerrain = 3, + FGMPlatformMapTypeHybrid = 4, +}; + +/// Wrapper for FGMPlatformMapType to allow for nullability. +@interface FGMPlatformMapTypeBox : NSObject +@property(nonatomic, assign) FGMPlatformMapType value; +- (instancetype)initWithValue:(FGMPlatformMapType)value; +@end + +/// Join types for polyline joints. +typedef NS_ENUM(NSUInteger, FGMPlatformJointType) { + FGMPlatformJointTypeMitered = 0, + FGMPlatformJointTypeBevel = 1, + FGMPlatformJointTypeRound = 2, +}; + +/// Wrapper for FGMPlatformJointType to allow for nullability. +@interface FGMPlatformJointTypeBox : NSObject +@property(nonatomic, assign) FGMPlatformJointType value; +- (instancetype)initWithValue:(FGMPlatformJointType)value; +@end + +/// Enumeration of possible types for PatternItem. +typedef NS_ENUM(NSUInteger, FGMPlatformPatternItemType) { + FGMPlatformPatternItemTypeDot = 0, + FGMPlatformPatternItemTypeDash = 1, + FGMPlatformPatternItemTypeGap = 2, +}; + +/// Wrapper for FGMPlatformPatternItemType to allow for nullability. +@interface FGMPlatformPatternItemTypeBox : NSObject +@property(nonatomic, assign) FGMPlatformPatternItemType value; +- (instancetype)initWithValue:(FGMPlatformPatternItemType)value; +@end + +/// Pigeon equivalent of [MapBitmapScaling]. +typedef NS_ENUM(NSUInteger, FGMPlatformMapBitmapScaling) { + FGMPlatformMapBitmapScalingAuto = 0, + FGMPlatformMapBitmapScalingNone = 1, +}; + +/// Wrapper for FGMPlatformMapBitmapScaling to allow for nullability. +@interface FGMPlatformMapBitmapScalingBox : NSObject +@property(nonatomic, assign) FGMPlatformMapBitmapScaling value; +- (instancetype)initWithValue:(FGMPlatformMapBitmapScaling)value; +@end + +@class FGMPlatformCameraPosition; +@class FGMPlatformCameraUpdate; +@class FGMPlatformCameraUpdateNewCameraPosition; +@class FGMPlatformCameraUpdateNewLatLng; +@class FGMPlatformCameraUpdateNewLatLngBounds; +@class FGMPlatformCameraUpdateNewLatLngZoom; +@class FGMPlatformCameraUpdateScrollBy; +@class FGMPlatformCameraUpdateZoomBy; +@class FGMPlatformCameraUpdateZoom; +@class FGMPlatformCameraUpdateZoomTo; +@class FGMPlatformCircle; +@class FGMPlatformHeatmap; +@class FGMPlatformHeatmapGradient; +@class FGMPlatformWeightedLatLng; +@class FGMPlatformInfoWindow; +@class FGMPlatformCluster; +@class FGMPlatformClusterManager; +@class FGMPlatformMarker; +@class FGMPlatformPolygon; +@class FGMPlatformPolyline; +@class FGMPlatformPatternItem; +@class FGMPlatformTile; +@class FGMPlatformTileOverlay; +@class FGMPlatformEdgeInsets; +@class FGMPlatformLatLng; +@class FGMPlatformLatLngBounds; +@class FGMPlatformCameraTargetBounds; +@class FGMPlatformGroundOverlay; +@class FGMPlatformMapViewCreationParams; +@class FGMPlatformMapConfiguration; +@class FGMPlatformPoint; +@class FGMPlatformSize; +@class FGMPlatformColor; +@class FGMPlatformTileLayer; +@class FGMPlatformZoomRange; +@class FGMPlatformBitmap; +@class FGMPlatformBitmapDefaultMarker; +@class FGMPlatformBitmapBytes; +@class FGMPlatformBitmapAsset; +@class FGMPlatformBitmapAssetImage; +@class FGMPlatformBitmapAssetMap; +@class FGMPlatformBitmapBytesMap; + +/// Pigeon representatation of a CameraPosition. +@interface FGMPlatformCameraPosition : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithBearing:(double)bearing + target:(FGMPlatformLatLng *)target + tilt:(double)tilt + zoom:(double)zoom; +@property(nonatomic, assign) double bearing; +@property(nonatomic, strong) FGMPlatformLatLng *target; +@property(nonatomic, assign) double tilt; +@property(nonatomic, assign) double zoom; +@end + +/// Pigeon representation of a CameraUpdate. +@interface FGMPlatformCameraUpdate : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithCameraUpdate:(id)cameraUpdate; +/// This Object must be one of the classes below prefixed with +/// PlatformCameraUpdate. Each such class represents a different type of +/// camera update, and each holds a different set of data, preventing the +/// use of a single unified class. +@property(nonatomic, strong) id cameraUpdate; +@end + +/// Pigeon equivalent of NewCameraPosition +@interface FGMPlatformCameraUpdateNewCameraPosition : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithCameraPosition:(FGMPlatformCameraPosition *)cameraPosition; +@property(nonatomic, strong) FGMPlatformCameraPosition *cameraPosition; +@end + +/// Pigeon equivalent of NewLatLng +@interface FGMPlatformCameraUpdateNewLatLng : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng; +@property(nonatomic, strong) FGMPlatformLatLng *latLng; +@end + +/// Pigeon equivalent of NewLatLngBounds +@interface FGMPlatformCameraUpdateNewLatLngBounds : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithBounds:(FGMPlatformLatLngBounds *)bounds padding:(double)padding; +@property(nonatomic, strong) FGMPlatformLatLngBounds *bounds; +@property(nonatomic, assign) double padding; +@end + +/// Pigeon equivalent of NewLatLngZoom +@interface FGMPlatformCameraUpdateNewLatLngZoom : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng zoom:(double)zoom; +@property(nonatomic, strong) FGMPlatformLatLng *latLng; +@property(nonatomic, assign) double zoom; +@end + +/// Pigeon equivalent of ScrollBy +@interface FGMPlatformCameraUpdateScrollBy : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithDx:(double)dx dy:(double)dy; +@property(nonatomic, assign) double dx; +@property(nonatomic, assign) double dy; +@end + +/// Pigeon equivalent of ZoomBy +@interface FGMPlatformCameraUpdateZoomBy : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAmount:(double)amount focus:(nullable FGMPlatformPoint *)focus; +@property(nonatomic, assign) double amount; +@property(nonatomic, strong, nullable) FGMPlatformPoint *focus; +@end + +/// Pigeon equivalent of ZoomIn/ZoomOut +@interface FGMPlatformCameraUpdateZoom : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithOut:(BOOL)out; +@property(nonatomic, assign) BOOL out; +@end + +/// Pigeon equivalent of ZoomTo +@interface FGMPlatformCameraUpdateZoomTo : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithZoom:(double)zoom; +@property(nonatomic, assign) double zoom; +@end + +/// Pigeon equivalent of the Circle class. +@interface FGMPlatformCircle : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithConsumeTapEvents:(BOOL)consumeTapEvents + fillColor:(FGMPlatformColor *)fillColor + strokeColor:(FGMPlatformColor *)strokeColor + visible:(BOOL)visible + strokeWidth:(NSInteger)strokeWidth + zIndex:(double)zIndex + center:(FGMPlatformLatLng *)center + radius:(double)radius + circleId:(NSString *)circleId; +@property(nonatomic, assign) BOOL consumeTapEvents; +@property(nonatomic, strong) FGMPlatformColor *fillColor; +@property(nonatomic, strong) FGMPlatformColor *strokeColor; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger strokeWidth; +@property(nonatomic, assign) double zIndex; +@property(nonatomic, strong) FGMPlatformLatLng *center; +@property(nonatomic, assign) double radius; +@property(nonatomic, copy) NSString *circleId; +@end + +/// Pigeon equivalent of the Heatmap class. +@interface FGMPlatformHeatmap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithHeatmapId:(NSString *)heatmapId + data:(NSArray *)data + gradient:(nullable FGMPlatformHeatmapGradient *)gradient + opacity:(double)opacity + radius:(NSInteger)radius + minimumZoomIntensity:(NSInteger)minimumZoomIntensity + maximumZoomIntensity:(NSInteger)maximumZoomIntensity; +@property(nonatomic, copy) NSString *heatmapId; +@property(nonatomic, copy) NSArray *data; +@property(nonatomic, strong, nullable) FGMPlatformHeatmapGradient *gradient; +@property(nonatomic, assign) double opacity; +@property(nonatomic, assign) NSInteger radius; +@property(nonatomic, assign) NSInteger minimumZoomIntensity; +@property(nonatomic, assign) NSInteger maximumZoomIntensity; +@end + +/// Pigeon equivalent of the HeatmapGradient class. +/// +/// The GMUGradient structure is slightly different from HeatmapGradient, so +/// this matches the iOS API so that conversion can be done on the Dart side +/// where the structures are easier to work with. +@interface FGMPlatformHeatmapGradient : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithColors:(NSArray *)colors + startPoints:(NSArray *)startPoints + colorMapSize:(NSInteger)colorMapSize; +@property(nonatomic, copy) NSArray *colors; +@property(nonatomic, copy) NSArray *startPoints; +@property(nonatomic, assign) NSInteger colorMapSize; +@end + +/// Pigeon equivalent of the WeightedLatLng class. +@interface FGMPlatformWeightedLatLng : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithPoint:(FGMPlatformLatLng *)point weight:(double)weight; +@property(nonatomic, strong) FGMPlatformLatLng *point; +@property(nonatomic, assign) double weight; +@end + +/// Pigeon equivalent of the InfoWindow class. +@interface FGMPlatformInfoWindow : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithTitle:(nullable NSString *)title + snippet:(nullable NSString *)snippet + anchor:(FGMPlatformPoint *)anchor; +@property(nonatomic, copy, nullable) NSString *title; +@property(nonatomic, copy, nullable) NSString *snippet; +@property(nonatomic, strong) FGMPlatformPoint *anchor; +@end + +/// Pigeon equivalent of Cluster. +@interface FGMPlatformCluster : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithClusterManagerId:(NSString *)clusterManagerId + position:(FGMPlatformLatLng *)position + bounds:(FGMPlatformLatLngBounds *)bounds + markerIds:(NSArray *)markerIds; +@property(nonatomic, copy) NSString *clusterManagerId; +@property(nonatomic, strong) FGMPlatformLatLng *position; +@property(nonatomic, strong) FGMPlatformLatLngBounds *bounds; +@property(nonatomic, copy) NSArray *markerIds; +@end + +/// Pigeon equivalent of the ClusterManager class. +@interface FGMPlatformClusterManager : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithIdentifier:(NSString *)identifier; +@property(nonatomic, copy) NSString *identifier; +@end + +/// Pigeon equivalent of the Marker class. +@interface FGMPlatformMarker : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAlpha:(double)alpha + anchor:(FGMPlatformPoint *)anchor + consumeTapEvents:(BOOL)consumeTapEvents + draggable:(BOOL)draggable + flat:(BOOL)flat + icon:(FGMPlatformBitmap *)icon + infoWindow:(FGMPlatformInfoWindow *)infoWindow + position:(FGMPlatformLatLng *)position + rotation:(double)rotation + visible:(BOOL)visible + zIndex:(NSInteger)zIndex + markerId:(NSString *)markerId + clusterManagerId:(nullable NSString *)clusterManagerId; +@property(nonatomic, assign) double alpha; +@property(nonatomic, strong) FGMPlatformPoint *anchor; +@property(nonatomic, assign) BOOL consumeTapEvents; +@property(nonatomic, assign) BOOL draggable; +@property(nonatomic, assign) BOOL flat; +@property(nonatomic, strong) FGMPlatformBitmap *icon; +@property(nonatomic, strong) FGMPlatformInfoWindow *infoWindow; +@property(nonatomic, strong) FGMPlatformLatLng *position; +@property(nonatomic, assign) double rotation; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger zIndex; +@property(nonatomic, copy) NSString *markerId; +@property(nonatomic, copy, nullable) NSString *clusterManagerId; +@end + +/// Pigeon equivalent of the Polygon class. +@interface FGMPlatformPolygon : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithPolygonId:(NSString *)polygonId + consumesTapEvents:(BOOL)consumesTapEvents + fillColor:(FGMPlatformColor *)fillColor + geodesic:(BOOL)geodesic + points:(NSArray *)points + holes:(NSArray *> *)holes + visible:(BOOL)visible + strokeColor:(FGMPlatformColor *)strokeColor + strokeWidth:(NSInteger)strokeWidth + zIndex:(NSInteger)zIndex; +@property(nonatomic, copy) NSString *polygonId; +@property(nonatomic, assign) BOOL consumesTapEvents; +@property(nonatomic, strong) FGMPlatformColor *fillColor; +@property(nonatomic, assign) BOOL geodesic; +@property(nonatomic, copy) NSArray *points; +@property(nonatomic, copy) NSArray *> *holes; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, strong) FGMPlatformColor *strokeColor; +@property(nonatomic, assign) NSInteger strokeWidth; +@property(nonatomic, assign) NSInteger zIndex; +@end + +/// Pigeon equivalent of the Polyline class. +@interface FGMPlatformPolyline : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithPolylineId:(NSString *)polylineId + consumesTapEvents:(BOOL)consumesTapEvents + color:(FGMPlatformColor *)color + geodesic:(BOOL)geodesic + jointType:(FGMPlatformJointType)jointType + patterns:(NSArray *)patterns + points:(NSArray *)points + visible:(BOOL)visible + width:(NSInteger)width + zIndex:(NSInteger)zIndex; +@property(nonatomic, copy) NSString *polylineId; +@property(nonatomic, assign) BOOL consumesTapEvents; +@property(nonatomic, strong) FGMPlatformColor *color; +@property(nonatomic, assign) BOOL geodesic; +/// The joint type. +@property(nonatomic, assign) FGMPlatformJointType jointType; +/// The pattern data, as a list of pattern items. +@property(nonatomic, copy) NSArray *patterns; +@property(nonatomic, copy) NSArray *points; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger width; +@property(nonatomic, assign) NSInteger zIndex; +@end + +/// Pigeon equivalent of the PatternItem class. +@interface FGMPlatformPatternItem : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithType:(FGMPlatformPatternItemType)type length:(nullable NSNumber *)length; +@property(nonatomic, assign) FGMPlatformPatternItemType type; +@property(nonatomic, strong, nullable) NSNumber *length; +@end + +/// Pigeon equivalent of the Tile class. +@interface FGMPlatformTile : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithWidth:(NSInteger)width + height:(NSInteger)height + data:(nullable FlutterStandardTypedData *)data; +@property(nonatomic, assign) NSInteger width; +@property(nonatomic, assign) NSInteger height; +@property(nonatomic, strong, nullable) FlutterStandardTypedData *data; +@end + +/// Pigeon equivalent of the TileOverlay class. +@interface FGMPlatformTileOverlay : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithTileOverlayId:(NSString *)tileOverlayId + fadeIn:(BOOL)fadeIn + transparency:(double)transparency + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + tileSize:(NSInteger)tileSize; +@property(nonatomic, copy) NSString *tileOverlayId; +@property(nonatomic, assign) BOOL fadeIn; +@property(nonatomic, assign) double transparency; +@property(nonatomic, assign) NSInteger zIndex; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger tileSize; +@end + +/// Pigeon equivalent of Flutter's EdgeInsets. +@interface FGMPlatformEdgeInsets : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithTop:(double)top bottom:(double)bottom left:(double)left right:(double)right; +@property(nonatomic, assign) double top; +@property(nonatomic, assign) double bottom; +@property(nonatomic, assign) double left; +@property(nonatomic, assign) double right; +@end + +/// Pigeon equivalent of LatLng. +@interface FGMPlatformLatLng : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithLatitude:(double)latitude longitude:(double)longitude; +@property(nonatomic, assign) double latitude; +@property(nonatomic, assign) double longitude; +@end + +/// Pigeon equivalent of LatLngBounds. +@interface FGMPlatformLatLngBounds : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithNortheast:(FGMPlatformLatLng *)northeast + southwest:(FGMPlatformLatLng *)southwest; +@property(nonatomic, strong) FGMPlatformLatLng *northeast; +@property(nonatomic, strong) FGMPlatformLatLng *southwest; +@end + +/// Pigeon equivalent of CameraTargetBounds. +/// +/// As with the Dart version, it exists to distinguish between not setting a +/// a target, and having an explicitly unbounded target (null [bounds]). +@interface FGMPlatformCameraTargetBounds : NSObject ++ (instancetype)makeWithBounds:(nullable FGMPlatformLatLngBounds *)bounds; +@property(nonatomic, strong, nullable) FGMPlatformLatLngBounds *bounds; +@end + +/// Pigeon equivalent of the GroundOverlay class. +@interface FGMPlatformGroundOverlay : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithGroundOverlayId:(NSString *)groundOverlayId + image:(FGMPlatformBitmap *)image + position:(nullable FGMPlatformLatLng *)position + bounds:(nullable FGMPlatformLatLngBounds *)bounds + anchor:(nullable FGMPlatformPoint *)anchor + transparency:(double)transparency + bearing:(double)bearing + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + clickable:(BOOL)clickable + zoomLevel:(nullable NSNumber *)zoomLevel; +@property(nonatomic, copy) NSString *groundOverlayId; +@property(nonatomic, strong) FGMPlatformBitmap *image; +@property(nonatomic, strong, nullable) FGMPlatformLatLng *position; +@property(nonatomic, strong, nullable) FGMPlatformLatLngBounds *bounds; +@property(nonatomic, strong, nullable) FGMPlatformPoint *anchor; +@property(nonatomic, assign) double transparency; +@property(nonatomic, assign) double bearing; +@property(nonatomic, assign) NSInteger zIndex; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) BOOL clickable; +@property(nonatomic, strong, nullable) NSNumber *zoomLevel; +@end + +/// Information passed to the platform view creation. +@interface FGMPlatformMapViewCreationParams : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype) + makeWithInitialCameraPosition:(FGMPlatformCameraPosition *)initialCameraPosition + mapConfiguration:(FGMPlatformMapConfiguration *)mapConfiguration + initialCircles:(NSArray *)initialCircles + initialMarkers:(NSArray *)initialMarkers + initialPolygons:(NSArray *)initialPolygons + initialPolylines:(NSArray *)initialPolylines + initialHeatmaps:(NSArray *)initialHeatmaps + initialTileOverlays:(NSArray *)initialTileOverlays + initialClusterManagers:(NSArray *)initialClusterManagers + initialGroundOverlays:(NSArray *)initialGroundOverlays; +@property(nonatomic, strong) FGMPlatformCameraPosition *initialCameraPosition; +@property(nonatomic, strong) FGMPlatformMapConfiguration *mapConfiguration; +@property(nonatomic, copy) NSArray *initialCircles; +@property(nonatomic, copy) NSArray *initialMarkers; +@property(nonatomic, copy) NSArray *initialPolygons; +@property(nonatomic, copy) NSArray *initialPolylines; +@property(nonatomic, copy) NSArray *initialHeatmaps; +@property(nonatomic, copy) NSArray *initialTileOverlays; +@property(nonatomic, copy) NSArray *initialClusterManagers; +@property(nonatomic, copy) NSArray *initialGroundOverlays; +@end + +/// Pigeon equivalent of MapConfiguration. +@interface FGMPlatformMapConfiguration : NSObject ++ (instancetype)makeWithCompassEnabled:(nullable NSNumber *)compassEnabled + cameraTargetBounds:(nullable FGMPlatformCameraTargetBounds *)cameraTargetBounds + mapType:(nullable FGMPlatformMapTypeBox *)mapType + minMaxZoomPreference:(nullable FGMPlatformZoomRange *)minMaxZoomPreference + rotateGesturesEnabled:(nullable NSNumber *)rotateGesturesEnabled + scrollGesturesEnabled:(nullable NSNumber *)scrollGesturesEnabled + tiltGesturesEnabled:(nullable NSNumber *)tiltGesturesEnabled + trackCameraPosition:(nullable NSNumber *)trackCameraPosition + zoomGesturesEnabled:(nullable NSNumber *)zoomGesturesEnabled + myLocationEnabled:(nullable NSNumber *)myLocationEnabled + myLocationButtonEnabled:(nullable NSNumber *)myLocationButtonEnabled + padding:(nullable FGMPlatformEdgeInsets *)padding + indoorViewEnabled:(nullable NSNumber *)indoorViewEnabled + trafficEnabled:(nullable NSNumber *)trafficEnabled + buildingsEnabled:(nullable NSNumber *)buildingsEnabled + mapId:(nullable NSString *)mapId + style:(nullable NSString *)style; +@property(nonatomic, strong, nullable) NSNumber *compassEnabled; +@property(nonatomic, strong, nullable) FGMPlatformCameraTargetBounds *cameraTargetBounds; +@property(nonatomic, strong, nullable) FGMPlatformMapTypeBox *mapType; +@property(nonatomic, strong, nullable) FGMPlatformZoomRange *minMaxZoomPreference; +@property(nonatomic, strong, nullable) NSNumber *rotateGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *scrollGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *tiltGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *trackCameraPosition; +@property(nonatomic, strong, nullable) NSNumber *zoomGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *myLocationEnabled; +@property(nonatomic, strong, nullable) NSNumber *myLocationButtonEnabled; +@property(nonatomic, strong, nullable) FGMPlatformEdgeInsets *padding; +@property(nonatomic, strong, nullable) NSNumber *indoorViewEnabled; +@property(nonatomic, strong, nullable) NSNumber *trafficEnabled; +@property(nonatomic, strong, nullable) NSNumber *buildingsEnabled; +@property(nonatomic, copy, nullable) NSString *mapId; +@property(nonatomic, copy, nullable) NSString *style; +@end + +/// Pigeon representation of an x,y coordinate. +@interface FGMPlatformPoint : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithX:(double)x y:(double)y; +@property(nonatomic, assign) double x; +@property(nonatomic, assign) double y; +@end + +/// Pigeon representation of a size. +@interface FGMPlatformSize : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithWidth:(double)width height:(double)height; +@property(nonatomic, assign) double width; +@property(nonatomic, assign) double height; +@end + +/// Pigeon representation of a color. +@interface FGMPlatformColor : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithRed:(double)red green:(double)green blue:(double)blue alpha:(double)alpha; +@property(nonatomic, assign) double red; +@property(nonatomic, assign) double green; +@property(nonatomic, assign) double blue; +@property(nonatomic, assign) double alpha; +@end + +/// Pigeon equivalent of GMSTileLayer properties. +@interface FGMPlatformTileLayer : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithVisible:(BOOL)visible + fadeIn:(BOOL)fadeIn + opacity:(double)opacity + zIndex:(NSInteger)zIndex; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) BOOL fadeIn; +@property(nonatomic, assign) double opacity; +@property(nonatomic, assign) NSInteger zIndex; +@end + +/// Pigeon equivalent of MinMaxZoomPreference. +@interface FGMPlatformZoomRange : NSObject ++ (instancetype)makeWithMin:(nullable NSNumber *)min max:(nullable NSNumber *)max; +@property(nonatomic, strong, nullable) NSNumber *min; +@property(nonatomic, strong, nullable) NSNumber *max; +@end + +/// Pigeon equivalent of [BitmapDescriptor]. As there are multiple disjoint +/// types of [BitmapDescriptor], [PlatformBitmap] contains a single field which +/// may hold the pigeon equivalent type of any of them. +@interface FGMPlatformBitmap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithBitmap:(id)bitmap; +/// One of [PlatformBitmapAssetMap], [PlatformBitmapAsset], +/// [PlatformBitmapAssetImage], [PlatformBitmapBytesMap], +/// [PlatformBitmapBytes], or [PlatformBitmapDefaultMarker]. +/// As Pigeon does not currently support data class inheritance, this +/// approach allows for the different bitmap implementations to be valid +/// argument and return types of the API methods. See +/// https://github.com/flutter/flutter/issues/117819. +@property(nonatomic, strong) id bitmap; +@end + +/// Pigeon equivalent of [DefaultMarker]. +@interface FGMPlatformBitmapDefaultMarker : NSObject ++ (instancetype)makeWithHue:(nullable NSNumber *)hue; +@property(nonatomic, strong, nullable) NSNumber *hue; +@end + +/// Pigeon equivalent of [BytesBitmap]. +@interface FGMPlatformBitmapBytes : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + size:(nullable FGMPlatformSize *)size; +@property(nonatomic, strong) FlutterStandardTypedData *byteData; +@property(nonatomic, strong, nullable) FGMPlatformSize *size; +@end + +/// Pigeon equivalent of [AssetBitmap]. +@interface FGMPlatformBitmapAsset : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithName:(NSString *)name pkg:(nullable NSString *)pkg; +@property(nonatomic, copy) NSString *name; +@property(nonatomic, copy, nullable) NSString *pkg; +@end + +/// Pigeon equivalent of [AssetImageBitmap]. +@interface FGMPlatformBitmapAssetImage : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithName:(NSString *)name + scale:(double)scale + size:(nullable FGMPlatformSize *)size; +@property(nonatomic, copy) NSString *name; +@property(nonatomic, assign) double scale; +@property(nonatomic, strong, nullable) FGMPlatformSize *size; +@end + +/// Pigeon equivalent of [AssetMapBitmap]. +@interface FGMPlatformBitmapAssetMap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAssetName:(NSString *)assetName + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height; +@property(nonatomic, copy) NSString *assetName; +@property(nonatomic, assign) FGMPlatformMapBitmapScaling bitmapScaling; +@property(nonatomic, assign) double imagePixelRatio; +@property(nonatomic, strong, nullable) NSNumber *width; +@property(nonatomic, strong, nullable) NSNumber *height; +@end + +/// Pigeon equivalent of [BytesMapBitmap]. +@interface FGMPlatformBitmapBytesMap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height; +@property(nonatomic, strong) FlutterStandardTypedData *byteData; +@property(nonatomic, assign) FGMPlatformMapBitmapScaling bitmapScaling; +@property(nonatomic, assign) double imagePixelRatio; +@property(nonatomic, strong, nullable) NSNumber *width; +@property(nonatomic, strong, nullable) NSNumber *height; +@end + +/// The codec used by all APIs. +NSObject *FGMGetGoogleMapsFlutterPigeonMessagesCodec(void); + +/// Interface for non-test interactions with the native SDK. +/// +/// For test-only state queries, see [MapsInspectorApi]. +@protocol FGMMapsApi +/// Returns once the map instance is available. +- (void)waitForMapWithError:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the map's configuration options. +/// +/// Only non-null configuration values will result in updates; options with +/// null values will remain unchanged. +- (void)updateWithMapConfiguration:(FGMPlatformMapConfiguration *)configuration + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of circles on the map. +- (void)updateCirclesByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of heatmaps on the map. +- (void)updateHeatmapsByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of custer managers for clusters on the map. +- (void)updateClusterManagersByAdding:(NSArray *)toAdd + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of markers on the map. +- (void)updateMarkersByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of polygonss on the map. +- (void)updatePolygonsByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of polylines on the map. +- (void)updatePolylinesByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of tile overlays on the map. +- (void)updateTileOverlaysByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of ground overlays on the map. +- (void)updateGroundOverlaysByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the screen coordinate for the given map location. +/// +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformPoint *)screenCoordinatesForLatLng:(FGMPlatformLatLng *)latLng + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the map location for the given screen coordinate. +/// +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformLatLng *)latLngForScreenCoordinate:(FGMPlatformPoint *)screenCoordinate + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the map region currently displayed on the map. +/// +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformLatLngBounds *)visibleMapRegion:(FlutterError *_Nullable *_Nonnull)error; +/// Moves the camera according to [cameraUpdate] immediately, with no +/// animation. +- (void)moveCameraWithUpdate:(FGMPlatformCameraUpdate *)cameraUpdate + error:(FlutterError *_Nullable *_Nonnull)error; +/// Moves the camera according to [cameraUpdate], animating the update using a +/// duration in milliseconds if provided. +- (void)animateCameraWithUpdate:(FGMPlatformCameraUpdate *)cameraUpdate + duration:(nullable NSNumber *)durationMilliseconds + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the current map zoom level. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)currentZoomLevel:(FlutterError *_Nullable *_Nonnull)error; +/// Show the info window for the marker with the given ID. +- (void)showInfoWindowForMarkerWithIdentifier:(NSString *)markerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Hide the info window for the marker with the given ID. +- (void)hideInfoWindowForMarkerWithIdentifier:(NSString *)markerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns true if the marker with the given ID is currently displaying its +/// info window. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *) + isShowingInfoWindowForMarkerWithIdentifier:(NSString *)markerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Sets the style to the given map style string, where an empty string +/// indicates that the style should be cleared. +/// +/// If there was an error setting the style, such as an invalid style string, +/// returns the error message. +- (nullable NSString *)setStyle:(NSString *)style error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the error string from the last attempt to set the map style, if +/// any. +/// +/// This allows checking asynchronously for initial style failures, as there +/// is no way to return failures from map initialization. +- (nullable NSString *)lastStyleError:(FlutterError *_Nullable *_Nonnull)error; +/// Clears the cache of tiles previously requseted from the tile provider. +- (void)clearTileCacheForOverlayWithIdentifier:(NSString *)tileOverlayId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Takes a snapshot of the map and returns its image data. +- (nullable FlutterStandardTypedData *)takeSnapshotWithError: + (FlutterError *_Nullable *_Nonnull)error; +@end + +extern void SetUpFGMMapsApi(id binaryMessenger, + NSObject *_Nullable api); + +extern void SetUpFGMMapsApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); + +/// Interface for calls from the native SDK to Dart. +@interface FGMMapsCallbackApi : NSObject +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger; +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + messageChannelSuffix:(nullable NSString *)messageChannelSuffix; +/// Called when the map camera starts moving. +- (void)didStartCameraMoveWithCompletion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map camera moves. +- (void)didMoveCameraToPosition:(FGMPlatformCameraPosition *)cameraPosition + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map camera stops moving. +- (void)didIdleCameraWithCompletion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map, not a specifc map object, is tapped. +- (void)didTapAtPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map, not a specifc map object, is long pressed. +- (void)didLongPressAtPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker is tapped. +- (void)didTapMarkerWithIdentifier:(NSString *)markerId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker drag starts. +- (void)didStartDragForMarkerWithIdentifier:(NSString *)markerId + atPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker drag updates. +- (void)didDragMarkerWithIdentifier:(NSString *)markerId + atPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker drag ends. +- (void)didEndDragForMarkerWithIdentifier:(NSString *)markerId + atPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker's info window is tapped. +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)markerId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a circle is tapped. +- (void)didTapCircleWithIdentifier:(NSString *)circleId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker cluster is tapped. +- (void)didTapCluster:(FGMPlatformCluster *)cluster + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a polygon is tapped. +- (void)didTapPolygonWithIdentifier:(NSString *)polygonId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a polyline is tapped. +- (void)didTapPolylineWithIdentifier:(NSString *)polylineId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a ground overlay is tapped. +- (void)didTapGroundOverlayWithIdentifier:(NSString *)groundOverlayId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called to get data for a map tile. +- (void)tileWithOverlayIdentifier:(NSString *)tileOverlayId + location:(FGMPlatformPoint *)location + zoom:(NSInteger)zoom + completion:(void (^)(FGMPlatformTile *_Nullable, + FlutterError *_Nullable))completion; +@end + +/// Dummy interface to force generation of the platform view creation params, +/// which are not used in any Pigeon calls, only the platform view creation +/// call made internally by Flutter. +@protocol FGMMapsPlatformViewApi +- (void)createViewType:(nullable FGMPlatformMapViewCreationParams *)type + error:(FlutterError *_Nullable *_Nonnull)error; +@end + +extern void SetUpFGMMapsPlatformViewApi(id binaryMessenger, + NSObject *_Nullable api); + +extern void SetUpFGMMapsPlatformViewApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); + +/// Inspector API only intended for use in integration tests. +@protocol FGMMapsInspectorApi +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areBuildingsEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areRotateGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areScrollGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areTiltGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areZoomGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isCompassEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isMyLocationButtonEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isTrafficEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +- (nullable FGMPlatformTileLayer *)tileOverlayWithIdentifier:(NSString *)tileOverlayId + error: + (FlutterError *_Nullable *_Nonnull)error; +- (nullable FGMPlatformGroundOverlay *) + groundOverlayWithIdentifier:(NSString *)groundOverlayId + error:(FlutterError *_Nullable *_Nonnull)error; +- (nullable FGMPlatformHeatmap *)heatmapWithIdentifier:(NSString *)heatmapId + error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformZoomRange *)zoomRange:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)clusterManagerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformCameraPosition *)cameraPosition:(FlutterError *_Nullable *_Nonnull)error; +@end + +extern void SetUpFGMMapsInspectorApi(id binaryMessenger, + NSObject *_Nullable api); + +extern void SetUpFGMMapsInspectorApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/google_maps_flutter_ios_sdk9.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/google_maps_flutter_ios_sdk9.dart new file mode 100644 index 000000000000..082ba90196cc --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/google_maps_flutter_ios_sdk9.dart @@ -0,0 +1,5 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +export 'src/google_maps_flutter_ios.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_map_inspector_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_map_inspector_ios.dart new file mode 100644 index 000000000000..a0057b9fdc54 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_map_inspector_ios.dart @@ -0,0 +1,277 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; +import 'package:flutter/foundation.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'google_maps_flutter_ios.dart'; +import 'messages.g.dart'; + +/// An Android of implementation of [GoogleMapsInspectorPlatform]. +@visibleForTesting +class GoogleMapsInspectorIOS extends GoogleMapsInspectorPlatform { + /// Creates an inspector API instance for a given map ID from + /// [inspectorProvider]. + GoogleMapsInspectorIOS( + MapsInspectorApi? Function(int mapId) inspectorProvider, + ) : _inspectorProvider = inspectorProvider; + + final MapsInspectorApi? Function(int mapId) _inspectorProvider; + + @override + Future areBuildingsEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areBuildingsEnabled(); + } + + @override + Future areRotateGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areRotateGesturesEnabled(); + } + + @override + Future areScrollGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areScrollGesturesEnabled(); + } + + @override + Future areTiltGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areTiltGesturesEnabled(); + } + + @override + Future areZoomControlsEnabled({required int mapId}) async { + // Does not exist on iOS. + return false; + } + + @override + Future areZoomGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areZoomGesturesEnabled(); + } + + @override + Future getMinMaxZoomLevels({required int mapId}) async { + final PlatformZoomRange zoomLevels = await _inspectorProvider( + mapId, + )!.getZoomRange(); + return MinMaxZoomPreference(zoomLevels.min, zoomLevels.max); + } + + @override + Future getTileOverlayInfo( + TileOverlayId tileOverlayId, { + required int mapId, + }) async { + final PlatformTileLayer? tileInfo = await _inspectorProvider( + mapId, + )!.getTileOverlayInfo(tileOverlayId.value); + if (tileInfo == null) { + return null; + } + return TileOverlay( + tileOverlayId: tileOverlayId, + fadeIn: tileInfo.fadeIn, + transparency: 1.0 - tileInfo.opacity, + visible: tileInfo.visible, + zIndex: tileInfo.zIndex, + ); + } + + @override + bool supportsGettingHeatmapInfo() => true; + + @override + Future getHeatmapInfo( + HeatmapId heatmapId, { + required int mapId, + }) async { + final PlatformHeatmap? heatmapInfo = await _inspectorProvider( + mapId, + )!.getHeatmapInfo(heatmapId.value); + if (heatmapInfo == null) { + return null; + } + + return Heatmap( + heatmapId: heatmapId, + data: heatmapInfo.data.map(_deserializeWeightedLatLng).toList(), + gradient: _deserializeHeatmapGradient(heatmapInfo.gradient), + opacity: heatmapInfo.opacity, + radius: HeatmapRadius.fromPixels(heatmapInfo.radius), + minimumZoomIntensity: heatmapInfo.minimumZoomIntensity, + maximumZoomIntensity: heatmapInfo.maximumZoomIntensity, + ); + } + + @override + bool supportsGettingGroundOverlayInfo() => true; + + @override + Future getGroundOverlayInfo( + GroundOverlayId groundOverlayId, { + required int mapId, + }) async { + final PlatformGroundOverlay? groundOverlayInfo = await _inspectorProvider( + mapId, + )!.getGroundOverlayInfo(groundOverlayId.value); + + if (groundOverlayInfo == null) { + return null; + } + + // Create dummy image to represent the image of the ground overlay. + final dummyImage = BytesMapBitmap( + Uint8List.fromList([0]), + bitmapScaling: MapBitmapScaling.none, + ); + + final PlatformLatLng? position = groundOverlayInfo.position; + final PlatformLatLngBounds? bounds = groundOverlayInfo.bounds; + + if (position != null) { + return GroundOverlay.fromPosition( + groundOverlayId: groundOverlayId, + position: LatLng(position.latitude, position.longitude), + image: dummyImage, + zIndex: groundOverlayInfo.zIndex, + bearing: groundOverlayInfo.bearing, + transparency: groundOverlayInfo.transparency, + visible: groundOverlayInfo.visible, + clickable: groundOverlayInfo.clickable, + anchor: Offset( + groundOverlayInfo.anchor!.x, + groundOverlayInfo.anchor!.y, + ), + zoomLevel: groundOverlayInfo.zoomLevel, + ); + } else if (bounds != null) { + return GroundOverlay.fromBounds( + groundOverlayId: groundOverlayId, + bounds: LatLngBounds( + southwest: LatLng( + bounds.southwest.latitude, + bounds.southwest.longitude, + ), + northeast: LatLng( + bounds.northeast.latitude, + bounds.northeast.longitude, + ), + ), + image: dummyImage, + zIndex: groundOverlayInfo.zIndex, + bearing: groundOverlayInfo.bearing, + transparency: groundOverlayInfo.transparency, + visible: groundOverlayInfo.visible, + clickable: groundOverlayInfo.clickable, + ); + } + return null; + } + + @override + Future isCompassEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.isCompassEnabled(); + } + + @override + Future isLiteModeEnabled({required int mapId}) async { + // Does not exist on iOS. + return false; + } + + @override + Future isMapToolbarEnabled({required int mapId}) async { + // Does not exist on iOS. + return false; + } + + @override + Future isMyLocationButtonEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.isMyLocationButtonEnabled(); + } + + @override + Future isTrafficEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.isTrafficEnabled(); + } + + @override + Future> getClusters({ + required int mapId, + required ClusterManagerId clusterManagerId, + }) async { + return (await _inspectorProvider( + mapId, + )!.getClusters(clusterManagerId.value)) + .map( + (PlatformCluster cluster) => + GoogleMapsFlutterIOS.clusterFromPlatformCluster(cluster), + ) + .toList(); + } + + @override + bool supportsGettingGameraPosition() => true; + + @override + Future getCameraPosition({required int mapId}) async { + final PlatformCameraPosition cameraPosition = await _inspectorProvider( + mapId, + )!.getCameraPosition(); + return CameraPosition( + target: LatLng( + cameraPosition.target.latitude, + cameraPosition.target.longitude, + ), + bearing: cameraPosition.bearing, + tilt: cameraPosition.tilt, + zoom: cameraPosition.zoom, + ); + } + + static HeatmapGradient? _deserializeHeatmapGradient( + PlatformHeatmapGradient? gradient, + ) { + if (gradient == null) { + return null; + } + return HeatmapGradient( + // Zip the colors and start points together, since they are parallel + // arrays on the platform side. + _mapEnumerated( + gradient.colors, + (PlatformColor color, int i) => HeatmapGradientColor( + Color.from( + red: color.red, + green: color.green, + blue: color.blue, + alpha: color.alpha, + ), + gradient.startPoints[i], + ), + ).toList(), + colorMapSize: gradient.colorMapSize, + ); + } + + static WeightedLatLng _deserializeWeightedLatLng( + PlatformWeightedLatLng weightedLatLng, + ) { + return WeightedLatLng( + LatLng(weightedLatLng.point.latitude, weightedLatLng.point.longitude), + weight: weightedLatLng.weight, + ); + } +} + +Iterable _mapEnumerated( + Iterable iterable, + E Function(T, int) fn, +) sync* { + var index = 0; + for (final item in iterable) { + yield fn(item, index++); + } +} 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 new file mode 100644 index 000000000000..c7e469ad1491 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/google_maps_flutter_ios.dart @@ -0,0 +1,1467 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:stream_transform/stream_transform.dart'; + +import 'google_map_inspector_ios.dart'; +import 'messages.g.dart'; + +/// The non-test implementation of `_apiProvider`. +MapsApi _productionApiProvider(int mapId) { + return MapsApi(messageChannelSuffix: mapId.toString()); +} + +/// Error thrown when an unknown map ID is provided to a method channel API. +class UnknownMapIDError extends Error { + /// Creates an assertion error with the provided [mapId] and optional + /// [message]. + UnknownMapIDError(this.mapId, [this.message]); + + /// The unknown ID. + final int mapId; + + /// Message describing the assertion error. + final Object? message; + + @override + String toString() { + if (message != null) { + return 'Unknown map ID $mapId: ${Error.safeToString(message)}'; + } + return 'Unknown map ID $mapId'; + } +} + +/// An implementation of [GoogleMapsFlutterPlatform] for iOS. +class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { + /// Creates a new Android maps implementation instance. + GoogleMapsFlutterIOS({ + @visibleForTesting MapsApi Function(int mapId)? apiProvider, + }) : _apiProvider = apiProvider ?? _productionApiProvider; + + /// Registers the iOS implementation of GoogleMapsFlutterPlatform. + static void registerWith() { + GoogleMapsFlutterPlatform.instance = GoogleMapsFlutterIOS(); + } + + final Map _hostMaps = {}; + + // A method to create MapsApi instances, which can be overridden for testing. + final MapsApi Function(int mapId) _apiProvider; + + /// The per-map handlers for callbacks from the host side. + @visibleForTesting + final Map hostMapHandlers = + {}; + + /// Accesses the MapsApi associated to the passed mapId. + MapsApi _hostApi(int mapId) { + final MapsApi? api = _hostMaps[mapId]; + if (api == null) { + throw UnknownMapIDError(mapId); + } + return api; + } + + // Keep a collection of mapId to a map of TileOverlays. + final Map> _tileOverlays = + >{}; + + /// Returns the handler for [mapId], creating it if it doesn't already exist. + @visibleForTesting + HostMapMessageHandler ensureHandlerInitialized(int mapId) { + HostMapMessageHandler? handler = hostMapHandlers[mapId]; + if (handler == null) { + handler = HostMapMessageHandler( + mapId, + _mapEventStreamController, + tileOverlayProvider: (TileOverlayId tileOverlayId) { + final Map? tileOverlaysForMap = + _tileOverlays[mapId]; + return tileOverlaysForMap?[tileOverlayId]; + }, + ); + hostMapHandlers[mapId] = handler; + } + return handler; + } + + /// Returns the API instance for [mapId], creating it if it doesn't already + /// exist. + @visibleForTesting + MapsApi ensureApiInitialized(int mapId) { + MapsApi? api = _hostMaps[mapId]; + if (api == null) { + api = _apiProvider(mapId); + _hostMaps[mapId] ??= api; + } + return api; + } + + @override + Future init(int mapId) { + ensureHandlerInitialized(mapId); + final MapsApi hostApi = ensureApiInitialized(mapId); + return hostApi.waitForMap(); + } + + @override + void dispose({required int mapId}) { + // Noop! + } + + // The controller we need to broadcast the different events coming + // from handleMethodCall. + // + // It is a `broadcast` because multiple controllers will connect to + // different stream views of this Controller. + final StreamController> _mapEventStreamController = + StreamController>.broadcast(); + + // Returns a filtered view of the events in the _controller, by mapId. + Stream> _events(int mapId) => _mapEventStreamController + .stream + .where((MapEvent event) => event.mapId == mapId); + + @override + Stream onCameraMoveStarted({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onCameraMove({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onCameraIdle({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onInfoWindowTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerDragStart({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerDrag({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerDragEnd({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onPolylineTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onPolygonTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onCircleTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onGroundOverlayTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onLongPress({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onClusterTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Future updateMapConfiguration( + MapConfiguration configuration, { + required int mapId, + }) { + return _hostApi(mapId).updateMapConfiguration( + _platformMapConfigurationFromMapConfiguration(configuration), + ); + } + + @override + Future updateMapOptions( + Map optionsUpdate, { + required int mapId, + }) { + return _hostApi(mapId).updateMapConfiguration( + _platformMapConfigurationFromOptionsJson(optionsUpdate), + ); + } + + @override + Future updateMarkers( + MarkerUpdates markerUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateMarkers( + markerUpdates.markersToAdd.map(_platformMarkerFromMarker).toList(), + markerUpdates.markersToChange.map(_platformMarkerFromMarker).toList(), + markerUpdates.markerIdsToRemove.map((MarkerId id) => id.value).toList(), + ); + } + + @override + Future updatePolygons( + PolygonUpdates polygonUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updatePolygons( + polygonUpdates.polygonsToAdd.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonsToChange.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonIdsToRemove + .map((PolygonId id) => id.value) + .toList(), + ); + } + + @override + Future updatePolylines( + PolylineUpdates polylineUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updatePolylines( + polylineUpdates.polylinesToAdd + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylinesToChange + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylineIdsToRemove + .map((PolylineId id) => id.value) + .toList(), + ); + } + + @override + Future updateCircles( + CircleUpdates circleUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateCircles( + circleUpdates.circlesToAdd.map(_platformCircleFromCircle).toList(), + circleUpdates.circlesToChange.map(_platformCircleFromCircle).toList(), + circleUpdates.circleIdsToRemove.map((CircleId id) => id.value).toList(), + ); + } + + @override + Future updateHeatmaps( + HeatmapUpdates heatmapUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateHeatmaps( + heatmapUpdates.heatmapsToAdd.map(_platformHeatmapFromHeatmap).toList(), + heatmapUpdates.heatmapsToChange.map(_platformHeatmapFromHeatmap).toList(), + heatmapUpdates.heatmapIdsToRemove + .map((HeatmapId id) => id.value) + .toList(), + ); + } + + @override + Future updateTileOverlays({ + required Set newTileOverlays, + required int mapId, + }) { + final Map? currentTileOverlays = + _tileOverlays[mapId]; + final Set previousSet = currentTileOverlays != null + ? currentTileOverlays.values.toSet() + : {}; + final updates = _TileOverlayUpdates.from(previousSet, newTileOverlays); + _tileOverlays[mapId] = keyTileOverlayId(newTileOverlays); + return _hostApi(mapId).updateTileOverlays( + updates.tileOverlaysToAdd + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlaysToChange + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlayIdsToRemove + .map((TileOverlayId id) => id.value) + .toList(), + ); + } + + @override + Future updateClusterManagers( + ClusterManagerUpdates clusterManagerUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateClusterManagers( + clusterManagerUpdates.clusterManagersToAdd + .map(_platformClusterManagerFromClusterManager) + .toList(), + clusterManagerUpdates.clusterManagerIdsToRemove + .map((ClusterManagerId id) => id.value) + .toList(), + ); + } + + @override + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) { + assert( + groundOverlayUpdates.groundOverlaysToAdd.every( + (GroundOverlay groundOverlay) => + groundOverlay.position == null || groundOverlay.zoomLevel != null, + ), + 'On iOS zoom level must be set when position is set for ground overlays.', + ); + + return _hostApi(mapId).updateGroundOverlays( + groundOverlayUpdates.groundOverlaysToAdd + .map(_platformGroundOverlayFromGroundOverlay) + .toList(), + groundOverlayUpdates.groundOverlaysToChange + .map(_platformGroundOverlayFromGroundOverlay) + .toList(), + groundOverlayUpdates.groundOverlayIdsToRemove + .map((GroundOverlayId id) => id.value) + .toList(), + ); + } + + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + required int mapId, + }) { + return _hostApi(mapId).clearTileCache(tileOverlayId.value); + } + + @override + Future animateCamera(CameraUpdate cameraUpdate, {required int mapId}) { + return animateCameraWithConfiguration( + cameraUpdate, + const CameraUpdateAnimationConfiguration(), + mapId: mapId, + ); + } + + @override + Future animateCameraWithConfiguration( + CameraUpdate cameraUpdate, + CameraUpdateAnimationConfiguration configuration, { + required int mapId, + }) { + return _hostApi(mapId).animateCamera( + _platformCameraUpdateFromCameraUpdate(cameraUpdate), + configuration.duration?.inMilliseconds, + ); + } + + @override + Future moveCamera(CameraUpdate cameraUpdate, {required int mapId}) { + return _hostApi( + mapId, + ).moveCamera(_platformCameraUpdateFromCameraUpdate(cameraUpdate)); + } + + @override + Future setMapStyle(String? mapStyle, {required int mapId}) async { + final String? errorDescription = await _hostApi( + mapId, + ).setStyle(mapStyle ?? ''); + if (errorDescription != null) { + throw MapStyleException(errorDescription); + } + } + + @override + Future getVisibleRegion({required int mapId}) async { + return _latLngBoundsFromPlatformLatLngBounds( + await _hostApi(mapId).getVisibleRegion(), + ); + } + + @override + Future getScreenCoordinate( + LatLng latLng, { + required int mapId, + }) async { + return _screenCoordinateFromPlatformPoint( + await _hostApi( + mapId, + ).getScreenCoordinate(_platformLatLngFromLatLng(latLng)), + ); + } + + @override + Future getLatLng( + ScreenCoordinate screenCoordinate, { + required int mapId, + }) async { + return _latLngFromPlatformLatLng( + await _hostApi( + mapId, + ).getLatLng(_platformPointFromScreenCoordinate(screenCoordinate)), + ); + } + + @override + Future showMarkerInfoWindow(MarkerId markerId, {required int mapId}) { + return _hostApi(mapId).showInfoWindow(markerId.value); + } + + @override + Future hideMarkerInfoWindow(MarkerId markerId, {required int mapId}) { + return _hostApi(mapId).hideInfoWindow(markerId.value); + } + + @override + Future isMarkerInfoWindowShown( + MarkerId markerId, { + required int mapId, + }) { + return _hostApi(mapId).isInfoWindowShown(markerId.value); + } + + @override + Future getZoomLevel({required int mapId}) { + return _hostApi(mapId).getZoomLevel(); + } + + @override + Future takeSnapshot({required int mapId}) { + return _hostApi(mapId).takeSnapshot(); + } + + @override + Future getStyleError({required int mapId}) { + return _hostApi(mapId).getLastStyleError(); + } + + Widget _buildView( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required PlatformMapConfiguration mapConfiguration, + required MapWidgetConfiguration widgetConfiguration, + MapObjects mapObjects = const MapObjects(), + }) { + assert( + mapObjects.groundOverlays.every( + (GroundOverlay groundOverlay) => + groundOverlay.position == null || groundOverlay.zoomLevel != null, + ), + 'On iOS zoom level must be set when position is set for ground overlays.', + ); + + final creationParams = PlatformMapViewCreationParams( + initialCameraPosition: _platformCameraPositionFromCameraPosition( + widgetConfiguration.initialCameraPosition, + ), + mapConfiguration: mapConfiguration, + initialMarkers: mapObjects.markers + .map(_platformMarkerFromMarker) + .toList(), + initialPolygons: mapObjects.polygons + .map(_platformPolygonFromPolygon) + .toList(), + initialPolylines: mapObjects.polylines + .map(_platformPolylineFromPolyline) + .toList(), + initialCircles: mapObjects.circles + .map(_platformCircleFromCircle) + .toList(), + initialHeatmaps: mapObjects.heatmaps + .map(_platformHeatmapFromHeatmap) + .toList(), + initialTileOverlays: mapObjects.tileOverlays + .map(_platformTileOverlayFromTileOverlay) + .toList(), + initialClusterManagers: mapObjects.clusterManagers + .map(_platformClusterManagerFromClusterManager) + .toList(), + initialGroundOverlays: mapObjects.groundOverlays + .map(_platformGroundOverlayFromGroundOverlay) + .toList(), + ); + + return UiKitView( + viewType: 'plugins.flutter.dev/google_maps_ios', + onPlatformViewCreated: onPlatformViewCreated, + gestureRecognizers: widgetConfiguration.gestureRecognizers, + creationParams: creationParams, + creationParamsCodec: MapsApi.pigeonChannelCodec, + ); + } + + @override + Widget buildViewWithConfiguration( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required MapWidgetConfiguration widgetConfiguration, + MapConfiguration mapConfiguration = const MapConfiguration(), + MapObjects mapObjects = const MapObjects(), + }) { + return _buildView( + creationId, + onPlatformViewCreated, + widgetConfiguration: widgetConfiguration, + mapObjects: mapObjects, + mapConfiguration: _platformMapConfigurationFromMapConfiguration( + mapConfiguration, + ), + ); + } + + @override + Widget buildViewWithTextDirection( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required CameraPosition initialCameraPosition, + required TextDirection textDirection, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set>? gestureRecognizers, + Map mapOptions = const {}, + }) { + return _buildView( + creationId, + onPlatformViewCreated, + widgetConfiguration: MapWidgetConfiguration( + initialCameraPosition: initialCameraPosition, + textDirection: textDirection, + ), + mapObjects: MapObjects( + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + tileOverlays: tileOverlays, + ), + mapConfiguration: _platformMapConfigurationFromOptionsJson(mapOptions), + ); + } + + @override + Widget buildView( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required CameraPosition initialCameraPosition, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set>? gestureRecognizers, + Map mapOptions = const {}, + }) { + return buildViewWithTextDirection( + creationId, + onPlatformViewCreated, + initialCameraPosition: initialCameraPosition, + textDirection: TextDirection.ltr, + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + tileOverlays: tileOverlays, + gestureRecognizers: gestureRecognizers, + mapOptions: mapOptions, + ); + } + + @override + @visibleForTesting + void enableDebugInspection() { + GoogleMapsInspectorPlatform.instance = GoogleMapsInspectorIOS( + (int mapId) => MapsInspectorApi(messageChannelSuffix: mapId.toString()), + ); + } + + /// Converts a Pigeon [PlatformCluster] to the corresponding [Cluster]. + static Cluster clusterFromPlatformCluster(PlatformCluster cluster) { + return Cluster( + ClusterManagerId(cluster.clusterManagerId), + cluster.markerIds.map((String markerId) => MarkerId(markerId)).toList(), + position: _latLngFromPlatformLatLng(cluster.position), + bounds: _latLngBoundsFromPlatformLatLngBounds(cluster.bounds), + ); + } + + static ScreenCoordinate _screenCoordinateFromPlatformPoint( + PlatformPoint point, + ) { + return ScreenCoordinate(x: point.x.round(), y: point.y.round()); + } + + static PlatformPoint _platformPointFromScreenCoordinate( + ScreenCoordinate coordinate, + ) { + return PlatformPoint( + x: coordinate.x.toDouble(), + y: coordinate.y.toDouble(), + ); + } + + static PlatformPoint _platformPointFromOffset(Offset offset) { + return PlatformPoint(x: offset.dx, y: offset.dy); + } + + static PlatformSize _platformSizeFromSize(Size size) { + return PlatformSize(width: size.width, height: size.height); + } + + static PlatformCircle _platformCircleFromCircle(Circle circle) { + return PlatformCircle( + consumeTapEvents: circle.consumeTapEvents, + fillColor: PlatformColor( + red: circle.fillColor.r, + green: circle.fillColor.g, + blue: circle.fillColor.b, + alpha: circle.fillColor.a, + ), + strokeColor: PlatformColor( + red: circle.strokeColor.r, + green: circle.strokeColor.g, + blue: circle.strokeColor.b, + alpha: circle.strokeColor.a, + ), + visible: circle.visible, + strokeWidth: circle.strokeWidth, + zIndex: circle.zIndex.toDouble(), + center: _platformLatLngFromLatLng(circle.center), + radius: circle.radius, + circleId: circle.circleId.value, + ); + } + + static PlatformHeatmap _platformHeatmapFromHeatmap(Heatmap heatmap) { + final HeatmapGradient? gradient = heatmap.gradient; + return PlatformHeatmap( + heatmapId: heatmap.heatmapId.value, + data: heatmap.data + .map(_platformWeightedLatLngFromWeightedLatLng) + .toList(), + gradient: _platformHeatmapGradientFromHeatmapGradient(gradient), + opacity: heatmap.opacity, + radius: heatmap.radius.radius, + minimumZoomIntensity: heatmap.minimumZoomIntensity, + maximumZoomIntensity: heatmap.maximumZoomIntensity, + ); + } + + static PlatformHeatmapGradient? _platformHeatmapGradientFromHeatmapGradient( + HeatmapGradient? gradient, + ) { + if (gradient == null) { + return null; + } + return PlatformHeatmapGradient( + colors: gradient.colors + .map( + (HeatmapGradientColor c) => PlatformColor( + red: c.color.r, + green: c.color.g, + blue: c.color.b, + alpha: c.color.a, + ), + ) + .toList(), + startPoints: gradient.colors + .map((HeatmapGradientColor c) => c.startPoint) + .toList(), + colorMapSize: gradient.colorMapSize, + ); + } + + static PlatformInfoWindow _platformInfoWindowFromInfoWindow( + InfoWindow window, + ) { + return PlatformInfoWindow( + title: window.title, + snippet: window.snippet, + anchor: _platformPointFromOffset(window.anchor), + ); + } + + static PlatformMarker _platformMarkerFromMarker(Marker marker) { + return PlatformMarker( + alpha: marker.alpha, + anchor: _platformPointFromOffset(marker.anchor), + consumeTapEvents: marker.consumeTapEvents, + draggable: marker.draggable, + flat: marker.flat, + icon: platformBitmapFromBitmapDescriptor(marker.icon), + infoWindow: _platformInfoWindowFromInfoWindow(marker.infoWindow), + position: _platformLatLngFromLatLng(marker.position), + rotation: marker.rotation, + visible: marker.visible, + zIndex: marker.zIndexInt, + markerId: marker.markerId.value, + clusterManagerId: marker.clusterManagerId?.value, + ); + } + + static PlatformGroundOverlay _platformGroundOverlayFromGroundOverlay( + GroundOverlay groundOverlay, + ) { + return PlatformGroundOverlay( + groundOverlayId: groundOverlay.groundOverlayId.value, + anchor: groundOverlay.anchor != null + ? _platformPointFromOffset(groundOverlay.anchor!) + : null, + image: platformBitmapFromBitmapDescriptor(groundOverlay.image), + position: groundOverlay.position != null + ? _platformLatLngFromLatLng(groundOverlay.position!) + : null, + bounds: _platformLatLngBoundsFromLatLngBounds(groundOverlay.bounds), + visible: groundOverlay.visible, + zIndex: groundOverlay.zIndex, + bearing: groundOverlay.bearing, + clickable: groundOverlay.clickable, + transparency: groundOverlay.transparency, + zoomLevel: groundOverlay.zoomLevel, + ); + } + + static PlatformPolygon _platformPolygonFromPolygon(Polygon polygon) { + final List points = polygon.points + .map(_platformLatLngFromLatLng) + .toList(); + final List> holes = polygon.holes.map(( + List hole, + ) { + return hole.map(_platformLatLngFromLatLng).toList(); + }).toList(); + return PlatformPolygon( + polygonId: polygon.polygonId.value, + fillColor: PlatformColor( + red: polygon.fillColor.r, + green: polygon.fillColor.g, + blue: polygon.fillColor.b, + alpha: polygon.fillColor.a, + ), + geodesic: polygon.geodesic, + consumesTapEvents: polygon.consumeTapEvents, + points: points, + holes: holes, + strokeColor: PlatformColor( + red: polygon.strokeColor.r, + green: polygon.strokeColor.g, + blue: polygon.strokeColor.b, + alpha: polygon.strokeColor.a, + ), + strokeWidth: polygon.strokeWidth, + zIndex: polygon.zIndex, + visible: polygon.visible, + ); + } + + static PlatformPolyline _platformPolylineFromPolyline(Polyline polyline) { + final List points = polyline.points + .map(_platformLatLngFromLatLng) + .toList(); + final List pattern = polyline.patterns + .map(platformPatternItemFromPatternItem) + .toList(); + return PlatformPolyline( + polylineId: polyline.polylineId.value, + consumesTapEvents: polyline.consumeTapEvents, + color: PlatformColor( + red: polyline.color.r, + green: polyline.color.g, + blue: polyline.color.b, + alpha: polyline.color.a, + ), + geodesic: polyline.geodesic, + visible: polyline.visible, + width: polyline.width, + zIndex: polyline.zIndex, + points: points, + jointType: platformJointTypeFromJointType(polyline.jointType), + patterns: pattern, + ); + } + + static PlatformTileOverlay _platformTileOverlayFromTileOverlay( + TileOverlay tileOverlay, + ) { + return PlatformTileOverlay( + tileOverlayId: tileOverlay.tileOverlayId.value, + fadeIn: tileOverlay.fadeIn, + transparency: tileOverlay.transparency, + zIndex: tileOverlay.zIndex, + visible: tileOverlay.visible, + tileSize: tileOverlay.tileSize, + ); + } + + static PlatformClusterManager _platformClusterManagerFromClusterManager( + ClusterManager clusterManager, + ) { + return PlatformClusterManager( + identifier: clusterManager.clusterManagerId.value, + ); + } + + static PlatformCameraUpdate _platformCameraUpdateFromCameraUpdate( + CameraUpdate update, + ) { + switch (update.updateType) { + case CameraUpdateType.newCameraPosition: + update as CameraUpdateNewCameraPosition; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewCameraPosition( + cameraPosition: _platformCameraPositionFromCameraPosition( + update.cameraPosition, + ), + ), + ); + case CameraUpdateType.newLatLng: + update as CameraUpdateNewLatLng; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewLatLng( + latLng: _platformLatLngFromLatLng(update.latLng), + ), + ); + case CameraUpdateType.newLatLngZoom: + update as CameraUpdateNewLatLngZoom; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewLatLngZoom( + latLng: _platformLatLngFromLatLng(update.latLng), + zoom: update.zoom, + ), + ); + case CameraUpdateType.newLatLngBounds: + update as CameraUpdateNewLatLngBounds; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewLatLngBounds( + bounds: _platformLatLngBoundsFromLatLngBounds(update.bounds)!, + padding: update.padding, + ), + ); + case CameraUpdateType.zoomTo: + update as CameraUpdateZoomTo; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoomTo(zoom: update.zoom), + ); + case CameraUpdateType.zoomBy: + update as CameraUpdateZoomBy; + final Offset? focus = update.focus; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoomBy( + amount: update.amount, + focus: focus == null ? null : _platformPointFromOffset(focus), + ), + ); + case CameraUpdateType.zoomIn: + update as CameraUpdateZoomIn; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoom(out: false), + ); + case CameraUpdateType.zoomOut: + update as CameraUpdateZoomOut; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoom(out: true), + ); + case CameraUpdateType.scrollBy: + update as CameraUpdateScrollBy; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateScrollBy( + dx: update.dx, + dy: update.dy, + ), + ); + } + } + + /// Converts [MapBitmapScaling] from platform interface to [PlatformMapBitmapScaling] Pigeon. + @visibleForTesting + static PlatformMapBitmapScaling platformMapBitmapScalingFromScaling( + MapBitmapScaling scaling, + ) { + switch (scaling) { + case MapBitmapScaling.auto: + return PlatformMapBitmapScaling.auto; + case MapBitmapScaling.none: + return PlatformMapBitmapScaling.none; + } + + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformMapBitmapScaling.auto; + } + + /// Converts [BitmapDescriptor] from platform interface to [PlatformBitmap] pigeon. + @visibleForTesting + static PlatformBitmap platformBitmapFromBitmapDescriptor( + BitmapDescriptor bitmap, + ) { + switch (bitmap) { + case final DefaultMarker marker: + return PlatformBitmap( + bitmap: PlatformBitmapDefaultMarker(hue: marker.hue?.toDouble()), + ); + // Clients may still use this deprecated format, so it must be supported. + // ignore: deprecated_member_use + case final BytesBitmap bytes: + final Size? size = bytes.size; + return PlatformBitmap( + bitmap: PlatformBitmapBytes( + byteData: bytes.byteData, + size: (size == null) ? null : _platformSizeFromSize(size), + ), + ); + case final AssetBitmap asset: + return PlatformBitmap( + bitmap: PlatformBitmapAsset(name: asset.name, pkg: asset.package), + ); + // Clients may still use this deprecated format, so it must be supported. + // ignore: deprecated_member_use + case final AssetImageBitmap asset: + final Size? size = asset.size; + return PlatformBitmap( + bitmap: PlatformBitmapAssetImage( + name: asset.name, + scale: asset.scale, + size: (size == null) ? null : _platformSizeFromSize(size), + ), + ); + case final AssetMapBitmap asset: + return PlatformBitmap( + bitmap: PlatformBitmapAssetMap( + assetName: asset.assetName, + bitmapScaling: platformMapBitmapScalingFromScaling( + asset.bitmapScaling, + ), + imagePixelRatio: asset.imagePixelRatio, + width: asset.width, + height: asset.height, + ), + ); + case final BytesMapBitmap bytes: + return PlatformBitmap( + bitmap: PlatformBitmapBytesMap( + byteData: bytes.byteData, + bitmapScaling: platformMapBitmapScalingFromScaling( + bytes.bitmapScaling, + ), + imagePixelRatio: bytes.imagePixelRatio, + width: bytes.width, + height: bytes.height, + ), + ); + default: + throw ArgumentError( + 'Unrecognized type of bitmap ${bitmap.runtimeType}', + 'bitmap', + ); + } + } +} + +/// Callback handler for map events from the platform host. +@visibleForTesting +class HostMapMessageHandler implements MapsCallbackApi { + /// Creates a new handler that listens for events from map [mapId], and + /// broadcasts them to [streamController]. + HostMapMessageHandler( + this.mapId, + this.streamController, { + required this.tileOverlayProvider, + }) { + MapsCallbackApi.setUp(this, messageChannelSuffix: mapId.toString()); + } + + /// Removes the handler for native messages. + void dispose() { + MapsCallbackApi.setUp(null, messageChannelSuffix: mapId.toString()); + } + + /// The map ID this handler listens for events from. + final int mapId; + + /// The controller used to broadcast map events coming from the + /// host platform. + final StreamController> streamController; + + /// The callback to get a tile overlay for the corresponding map. + final TileOverlay? Function(TileOverlayId tileOverlayId) tileOverlayProvider; + + @override + Future getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ) async { + final TileOverlay? tileOverlay = tileOverlayProvider( + TileOverlayId(tileOverlayId), + ); + final TileProvider? tileProvider = tileOverlay?.tileProvider; + final Tile tile = tileProvider == null + ? TileProvider.noTile + : await tileProvider.getTile( + location.x.round(), + location.y.round(), + zoom, + ); + return _platformTileFromTile(tile); + } + + @override + void onCameraIdle() { + streamController.add(CameraIdleEvent(mapId)); + } + + @override + void onCameraMove(PlatformCameraPosition cameraPosition) { + streamController.add( + CameraMoveEvent( + mapId, + CameraPosition( + target: _latLngFromPlatformLatLng(cameraPosition.target), + bearing: cameraPosition.bearing, + tilt: cameraPosition.tilt, + zoom: cameraPosition.zoom, + ), + ), + ); + } + + @override + void onCameraMoveStarted() { + streamController.add(CameraMoveStartedEvent(mapId)); + } + + @override + void onCircleTap(String circleId) { + streamController.add(CircleTapEvent(mapId, CircleId(circleId))); + } + + @override + void onClusterTap(PlatformCluster cluster) { + streamController.add( + ClusterTapEvent( + mapId, + GoogleMapsFlutterIOS.clusterFromPlatformCluster(cluster), + ), + ); + } + + @override + void onInfoWindowTap(String markerId) { + streamController.add(InfoWindowTapEvent(mapId, MarkerId(markerId))); + } + + @override + void onLongPress(PlatformLatLng position) { + streamController.add( + MapLongPressEvent(mapId, _latLngFromPlatformLatLng(position)), + ); + } + + @override + void onMarkerDrag(String markerId, PlatformLatLng position) { + streamController.add( + MarkerDragEvent( + mapId, + _latLngFromPlatformLatLng(position), + MarkerId(markerId), + ), + ); + } + + @override + void onMarkerDragStart(String markerId, PlatformLatLng position) { + streamController.add( + MarkerDragStartEvent( + mapId, + _latLngFromPlatformLatLng(position), + MarkerId(markerId), + ), + ); + } + + @override + void onMarkerDragEnd(String markerId, PlatformLatLng position) { + streamController.add( + MarkerDragEndEvent( + mapId, + _latLngFromPlatformLatLng(position), + MarkerId(markerId), + ), + ); + } + + @override + void onMarkerTap(String markerId) { + streamController.add(MarkerTapEvent(mapId, MarkerId(markerId))); + } + + @override + void onPolygonTap(String polygonId) { + streamController.add(PolygonTapEvent(mapId, PolygonId(polygonId))); + } + + @override + void onPolylineTap(String polylineId) { + streamController.add(PolylineTapEvent(mapId, PolylineId(polylineId))); + } + + @override + void onGroundOverlayTap(String groundOverlayId) { + streamController.add( + GroundOverlayTapEvent(mapId, GroundOverlayId(groundOverlayId)), + ); + } + + @override + void onTap(PlatformLatLng position) { + streamController.add( + MapTapEvent(mapId, _latLngFromPlatformLatLng(position)), + ); + } +} + +LatLng _latLngFromPlatformLatLng(PlatformLatLng latLng) { + return LatLng(latLng.latitude, latLng.longitude); +} + +LatLngBounds _latLngBoundsFromPlatformLatLngBounds( + PlatformLatLngBounds bounds, +) { + return LatLngBounds( + southwest: _latLngFromPlatformLatLng(bounds.southwest), + northeast: _latLngFromPlatformLatLng(bounds.northeast), + ); +} + +PlatformLatLng _platformLatLngFromLatLng(LatLng latLng) { + return PlatformLatLng(latitude: latLng.latitude, longitude: latLng.longitude); +} + +PlatformLatLngBounds? _platformLatLngBoundsFromLatLngBounds( + LatLngBounds? bounds, +) { + if (bounds == null) { + return null; + } + return PlatformLatLngBounds( + northeast: _platformLatLngFromLatLng(bounds.northeast), + southwest: _platformLatLngFromLatLng(bounds.southwest), + ); +} + +PlatformWeightedLatLng _platformWeightedLatLngFromWeightedLatLng( + WeightedLatLng weightedLatLng, +) { + return PlatformWeightedLatLng( + point: _platformLatLngFromLatLng(weightedLatLng.point), + weight: weightedLatLng.weight, + ); +} + +PlatformCameraTargetBounds? _platformCameraTargetBoundsFromCameraTargetBounds( + CameraTargetBounds? bounds, +) { + return bounds == null + ? null + : PlatformCameraTargetBounds( + bounds: _platformLatLngBoundsFromLatLngBounds(bounds.bounds), + ); +} + +PlatformTile _platformTileFromTile(Tile tile) { + return PlatformTile(width: tile.width, height: tile.height, data: tile.data); +} + +PlatformMapType? _platformMapTypeFromMapType(MapType? type) { + switch (type) { + case null: + return null; + case MapType.none: + return PlatformMapType.none; + case MapType.normal: + return PlatformMapType.normal; + case MapType.satellite: + return PlatformMapType.satellite; + case MapType.terrain: + return PlatformMapType.terrain; + case MapType.hybrid: + return PlatformMapType.hybrid; + } + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformMapType.normal; +} + +PlatformZoomRange? _platformZoomRangeFromMinMaxZoomPreference( + MinMaxZoomPreference? zoomPref, +) { + return zoomPref == null + ? null + : PlatformZoomRange(min: zoomPref.minZoom, max: zoomPref.maxZoom); +} + +PlatformEdgeInsets? _platformEdgeInsetsFromEdgeInsets(EdgeInsets? insets) { + return insets == null + ? null + : PlatformEdgeInsets( + top: insets.top, + bottom: insets.bottom, + left: insets.left, + right: insets.right, + ); +} + +PlatformMapConfiguration _platformMapConfigurationFromMapConfiguration( + MapConfiguration config, +) { + return PlatformMapConfiguration( + compassEnabled: config.compassEnabled, + cameraTargetBounds: _platformCameraTargetBoundsFromCameraTargetBounds( + config.cameraTargetBounds, + ), + mapType: _platformMapTypeFromMapType(config.mapType), + minMaxZoomPreference: _platformZoomRangeFromMinMaxZoomPreference( + config.minMaxZoomPreference, + ), + rotateGesturesEnabled: config.rotateGesturesEnabled, + scrollGesturesEnabled: config.scrollGesturesEnabled, + tiltGesturesEnabled: config.tiltGesturesEnabled, + trackCameraPosition: config.trackCameraPosition, + zoomGesturesEnabled: config.zoomGesturesEnabled, + myLocationEnabled: config.myLocationEnabled, + myLocationButtonEnabled: config.myLocationButtonEnabled, + padding: _platformEdgeInsetsFromEdgeInsets(config.padding), + indoorViewEnabled: config.indoorViewEnabled, + trafficEnabled: config.trafficEnabled, + buildingsEnabled: config.buildingsEnabled, + mapId: config.mapId, + style: config.style, + ); +} + +// For supporting the deprecated updateMapOptions API. +PlatformMapConfiguration _platformMapConfigurationFromOptionsJson( + Map options, +) { + // All of these hard-coded values and structures come from + // google_maps_flutter_platform_interface/lib/src/types/utils/map_configuration_serialization.dart + // to support this legacy API that relied on cross-package magic strings. + final List? padding = (options['padding'] as List?) + ?.cast(); + final mapType = options['mapType'] as int?; + return PlatformMapConfiguration( + compassEnabled: options['compassEnabled'] as bool?, + cameraTargetBounds: _platformCameraTargetBoundsFromCameraTargetBoundsJson( + options['cameraTargetBounds'], + ), + mapType: mapType == null ? null : _platformMapTypeFromMapTypeIndex(mapType), + minMaxZoomPreference: _platformZoomRangeFromMinMaxZoomPreferenceJson( + options['minMaxZoomPreference'], + ), + rotateGesturesEnabled: options['rotateGesturesEnabled'] as bool?, + scrollGesturesEnabled: options['scrollGesturesEnabled'] as bool?, + tiltGesturesEnabled: options['tiltGesturesEnabled'] as bool?, + trackCameraPosition: options['trackCameraPosition'] as bool?, + zoomGesturesEnabled: options['zoomGesturesEnabled'] as bool?, + myLocationEnabled: options['myLocationEnabled'] as bool?, + myLocationButtonEnabled: options['myLocationButtonEnabled'] as bool?, + padding: padding == null + ? null + : PlatformEdgeInsets( + top: padding[0], + left: padding[1], + bottom: padding[2], + right: padding[3], + ), + indoorViewEnabled: options['indoorEnabled'] as bool?, + trafficEnabled: options['trafficEnabled'] as bool?, + buildingsEnabled: options['buildingsEnabled'] as bool?, + mapId: options['cloudMapId'] as String?, + style: options['style'] as String?, + ); +} + +PlatformCameraPosition _platformCameraPositionFromCameraPosition( + CameraPosition position, +) { + return PlatformCameraPosition( + bearing: position.bearing, + target: _platformLatLngFromLatLng(position.target), + tilt: position.tilt, + zoom: position.zoom, + ); +} + +PlatformMapType _platformMapTypeFromMapTypeIndex(int index) { + // This is inherently fragile, but see comment in updateMapOptions. + return switch (index) { + 0 => PlatformMapType.none, + 1 => PlatformMapType.normal, + 2 => PlatformMapType.satellite, + 3 => PlatformMapType.terrain, + 4 => PlatformMapType.hybrid, + // For a new, unsupported type, just use normal. + _ => PlatformMapType.normal, + }; +} + +PlatformLatLng _platformLatLngFromLatLngJson(Object latLngJson) { + // See `LatLng.toJson`. + final List list = (latLngJson as List).cast(); + return PlatformLatLng(latitude: list[0], longitude: list[1]); +} + +PlatformLatLngBounds? _platformLatLngBoundsFromLatLngBoundsJson( + Object? boundsJson, +) { + if (boundsJson == null) { + return null; + } + // See `LatLngBounds.toJson`. + final List boundsList = (boundsJson as List).cast(); + return PlatformLatLngBounds( + southwest: _platformLatLngFromLatLngJson(boundsList[0]), + northeast: _platformLatLngFromLatLngJson(boundsList[1]), + ); +} + +PlatformCameraTargetBounds? +_platformCameraTargetBoundsFromCameraTargetBoundsJson(Object? targetJson) { + if (targetJson == null) { + return null; + } + // See `CameraTargetBounds.toJson`. + return PlatformCameraTargetBounds( + bounds: _platformLatLngBoundsFromLatLngBoundsJson( + (targetJson as List)[0], + ), + ); +} + +PlatformZoomRange? _platformZoomRangeFromMinMaxZoomPreferenceJson( + Object? zoomPrefsJson, +) { + if (zoomPrefsJson == null) { + return null; + } + // See `MinMaxZoomPreference.toJson`. + final List minMaxZoom = (zoomPrefsJson as List) + .cast(); + return PlatformZoomRange(min: minMaxZoom[0], max: minMaxZoom[1]); +} + +/// Converts platform interface's JointType to Pigeon's PlatformJointType. +@visibleForTesting +PlatformJointType platformJointTypeFromJointType(JointType jointType) { + switch (jointType) { + case JointType.mitered: + return PlatformJointType.mitered; + case JointType.bevel: + return PlatformJointType.bevel; + case JointType.round: + return PlatformJointType.round; + } + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformJointType.mitered; +} + +/// Converts a PatternItem to Pigeon's PlatformPatternItem for PlatformPolyline +/// pattern member. +@visibleForTesting +PlatformPatternItem platformPatternItemFromPatternItem(PatternItem item) { + switch (item.type) { + case PatternItemType.dot: + return PlatformPatternItem(type: PlatformPatternItemType.dot); + case PatternItemType.dash: + final double length = (item as VariableLengthPatternItem).length; + return PlatformPatternItem( + type: PlatformPatternItemType.dash, + length: length, + ); + case PatternItemType.gap: + final double length = (item as VariableLengthPatternItem).length; + return PlatformPatternItem( + type: PlatformPatternItemType.gap, + length: length, + ); + } + + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformPatternItem(type: PlatformPatternItemType.dot); +} + +/// Update specification for a set of [TileOverlay]s. +// TODO(stuartmorgan): Fix the missing export of this class in the platform +// interface, and remove this copy. +class _TileOverlayUpdates extends MapsObjectUpdates { + /// Computes [TileOverlayUpdates] given previous and current [TileOverlay]s. + _TileOverlayUpdates.from(super.previous, super.current) + : super.from(objectName: 'tileOverlay'); + + /// Set of TileOverlays to be added in this update. + Set get tileOverlaysToAdd => objectsToAdd; + + /// Set of TileOverlayIds to be removed in this update. + Set get tileOverlayIdsToRemove => + objectIdsToRemove.cast(); + + /// Set of TileOverlays to be changed in this update. + Set get tileOverlaysToChange => objectsToChange; +} 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 new file mode 100644 index 000000000000..bd54d5f62322 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/lib/src/messages.g.dart @@ -0,0 +1,4311 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, omit_obvious_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +List wrapResponse({ + Object? result, + PlatformException? error, + bool empty = false, +}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [error.code, error.message, error.details]; +} + +bool _deepEquals(Object? a, Object? b) { + if (a is List && b is List) { + return a.length == b.length && + a.indexed.every( + ((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), + ); + } + if (a is Map && b is Map) { + return a.length == b.length && + a.entries.every( + (MapEntry entry) => + (b as Map).containsKey(entry.key) && + _deepEquals(entry.value, b[entry.key]), + ); + } + return a == b; +} + +/// Pigeon equivalent of MapType +enum PlatformMapType { none, normal, satellite, terrain, hybrid } + +/// Join types for polyline joints. +enum PlatformJointType { mitered, bevel, round } + +/// Enumeration of possible types for PatternItem. +enum PlatformPatternItemType { dot, dash, gap } + +/// Pigeon equivalent of [MapBitmapScaling]. +enum PlatformMapBitmapScaling { auto, none } + +/// Pigeon representatation of a CameraPosition. +class PlatformCameraPosition { + PlatformCameraPosition({ + required this.bearing, + required this.target, + required this.tilt, + required this.zoom, + }); + + double bearing; + + PlatformLatLng target; + + double tilt; + + double zoom; + + List _toList() { + return [bearing, target, tilt, zoom]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraPosition decode(Object result) { + result as List; + return PlatformCameraPosition( + bearing: result[0]! as double, + target: result[1]! as PlatformLatLng, + tilt: result[2]! as double, + zoom: result[3]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraPosition || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate({required this.cameraUpdate}); + + /// This Object must be one of the classes below prefixed with + /// PlatformCameraUpdate. Each such class represents a different type of + /// camera update, and each holds a different set of data, preventing the + /// use of a single unified class. + Object cameraUpdate; + + List _toList() { + return [cameraUpdate]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdate decode(Object result) { + result as List; + return PlatformCameraUpdate(cameraUpdate: result[0]!); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdate || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewCameraPosition +class PlatformCameraUpdateNewCameraPosition { + PlatformCameraUpdateNewCameraPosition({required this.cameraPosition}); + + PlatformCameraPosition cameraPosition; + + List _toList() { + return [cameraPosition]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewCameraPosition decode(Object result) { + result as List; + return PlatformCameraUpdateNewCameraPosition( + cameraPosition: result[0]! as PlatformCameraPosition, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewCameraPosition || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewLatLng +class PlatformCameraUpdateNewLatLng { + PlatformCameraUpdateNewLatLng({required this.latLng}); + + PlatformLatLng latLng; + + List _toList() { + return [latLng]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewLatLng decode(Object result) { + result as List; + return PlatformCameraUpdateNewLatLng(latLng: result[0]! as PlatformLatLng); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewLatLng || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewLatLngBounds +class PlatformCameraUpdateNewLatLngBounds { + PlatformCameraUpdateNewLatLngBounds({ + required this.bounds, + required this.padding, + }); + + PlatformLatLngBounds bounds; + + double padding; + + List _toList() { + return [bounds, padding]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewLatLngBounds decode(Object result) { + result as List; + return PlatformCameraUpdateNewLatLngBounds( + bounds: result[0]! as PlatformLatLngBounds, + padding: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewLatLngBounds || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewLatLngZoom +class PlatformCameraUpdateNewLatLngZoom { + PlatformCameraUpdateNewLatLngZoom({required this.latLng, required this.zoom}); + + PlatformLatLng latLng; + + double zoom; + + List _toList() { + return [latLng, zoom]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewLatLngZoom decode(Object result) { + result as List; + return PlatformCameraUpdateNewLatLngZoom( + latLng: result[0]! as PlatformLatLng, + zoom: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewLatLngZoom || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ScrollBy +class PlatformCameraUpdateScrollBy { + PlatformCameraUpdateScrollBy({required this.dx, required this.dy}); + + double dx; + + double dy; + + List _toList() { + return [dx, dy]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateScrollBy decode(Object result) { + result as List; + return PlatformCameraUpdateScrollBy( + dx: result[0]! as double, + dy: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateScrollBy || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ZoomBy +class PlatformCameraUpdateZoomBy { + PlatformCameraUpdateZoomBy({required this.amount, this.focus}); + + double amount; + + PlatformPoint? focus; + + List _toList() { + return [amount, focus]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateZoomBy decode(Object result) { + result as List; + return PlatformCameraUpdateZoomBy( + amount: result[0]! as double, + focus: result[1] as PlatformPoint?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateZoomBy || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ZoomIn/ZoomOut +class PlatformCameraUpdateZoom { + PlatformCameraUpdateZoom({required this.out}); + + bool out; + + List _toList() { + return [out]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateZoom decode(Object result) { + result as List; + return PlatformCameraUpdateZoom(out: result[0]! as bool); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateZoom || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ZoomTo +class PlatformCameraUpdateZoomTo { + PlatformCameraUpdateZoomTo({required this.zoom}); + + double zoom; + + List _toList() { + return [zoom]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateZoomTo decode(Object result) { + result as List; + return PlatformCameraUpdateZoomTo(zoom: result[0]! as double); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateZoomTo || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle({ + this.consumeTapEvents = false, + required this.fillColor, + required this.strokeColor, + this.visible = true, + this.strokeWidth = 10, + this.zIndex = 0.0, + required this.center, + this.radius = 0, + required this.circleId, + }); + + bool consumeTapEvents; + + PlatformColor fillColor; + + PlatformColor strokeColor; + + bool visible; + + int strokeWidth; + + double zIndex; + + PlatformLatLng center; + + double radius; + + String circleId; + + List _toList() { + return [ + consumeTapEvents, + fillColor, + strokeColor, + visible, + strokeWidth, + zIndex, + center, + radius, + circleId, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformCircle decode(Object result) { + result as List; + return PlatformCircle( + consumeTapEvents: result[0]! as bool, + fillColor: result[1]! as PlatformColor, + strokeColor: result[2]! as PlatformColor, + visible: result[3]! as bool, + strokeWidth: result[4]! as int, + zIndex: result[5]! as double, + center: result[6]! as PlatformLatLng, + radius: result[7]! as double, + circleId: result[8]! as String, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCircle || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Heatmap class. +class PlatformHeatmap { + PlatformHeatmap({ + required this.heatmapId, + required this.data, + this.gradient, + required this.opacity, + required this.radius, + required this.minimumZoomIntensity, + required this.maximumZoomIntensity, + }); + + String heatmapId; + + List data; + + PlatformHeatmapGradient? gradient; + + double opacity; + + int radius; + + int minimumZoomIntensity; + + int maximumZoomIntensity; + + List _toList() { + return [ + heatmapId, + data, + gradient, + opacity, + radius, + minimumZoomIntensity, + maximumZoomIntensity, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformHeatmap decode(Object result) { + result as List; + return PlatformHeatmap( + heatmapId: result[0]! as String, + data: (result[1] as List?)!.cast(), + gradient: result[2] as PlatformHeatmapGradient?, + opacity: result[3]! as double, + radius: result[4]! as int, + minimumZoomIntensity: result[5]! as int, + maximumZoomIntensity: result[6]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformHeatmap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the HeatmapGradient class. +/// +/// The GMUGradient structure is slightly different from HeatmapGradient, so +/// this matches the iOS API so that conversion can be done on the Dart side +/// where the structures are easier to work with. +class PlatformHeatmapGradient { + PlatformHeatmapGradient({ + required this.colors, + required this.startPoints, + required this.colorMapSize, + }); + + List colors; + + List startPoints; + + int colorMapSize; + + List _toList() { + return [colors, startPoints, colorMapSize]; + } + + Object encode() { + return _toList(); + } + + static PlatformHeatmapGradient decode(Object result) { + result as List; + return PlatformHeatmapGradient( + colors: (result[0] as List?)!.cast(), + startPoints: (result[1] as List?)!.cast(), + colorMapSize: result[2]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformHeatmapGradient || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the WeightedLatLng class. +class PlatformWeightedLatLng { + PlatformWeightedLatLng({required this.point, required this.weight}); + + PlatformLatLng point; + + double weight; + + List _toList() { + return [point, weight]; + } + + Object encode() { + return _toList(); + } + + static PlatformWeightedLatLng decode(Object result) { + result as List; + return PlatformWeightedLatLng( + point: result[0]! as PlatformLatLng, + weight: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformWeightedLatLng || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the InfoWindow class. +class PlatformInfoWindow { + PlatformInfoWindow({this.title, this.snippet, required this.anchor}); + + String? title; + + String? snippet; + + PlatformPoint anchor; + + List _toList() { + return [title, snippet, anchor]; + } + + Object encode() { + return _toList(); + } + + static PlatformInfoWindow decode(Object result) { + result as List; + return PlatformInfoWindow( + title: result[0] as String?, + snippet: result[1] as String?, + anchor: result[2]! as PlatformPoint, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformInfoWindow || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of Cluster. +class PlatformCluster { + PlatformCluster({ + required this.clusterManagerId, + required this.position, + required this.bounds, + required this.markerIds, + }); + + String clusterManagerId; + + PlatformLatLng position; + + PlatformLatLngBounds bounds; + + List markerIds; + + List _toList() { + return [clusterManagerId, position, bounds, markerIds]; + } + + Object encode() { + return _toList(); + } + + static PlatformCluster decode(Object result) { + result as List; + return PlatformCluster( + clusterManagerId: result[0]! as String, + position: result[1]! as PlatformLatLng, + bounds: result[2]! as PlatformLatLngBounds, + markerIds: (result[3] as List?)!.cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCluster || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({required this.identifier}); + + String identifier; + + List _toList() { + return [identifier]; + } + + Object encode() { + return _toList(); + } + + static PlatformClusterManager decode(Object result) { + result as List; + return PlatformClusterManager(identifier: result[0]! as String); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformClusterManager || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker({ + this.alpha = 1.0, + required this.anchor, + this.consumeTapEvents = false, + this.draggable = false, + this.flat = false, + required this.icon, + required this.infoWindow, + required this.position, + this.rotation = 0.0, + this.visible = true, + this.zIndex = 0, + required this.markerId, + this.clusterManagerId, + }); + + double alpha; + + PlatformPoint anchor; + + bool consumeTapEvents; + + bool draggable; + + bool flat; + + PlatformBitmap icon; + + PlatformInfoWindow infoWindow; + + PlatformLatLng position; + + double rotation; + + bool visible; + + int zIndex; + + String markerId; + + String? clusterManagerId; + + List _toList() { + return [ + alpha, + anchor, + consumeTapEvents, + draggable, + flat, + icon, + infoWindow, + position, + rotation, + visible, + zIndex, + markerId, + clusterManagerId, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformMarker decode(Object result) { + result as List; + return PlatformMarker( + alpha: result[0]! as double, + anchor: result[1]! as PlatformPoint, + consumeTapEvents: result[2]! as bool, + draggable: result[3]! as bool, + flat: result[4]! as bool, + icon: result[5]! as PlatformBitmap, + infoWindow: result[6]! as PlatformInfoWindow, + position: result[7]! as PlatformLatLng, + rotation: result[8]! as double, + visible: result[9]! as bool, + zIndex: result[10]! as int, + markerId: result[11]! as String, + clusterManagerId: result[12] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformMarker || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon({ + required this.polygonId, + required this.consumesTapEvents, + required this.fillColor, + required this.geodesic, + required this.points, + required this.holes, + required this.visible, + required this.strokeColor, + required this.strokeWidth, + required this.zIndex, + }); + + String polygonId; + + bool consumesTapEvents; + + PlatformColor fillColor; + + bool geodesic; + + List points; + + List> holes; + + bool visible; + + PlatformColor strokeColor; + + int strokeWidth; + + int zIndex; + + List _toList() { + return [ + polygonId, + consumesTapEvents, + fillColor, + geodesic, + points, + holes, + visible, + strokeColor, + strokeWidth, + zIndex, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformPolygon decode(Object result) { + result as List; + return PlatformPolygon( + polygonId: result[0]! as String, + consumesTapEvents: result[1]! as bool, + fillColor: result[2]! as PlatformColor, + geodesic: result[3]! as bool, + points: (result[4] as List?)!.cast(), + holes: (result[5] as List?)!.cast>(), + visible: result[6]! as bool, + strokeColor: result[7]! as PlatformColor, + strokeWidth: result[8]! as int, + zIndex: result[9]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPolygon || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline({ + required this.polylineId, + required this.consumesTapEvents, + required this.color, + required this.geodesic, + required this.jointType, + required this.patterns, + required this.points, + required this.visible, + required this.width, + required this.zIndex, + }); + + String polylineId; + + bool consumesTapEvents; + + PlatformColor color; + + bool geodesic; + + /// The joint type. + PlatformJointType jointType; + + /// The pattern data, as a list of pattern items. + List patterns; + + List points; + + bool visible; + + int width; + + int zIndex; + + List _toList() { + return [ + polylineId, + consumesTapEvents, + color, + geodesic, + jointType, + patterns, + points, + visible, + width, + zIndex, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformPolyline decode(Object result) { + result as List; + return PlatformPolyline( + polylineId: result[0]! as String, + consumesTapEvents: result[1]! as bool, + color: result[2]! as PlatformColor, + geodesic: result[3]! as bool, + jointType: result[4]! as PlatformJointType, + patterns: (result[5] as List?)!.cast(), + points: (result[6] as List?)!.cast(), + visible: result[7]! as bool, + width: result[8]! as int, + zIndex: result[9]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPolyline || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the PatternItem class. +class PlatformPatternItem { + PlatformPatternItem({required this.type, this.length}); + + PlatformPatternItemType type; + + double? length; + + List _toList() { + return [type, length]; + } + + Object encode() { + return _toList(); + } + + static PlatformPatternItem decode(Object result) { + result as List; + return PlatformPatternItem( + type: result[0]! as PlatformPatternItemType, + length: result[1] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPatternItem || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Tile class. +class PlatformTile { + PlatformTile({required this.width, required this.height, this.data}); + + int width; + + int height; + + Uint8List? data; + + List _toList() { + return [width, height, data]; + } + + Object encode() { + return _toList(); + } + + static PlatformTile decode(Object result) { + result as List; + return PlatformTile( + width: result[0]! as int, + height: result[1]! as int, + data: result[2] as Uint8List?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTile || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay({ + required this.tileOverlayId, + required this.fadeIn, + required this.transparency, + required this.zIndex, + required this.visible, + required this.tileSize, + }); + + String tileOverlayId; + + bool fadeIn; + + double transparency; + + int zIndex; + + bool visible; + + int tileSize; + + List _toList() { + return [ + tileOverlayId, + fadeIn, + transparency, + zIndex, + visible, + tileSize, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformTileOverlay decode(Object result) { + result as List; + return PlatformTileOverlay( + tileOverlayId: result[0]! as String, + fadeIn: result[1]! as bool, + transparency: result[2]! as double, + zIndex: result[3]! as int, + visible: result[4]! as bool, + tileSize: result[5]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTileOverlay || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of Flutter's EdgeInsets. +class PlatformEdgeInsets { + PlatformEdgeInsets({ + required this.top, + required this.bottom, + required this.left, + required this.right, + }); + + double top; + + double bottom; + + double left; + + double right; + + List _toList() { + return [top, bottom, left, right]; + } + + Object encode() { + return _toList(); + } + + static PlatformEdgeInsets decode(Object result) { + result as List; + return PlatformEdgeInsets( + top: result[0]! as double, + bottom: result[1]! as double, + left: result[2]! as double, + right: result[3]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformEdgeInsets || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of LatLng. +class PlatformLatLng { + PlatformLatLng({required this.latitude, required this.longitude}); + + double latitude; + + double longitude; + + List _toList() { + return [latitude, longitude]; + } + + Object encode() { + return _toList(); + } + + static PlatformLatLng decode(Object result) { + result as List; + return PlatformLatLng( + latitude: result[0]! as double, + longitude: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformLatLng || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of LatLngBounds. +class PlatformLatLngBounds { + PlatformLatLngBounds({required this.northeast, required this.southwest}); + + PlatformLatLng northeast; + + PlatformLatLng southwest; + + List _toList() { + return [northeast, southwest]; + } + + Object encode() { + return _toList(); + } + + static PlatformLatLngBounds decode(Object result) { + result as List; + return PlatformLatLngBounds( + northeast: result[0]! as PlatformLatLng, + southwest: result[1]! as PlatformLatLng, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformLatLngBounds || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of CameraTargetBounds. +/// +/// As with the Dart version, it exists to distinguish between not setting a +/// a target, and having an explicitly unbounded target (null [bounds]). +class PlatformCameraTargetBounds { + PlatformCameraTargetBounds({this.bounds}); + + PlatformLatLngBounds? bounds; + + List _toList() { + return [bounds]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraTargetBounds decode(Object result) { + result as List; + return PlatformCameraTargetBounds( + bounds: result[0] as PlatformLatLngBounds?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraTargetBounds || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the GroundOverlay class. +class PlatformGroundOverlay { + PlatformGroundOverlay({ + required this.groundOverlayId, + required this.image, + this.position, + this.bounds, + this.anchor, + required this.transparency, + required this.bearing, + required this.zIndex, + required this.visible, + required this.clickable, + this.zoomLevel, + }); + + String groundOverlayId; + + PlatformBitmap image; + + PlatformLatLng? position; + + PlatformLatLngBounds? bounds; + + PlatformPoint? anchor; + + double transparency; + + double bearing; + + int zIndex; + + bool visible; + + bool clickable; + + double? zoomLevel; + + List _toList() { + return [ + groundOverlayId, + image, + position, + bounds, + anchor, + transparency, + bearing, + zIndex, + visible, + clickable, + zoomLevel, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformGroundOverlay decode(Object result) { + result as List; + return PlatformGroundOverlay( + groundOverlayId: result[0]! as String, + image: result[1]! as PlatformBitmap, + position: result[2] as PlatformLatLng?, + bounds: result[3] as PlatformLatLngBounds?, + anchor: result[4] as PlatformPoint?, + transparency: result[5]! as double, + bearing: result[6]! as double, + zIndex: result[7]! as int, + visible: result[8]! as bool, + clickable: result[9]! as bool, + zoomLevel: result[10] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformGroundOverlay || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Information passed to the platform view creation. +class PlatformMapViewCreationParams { + PlatformMapViewCreationParams({ + required this.initialCameraPosition, + required this.mapConfiguration, + required this.initialCircles, + required this.initialMarkers, + required this.initialPolygons, + required this.initialPolylines, + required this.initialHeatmaps, + required this.initialTileOverlays, + required this.initialClusterManagers, + required this.initialGroundOverlays, + }); + + PlatformCameraPosition initialCameraPosition; + + PlatformMapConfiguration mapConfiguration; + + List initialCircles; + + List initialMarkers; + + List initialPolygons; + + List initialPolylines; + + List initialHeatmaps; + + List initialTileOverlays; + + List initialClusterManagers; + + List initialGroundOverlays; + + List _toList() { + return [ + initialCameraPosition, + mapConfiguration, + initialCircles, + initialMarkers, + initialPolygons, + initialPolylines, + initialHeatmaps, + initialTileOverlays, + initialClusterManagers, + initialGroundOverlays, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformMapViewCreationParams decode(Object result) { + result as List; + return PlatformMapViewCreationParams( + initialCameraPosition: result[0]! as PlatformCameraPosition, + mapConfiguration: result[1]! as PlatformMapConfiguration, + initialCircles: (result[2] as List?)!.cast(), + initialMarkers: (result[3] as List?)!.cast(), + initialPolygons: (result[4] as List?)!.cast(), + initialPolylines: (result[5] as List?)!.cast(), + initialHeatmaps: (result[6] as List?)!.cast(), + initialTileOverlays: (result[7] as List?)! + .cast(), + initialClusterManagers: (result[8] as List?)! + .cast(), + initialGroundOverlays: (result[9] as List?)! + .cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformMapViewCreationParams || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({ + this.compassEnabled, + this.cameraTargetBounds, + this.mapType, + this.minMaxZoomPreference, + this.rotateGesturesEnabled, + this.scrollGesturesEnabled, + this.tiltGesturesEnabled, + this.trackCameraPosition, + this.zoomGesturesEnabled, + this.myLocationEnabled, + this.myLocationButtonEnabled, + this.padding, + this.indoorViewEnabled, + this.trafficEnabled, + this.buildingsEnabled, + this.mapId, + this.style, + }); + + bool? compassEnabled; + + PlatformCameraTargetBounds? cameraTargetBounds; + + PlatformMapType? mapType; + + PlatformZoomRange? minMaxZoomPreference; + + bool? rotateGesturesEnabled; + + bool? scrollGesturesEnabled; + + bool? tiltGesturesEnabled; + + bool? trackCameraPosition; + + bool? zoomGesturesEnabled; + + bool? myLocationEnabled; + + bool? myLocationButtonEnabled; + + PlatformEdgeInsets? padding; + + bool? indoorViewEnabled; + + bool? trafficEnabled; + + bool? buildingsEnabled; + + String? mapId; + + String? style; + + List _toList() { + return [ + compassEnabled, + cameraTargetBounds, + mapType, + minMaxZoomPreference, + rotateGesturesEnabled, + scrollGesturesEnabled, + tiltGesturesEnabled, + trackCameraPosition, + zoomGesturesEnabled, + myLocationEnabled, + myLocationButtonEnabled, + padding, + indoorViewEnabled, + trafficEnabled, + buildingsEnabled, + mapId, + style, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformMapConfiguration decode(Object result) { + result as List; + return PlatformMapConfiguration( + compassEnabled: result[0] as bool?, + cameraTargetBounds: result[1] as PlatformCameraTargetBounds?, + mapType: result[2] as PlatformMapType?, + minMaxZoomPreference: result[3] as PlatformZoomRange?, + rotateGesturesEnabled: result[4] as bool?, + scrollGesturesEnabled: result[5] as bool?, + tiltGesturesEnabled: result[6] as bool?, + trackCameraPosition: result[7] as bool?, + zoomGesturesEnabled: result[8] as bool?, + myLocationEnabled: result[9] as bool?, + myLocationButtonEnabled: result[10] as bool?, + padding: result[11] as PlatformEdgeInsets?, + indoorViewEnabled: result[12] as bool?, + trafficEnabled: result[13] as bool?, + buildingsEnabled: result[14] as bool?, + mapId: result[15] as String?, + style: result[16] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformMapConfiguration || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of an x,y coordinate. +class PlatformPoint { + PlatformPoint({required this.x, required this.y}); + + double x; + + double y; + + List _toList() { + return [x, y]; + } + + Object encode() { + return _toList(); + } + + static PlatformPoint decode(Object result) { + result as List; + return PlatformPoint(x: result[0]! as double, y: result[1]! as double); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPoint || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of a size. +class PlatformSize { + PlatformSize({required this.width, required this.height}); + + double width; + + double height; + + List _toList() { + return [width, height]; + } + + Object encode() { + return _toList(); + } + + static PlatformSize decode(Object result) { + result as List; + return PlatformSize( + width: result[0]! as double, + height: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformSize || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of a color. +class PlatformColor { + PlatformColor({ + required this.red, + required this.green, + required this.blue, + required this.alpha, + }); + + double red; + + double green; + + double blue; + + double alpha; + + List _toList() { + return [red, green, blue, alpha]; + } + + Object encode() { + return _toList(); + } + + static PlatformColor decode(Object result) { + result as List; + return PlatformColor( + red: result[0]! as double, + green: result[1]! as double, + blue: result[2]! as double, + alpha: result[3]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformColor || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of GMSTileLayer properties. +class PlatformTileLayer { + PlatformTileLayer({ + required this.visible, + required this.fadeIn, + required this.opacity, + required this.zIndex, + }); + + bool visible; + + bool fadeIn; + + double opacity; + + int zIndex; + + List _toList() { + return [visible, fadeIn, opacity, zIndex]; + } + + Object encode() { + return _toList(); + } + + static PlatformTileLayer decode(Object result) { + result as List; + return PlatformTileLayer( + visible: result[0]! as bool, + fadeIn: result[1]! as bool, + opacity: result[2]! as double, + zIndex: result[3]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTileLayer || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of MinMaxZoomPreference. +class PlatformZoomRange { + PlatformZoomRange({this.min, this.max}); + + double? min; + + double? max; + + List _toList() { + return [min, max]; + } + + Object encode() { + return _toList(); + } + + static PlatformZoomRange decode(Object result) { + result as List; + return PlatformZoomRange( + min: result[0] as double?, + max: result[1] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformZoomRange || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [BitmapDescriptor]. As there are multiple disjoint +/// types of [BitmapDescriptor], [PlatformBitmap] contains a single field which +/// may hold the pigeon equivalent type of any of them. +class PlatformBitmap { + PlatformBitmap({required this.bitmap}); + + /// One of [PlatformBitmapAssetMap], [PlatformBitmapAsset], + /// [PlatformBitmapAssetImage], [PlatformBitmapBytesMap], + /// [PlatformBitmapBytes], or [PlatformBitmapDefaultMarker]. + /// As Pigeon does not currently support data class inheritance, this + /// approach allows for the different bitmap implementations to be valid + /// argument and return types of the API methods. See + /// https://github.com/flutter/flutter/issues/117819. + Object bitmap; + + List _toList() { + return [bitmap]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmap decode(Object result) { + result as List; + return PlatformBitmap(bitmap: result[0]!); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [DefaultMarker]. +class PlatformBitmapDefaultMarker { + PlatformBitmapDefaultMarker({this.hue}); + + double? hue; + + List _toList() { + return [hue]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapDefaultMarker decode(Object result) { + result as List; + return PlatformBitmapDefaultMarker(hue: result[0] as double?); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapDefaultMarker || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [BytesBitmap]. +class PlatformBitmapBytes { + PlatformBitmapBytes({required this.byteData, this.size}); + + Uint8List byteData; + + PlatformSize? size; + + List _toList() { + return [byteData, size]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapBytes decode(Object result) { + result as List; + return PlatformBitmapBytes( + byteData: result[0]! as Uint8List, + size: result[1] as PlatformSize?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapBytes || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [AssetBitmap]. +class PlatformBitmapAsset { + PlatformBitmapAsset({required this.name, this.pkg}); + + String name; + + String? pkg; + + List _toList() { + return [name, pkg]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapAsset decode(Object result) { + result as List; + return PlatformBitmapAsset( + name: result[0]! as String, + pkg: result[1] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapAsset || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [AssetImageBitmap]. +class PlatformBitmapAssetImage { + PlatformBitmapAssetImage({ + required this.name, + required this.scale, + this.size, + }); + + String name; + + double scale; + + PlatformSize? size; + + List _toList() { + return [name, scale, size]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapAssetImage decode(Object result) { + result as List; + return PlatformBitmapAssetImage( + name: result[0]! as String, + scale: result[1]! as double, + size: result[2] as PlatformSize?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapAssetImage || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [AssetMapBitmap]. +class PlatformBitmapAssetMap { + PlatformBitmapAssetMap({ + required this.assetName, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + + String assetName; + + PlatformMapBitmapScaling bitmapScaling; + + double imagePixelRatio; + + double? width; + + double? height; + + List _toList() { + return [assetName, bitmapScaling, imagePixelRatio, width, height]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapAssetMap decode(Object result) { + result as List; + return PlatformBitmapAssetMap( + assetName: result[0]! as String, + bitmapScaling: result[1]! as PlatformMapBitmapScaling, + imagePixelRatio: result[2]! as double, + width: result[3] as double?, + height: result[4] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapAssetMap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [BytesMapBitmap]. +class PlatformBitmapBytesMap { + PlatformBitmapBytesMap({ + required this.byteData, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + + Uint8List byteData; + + PlatformMapBitmapScaling bitmapScaling; + + double imagePixelRatio; + + double? width; + + double? height; + + List _toList() { + return [byteData, bitmapScaling, imagePixelRatio, width, height]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapBytesMap decode(Object result) { + result as List; + return PlatformBitmapBytesMap( + byteData: result[0]! as Uint8List, + bitmapScaling: result[1]! as PlatformMapBitmapScaling, + imagePixelRatio: result[2]! as double, + width: result[3] as double?, + height: result[4] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapBytesMap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is PlatformMapType) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is PlatformJointType) { + buffer.putUint8(130); + writeValue(buffer, value.index); + } else if (value is PlatformPatternItemType) { + buffer.putUint8(131); + writeValue(buffer, value.index); + } else if (value is PlatformMapBitmapScaling) { + buffer.putUint8(132); + writeValue(buffer, value.index); + } else if (value is PlatformCameraPosition) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdate) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewCameraPosition) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewLatLng) { + buffer.putUint8(136); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewLatLngBounds) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewLatLngZoom) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateScrollBy) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateZoomBy) { + buffer.putUint8(140); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateZoom) { + buffer.putUint8(141); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateZoomTo) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); + } else if (value is PlatformCircle) { + buffer.putUint8(143); + writeValue(buffer, value.encode()); + } else if (value is PlatformHeatmap) { + buffer.putUint8(144); + writeValue(buffer, value.encode()); + } else if (value is PlatformHeatmapGradient) { + buffer.putUint8(145); + writeValue(buffer, value.encode()); + } else if (value is PlatformWeightedLatLng) { + buffer.putUint8(146); + writeValue(buffer, value.encode()); + } else if (value is PlatformInfoWindow) { + buffer.putUint8(147); + writeValue(buffer, value.encode()); + } else if (value is PlatformCluster) { + buffer.putUint8(148); + writeValue(buffer, value.encode()); + } else if (value is PlatformClusterManager) { + buffer.putUint8(149); + writeValue(buffer, value.encode()); + } else if (value is PlatformMarker) { + buffer.putUint8(150); + writeValue(buffer, value.encode()); + } else if (value is PlatformPolygon) { + buffer.putUint8(151); + writeValue(buffer, value.encode()); + } else if (value is PlatformPolyline) { + buffer.putUint8(152); + writeValue(buffer, value.encode()); + } else if (value is PlatformPatternItem) { + buffer.putUint8(153); + writeValue(buffer, value.encode()); + } else if (value is PlatformTile) { + buffer.putUint8(154); + writeValue(buffer, value.encode()); + } else if (value is PlatformTileOverlay) { + buffer.putUint8(155); + writeValue(buffer, value.encode()); + } else if (value is PlatformEdgeInsets) { + buffer.putUint8(156); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLng) { + buffer.putUint8(157); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLngBounds) { + buffer.putUint8(158); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraTargetBounds) { + buffer.putUint8(159); + writeValue(buffer, value.encode()); + } else if (value is PlatformGroundOverlay) { + buffer.putUint8(160); + writeValue(buffer, value.encode()); + } else if (value is PlatformMapViewCreationParams) { + buffer.putUint8(161); + writeValue(buffer, value.encode()); + } else if (value is PlatformMapConfiguration) { + buffer.putUint8(162); + writeValue(buffer, value.encode()); + } else if (value is PlatformPoint) { + buffer.putUint8(163); + writeValue(buffer, value.encode()); + } else if (value is PlatformSize) { + buffer.putUint8(164); + writeValue(buffer, value.encode()); + } else if (value is PlatformColor) { + buffer.putUint8(165); + writeValue(buffer, value.encode()); + } else if (value is PlatformTileLayer) { + buffer.putUint8(166); + writeValue(buffer, value.encode()); + } else if (value is PlatformZoomRange) { + buffer.putUint8(167); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmap) { + buffer.putUint8(168); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapDefaultMarker) { + buffer.putUint8(169); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapBytes) { + buffer.putUint8(170); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapAsset) { + buffer.putUint8(171); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapAssetImage) { + buffer.putUint8(172); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapAssetMap) { + buffer.putUint8(173); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapBytesMap) { + buffer.putUint8(174); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformMapType.values[value]; + case 130: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformJointType.values[value]; + case 131: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformPatternItemType.values[value]; + case 132: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformMapBitmapScaling.values[value]; + case 133: + return PlatformCameraPosition.decode(readValue(buffer)!); + case 134: + return PlatformCameraUpdate.decode(readValue(buffer)!); + case 135: + return PlatformCameraUpdateNewCameraPosition.decode(readValue(buffer)!); + case 136: + return PlatformCameraUpdateNewLatLng.decode(readValue(buffer)!); + case 137: + return PlatformCameraUpdateNewLatLngBounds.decode(readValue(buffer)!); + case 138: + return PlatformCameraUpdateNewLatLngZoom.decode(readValue(buffer)!); + case 139: + return PlatformCameraUpdateScrollBy.decode(readValue(buffer)!); + case 140: + return PlatformCameraUpdateZoomBy.decode(readValue(buffer)!); + case 141: + return PlatformCameraUpdateZoom.decode(readValue(buffer)!); + case 142: + return PlatformCameraUpdateZoomTo.decode(readValue(buffer)!); + case 143: + return PlatformCircle.decode(readValue(buffer)!); + case 144: + return PlatformHeatmap.decode(readValue(buffer)!); + case 145: + return PlatformHeatmapGradient.decode(readValue(buffer)!); + case 146: + return PlatformWeightedLatLng.decode(readValue(buffer)!); + case 147: + return PlatformInfoWindow.decode(readValue(buffer)!); + case 148: + return PlatformCluster.decode(readValue(buffer)!); + case 149: + return PlatformClusterManager.decode(readValue(buffer)!); + case 150: + return PlatformMarker.decode(readValue(buffer)!); + case 151: + return PlatformPolygon.decode(readValue(buffer)!); + case 152: + return PlatformPolyline.decode(readValue(buffer)!); + case 153: + return PlatformPatternItem.decode(readValue(buffer)!); + case 154: + return PlatformTile.decode(readValue(buffer)!); + case 155: + return PlatformTileOverlay.decode(readValue(buffer)!); + case 156: + return PlatformEdgeInsets.decode(readValue(buffer)!); + case 157: + return PlatformLatLng.decode(readValue(buffer)!); + case 158: + return PlatformLatLngBounds.decode(readValue(buffer)!); + case 159: + return PlatformCameraTargetBounds.decode(readValue(buffer)!); + case 160: + return PlatformGroundOverlay.decode(readValue(buffer)!); + case 161: + return PlatformMapViewCreationParams.decode(readValue(buffer)!); + case 162: + return PlatformMapConfiguration.decode(readValue(buffer)!); + case 163: + return PlatformPoint.decode(readValue(buffer)!); + case 164: + return PlatformSize.decode(readValue(buffer)!); + case 165: + return PlatformColor.decode(readValue(buffer)!); + case 166: + return PlatformTileLayer.decode(readValue(buffer)!); + case 167: + return PlatformZoomRange.decode(readValue(buffer)!); + case 168: + return PlatformBitmap.decode(readValue(buffer)!); + case 169: + return PlatformBitmapDefaultMarker.decode(readValue(buffer)!); + case 170: + return PlatformBitmapBytes.decode(readValue(buffer)!); + case 171: + return PlatformBitmapAsset.decode(readValue(buffer)!); + case 172: + return PlatformBitmapAssetImage.decode(readValue(buffer)!); + case 173: + return PlatformBitmapAssetMap.decode(readValue(buffer)!); + case 174: + return PlatformBitmapBytesMap.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// Interface for non-test interactions with the native SDK. +/// +/// For test-only state queries, see [MapsInspectorApi]. +class MapsApi { + /// Constructor for [MapsApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + /// Returns once the map instance is available. + Future waitForMap() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.waitForMap$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + Future updateMapConfiguration( + PlatformMapConfiguration configuration, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateMapConfiguration$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [configuration], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of circles on the map. + Future updateCircles( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateCircles$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of heatmaps on the map. + Future updateHeatmaps( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateHeatmaps$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of custer managers for clusters on the map. + Future updateClusterManagers( + List toAdd, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateClusterManagers$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of markers on the map. + Future updateMarkers( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateMarkers$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polygonss on the map. + Future updatePolygons( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updatePolygons$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polylines on the map. + Future updatePolylines( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updatePolylines$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of tile overlays on the map. + Future updateTileOverlays( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateTileOverlays$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of ground overlays on the map. + Future updateGroundOverlays( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateGroundOverlays$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Gets the screen coordinate for the given map location. + Future getScreenCoordinate(PlatformLatLng latLng) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getScreenCoordinate$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [latLng], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformPoint?)!; + } + } + + /// Gets the map location for the given screen coordinate. + Future getLatLng(PlatformPoint screenCoordinate) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getLatLng$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [screenCoordinate], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformLatLng?)!; + } + } + + /// Gets the map region currently displayed on the map. + Future getVisibleRegion() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getVisibleRegion$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformLatLngBounds?)!; + } + } + + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + Future moveCamera(PlatformCameraUpdate cameraUpdate) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.moveCamera$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [cameraUpdate], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Moves the camera according to [cameraUpdate], animating the update using a + /// duration in milliseconds if provided. + Future animateCamera( + PlatformCameraUpdate cameraUpdate, + int? durationMilliseconds, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.animateCamera$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [cameraUpdate, durationMilliseconds], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Gets the current map zoom level. + Future getZoomLevel() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getZoomLevel$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as double?)!; + } + } + + /// Show the info window for the marker with the given ID. + Future showInfoWindow(String markerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.showInfoWindow$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [markerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Hide the info window for the marker with the given ID. + Future hideInfoWindow(String markerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.hideInfoWindow$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [markerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Returns true if the marker with the given ID is currently displaying its + /// info window. + Future isInfoWindowShown(String markerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.isInfoWindowShown$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [markerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Sets the style to the given map style string, where an empty string + /// indicates that the style should be cleared. + /// + /// If there was an error setting the style, such as an invalid style string, + /// returns the error message. + Future setStyle(String style) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.setStyle$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [style], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Returns the error string from the last attempt to set the map style, if + /// any. + /// + /// This allows checking asynchronously for initial style failures, as there + /// is no way to return failures from map initialization. + Future getLastStyleError() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getLastStyleError$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Clears the cache of tiles previously requseted from the tile provider. + Future clearTileCache(String tileOverlayId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.clearTileCache$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [tileOverlayId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Takes a snapshot of the map and returns its image data. + Future takeSnapshot() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.takeSnapshot$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as Uint8List?); + } + } +} + +/// Interface for calls from the native SDK to Dart. +abstract class MapsCallbackApi { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + /// Called when the map camera starts moving. + void onCameraMoveStarted(); + + /// Called when the map camera moves. + void onCameraMove(PlatformCameraPosition cameraPosition); + + /// Called when the map camera stops moving. + void onCameraIdle(); + + /// Called when the map, not a specifc map object, is tapped. + void onTap(PlatformLatLng position); + + /// Called when the map, not a specifc map object, is long pressed. + void onLongPress(PlatformLatLng position); + + /// Called when a marker is tapped. + void onMarkerTap(String markerId); + + /// Called when a marker drag starts. + void onMarkerDragStart(String markerId, PlatformLatLng position); + + /// Called when a marker drag updates. + void onMarkerDrag(String markerId, PlatformLatLng position); + + /// Called when a marker drag ends. + void onMarkerDragEnd(String markerId, PlatformLatLng position); + + /// Called when a marker's info window is tapped. + void onInfoWindowTap(String markerId); + + /// Called when a circle is tapped. + void onCircleTap(String circleId); + + /// Called when a marker cluster is tapped. + void onClusterTap(PlatformCluster cluster); + + /// Called when a polygon is tapped. + void onPolygonTap(String polygonId); + + /// Called when a polyline is tapped. + void onPolylineTap(String polylineId); + + /// Called when a ground overlay is tapped. + void onGroundOverlayTap(String groundOverlayId); + + /// Called to get data for a map tile. + Future getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ); + + static void setUp( + MapsCallbackApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMoveStarted$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onCameraMoveStarted(); + 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.onCameraMove$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMove was null.', + ); + final List args = (message as List?)!; + final PlatformCameraPosition? arg_cameraPosition = + (args[0] as PlatformCameraPosition?); + assert( + arg_cameraPosition != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMove was null, expected non-null PlatformCameraPosition.', + ); + try { + api.onCameraMove(arg_cameraPosition!); + 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.onCameraIdle$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onCameraIdle(); + 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.onTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onTap was null.', + ); + final List args = (message as List?)!; + final PlatformLatLng? arg_position = (args[0] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onTap was null, expected non-null PlatformLatLng.', + ); + try { + api.onTap(arg_position!); + 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.onLongPress$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onLongPress was null.', + ); + final List args = (message as List?)!; + final PlatformLatLng? arg_position = (args[0] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onLongPress was null, expected non-null PlatformLatLng.', + ); + try { + api.onLongPress(arg_position!); + 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.onMarkerTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerTap was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerTap was null, expected non-null String.', + ); + try { + api.onMarkerTap(arg_markerId!); + 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.onMarkerDragStart$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart was null, expected non-null String.', + ); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart was null, expected non-null PlatformLatLng.', + ); + try { + api.onMarkerDragStart(arg_markerId!, arg_position!); + 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.onMarkerDrag$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag was null, expected non-null String.', + ); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag was null, expected non-null PlatformLatLng.', + ); + try { + api.onMarkerDrag(arg_markerId!, arg_position!); + 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.onMarkerDragEnd$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd was null, expected non-null String.', + ); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd was null, expected non-null PlatformLatLng.', + ); + try { + api.onMarkerDragEnd(arg_markerId!, arg_position!); + 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.onInfoWindowTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onInfoWindowTap was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onInfoWindowTap was null, expected non-null String.', + ); + try { + api.onInfoWindowTap(arg_markerId!); + 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.onCircleTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCircleTap was null.', + ); + final List args = (message as List?)!; + final String? arg_circleId = (args[0] as String?); + assert( + arg_circleId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCircleTap was null, expected non-null String.', + ); + try { + api.onCircleTap(arg_circleId!); + 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', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap was null.', + ); + final List args = (message as List?)!; + final PlatformCluster? arg_cluster = (args[0] as PlatformCluster?); + assert( + arg_cluster != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap was null, expected non-null PlatformCluster.', + ); + try { + api.onClusterTap(arg_cluster!); + 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.onPolygonTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolygonTap was null.', + ); + final List args = (message as List?)!; + final String? arg_polygonId = (args[0] as String?); + assert( + arg_polygonId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolygonTap was null, expected non-null String.', + ); + try { + api.onPolygonTap(arg_polygonId!); + 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.onPolylineTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolylineTap was null.', + ); + final List args = (message as List?)!; + final String? arg_polylineId = (args[0] as String?); + assert( + arg_polylineId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolylineTap was null, expected non-null String.', + ); + try { + api.onPolylineTap(arg_polylineId!); + 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.onGroundOverlayTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onGroundOverlayTap was null.', + ); + final List args = (message as List?)!; + final String? arg_groundOverlayId = (args[0] as String?); + assert( + arg_groundOverlayId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onGroundOverlayTap was null, expected non-null String.', + ); + try { + api.onGroundOverlayTap(arg_groundOverlayId!); + 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.getTileOverlayTile$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null.', + ); + final List args = (message as List?)!; + final String? arg_tileOverlayId = (args[0] as String?); + assert( + arg_tileOverlayId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null, expected non-null String.', + ); + final PlatformPoint? arg_location = (args[1] as PlatformPoint?); + assert( + arg_location != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null, expected non-null PlatformPoint.', + ); + final int? arg_zoom = (args[2] as int?); + assert( + arg_zoom != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null, expected non-null int.', + ); + try { + final PlatformTile output = await api.getTileOverlayTile( + arg_tileOverlayId!, + arg_location!, + arg_zoom!, + ); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString()), + ); + } + }); + } + } + } +} + +/// Dummy interface to force generation of the platform view creation params, +/// which are not used in any Pigeon calls, only the platform view creation +/// call made internally by Flutter. +class MapsPlatformViewApi { + /// Constructor for [MapsPlatformViewApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsPlatformViewApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future createView(PlatformMapViewCreationParams? type) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsPlatformViewApi.createView$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [type], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } +} + +/// Inspector API only intended for use in integration tests. +class MapsInspectorApi { + /// Constructor for [MapsInspectorApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsInspectorApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future areBuildingsEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areBuildingsEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areRotateGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areRotateGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areScrollGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areScrollGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areTiltGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areTiltGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areZoomGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areZoomGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future isCompassEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.isCompassEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future isMyLocationButtonEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.isMyLocationButtonEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future isTrafficEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.isTrafficEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future getTileOverlayInfo(String tileOverlayId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getTileOverlayInfo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [tileOverlayId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as PlatformTileLayer?); + } + } + + Future getGroundOverlayInfo( + String groundOverlayId, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getGroundOverlayInfo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [groundOverlayId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as PlatformGroundOverlay?); + } + } + + Future getHeatmapInfo(String heatmapId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getHeatmapInfo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [heatmapId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as PlatformHeatmap?); + } + } + + Future getZoomRange() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getZoomRange$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformZoomRange?)!; + } + } + + Future> getClusters(String clusterManagerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getClusters$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [clusterManagerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as List?)! + .cast(); + } + } + + Future getCameraPosition() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getCameraPosition$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformCameraPosition?)!; + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/copyright.txt b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/copyright.txt new file mode 100644 index 000000000000..07e5f8598a80 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/copyright.txt @@ -0,0 +1,3 @@ +Copyright 2013 The Flutter Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. 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 new file mode 100644 index 000000000000..50c2bee1fdcf --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pigeons/messages.dart @@ -0,0 +1,871 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + dartOut: 'lib/src/messages.g.dart', + // This uses a different output name to avoid conflicts with the pigeon + // files in other packages, without having to use full relative paths + // in #includes (which would make source sharing harder to manage). + objcHeaderOut: + 'ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h', + objcSourceOut: + 'ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m', + objcOptions: ObjcOptions(prefix: 'FGM'), + copyrightHeader: 'pigeons/copyright.txt', + // Use the base package name so that the generated code can be shared + // across the implementation copies. + dartPackageName: 'google_maps_flutter_ios', + ), +) +/// Pigeon equivalent of MapType +enum PlatformMapType { none, normal, satellite, terrain, hybrid } + +/// Pigeon representatation of a CameraPosition. +class PlatformCameraPosition { + PlatformCameraPosition({ + required this.bearing, + required this.target, + required this.tilt, + required this.zoom, + }); + + final double bearing; + final PlatformLatLng target; + final double tilt; + final double zoom; +} + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate(this.cameraUpdate); + + /// This Object must be one of the classes below prefixed with + /// PlatformCameraUpdate. Each such class represents a different type of + /// camera update, and each holds a different set of data, preventing the + /// use of a single unified class. + // Pigeon does not support inheritance, which prevents a more strict type + // bound. See https://github.com/flutter/flutter/issues/117819. + final Object cameraUpdate; +} + +/// Pigeon equivalent of NewCameraPosition +class PlatformCameraUpdateNewCameraPosition { + PlatformCameraUpdateNewCameraPosition(this.cameraPosition); + final PlatformCameraPosition cameraPosition; +} + +/// Pigeon equivalent of NewLatLng +class PlatformCameraUpdateNewLatLng { + PlatformCameraUpdateNewLatLng(this.latLng); + final PlatformLatLng latLng; +} + +/// Pigeon equivalent of NewLatLngBounds +class PlatformCameraUpdateNewLatLngBounds { + PlatformCameraUpdateNewLatLngBounds(this.bounds, this.padding); + final PlatformLatLngBounds bounds; + final double padding; +} + +/// Pigeon equivalent of NewLatLngZoom +class PlatformCameraUpdateNewLatLngZoom { + PlatformCameraUpdateNewLatLngZoom(this.latLng, this.zoom); + final PlatformLatLng latLng; + final double zoom; +} + +/// Pigeon equivalent of ScrollBy +class PlatformCameraUpdateScrollBy { + PlatformCameraUpdateScrollBy(this.dx, this.dy); + final double dx; + final double dy; +} + +/// Pigeon equivalent of ZoomBy +class PlatformCameraUpdateZoomBy { + PlatformCameraUpdateZoomBy(this.amount, [this.focus]); + final double amount; + final PlatformPoint? focus; +} + +/// Pigeon equivalent of ZoomIn/ZoomOut +class PlatformCameraUpdateZoom { + PlatformCameraUpdateZoom(this.out); + final bool out; +} + +/// Pigeon equivalent of ZoomTo +class PlatformCameraUpdateZoomTo { + PlatformCameraUpdateZoomTo(this.zoom); + final double zoom; +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle({ + required this.circleId, + required this.center, + required this.fillColor, + required this.strokeColor, + this.consumeTapEvents = false, + this.visible = true, + this.strokeWidth = 10, + this.zIndex = 0.0, + this.radius = 0, + }); + + final bool consumeTapEvents; + final PlatformColor fillColor; + final PlatformColor strokeColor; + final bool visible; + final int strokeWidth; + final double zIndex; + final PlatformLatLng center; + final double radius; + final String circleId; +} + +/// Pigeon equivalent of the Heatmap class. +class PlatformHeatmap { + PlatformHeatmap({ + required this.heatmapId, + required this.data, + this.gradient, + required this.opacity, + required this.radius, + required this.minimumZoomIntensity, + required this.maximumZoomIntensity, + }); + + final String heatmapId; + final List data; + final PlatformHeatmapGradient? gradient; + final double opacity; + final int radius; + final int minimumZoomIntensity; + final int maximumZoomIntensity; +} + +/// Pigeon equivalent of the HeatmapGradient class. +/// +/// The GMUGradient structure is slightly different from HeatmapGradient, so +/// this matches the iOS API so that conversion can be done on the Dart side +/// where the structures are easier to work with. +class PlatformHeatmapGradient { + PlatformHeatmapGradient({ + required this.colors, + required this.startPoints, + required this.colorMapSize, + }); + + final List colors; + final List startPoints; + final int colorMapSize; +} + +/// Pigeon equivalent of the WeightedLatLng class. +class PlatformWeightedLatLng { + PlatformWeightedLatLng({required this.point, required this.weight}); + + final PlatformLatLng point; + final double weight; +} + +/// Pigeon equivalent of the InfoWindow class. +class PlatformInfoWindow { + PlatformInfoWindow({required this.anchor, this.title, this.snippet}); + + final String? title; + final String? snippet; + final PlatformPoint anchor; +} + +/// Pigeon equivalent of Cluster. +class PlatformCluster { + PlatformCluster({ + required this.clusterManagerId, + required this.position, + required this.bounds, + required this.markerIds, + }); + + final String clusterManagerId; + final PlatformLatLng position; + final PlatformLatLngBounds bounds; + final List markerIds; +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({required this.identifier}); + + final String identifier; +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker({ + required this.markerId, + required this.icon, + this.alpha = 1.0, + required this.anchor, + this.consumeTapEvents = false, + this.draggable = false, + this.flat = false, + required this.infoWindow, + required this.position, + this.rotation = 0.0, + this.visible = true, + this.zIndex = 0, + this.clusterManagerId, + }); + + final double alpha; + final PlatformPoint anchor; + final bool consumeTapEvents; + final bool draggable; + final bool flat; + + final PlatformBitmap icon; + final PlatformInfoWindow infoWindow; + final PlatformLatLng position; + final double rotation; + final bool visible; + final int zIndex; + final String markerId; + final String? clusterManagerId; +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon({ + required this.polygonId, + required this.consumesTapEvents, + required this.fillColor, + required this.geodesic, + required this.points, + required this.holes, + required this.visible, + required this.strokeColor, + required this.strokeWidth, + required this.zIndex, + }); + + final String polygonId; + final bool consumesTapEvents; + final PlatformColor fillColor; + final bool geodesic; + final List points; + final List> holes; + final bool visible; + final PlatformColor strokeColor; + final int strokeWidth; + final int zIndex; +} + +/// Join types for polyline joints. +enum PlatformJointType { mitered, bevel, round } + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline({ + required this.polylineId, + required this.consumesTapEvents, + required this.color, + required this.geodesic, + required this.jointType, + required this.patterns, + required this.points, + required this.visible, + required this.width, + required this.zIndex, + }); + + final String polylineId; + final bool consumesTapEvents; + final PlatformColor color; + final bool geodesic; + + /// The joint type. + final PlatformJointType jointType; + + /// The pattern data, as a list of pattern items. + final List patterns; + final List points; + + final bool visible; + final int width; + final int zIndex; +} + +/// Enumeration of possible types for PatternItem. +enum PlatformPatternItemType { dot, dash, gap } + +/// Pigeon equivalent of the PatternItem class. +class PlatformPatternItem { + PlatformPatternItem({required this.type, this.length}); + + final PlatformPatternItemType type; + final double? length; +} + +/// Pigeon equivalent of the Tile class. +class PlatformTile { + PlatformTile({required this.width, required this.height, required this.data}); + + final int width; + final int height; + final Uint8List? data; +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay({ + required this.tileOverlayId, + required this.fadeIn, + required this.transparency, + required this.zIndex, + required this.visible, + required this.tileSize, + }); + + final String tileOverlayId; + final bool fadeIn; + final double transparency; + final int zIndex; + final bool visible; + final int tileSize; +} + +/// Pigeon equivalent of Flutter's EdgeInsets. +class PlatformEdgeInsets { + PlatformEdgeInsets({ + required this.top, + required this.bottom, + required this.left, + required this.right, + }); + + final double top; + final double bottom; + final double left; + final double right; +} + +/// Pigeon equivalent of LatLng. +class PlatformLatLng { + PlatformLatLng({required this.latitude, required this.longitude}); + + final double latitude; + final double longitude; +} + +/// Pigeon equivalent of LatLngBounds. +class PlatformLatLngBounds { + PlatformLatLngBounds({required this.northeast, required this.southwest}); + + final PlatformLatLng northeast; + final PlatformLatLng southwest; +} + +/// Pigeon equivalent of CameraTargetBounds. +/// +/// As with the Dart version, it exists to distinguish between not setting a +/// a target, and having an explicitly unbounded target (null [bounds]). +class PlatformCameraTargetBounds { + PlatformCameraTargetBounds({required this.bounds}); + + final PlatformLatLngBounds? bounds; +} + +/// Pigeon equivalent of the GroundOverlay class. +class PlatformGroundOverlay { + PlatformGroundOverlay({ + required this.groundOverlayId, + required this.image, + required this.position, + required this.bounds, + required this.anchor, + required this.transparency, + required this.bearing, + required this.zIndex, + required this.visible, + required this.clickable, + required this.zoomLevel, + }); + + final String groundOverlayId; + final PlatformBitmap image; + final PlatformLatLng? position; + final PlatformLatLngBounds? bounds; + final PlatformPoint? anchor; + final double transparency; + final double bearing; + final int zIndex; + final bool visible; + final bool clickable; + final double? zoomLevel; +} + +/// Information passed to the platform view creation. +class PlatformMapViewCreationParams { + PlatformMapViewCreationParams({ + required this.initialCameraPosition, + required this.mapConfiguration, + required this.initialCircles, + required this.initialMarkers, + required this.initialPolygons, + required this.initialPolylines, + required this.initialHeatmaps, + required this.initialTileOverlays, + required this.initialClusterManagers, + required this.initialGroundOverlays, + }); + + final PlatformCameraPosition initialCameraPosition; + final PlatformMapConfiguration mapConfiguration; + final List initialCircles; + final List initialMarkers; + final List initialPolygons; + final List initialPolylines; + final List initialHeatmaps; + final List initialTileOverlays; + final List initialClusterManagers; + final List initialGroundOverlays; +} + +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({ + required this.compassEnabled, + required this.cameraTargetBounds, + required this.mapType, + required this.minMaxZoomPreference, + required this.rotateGesturesEnabled, + required this.scrollGesturesEnabled, + required this.tiltGesturesEnabled, + required this.trackCameraPosition, + required this.zoomGesturesEnabled, + required this.myLocationEnabled, + required this.myLocationButtonEnabled, + required this.padding, + required this.indoorViewEnabled, + required this.trafficEnabled, + required this.buildingsEnabled, + required this.mapId, + required this.style, + }); + + final bool? compassEnabled; + final PlatformCameraTargetBounds? cameraTargetBounds; + final PlatformMapType? mapType; + final PlatformZoomRange? minMaxZoomPreference; + final bool? rotateGesturesEnabled; + final bool? scrollGesturesEnabled; + final bool? tiltGesturesEnabled; + final bool? trackCameraPosition; + final bool? zoomGesturesEnabled; + final bool? myLocationEnabled; + final bool? myLocationButtonEnabled; + final PlatformEdgeInsets? padding; + final bool? indoorViewEnabled; + final bool? trafficEnabled; + final bool? buildingsEnabled; + final String? mapId; + final String? style; +} + +/// Pigeon representation of an x,y coordinate. +class PlatformPoint { + PlatformPoint({required this.x, required this.y}); + + final double x; + final double y; +} + +/// Pigeon representation of a size. +class PlatformSize { + PlatformSize({required this.width, required this.height}); + + final double width; + final double height; +} + +/// Pigeon representation of a color. +class PlatformColor { + PlatformColor({ + required this.red, + required this.green, + required this.blue, + required this.alpha, + }); + + final double red; + final double green; + final double blue; + final double alpha; +} + +/// Pigeon equivalent of GMSTileLayer properties. +class PlatformTileLayer { + PlatformTileLayer({ + required this.visible, + required this.fadeIn, + required this.opacity, + required this.zIndex, + }); + + final bool visible; + final bool fadeIn; + final double opacity; + final int zIndex; +} + +/// Pigeon equivalent of MinMaxZoomPreference. +class PlatformZoomRange { + PlatformZoomRange({required this.min, required this.max}); + + final double? min; + final double? max; +} + +/// Pigeon equivalent of [BitmapDescriptor]. As there are multiple disjoint +/// types of [BitmapDescriptor], [PlatformBitmap] contains a single field which +/// may hold the pigeon equivalent type of any of them. +class PlatformBitmap { + PlatformBitmap({required this.bitmap}); + + /// One of [PlatformBitmapAssetMap], [PlatformBitmapAsset], + /// [PlatformBitmapAssetImage], [PlatformBitmapBytesMap], + /// [PlatformBitmapBytes], or [PlatformBitmapDefaultMarker]. + /// As Pigeon does not currently support data class inheritance, this + /// approach allows for the different bitmap implementations to be valid + /// argument and return types of the API methods. See + /// https://github.com/flutter/flutter/issues/117819. + final Object bitmap; +} + +/// Pigeon equivalent of [DefaultMarker]. +class PlatformBitmapDefaultMarker { + PlatformBitmapDefaultMarker({this.hue}); + + final double? hue; +} + +/// Pigeon equivalent of [BytesBitmap]. +class PlatformBitmapBytes { + PlatformBitmapBytes({required this.byteData, this.size}); + + final Uint8List byteData; + final PlatformSize? size; +} + +/// Pigeon equivalent of [AssetBitmap]. +class PlatformBitmapAsset { + PlatformBitmapAsset({required this.name, this.pkg}); + + final String name; + final String? pkg; +} + +/// Pigeon equivalent of [AssetImageBitmap]. +class PlatformBitmapAssetImage { + PlatformBitmapAssetImage({ + required this.name, + required this.scale, + this.size, + }); + final String name; + final double scale; + final PlatformSize? size; +} + +/// Pigeon equivalent of [AssetMapBitmap]. +class PlatformBitmapAssetMap { + PlatformBitmapAssetMap({ + required this.assetName, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + final String assetName; + final PlatformMapBitmapScaling bitmapScaling; + final double imagePixelRatio; + final double? width; + final double? height; +} + +/// Pigeon equivalent of [BytesMapBitmap]. +class PlatformBitmapBytesMap { + PlatformBitmapBytesMap({ + required this.byteData, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + final Uint8List byteData; + final PlatformMapBitmapScaling bitmapScaling; + final double imagePixelRatio; + final double? width; + final double? height; +} + +/// Pigeon equivalent of [MapBitmapScaling]. +enum PlatformMapBitmapScaling { auto, none } + +/// Interface for non-test interactions with the native SDK. +/// +/// For test-only state queries, see [MapsInspectorApi]. +@HostApi() +abstract class MapsApi { + /// Returns once the map instance is available. + void waitForMap(); + + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + @ObjCSelector('updateWithMapConfiguration:') + void updateMapConfiguration(PlatformMapConfiguration configuration); + + /// Updates the set of circles on the map. + @ObjCSelector('updateCirclesByAdding:changing:removing:') + void updateCircles( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of heatmaps on the map. + @ObjCSelector('updateHeatmapsByAdding:changing:removing:') + void updateHeatmaps( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of custer managers for clusters on the map. + @ObjCSelector('updateClusterManagersByAdding:removing:') + void updateClusterManagers( + List toAdd, + List idsToRemove, + ); + + /// Updates the set of markers on the map. + @ObjCSelector('updateMarkersByAdding:changing:removing:') + void updateMarkers( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of polygonss on the map. + @ObjCSelector('updatePolygonsByAdding:changing:removing:') + void updatePolygons( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of polylines on the map. + @ObjCSelector('updatePolylinesByAdding:changing:removing:') + void updatePolylines( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of tile overlays on the map. + @ObjCSelector('updateTileOverlaysByAdding:changing:removing:') + void updateTileOverlays( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of ground overlays on the map. + @ObjCSelector('updateGroundOverlaysByAdding:changing:removing:') + void updateGroundOverlays( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Gets the screen coordinate for the given map location. + @ObjCSelector('screenCoordinatesForLatLng:') + PlatformPoint getScreenCoordinate(PlatformLatLng latLng); + + /// Gets the map location for the given screen coordinate. + @ObjCSelector('latLngForScreenCoordinate:') + PlatformLatLng getLatLng(PlatformPoint screenCoordinate); + + /// Gets the map region currently displayed on the map. + @ObjCSelector('visibleMapRegion') + PlatformLatLngBounds getVisibleRegion(); + + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + @ObjCSelector('moveCameraWithUpdate:') + void moveCamera(PlatformCameraUpdate cameraUpdate); + + /// Moves the camera according to [cameraUpdate], animating the update using a + /// duration in milliseconds if provided. + @ObjCSelector('animateCameraWithUpdate:duration:') + void animateCamera( + PlatformCameraUpdate cameraUpdate, + int? durationMilliseconds, + ); + + /// Gets the current map zoom level. + @ObjCSelector('currentZoomLevel') + double getZoomLevel(); + + /// Show the info window for the marker with the given ID. + @ObjCSelector('showInfoWindowForMarkerWithIdentifier:') + void showInfoWindow(String markerId); + + /// Hide the info window for the marker with the given ID. + @ObjCSelector('hideInfoWindowForMarkerWithIdentifier:') + void hideInfoWindow(String markerId); + + /// Returns true if the marker with the given ID is currently displaying its + /// info window. + @ObjCSelector('isShowingInfoWindowForMarkerWithIdentifier:') + bool isInfoWindowShown(String markerId); + + /// Sets the style to the given map style string, where an empty string + /// indicates that the style should be cleared. + /// + /// If there was an error setting the style, such as an invalid style string, + /// returns the error message. + @ObjCSelector('setStyle:') + String? setStyle(String style); + + /// Returns the error string from the last attempt to set the map style, if + /// any. + /// + /// This allows checking asynchronously for initial style failures, as there + /// is no way to return failures from map initialization. + @ObjCSelector('lastStyleError') + String? getLastStyleError(); + + /// Clears the cache of tiles previously requseted from the tile provider. + @ObjCSelector('clearTileCacheForOverlayWithIdentifier:') + void clearTileCache(String tileOverlayId); + + /// Takes a snapshot of the map and returns its image data. + Uint8List? takeSnapshot(); +} + +/// Interface for calls from the native SDK to Dart. +@FlutterApi() +abstract class MapsCallbackApi { + /// Called when the map camera starts moving. + @ObjCSelector('didStartCameraMoveWithCompletion') + void onCameraMoveStarted(); + + /// Called when the map camera moves. + @ObjCSelector('didMoveCameraToPosition:') + void onCameraMove(PlatformCameraPosition cameraPosition); + + /// Called when the map camera stops moving. + @ObjCSelector('didIdleCameraWithCompletion') + void onCameraIdle(); + + /// Called when the map, not a specifc map object, is tapped. + @ObjCSelector('didTapAtPosition:') + void onTap(PlatformLatLng position); + + /// Called when the map, not a specifc map object, is long pressed. + @ObjCSelector('didLongPressAtPosition:') + void onLongPress(PlatformLatLng position); + + /// Called when a marker is tapped. + @ObjCSelector('didTapMarkerWithIdentifier:') + void onMarkerTap(String markerId); + + /// Called when a marker drag starts. + @ObjCSelector('didStartDragForMarkerWithIdentifier:atPosition:') + void onMarkerDragStart(String markerId, PlatformLatLng position); + + /// Called when a marker drag updates. + @ObjCSelector('didDragMarkerWithIdentifier:atPosition:') + void onMarkerDrag(String markerId, PlatformLatLng position); + + /// Called when a marker drag ends. + @ObjCSelector('didEndDragForMarkerWithIdentifier:atPosition:') + void onMarkerDragEnd(String markerId, PlatformLatLng position); + + /// Called when a marker's info window is tapped. + @ObjCSelector('didTapInfoWindowOfMarkerWithIdentifier:') + void onInfoWindowTap(String markerId); + + /// Called when a circle is tapped. + @ObjCSelector('didTapCircleWithIdentifier:') + void onCircleTap(String circleId); + + /// Called when a marker cluster is tapped. + @ObjCSelector('didTapCluster:') + void onClusterTap(PlatformCluster cluster); + + /// Called when a polygon is tapped. + @ObjCSelector('didTapPolygonWithIdentifier:') + void onPolygonTap(String polygonId); + + /// Called when a polyline is tapped. + @ObjCSelector('didTapPolylineWithIdentifier:') + void onPolylineTap(String polylineId); + + /// Called when a ground overlay is tapped. + @ObjCSelector('didTapGroundOverlayWithIdentifier:') + void onGroundOverlayTap(String groundOverlayId); + + /// Called to get data for a map tile. + @async + @ObjCSelector('tileWithOverlayIdentifier:location:zoom:') + PlatformTile getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ); +} + +/// Dummy interface to force generation of the platform view creation params, +/// which are not used in any Pigeon calls, only the platform view creation +/// call made internally by Flutter. +@HostApi() +abstract class MapsPlatformViewApi { + // This is never actually called. + void createView(PlatformMapViewCreationParams? type); +} + +/// Inspector API only intended for use in integration tests. +@HostApi() +abstract class MapsInspectorApi { + bool areBuildingsEnabled(); + bool areRotateGesturesEnabled(); + bool areScrollGesturesEnabled(); + bool areTiltGesturesEnabled(); + bool areZoomGesturesEnabled(); + bool isCompassEnabled(); + bool isMyLocationButtonEnabled(); + bool isTrafficEnabled(); + @ObjCSelector('tileOverlayWithIdentifier:') + PlatformTileLayer? getTileOverlayInfo(String tileOverlayId); + @ObjCSelector('groundOverlayWithIdentifier:') + PlatformGroundOverlay? getGroundOverlayInfo(String groundOverlayId); + @ObjCSelector('heatmapWithIdentifier:') + PlatformHeatmap? getHeatmapInfo(String heatmapId); + @ObjCSelector('zoomRange') + PlatformZoomRange getZoomRange(); + @ObjCSelector('clustersWithIdentifier:') + List getClusters(String clusterManagerId); + @ObjCSelector('cameraPosition') + PlatformCameraPosition getCameraPosition(); +} 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 new file mode 100644 index 000000000000..136ccda24364 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/pubspec.yaml @@ -0,0 +1,39 @@ +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.16.1 + +environment: + sdk: ^3.9.0 + flutter: ">=3.35.0" + +flutter: + plugin: + implements: google_maps_flutter + platforms: + ios: + pluginClass: FLTGoogleMapsPlugin + dartPluginClass: GoogleMapsFlutterIOS + +dependencies: + flutter: + sdk: flutter + google_maps_flutter_platform_interface: ^2.13.0 + stream_transform: ^2.0.0 + +dev_dependencies: + async: ^2.5.0 + build_runner: ^2.4.11 + flutter_test: + sdk: flutter + mockito: ^5.4.4 + path: ^1.8.0 + pigeon: ^26.1.0 + plugin_platform_interface: ^2.1.7 + process: ^5.0.5 + +topics: + - google-maps + - google-maps-flutter + - map 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 new file mode 100644 index 000000000000..4dee18297412 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.dart @@ -0,0 +1,1357 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +import 'dart:async'; + +import 'package:async/async.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'google_maps_flutter_ios_test.mocks.dart'; +import 'package_specific_test_import.dart'; + +@GenerateNiceMocks(>[MockSpec()]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + (GoogleMapsFlutterIOS, MockMapsApi) setUpMockMap({required int mapId}) { + final api = MockMapsApi(); + final maps = GoogleMapsFlutterIOS(apiProvider: (_) => api); + maps.ensureApiInitialized(mapId); + return (maps, api); + } + + test('registers instance', () async { + GoogleMapsFlutterIOS.registerWith(); + expect(GoogleMapsFlutterPlatform.instance, isA()); + }); + + test('init calls waitForMap', () async { + final api = MockMapsApi(); + final maps = GoogleMapsFlutterIOS(apiProvider: (_) => api); + + await maps.init(1); + + verify(api.waitForMap()); + }); + + test('getScreenCoordinate converts and passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Arbitrary values that are all different from each other. + const latLng = LatLng(10, 20); + const expectedCoord = ScreenCoordinate(x: 30, y: 40); + when(api.getScreenCoordinate(any)).thenAnswer( + (_) async => PlatformPoint( + x: expectedCoord.x.toDouble(), + y: expectedCoord.y.toDouble(), + ), + ); + + final ScreenCoordinate coord = await maps.getScreenCoordinate( + latLng, + mapId: mapId, + ); + expect(coord, expectedCoord); + final VerificationResult verification = verify( + api.getScreenCoordinate(captureAny), + ); + final passedLatLng = verification.captured[0] as PlatformLatLng; + expect(passedLatLng.latitude, latLng.latitude); + expect(passedLatLng.longitude, latLng.longitude); + }); + + test('getLatLng converts and passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Arbitrary values that are all different from each other. + const expectedLatLng = LatLng(10, 20); + const coord = ScreenCoordinate(x: 30, y: 40); + when(api.getLatLng(any)).thenAnswer( + (_) async => PlatformLatLng( + latitude: expectedLatLng.latitude, + longitude: expectedLatLng.longitude, + ), + ); + + final LatLng latLng = await maps.getLatLng(coord, mapId: mapId); + expect(latLng, expectedLatLng); + final VerificationResult verification = verify(api.getLatLng(captureAny)); + final passedCoord = verification.captured[0] as PlatformPoint; + expect(passedCoord.x, coord.x); + expect(passedCoord.y, coord.y); + }); + + test('getVisibleRegion converts and passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Arbitrary values that are all different from each other. + final expectedBounds = LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ); + when(api.getVisibleRegion()).thenAnswer( + (_) async => PlatformLatLngBounds( + southwest: PlatformLatLng( + latitude: expectedBounds.southwest.latitude, + longitude: expectedBounds.southwest.longitude, + ), + northeast: PlatformLatLng( + latitude: expectedBounds.northeast.latitude, + longitude: expectedBounds.northeast.longitude, + ), + ), + ); + + final LatLngBounds bounds = await maps.getVisibleRegion(mapId: mapId); + expect(bounds, expectedBounds); + }); + + test('moveCamera calls through with expected scrollBy', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final scroll = passedUpdate.cameraUpdate as PlatformCameraUpdateScrollBy; + update as CameraUpdateScrollBy; + expect(scroll.dx, update.dx); + expect(scroll.dy, update.dy); + }); + + test('animateCamera calls through with expected scrollBy', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.animateCamera(update, mapId: mapId); + + final VerificationResult verification = verify( + api.animateCamera(captureAny, captureAny), + ); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final scroll = passedUpdate.cameraUpdate as PlatformCameraUpdateScrollBy; + update as CameraUpdateScrollBy; + expect(scroll.dx, update.dx); + expect(scroll.dy, update.dy); + expect(verification.captured[1], isNull); + }); + + test('animateCameraWithConfiguration calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + const configuration = CameraUpdateAnimationConfiguration( + duration: Duration(seconds: 1), + ); + expect(configuration.duration?.inSeconds, 1); + await maps.animateCameraWithConfiguration( + update, + configuration, + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.animateCamera(captureAny, captureAny), + ); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final scroll = passedUpdate.cameraUpdate as PlatformCameraUpdateScrollBy; + update as CameraUpdateScrollBy; + expect(scroll.dx, update.dx); + expect(scroll.dy, update.dy); + + final passedDuration = verification.captured[1] as int?; + expect(passedDuration, configuration.duration?.inMilliseconds); + }); + + test('getZoomLevel passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const expectedZoom = 4.2; + when(api.getZoomLevel()).thenAnswer((_) async => expectedZoom); + + final double zoom = await maps.getZoomLevel(mapId: mapId); + expect(zoom, expectedZoom); + }); + + test('showInfoWindow calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const markedId = 'a_marker'; + await maps.showMarkerInfoWindow(const MarkerId(markedId), mapId: mapId); + + verify(api.showInfoWindow(markedId)); + }); + + test('hideInfoWindow calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const markedId = 'a_marker'; + await maps.hideMarkerInfoWindow(const MarkerId(markedId), mapId: mapId); + + verify(api.hideInfoWindow(markedId)); + }); + + test('isInfoWindowShown calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const markedId = 'a_marker'; + when(api.isInfoWindowShown(markedId)).thenAnswer((_) async => true); + + expect( + await maps.isMarkerInfoWindowShown( + const MarkerId(markedId), + mapId: mapId, + ), + true, + ); + }); + + test('takeSnapshot calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final fakeSnapshot = Uint8List(10); + when(api.takeSnapshot()).thenAnswer((_) async => fakeSnapshot); + + expect(await maps.takeSnapshot(mapId: mapId), fakeSnapshot); + }); + + test('clearTileCache calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const tileOverlayId = 'overlay'; + await maps.clearTileCache(const TileOverlayId(tileOverlayId), mapId: mapId); + + verify(api.clearTileCache(tileOverlayId)); + }); + + test('updateMapConfiguration passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Set some arbitrary options. + final cameraBounds = CameraTargetBounds( + LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + ); + final config = MapConfiguration( + compassEnabled: true, + mapType: MapType.terrain, + cameraTargetBounds: cameraBounds, + ); + await maps.updateMapConfiguration(config, mapId: mapId); + + final VerificationResult verification = verify( + api.updateMapConfiguration(captureAny), + ); + final passedConfig = verification.captured[0] as PlatformMapConfiguration; + // Each set option should be present. + expect(passedConfig.compassEnabled, true); + expect(passedConfig.mapType, PlatformMapType.terrain); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.latitude, + cameraBounds.bounds?.northeast.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.longitude, + cameraBounds.bounds?.northeast.longitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.latitude, + cameraBounds.bounds?.southwest.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.longitude, + cameraBounds.bounds?.southwest.longitude, + ); + // Spot-check that unset options are not be present. + expect(passedConfig.myLocationEnabled, isNull); + expect(passedConfig.minMaxZoomPreference, isNull); + expect(passedConfig.padding, isNull); + }); + + test('updateMapOptions passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Set some arbitrary options. + final cameraBounds = CameraTargetBounds( + LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + ); + final config = { + 'compassEnabled': true, + 'mapType': MapType.terrain.index, + 'cameraTargetBounds': cameraBounds.toJson(), + }; + await maps.updateMapOptions(config, mapId: mapId); + + final VerificationResult verification = verify( + api.updateMapConfiguration(captureAny), + ); + final passedConfig = verification.captured[0] as PlatformMapConfiguration; + // Each set option should be present. + expect(passedConfig.compassEnabled, true); + expect(passedConfig.mapType, PlatformMapType.terrain); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.latitude, + cameraBounds.bounds?.northeast.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.longitude, + cameraBounds.bounds?.northeast.longitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.latitude, + cameraBounds.bounds?.southwest.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.longitude, + cameraBounds.bounds?.southwest.longitude, + ); + // Spot-check that unset options are not be present. + expect(passedConfig.myLocationEnabled, isNull); + expect(passedConfig.minMaxZoomPreference, isNull); + expect(passedConfig.padding, isNull); + }); + + test('updateCircles passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Circle(circleId: CircleId('1')); + const object2old = Circle(circleId: CircleId('2')); + final Circle object2new = object2old.copyWith(radiusParam: 42); + const object3 = Circle(circleId: CircleId('3')); + await maps.updateCircles( + CircleUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateCircles(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.circleId.value); + // Object two should be changed. + { + expect(toChange.length, 1); + final PlatformCircle firstChanged = toChange.first; + expect(firstChanged.consumeTapEvents, object2new.consumeTapEvents); + _expectColorsEqual(firstChanged.fillColor, object2new.fillColor); + _expectColorsEqual(firstChanged.strokeColor, object2new.strokeColor); + expect(firstChanged.visible, object2new.visible); + expect(firstChanged.strokeWidth, object2new.strokeWidth); + expect(firstChanged.zIndex, object2new.zIndex.toDouble()); + expect(firstChanged.center.latitude, object2new.center.latitude); + expect(firstChanged.center.longitude, object2new.center.longitude); + expect(firstChanged.radius, object2new.radius); + expect(firstChanged.circleId, object2new.circleId.value); + } + // Object 3 should be added. + { + expect(toAdd.length, 1); + final PlatformCircle firstAdded = toAdd.first; + expect(firstAdded.consumeTapEvents, object3.consumeTapEvents); + _expectColorsEqual(firstAdded.fillColor, object3.fillColor); + _expectColorsEqual(firstAdded.strokeColor, object3.strokeColor); + expect(firstAdded.visible, object3.visible); + expect(firstAdded.strokeWidth, object3.strokeWidth); + expect(firstAdded.zIndex, object3.zIndex.toDouble()); + expect(firstAdded.center.latitude, object3.center.latitude); + expect(firstAdded.center.longitude, object3.center.longitude); + expect(firstAdded.radius, object3.radius); + expect(firstAdded.circleId, object3.circleId.value); + } + }); + + test('updateClusterManagers passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = ClusterManager(clusterManagerId: ClusterManagerId('1')); + const object3 = ClusterManager(clusterManagerId: ClusterManagerId('3')); + await maps.updateClusterManagers( + ClusterManagerUpdates.from( + {object1}, + {object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateClusterManagers(captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toRemove = verification.captured[1] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.clusterManagerId.value); + // Unlike other map object types, changes are not possible for cluster + // managers, since they have no non-ID properties. + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first.identifier, object3.clusterManagerId.value); + }); + + test('updateMarkers passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Marker(markerId: MarkerId('1')); + const object2old = Marker(markerId: MarkerId('2')); + final Marker object2new = object2old.copyWith(rotationParam: 42); + const object3 = Marker(markerId: MarkerId('3')); + await maps.updateMarkers( + MarkerUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateMarkers(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.markerId.value); + // Object two should be changed. + { + expect(toChange.length, 1); + final PlatformMarker firstChanged = toChange.first; + expect(firstChanged.alpha, object2new.alpha); + expect(firstChanged.anchor.x, object2new.anchor.dx); + expect(firstChanged.anchor.y, object2new.anchor.dy); + expect(firstChanged.consumeTapEvents, object2new.consumeTapEvents); + expect(firstChanged.draggable, object2new.draggable); + expect(firstChanged.flat, object2new.flat); + expect( + firstChanged.icon.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object2new.icon, + ).bitmap.runtimeType, + ); + expect(firstChanged.infoWindow.title, object2new.infoWindow.title); + expect(firstChanged.infoWindow.snippet, object2new.infoWindow.snippet); + expect(firstChanged.infoWindow.anchor.x, object2new.infoWindow.anchor.dx); + expect(firstChanged.infoWindow.anchor.y, object2new.infoWindow.anchor.dy); + expect(firstChanged.position.latitude, object2new.position.latitude); + expect(firstChanged.position.longitude, object2new.position.longitude); + expect(firstChanged.rotation, object2new.rotation); + expect(firstChanged.visible, object2new.visible); + expect(firstChanged.zIndex, object2new.zIndexInt); + expect(firstChanged.markerId, object2new.markerId.value); + expect(firstChanged.clusterManagerId, object2new.clusterManagerId?.value); + } + // Object 3 should be added. + { + expect(toAdd.length, 1); + final PlatformMarker firstAdded = toAdd.first; + expect(firstAdded.alpha, object3.alpha); + expect(firstAdded.anchor.x, object3.anchor.dx); + expect(firstAdded.anchor.y, object3.anchor.dy); + expect(firstAdded.consumeTapEvents, object3.consumeTapEvents); + expect(firstAdded.draggable, object3.draggable); + expect(firstAdded.flat, object3.flat); + expect( + firstAdded.icon.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object3.icon, + ).bitmap.runtimeType, + ); + expect(firstAdded.infoWindow.title, object3.infoWindow.title); + expect(firstAdded.infoWindow.snippet, object3.infoWindow.snippet); + expect(firstAdded.infoWindow.anchor.x, object3.infoWindow.anchor.dx); + expect(firstAdded.infoWindow.anchor.y, object3.infoWindow.anchor.dy); + expect(firstAdded.position.latitude, object3.position.latitude); + expect(firstAdded.position.longitude, object3.position.longitude); + expect(firstAdded.rotation, object3.rotation); + expect(firstAdded.visible, object3.visible); + expect(firstAdded.zIndex, object3.zIndexInt); + expect(firstAdded.markerId, object3.markerId.value); + expect(firstAdded.clusterManagerId, object3.clusterManagerId?.value); + } + }); + + test('updatePolygons passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Polygon(polygonId: PolygonId('1')); + const object2old = Polygon(polygonId: PolygonId('2')); + final Polygon object2new = object2old.copyWith(strokeWidthParam: 42); + const object3 = Polygon(polygonId: PolygonId('3')); + await maps.updatePolygons( + PolygonUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updatePolygons(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polygonId.value); + void expectPolygon(PlatformPolygon actual, Polygon expected) { + expect(actual.polygonId, expected.polygonId.value); + expect(actual.consumesTapEvents, expected.consumeTapEvents); + _expectColorsEqual(actual.fillColor, expected.fillColor); + expect(actual.geodesic, expected.geodesic); + expect(actual.points.length, expected.points.length); + for (final (int i, PlatformLatLng? point) in actual.points.indexed) { + expect(point?.latitude, expected.points[i].latitude); + expect(point?.longitude, expected.points[i].longitude); + } + expect(actual.holes.length, expected.holes.length); + for (final (int i, List? hole) in actual.holes.indexed) { + final List expectedHole = expected.holes[i]; + for (final (int j, PlatformLatLng? point) in hole!.indexed) { + expect(point?.latitude, expectedHole[j].latitude); + expect(point?.longitude, expectedHole[j].longitude); + } + } + expect(actual.visible, expected.visible); + _expectColorsEqual(actual.strokeColor, expected.strokeColor); + expect(actual.strokeWidth, expected.strokeWidth); + expect(actual.zIndex, expected.zIndex); + } + + // Object two should be changed. + expect(toChange.length, 1); + expectPolygon(toChange.first, object2new); + // Object 3 should be added. + expect(toAdd.length, 1); + expectPolygon(toAdd.first, object3); + }); + + test('updatePolylines passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Polyline(polylineId: PolylineId('1')); + const object2old = Polyline(polylineId: PolylineId('2')); + final Polyline object2new = object2old.copyWith( + widthParam: 42, + startCapParam: Cap.squareCap, + endCapParam: Cap.buttCap, + ); + final Cap customCap = Cap.customCapFromBitmap( + BitmapDescriptor.defaultMarker, + refWidth: 15, + ); + final object3 = Polyline( + polylineId: const PolylineId('3'), + startCap: customCap, + endCap: Cap.roundCap, + ); + await maps.updatePolylines( + PolylineUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updatePolylines(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + void expectPolyline(PlatformPolyline actual, Polyline expected) { + expect(actual.polylineId, expected.polylineId.value); + expect(actual.consumesTapEvents, expected.consumeTapEvents); + _expectColorsEqual(actual.color, expected.color); + expect(actual.geodesic, expected.geodesic); + expect( + actual.jointType, + platformJointTypeFromJointType(expected.jointType), + ); + expect(actual.visible, expected.visible); + expect(actual.width, expected.width); + expect(actual.zIndex, expected.zIndex); + expect(actual.points.length, expected.points.length); + for (final (int i, PlatformLatLng? point) in actual.points.indexed) { + expect(point?.latitude, actual.points[i].latitude); + expect(point?.longitude, actual.points[i].longitude); + } + expect(actual.patterns.length, expected.patterns.length); + for (final (int i, PlatformPatternItem? pattern) + in actual.patterns.indexed) { + expect( + pattern?.encode(), + platformPatternItemFromPatternItem(expected.patterns[i]).encode(), + ); + } + } + + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polylineId.value); + // Object two should be changed. + expect(toChange.length, 1); + expectPolyline(toChange.first, object2new); + // Object 3 should be added. + expect(toAdd.length, 1); + expectPolyline(toAdd.first, object3); + }); + + test('updateTileOverlays passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = TileOverlay(tileOverlayId: TileOverlayId('1')); + const object2old = TileOverlay(tileOverlayId: TileOverlayId('2')); + final TileOverlay object2new = object2old.copyWith(zIndexParam: 42); + const object3 = TileOverlay(tileOverlayId: TileOverlayId('3')); + // Pre-set the initial state, since this update method doesn't take the old + // state. + await maps.updateTileOverlays( + newTileOverlays: {object1, object2old}, + mapId: mapId, + ); + clearInteractions(api); + + await maps.updateTileOverlays( + newTileOverlays: {object2new, object3}, + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateTileOverlays(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + void expectTileOverlay(PlatformTileOverlay actual, TileOverlay expected) { + expect(actual.tileOverlayId, expected.tileOverlayId.value); + expect(actual.fadeIn, expected.fadeIn); + expect(actual.transparency, expected.transparency); + expect(actual.zIndex, expected.zIndex); + expect(actual.visible, expected.visible); + expect(actual.tileSize, expected.tileSize); + } + + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.tileOverlayId.value); + // Object two should be changed. + expect(toChange.length, 1); + expectTileOverlay(toChange.first, object2new); + // Object 3 should be added. + expect(toAdd.length, 1); + expectTileOverlay(toAdd.first, object3); + }); + + test('updateGroundOverlays passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final image = AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ); + + final object1 = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('1'), + bounds: LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + image: image, + ); + final object2old = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('2'), + bounds: LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + image: image, + ); + final GroundOverlay object2new = object2old.copyWith( + visibleParam: false, + bearingParam: 10, + clickableParam: false, + transparencyParam: 0.5, + zIndexParam: 100, + ); + final object3 = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('3'), + position: const LatLng(10, 20), + width: 100, + image: image, + zoomLevel: 14.0, + ); + await maps.updateGroundOverlays( + GroundOverlayUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateGroundOverlays(captureAny, captureAny, captureAny), + ); + + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.groundOverlayId.value); + // Object two should be changed. + { + expect(toChange.length, 1); + final PlatformGroundOverlay firstChanged = toChange.first; + expect(firstChanged.anchor?.x, object2new.anchor?.dx); + expect(firstChanged.anchor?.y, object2new.anchor?.dy); + expect(firstChanged.bearing, object2new.bearing); + expect( + firstChanged.bounds?.northeast.latitude, + object2new.bounds?.northeast.latitude, + ); + expect( + firstChanged.bounds?.northeast.longitude, + object2new.bounds?.northeast.longitude, + ); + expect( + firstChanged.bounds?.southwest.latitude, + object2new.bounds?.southwest.latitude, + ); + expect( + firstChanged.bounds?.southwest.longitude, + object2new.bounds?.southwest.longitude, + ); + expect(firstChanged.visible, object2new.visible); + expect(firstChanged.clickable, object2new.clickable); + expect(firstChanged.zIndex, object2new.zIndex); + expect(firstChanged.position?.latitude, object2new.position?.latitude); + expect(firstChanged.position?.longitude, object2new.position?.longitude); + expect(firstChanged.zoomLevel, object2new.zoomLevel); + expect(firstChanged.transparency, object2new.transparency); + expect( + firstChanged.image.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object2new.image, + ).bitmap.runtimeType, + ); + } + // Object three should be added. + { + expect(toAdd.length, 1); + final PlatformGroundOverlay firstAdded = toAdd.first; + expect(firstAdded.anchor?.x, object3.anchor?.dx); + expect(firstAdded.anchor?.y, object3.anchor?.dy); + expect(firstAdded.bearing, object3.bearing); + expect( + firstAdded.bounds?.northeast.latitude, + object3.bounds?.northeast.latitude, + ); + expect( + firstAdded.bounds?.northeast.longitude, + object3.bounds?.northeast.longitude, + ); + expect( + firstAdded.bounds?.southwest.latitude, + object3.bounds?.southwest.latitude, + ); + expect( + firstAdded.bounds?.southwest.longitude, + object3.bounds?.southwest.longitude, + ); + expect(firstAdded.visible, object3.visible); + expect(firstAdded.clickable, object3.clickable); + expect(firstAdded.zIndex, object3.zIndex); + expect(firstAdded.position?.latitude, object3.position?.latitude); + expect(firstAdded.position?.longitude, object3.position?.longitude); + expect(firstAdded.zoomLevel, object3.zoomLevel); + expect(firstAdded.transparency, object3.transparency); + expect( + firstAdded.image.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object3.image, + ).bitmap.runtimeType, + ); + } + }); + + test( + 'updateGroundOverlays throws assertion error on unsupported ground overlays', + () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final image = AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ); + + final object3 = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('1'), + position: const LatLng(10, 20), + // Assert should be thrown because zoomLevel is not set for position-based + // ground overlay on iOS. + // ignore: avoid_redundant_argument_values + zoomLevel: null, + image: image, + ); + + expect( + () async => maps.updateGroundOverlays( + GroundOverlayUpdates.from(const {}, { + object3, + }), + mapId: mapId, + ), + throwsAssertionError, + ); + }, + ); + + test('markers send drag event to correct streams', () async { + const mapId = 1; + const dragStartId = 'drag-start-marker'; + const dragId = 'drag-marker'; + const dragEndId = 'drag-end-marker'; + final fakePosition = PlatformLatLng(latitude: 1.0, longitude: 1.0); + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final markerDragStartStream = StreamQueue( + maps.onMarkerDragStart(mapId: mapId), + ); + final markerDragStream = StreamQueue( + maps.onMarkerDrag(mapId: mapId), + ); + final markerDragEndStream = StreamQueue( + maps.onMarkerDragEnd(mapId: mapId), + ); + + // Simulate messages from the native side. + callbackHandler.onMarkerDragStart(dragStartId, fakePosition); + callbackHandler.onMarkerDrag(dragId, fakePosition); + callbackHandler.onMarkerDragEnd(dragEndId, fakePosition); + + expect((await markerDragStartStream.next).value.value, equals(dragStartId)); + expect((await markerDragStream.next).value.value, equals(dragId)); + expect((await markerDragEndStream.next).value.value, equals(dragEndId)); + }); + + test('markers send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue(maps.onMarkerTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onMarkerTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('circles send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue(maps.onCircleTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onCircleTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('clusters send tap events to correct stream', () async { + const mapId = 1; + const managerId = 'manager-id'; + final fakePosition = PlatformLatLng(latitude: 10, longitude: 20); + final fakeBounds = PlatformLatLngBounds( + southwest: PlatformLatLng(latitude: 30, longitude: 40), + northeast: PlatformLatLng(latitude: 50, longitude: 60), + ); + const markerIds = ['marker-1', 'marker-2']; + final cluster = PlatformCluster( + clusterManagerId: managerId, + position: fakePosition, + bounds: fakeBounds, + markerIds: markerIds, + ); + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onClusterTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onClusterTap(cluster); + + final Cluster eventValue = (await stream.next).value; + expect(eventValue.clusterManagerId.value, managerId); + expect(eventValue.position.latitude, fakePosition.latitude); + expect(eventValue.position.longitude, fakePosition.longitude); + expect(eventValue.bounds.southwest.latitude, fakeBounds.southwest.latitude); + expect( + eventValue.bounds.southwest.longitude, + fakeBounds.southwest.longitude, + ); + expect(eventValue.bounds.northeast.latitude, fakeBounds.northeast.latitude); + expect( + eventValue.bounds.northeast.longitude, + fakeBounds.northeast.longitude, + ); + expect(eventValue.markerIds.length, markerIds.length); + expect(eventValue.markerIds.first.value, markerIds.first); + }); + + test('polygons send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onPolygonTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onPolygonTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('polylines send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onPolylineTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onPolylineTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('ground overlays send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onGroundOverlayTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onGroundOverlayTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('moveCamera calls through with expected newCameraPosition', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const latLng = LatLng(10.0, 20.0); + const position = CameraPosition(target: latLng); + final CameraUpdate update = CameraUpdate.newCameraPosition(position); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewCameraPosition; + update as CameraUpdateNewCameraPosition; + expect( + typedUpdate.cameraPosition.target.latitude, + update.cameraPosition.target.latitude, + ); + expect( + typedUpdate.cameraPosition.target.longitude, + update.cameraPosition.target.longitude, + ); + }); + + test('moveCamera calls through with expected newLatLng', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const latLng = LatLng(10.0, 20.0); + final CameraUpdate update = CameraUpdate.newLatLng(latLng); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewLatLng; + update as CameraUpdateNewLatLng; + expect(typedUpdate.latLng.latitude, update.latLng.latitude); + expect(typedUpdate.latLng.longitude, update.latLng.longitude); + }); + + test('moveCamera calls through with expected newLatLngBounds', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final latLng = LatLngBounds( + northeast: const LatLng(10.0, 20.0), + southwest: const LatLng(9.0, 21.0), + ); + final CameraUpdate update = CameraUpdate.newLatLngBounds(latLng, 1.0); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewLatLngBounds; + update as CameraUpdateNewLatLngBounds; + expect( + typedUpdate.bounds.northeast.latitude, + update.bounds.northeast.latitude, + ); + expect( + typedUpdate.bounds.northeast.longitude, + update.bounds.northeast.longitude, + ); + expect( + typedUpdate.bounds.southwest.latitude, + update.bounds.southwest.latitude, + ); + expect( + typedUpdate.bounds.southwest.longitude, + update.bounds.southwest.longitude, + ); + expect(typedUpdate.padding, update.padding); + }); + + test('moveCamera calls through with expected newLatLngZoom', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const latLng = LatLng(10.0, 20.0); + final CameraUpdate update = CameraUpdate.newLatLngZoom(latLng, 2.0); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewLatLngZoom; + update as CameraUpdateNewLatLngZoom; + expect(typedUpdate.latLng.latitude, update.latLng.latitude); + expect(typedUpdate.latLng.longitude, update.latLng.longitude); + expect(typedUpdate.zoom, update.zoom); + }); + + test('moveCamera calls through with expected zoomBy', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const focus = Offset(10.0, 20.0); + final CameraUpdate update = CameraUpdate.zoomBy(2.0, focus); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoomBy; + update as CameraUpdateZoomBy; + expect(typedUpdate.focus?.x, update.focus?.dx); + expect(typedUpdate.focus?.y, update.focus?.dy); + expect(typedUpdate.amount, update.amount); + }); + + test('moveCamera calls through with expected zoomTo', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.zoomTo(2.0); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoomTo; + update as CameraUpdateZoomTo; + expect(typedUpdate.zoom, update.zoom); + }); + + test('moveCamera calls through with expected zoomIn', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.zoomIn(); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoom; + expect(typedUpdate.out, false); + }); + + test('moveCamera calls through with expected zoomOut', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.zoomOut(); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoom; + expect(typedUpdate.out, true); + }); + + test('MapBitmapScaling to PlatformMapBitmapScaling', () { + expect( + GoogleMapsFlutterIOS.platformMapBitmapScalingFromScaling( + MapBitmapScaling.auto, + ), + PlatformMapBitmapScaling.auto, + ); + expect( + GoogleMapsFlutterIOS.platformMapBitmapScalingFromScaling( + MapBitmapScaling.none, + ), + PlatformMapBitmapScaling.none, + ); + }); + + test('DefaultMarker bitmap to PlatformBitmap', () { + final BitmapDescriptor bitmap = BitmapDescriptor.defaultMarkerWithHue(10.0); + final PlatformBitmap platformBitmap = + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor(bitmap); + expect(platformBitmap.bitmap, isA()); + final typedBitmap = platformBitmap.bitmap as PlatformBitmapDefaultMarker; + expect(typedBitmap.hue, 10.0); + }); + + test('BytesMapBitmap bitmap to PlatformBitmap', () { + final data = Uint8List.fromList([1, 2, 3, 4]); + final BytesMapBitmap bitmap = BitmapDescriptor.bytes( + data, + imagePixelRatio: 2.0, + width: 100.0, + height: 200.0, + ); + final PlatformBitmap platformBitmap = + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor(bitmap); + expect(platformBitmap.bitmap, isA()); + final typedBitmap = platformBitmap.bitmap as PlatformBitmapBytesMap; + expect(typedBitmap.byteData, data); + expect(typedBitmap.bitmapScaling, PlatformMapBitmapScaling.auto); + expect(typedBitmap.imagePixelRatio, 2.0); + expect(typedBitmap.width, 100.0); + expect(typedBitmap.height, 200.0); + }); + + test('AssetMapBitmap bitmap to PlatformBitmap', () { + const assetName = 'fake_asset_name'; + final bitmap = AssetMapBitmap( + assetName, + imagePixelRatio: 2.0, + width: 100.0, + height: 200.0, + ); + final PlatformBitmap platformBitmap = + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor(bitmap); + expect(platformBitmap.bitmap, isA()); + final typedBitmap = platformBitmap.bitmap as PlatformBitmapAssetMap; + expect(typedBitmap.assetName, assetName); + expect(typedBitmap.bitmapScaling, PlatformMapBitmapScaling.auto); + expect(typedBitmap.imagePixelRatio, 2.0); + expect(typedBitmap.width, 100.0); + expect(typedBitmap.height, 200.0); + }); + + testWidgets('mapId is passed', (WidgetTester tester) async { + const cloudMapId = '000000000000000'; // Dummy map ID. + final passedCloudMapIdCompleter = Completer(); + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform_views, ( + MethodCall methodCall, + ) { + if (methodCall.method == 'create') { + final args = Map.from( + methodCall.arguments as Map, + ); + if (args.containsKey('params')) { + final paramsUint8List = args['params'] as Uint8List; + final byteData = ByteData.sublistView(paramsUint8List); + final creationParams = + MapsApi.pigeonChannelCodec.decodeMessage(byteData) + as PlatformMapViewCreationParams?; + if (creationParams != null) { + final String? passedMapId = + creationParams.mapConfiguration.mapId; + if (passedMapId != null) { + passedCloudMapIdCompleter.complete(passedMapId); + } + } + } + } + return null; + }); + + final maps = GoogleMapsFlutterIOS(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: maps.buildViewWithConfiguration( + 1, + (int id) {}, + widgetConfiguration: const MapWidgetConfiguration( + initialCameraPosition: CameraPosition( + target: LatLng(0, 0), + zoom: 1, + ), + textDirection: TextDirection.ltr, + ), + mapConfiguration: const MapConfiguration(mapId: cloudMapId), + ), + ), + ); + + expect( + await passedCloudMapIdCompleter.future, + cloudMapId, + reason: 'Should pass mapId on PlatformView creation message', + ); + }); +} + +void _expectColorsEqual(PlatformColor actual, Color expected) { + expect(actual.red, expected.r); + expect(actual.green, expected.g); + expect(actual.blue, expected.b); + expect(actual.alpha, expected.a); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.mocks.dart new file mode 100644 index 000000000000..428e096b78eb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/google_maps_flutter_ios_test.mocks.dart @@ -0,0 +1,351 @@ +// Mocks generated by Mockito 5.4.5 from annotations +// in google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; +import 'dart:typed_data' as _i5; + +import 'package:google_maps_flutter_ios_sdk9/src/messages.g.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i3; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakePlatformPoint_0 extends _i1.SmartFake implements _i2.PlatformPoint { + _FakePlatformPoint_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakePlatformLatLng_1 extends _i1.SmartFake + implements _i2.PlatformLatLng { + _FakePlatformLatLng_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakePlatformLatLngBounds_2 extends _i1.SmartFake + implements _i2.PlatformLatLngBounds { + _FakePlatformLatLngBounds_2(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [MapsApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMapsApi extends _i1.Mock implements _i2.MapsApi { + @override + String get pigeonVar_messageChannelSuffix => + (super.noSuchMethod( + Invocation.getter(#pigeonVar_messageChannelSuffix), + returnValue: _i3.dummyValue( + this, + Invocation.getter(#pigeonVar_messageChannelSuffix), + ), + returnValueForMissingStub: _i3.dummyValue( + this, + Invocation.getter(#pigeonVar_messageChannelSuffix), + ), + ) + as String); + + @override + _i4.Future waitForMap() => + (super.noSuchMethod( + Invocation.method(#waitForMap, []), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateMapConfiguration( + _i2.PlatformMapConfiguration? configuration, + ) => + (super.noSuchMethod( + Invocation.method(#updateMapConfiguration, [configuration]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateCircles( + List<_i2.PlatformCircle>? toAdd, + List<_i2.PlatformCircle>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateCircles, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateHeatmaps( + List<_i2.PlatformHeatmap>? toAdd, + List<_i2.PlatformHeatmap>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateHeatmaps, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateClusterManagers( + List<_i2.PlatformClusterManager>? toAdd, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateClusterManagers, [toAdd, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateMarkers( + List<_i2.PlatformMarker>? toAdd, + List<_i2.PlatformMarker>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateMarkers, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updatePolygons( + List<_i2.PlatformPolygon>? toAdd, + List<_i2.PlatformPolygon>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updatePolygons, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updatePolylines( + List<_i2.PlatformPolyline>? toAdd, + List<_i2.PlatformPolyline>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updatePolylines, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateTileOverlays( + List<_i2.PlatformTileOverlay>? toAdd, + List<_i2.PlatformTileOverlay>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateTileOverlays, [ + toAdd, + toChange, + idsToRemove, + ]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateGroundOverlays( + List<_i2.PlatformGroundOverlay>? toAdd, + List<_i2.PlatformGroundOverlay>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateGroundOverlays, [ + toAdd, + toChange, + idsToRemove, + ]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future<_i2.PlatformPoint> getScreenCoordinate( + _i2.PlatformLatLng? latLng, + ) => + (super.noSuchMethod( + Invocation.method(#getScreenCoordinate, [latLng]), + returnValue: _i4.Future<_i2.PlatformPoint>.value( + _FakePlatformPoint_0( + this, + Invocation.method(#getScreenCoordinate, [latLng]), + ), + ), + returnValueForMissingStub: _i4.Future<_i2.PlatformPoint>.value( + _FakePlatformPoint_0( + this, + Invocation.method(#getScreenCoordinate, [latLng]), + ), + ), + ) + as _i4.Future<_i2.PlatformPoint>); + + @override + _i4.Future<_i2.PlatformLatLng> getLatLng( + _i2.PlatformPoint? screenCoordinate, + ) => + (super.noSuchMethod( + Invocation.method(#getLatLng, [screenCoordinate]), + returnValue: _i4.Future<_i2.PlatformLatLng>.value( + _FakePlatformLatLng_1( + this, + Invocation.method(#getLatLng, [screenCoordinate]), + ), + ), + returnValueForMissingStub: _i4.Future<_i2.PlatformLatLng>.value( + _FakePlatformLatLng_1( + this, + Invocation.method(#getLatLng, [screenCoordinate]), + ), + ), + ) + as _i4.Future<_i2.PlatformLatLng>); + + @override + _i4.Future<_i2.PlatformLatLngBounds> getVisibleRegion() => + (super.noSuchMethod( + Invocation.method(#getVisibleRegion, []), + returnValue: _i4.Future<_i2.PlatformLatLngBounds>.value( + _FakePlatformLatLngBounds_2( + this, + Invocation.method(#getVisibleRegion, []), + ), + ), + returnValueForMissingStub: + _i4.Future<_i2.PlatformLatLngBounds>.value( + _FakePlatformLatLngBounds_2( + this, + Invocation.method(#getVisibleRegion, []), + ), + ), + ) + as _i4.Future<_i2.PlatformLatLngBounds>); + + @override + _i4.Future moveCamera(_i2.PlatformCameraUpdate? cameraUpdate) => + (super.noSuchMethod( + Invocation.method(#moveCamera, [cameraUpdate]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future animateCamera( + _i2.PlatformCameraUpdate? cameraUpdate, + int? durationMilliseconds, + ) => + (super.noSuchMethod( + Invocation.method(#animateCamera, [ + cameraUpdate, + durationMilliseconds, + ]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future getZoomLevel() => + (super.noSuchMethod( + Invocation.method(#getZoomLevel, []), + returnValue: _i4.Future.value(0.0), + returnValueForMissingStub: _i4.Future.value(0.0), + ) + as _i4.Future); + + @override + _i4.Future showInfoWindow(String? markerId) => + (super.noSuchMethod( + Invocation.method(#showInfoWindow, [markerId]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future hideInfoWindow(String? markerId) => + (super.noSuchMethod( + Invocation.method(#hideInfoWindow, [markerId]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future isInfoWindowShown(String? markerId) => + (super.noSuchMethod( + Invocation.method(#isInfoWindowShown, [markerId]), + returnValue: _i4.Future.value(false), + returnValueForMissingStub: _i4.Future.value(false), + ) + as _i4.Future); + + @override + _i4.Future setStyle(String? style) => + (super.noSuchMethod( + Invocation.method(#setStyle, [style]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future getLastStyleError() => + (super.noSuchMethod( + Invocation.method(#getLastStyleError, []), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearTileCache(String? tileOverlayId) => + (super.noSuchMethod( + Invocation.method(#clearTileCache, [tileOverlayId]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future<_i5.Uint8List?> takeSnapshot() => + (super.noSuchMethod( + Invocation.method(#takeSnapshot, []), + returnValue: _i4.Future<_i5.Uint8List?>.value(), + returnValueForMissingStub: _i4.Future<_i5.Uint8List?>.value(), + ) + as _i4.Future<_i5.Uint8List?>); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/package_specific_test_import.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/package_specific_test_import.dart new file mode 100644 index 000000000000..2f86f15121d5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/test/package_specific_test_import.dart @@ -0,0 +1,11 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is a separate file so that all test files that need to import the +// implementation package can do so without causing diffs among the shared code +// due to the package names being different. This way, all the test files can +// be shared exactly, and only this file needs to diverge between the packages. + +export 'package:google_maps_flutter_ios_sdk9/google_maps_flutter_ios_sdk9.dart'; +export 'package:google_maps_flutter_ios_sdk9/src/messages.g.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/run_tests.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/run_tests.dart new file mode 100644 index 000000000000..114db5c7b00f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/run_tests.dart @@ -0,0 +1,102 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: avoid_print + +// Ensures that all files that are intended to be shared between +// google_maps_flutter_ios_* packages are in sync with the shared source of +// truth. See google_maps_flutter_ios_shared_code/README.md for details. +// +// Called from the custom-tests CI action. + +import 'dart:async'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +import 'utils.dart'; + +Future main(List args) async { + // There's no reason to run this on multiple platforms in CI, so limit it to + // macOS where local development of this package will be happening. + if (!Platform.isMacOS) { + print('Skipping for non-macOS host'); + exit(0); + } + + final Directory packageRoot = Directory( + p.dirname(Platform.script.path), + ).parent; + final String packageName = p.basename(packageRoot.path); + final sharedSourceRoot = Directory( + p.join(packageRoot.parent.path, 'google_maps_flutter_ios_shared_code'), + ); + + var failed = false; + for (final FileSystemEntity entity in sharedSourceRoot.listSync( + recursive: true, + )) { + if (entity is! File) { + continue; + } + final String relativePath = p.relative( + entity.path, + from: sharedSourceRoot.path, + ); + // The shared source README.md is not part of the shared source of truth, + // just an explanation of this source-sharing system. + if (relativePath == 'README.md') { + continue; + } + + // Adjust the paths to account for the package name being part of the + // directory structure for Swift packages. + final String packagePath = p.join( + packageRoot.path, + packageRelativePathForSharedSourceRelativePath(packageName, relativePath), + ); + + print('Validating $relativePath'); + final packageFile = File(packagePath); + if (!packageFile.existsSync()) { + print(' File $relativePath does not exist in $packageName'); + failed = true; + continue; + } + final String expectedContents = normalizedFileContents(entity); + final String contents = normalizedFileContents(packageFile); + if (contents != expectedContents) { + print(' File $relativePath does not match expected contents:'); + await _printDiff(entity, packageFile); + failed = true; + } + } + + if (failed) { + print(''' + +If the changes you made should be shared with other copies of the +implementation, copy the changes to google_maps_flutter_ios_* directories: + dart run tool/sync_shared_files.dart +To validate that the changes have been shared correctly, run this tool again. + +If the changes you made should only be made to one copy of the implementation, +discuss with your reviewer or #hackers-ecosystem on Discord about the best +approach to sharing as much code as can still be shared. + +For more information on the code sharing structure used by this package, see +the google_maps_flutter_ios_shared_code/README.md file. + '''); + exit(1); + } +} + +Future _printDiff(File expected, File actual) async { + final Process process = await Process.start('diff', [ + '-u', + expected.absolute.path, + actual.absolute.path, + ], mode: ProcessStartMode.inheritStdio); + await process.exitCode; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart new file mode 100644 index 000000000000..1a423bba92e6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart @@ -0,0 +1,198 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: avoid_print + +// Synchronizes files that are intended to be shared between +// google_maps_flutter_ios_* packages with the shared source of truth and other +// copies. See google_maps_flutter_ios_shared_code/README.md for details. + +import 'dart:async'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +import 'utils.dart'; + +const String _sharedSourceRootName = 'google_maps_flutter_ios_shared_code'; + +Future main(List args) async { + final Directory packageRoot = Directory( + p.dirname(Platform.script.path), + ).parent; + final String packageName = p.basename(packageRoot.path); + final sharedSourceRoot = Directory( + p.join(packageRoot.parent.path, _sharedSourceRootName), + ); + + _syncSharedFiles(packageRoot, packageName, sharedSourceRoot); + _reportUnsharedFiles(packageRoot, packageName, sharedSourceRoot); +} + +void _syncSharedFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List otherImplementationPackages = sharedSourceRoot.parent + .listSync() + .whereType() + .map((e) => p.basename(e.path)) + .where( + (name) => + name.startsWith('google_maps_flutter_ios') && + name != _sharedSourceRootName && + name != packageName, + ) + .toList(); + + final copiedFiles = []; + final missingFiles = []; + for (final FileSystemEntity entity in sharedSourceRoot.listSync( + recursive: true, + )) { + if (entity is! File) { + continue; + } + final String relativePath = p.relative( + entity.path, + from: sharedSourceRoot.path, + ); + // The shared source README.md is not part of the shared source of truth, + // just an explanation of this source-sharing system. + if (relativePath == 'README.md') { + continue; + } + + // Adjust the paths to account for the package name being part of the + // directory structure for Swift packages. + final String packagePath = p.join( + packageRoot.path, + packageRelativePathForSharedSourceRelativePath(packageName, relativePath), + ); + + final packageFile = File(packagePath); + if (!packageFile.existsSync()) { + missingFiles.add(relativePath); + continue; + } + final String sharedContents = normalizedFileContents(entity); + final String newContents = normalizedFileContents(packageFile); + if (newContents != sharedContents) { + copiedFiles.add(relativePath); + // Copy to shared source. + _syncFile(packageFile, entity.path, 'google_maps_flutter_ios'); + // Copy to other implementation packages. + for (final otherPackageName in otherImplementationPackages) { + final String otherPackagePath = p.join( + packageRoot.parent.path, + otherPackageName, + packageRelativePathForSharedSourceRelativePath( + otherPackageName, + relativePath, + ), + ); + _syncFile(packageFile, otherPackagePath, otherPackageName); + } + } + } + + if (copiedFiles.isNotEmpty) { + print('Copied files:'); + for (final file in copiedFiles) { + print(' $file'); + } + } + if (missingFiles.isNotEmpty) { + print( + 'This package is missing the following files from the shared source:', + ); + for (final file in missingFiles) { + print(' $file'); + } + print( + 'If these files should no longer be shared, remove them from the shared source.', + ); + } +} + +/// Syncs a file from the given source to a destination package. +/// +/// If the file needs special handling of package names that appear within the +/// contents of the file, it will update the package name in the file to match +/// the destination package name. +void _syncFile( + File source, + String destinationPath, + String destinationPackageName, +) { + source.copySync(destinationPath); + if ([ + // The Pigeon definition file has output paths that must use the + // package name, to follow Swift package naming rules. + '/pigeons/', + // The mock needs to import the package. + '.mocks.dart', + ].any((pattern) => source.absolute.path.contains(pattern))) { + updatePackageNameInPathReferences( + File(destinationPath), + destinationPackageName, + ); + } +} + +void _reportUnsharedFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List codeFiles = packageRoot + .listSync(recursive: true) + .whereType() + // Only report code files. + .where( + (file) => + ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), + ) + // Flutter-generated files aren't expected to be shared. + .where((file) => !file.path.contains('GeneratedPluginRegistrant')) + // Ignore intermediate file directories. + .where((file) => !_isInIntermediateDirectory(file.path)) + .toList(); + + final unsharedFiles = []; + for (final file in codeFiles) { + final String relativePath = p.relative(file.path, from: packageRoot.path); + final String sharedPath = p.join( + sharedSourceRoot.path, + sharedSourceRelativePathForPackagePath(relativePath), + ); + final sharedFile = File(sharedPath); + if (!sharedFile.existsSync()) { + unsharedFiles.add(relativePath); + } + } + + if (unsharedFiles.isNotEmpty) { + print('\nThe following code files are not shared with other packages:'); + for (final file in unsharedFiles) { + print(' $file'); + } + print( + 'If this is not intentional, copy the relevant files to ' + '$_sharedSourceRootName, then re-run this tool.', + ); + } +} + +bool _isInIntermediateDirectory(String path) { + return [ + '.dart_tool', + '.symlinks', + '.build', + 'build', + 'ephemeral', + 'Pods', + ].any((dir) => path.contains('/$dir/')); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart new file mode 100644 index 000000000000..d311e4f64891 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +/// Adjusts a package-relative path to account for the package name being part of +/// the directory structure for Swift packages. +String sharedSourceRelativePathForPackagePath(String packageRelativePath) { + return packageRelativePath.replaceAll( + RegExp(r'/google_maps_flutter_ios[_\w\d]*/'), + '/google_maps_flutter_ios/', + ); +} + +/// Adjusts a shared-source-relative path to account for the package name being +/// part of the directory structure for Swift packages. +String packageRelativePathForSharedSourceRelativePath( + String packageName, + String sharedSourceRelativePath, +) { + return sharedSourceRelativePath.replaceAll( + '/google_maps_flutter_ios/', + '/$packageName/', + ); +} + +/// Returns the contents of the file with any differences caused only by the +/// package name removed. +String normalizedFileContents(File file) { + return file + .readAsStringSync() + // Ignore differences caused only by the package name. + .replaceAll( + RegExp(r'google_maps_flutter_ios_[\w\d]+'), + 'google_maps_flutter_ios', + ) + // Package name diffs could change line wrapping, so collapse whitespace. + .replaceAll(RegExp(r'[\s\n]+'), ' ') + .trim(); +} + +/// Updates the contents of [file] to replace any occurrences of variants of the +/// package name in things that look like paths with [packageName]. +/// +/// This should only be used on files where this is the only option, and where +/// the diffs are known to be safe, as not all instances of the package name +/// should be replaced in all files. +void updatePackageNameInPathReferences(File file, String packageName) { + final String newContents = file.readAsStringSync().replaceAllMapped( + RegExp(r'google_maps_flutter_ios[_\w\d]*([:/])'), + (match) => '$packageName${match.group(1)}', + ); + file.writeAsStringSync(newContents); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/README.md new file mode 100644 index 000000000000..c40737087d93 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/README.md @@ -0,0 +1,31 @@ +# Shared source-of-truth code for google_maps_flutter on iOS + +This directory is not a package; instead it contains code that should be +identical in all versions of `google_maps_flutter_ios_*`. While each package +has its own copy of these files—allowing us to maintain multiple major version +wrappers without complex branching—each implementation package has a CI test +that validates that its copies of these files have not diverged. + +This means that for almost all changes to `google_maps_flutter_ios_*`, the +changes need to be copied here, and to all instances of the package, with any +instance of the package name itself changed in each copy. After making changes +in an implementation, run: +- `dart tool/sync_shared_files.dart` to automated most of the file copying. +- `dart tool/run_tests.dart` to ensure that all shared files match. + +See [this design document](https://docs.google.com/document/d/1g_GeFy4FnTHgUg-Kdmh5VOU8qOGaxGZ0J7cW75Gy8Uk/edit?usp=sharing) +for background on why the packages are structured this way. This approach +corresponds to solution E.1b in that document. + +When a new major version of the Google Maps SDK is released: +- Copy the latest google_maps_flutter_ios_sdk{N} package to + google_maps_flutter_ios_sdk{N+1}. +- Update the package name in all the relevant places (Swift Package directory + structure, pubspec, top-level lib/ file, pigeons/messages.dart, etc.). +- Update the versions in Package.swift. + - When creating google_maps_flutter_ios_sdk11, delete the podspec, since + version 10 is the last to support CocoaPods. +- Update the minimum deployment version in the example/ Xcode project. +- If there are any source-level breaking changes, fork files as necessary. + When feasible, refactor to minimize the amount of code that needs to diverge + from the shared source files. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/integration_test/google_maps_test.dart new file mode 100644 index 000000000000..824dea7d30c5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/integration_test/google_maps_test.dart @@ -0,0 +1,2257 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_example/example_google_map.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'resources/icon_image_base64.dart'; + +const LatLng _kInitialMapCenter = LatLng(0, 0); +const double _kInitialZoomLevel = 5; +const CameraPosition _kInitialCameraPosition = CameraPosition( + target: _kInitialMapCenter, + zoom: _kInitialZoomLevel, +); +const String _kCloudMapId = '000000000000000'; // Dummy map ID. + +// The tolerance value for floating-point comparisons in the tests. +// This value was selected as the minimum possible value that the test passes. +// There are multiple float conversions and calculations when data is converted +// between Dart and platform implementations. +const double _floatTolerance = 1e-6; +const double _kTestCameraZoomLevel = 10; +const double _kTestZoomByAmount = 2; +const LatLng _kTestMapCenter = LatLng(65, 25.5); +const CameraPosition _kTestCameraPosition = CameraPosition( + target: _kTestMapCenter, + zoom: _kTestCameraZoomLevel, + bearing: 1.0, + tilt: 1.0, +); +final LatLngBounds _testCameraBounds = LatLngBounds( + northeast: const LatLng(50, -65), + southwest: const LatLng(28.5, -123), +); +final ValueVariant _cameraUpdateTypeVariants = + ValueVariant(CameraUpdateType.values.toSet()); + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + GoogleMapsFlutterPlatform.instance.enableDebugInspection(); + + testWidgets('testCompassToggle', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + compassEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool compassEnabled = await inspector.isCompassEnabled(mapId: mapId); + expect(compassEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + compassEnabled = await inspector.isCompassEnabled(mapId: mapId); + expect(compassEnabled, true); + }); + + testWidgets('testMapToolbar returns false', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool mapToolbarEnabled = await inspector.isMapToolbarEnabled( + mapId: mapId, + ); + // This is only supported on Android, so should always return false. + expect(mapToolbarEnabled, false); + }); + + testWidgets('updateMinMaxZoomLevels', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + const initialZoomLevel = MinMaxZoomPreference(4, 8); + const finalZoomLevel = MinMaxZoomPreference(6, 10); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + minMaxZoomPreference: initialZoomLevel, + onMapCreated: (ExampleGoogleMapController c) async { + controllerCompleter.complete(c); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + MinMaxZoomPreference zoomLevel = await inspector.getMinMaxZoomLevels( + mapId: controller.mapId, + ); + expect(zoomLevel, equals(initialZoomLevel)); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + minMaxZoomPreference: finalZoomLevel, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + zoomLevel = await inspector.getMinMaxZoomLevels(mapId: controller.mapId); + expect(zoomLevel, equals(finalZoomLevel)); + }); + + testWidgets('testZoomGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + zoomGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool zoomGesturesEnabled = await inspector.areZoomGesturesEnabled( + mapId: mapId, + ); + expect(zoomGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + zoomGesturesEnabled = await inspector.areZoomGesturesEnabled(mapId: mapId); + expect(zoomGesturesEnabled, true); + }); + + testWidgets('testZoomControlsEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool zoomControlsEnabled = await inspector.areZoomControlsEnabled( + mapId: mapId, + ); + + /// Zoom Controls functionality is not available on iOS at the moment. + expect(zoomControlsEnabled, false); + }); + + testWidgets('testRotateGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + rotateGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool rotateGesturesEnabled = await inspector.areRotateGesturesEnabled( + mapId: mapId, + ); + expect(rotateGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + rotateGesturesEnabled = await inspector.areRotateGesturesEnabled( + mapId: mapId, + ); + expect(rotateGesturesEnabled, true); + }); + + testWidgets('testTiltGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tiltGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool tiltGesturesEnabled = await inspector.areTiltGesturesEnabled( + mapId: mapId, + ); + expect(tiltGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + tiltGesturesEnabled = await inspector.areTiltGesturesEnabled(mapId: mapId); + expect(tiltGesturesEnabled, true); + }); + + testWidgets('testScrollGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + scrollGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool scrollGesturesEnabled = await inspector.areScrollGesturesEnabled( + mapId: mapId, + ); + expect(scrollGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + scrollGesturesEnabled = await inspector.areScrollGesturesEnabled( + mapId: mapId, + ); + expect(scrollGesturesEnabled, true); + }); + + testWidgets( + 'testInitialCenterLocationAtCenter', + (WidgetTester tester) async { + await tester.binding.setSurfaceSize(const Size(800, 600)); + + final mapControllerCompleter = Completer(); + final Key key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapControllerCompleter.complete(controller); + }, + ), + ), + ); + final ExampleGoogleMapController mapController = + await mapControllerCompleter.future; + + await tester.pumpAndSettle(); + + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + final ScreenCoordinate coordinate = await mapController + .getScreenCoordinate(_kInitialCameraPosition.target); + final Rect rect = tester.getRect(find.byKey(key)); + expect(coordinate.x, (rect.center.dx - rect.topLeft.dx).round()); + expect(coordinate.y, (rect.center.dy - rect.topLeft.dy).round()); + + await tester.binding.setSurfaceSize(null); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets( + 'testGetVisibleRegion', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final zeroLatLngBounds = LatLngBounds( + southwest: const LatLng(0, 0), + northeast: const LatLng(0, 0), + ); + + final mapControllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapControllerCompleter.complete(controller); + }, + ), + ), + ); + await tester.pumpAndSettle(); + + final ExampleGoogleMapController mapController = + await mapControllerCompleter.future; + + final LatLngBounds firstVisibleRegion = await mapController + .getVisibleRegion(); + + expect(firstVisibleRegion, isNotNull); + expect(firstVisibleRegion.southwest, isNotNull); + expect(firstVisibleRegion.northeast, isNotNull); + expect(firstVisibleRegion, isNot(zeroLatLngBounds)); + expect(firstVisibleRegion.contains(_kInitialMapCenter), isTrue); + + // Making a new `LatLngBounds` about (10, 10) distance south west to the `firstVisibleRegion`. + // The size of the `LatLngBounds` is 10 by 10. + final southWest = LatLng( + firstVisibleRegion.southwest.latitude - 20, + firstVisibleRegion.southwest.longitude - 20, + ); + final northEast = LatLng( + firstVisibleRegion.southwest.latitude - 10, + firstVisibleRegion.southwest.longitude - 10, + ); + final newCenter = LatLng( + (northEast.latitude + southWest.latitude) / 2, + (northEast.longitude + southWest.longitude) / 2, + ); + + expect(firstVisibleRegion.contains(northEast), isFalse); + expect(firstVisibleRegion.contains(southWest), isFalse); + + final latLngBounds = LatLngBounds( + southwest: southWest, + northeast: northEast, + ); + + // TODO(iskakaushik): non-zero padding is needed for some device configurations + // https://github.com/flutter/flutter/issues/30575 + const double padding = 0; + await mapController.moveCamera( + CameraUpdate.newLatLngBounds(latLngBounds, padding), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final LatLngBounds secondVisibleRegion = await mapController + .getVisibleRegion(); + + expect(secondVisibleRegion, isNotNull); + expect(secondVisibleRegion.southwest, isNotNull); + expect(secondVisibleRegion.northeast, isNotNull); + expect(secondVisibleRegion, isNot(zeroLatLngBounds)); + + expect(firstVisibleRegion, isNot(secondVisibleRegion)); + expect(secondVisibleRegion.contains(newCenter), isTrue); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets('testTraffic', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + trafficEnabled: true, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool isTrafficEnabled = await inspector.isTrafficEnabled(mapId: mapId); + expect(isTrafficEnabled, true); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + isTrafficEnabled = await inspector.isTrafficEnabled(mapId: mapId); + expect(isTrafficEnabled, false); + }); + + testWidgets('testBuildings', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool isBuildingsEnabled = await inspector.areBuildingsEnabled( + mapId: mapId, + ); + expect(isBuildingsEnabled, true); + }); + + testWidgets('testMyLocationButtonToggle', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool myLocationButtonEnabled = await inspector.isMyLocationButtonEnabled( + mapId: mapId, + ); + expect(myLocationButtonEnabled, true); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + myLocationButtonEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + myLocationButtonEnabled = await inspector.isMyLocationButtonEnabled( + mapId: mapId, + ); + expect(myLocationButtonEnabled, false); + }); + + testWidgets('testMyLocationButton initial value false', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + myLocationButtonEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool myLocationButtonEnabled = await inspector + .isMyLocationButtonEnabled(mapId: mapId); + expect(myLocationButtonEnabled, false); + }); + + testWidgets('testMyLocationButton initial value true', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool myLocationButtonEnabled = await inspector + .isMyLocationButtonEnabled(mapId: mapId); + expect(myLocationButtonEnabled, true); + }); + + testWidgets('testSetMapStyle valid Json String', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + const mapStyle = + '[{"elementType":"geometry","stylers":[{"color":"#242f3e"}]}]'; + await GoogleMapsFlutterPlatform.instance.setMapStyle( + mapStyle, + mapId: controller.mapId, + ); + }); + + testWidgets('testSetMapStyle invalid Json String', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + try { + await GoogleMapsFlutterPlatform.instance.setMapStyle( + 'invalid_value', + mapId: controller.mapId, + ); + fail('expected MapStyleException'); + } on MapStyleException catch (e) { + expect(e.cause, isNotNull); + expect(await controller.getStyleError(), isNotNull); + } + }); + + testWidgets('testSetMapStyle null string', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + await GoogleMapsFlutterPlatform.instance.setMapStyle( + null, + mapId: controller.mapId, + ); + }); + + testWidgets('testGetLatLng', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + final LatLngBounds visibleRegion = await controller.getVisibleRegion(); + final LatLng topLeft = await controller.getLatLng( + const ScreenCoordinate(x: 0, y: 0), + ); + final northWest = LatLng( + visibleRegion.northeast.latitude, + visibleRegion.southwest.longitude, + ); + + expect(topLeft, northWest); + }); + + testWidgets( + 'testGetZoomLevel', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + double zoom = await controller.getZoomLevel(); + expect(zoom, _kInitialZoomLevel); + + await controller.moveCamera(CameraUpdate.zoomTo(7)); + await tester.pumpAndSettle(); + zoom = await controller.getZoomLevel(); + expect(zoom, equals(7)); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets( + 'testScreenCoordinate', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + final LatLngBounds visibleRegion = await controller.getVisibleRegion(); + final northWest = LatLng( + visibleRegion.northeast.latitude, + visibleRegion.southwest.longitude, + ); + final ScreenCoordinate topLeft = await controller.getScreenCoordinate( + northWest, + ); + expect(topLeft, const ScreenCoordinate(x: 0, y: 0)); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets('testResizeWidget', (WidgetTester tester) async { + final controllerCompleter = Completer(); + final map = ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) async { + controllerCompleter.complete(controller); + }, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MaterialApp( + home: Scaffold(body: SizedBox(height: 100, width: 100, child: map)), + ), + ), + ); + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MaterialApp( + home: Scaffold(body: SizedBox(height: 400, width: 400, child: map)), + ), + ), + ); + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + // Simple call to make sure that the app hasn't crashed. + final LatLngBounds bounds1 = await controller.getVisibleRegion(); + final LatLngBounds bounds2 = await controller.getVisibleRegion(); + expect(bounds1, bounds2); + }); + + testWidgets('testToggleInfoWindow', (WidgetTester tester) async { + const marker = Marker( + markerId: MarkerId('marker'), + infoWindow: InfoWindow(title: 'InfoWindow'), + ); + final markers = {marker}; + + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + onMapCreated: (ExampleGoogleMapController googleMapController) { + controllerCompleter.complete(googleMapController); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + bool iwVisibleStatus = await controller.isMarkerInfoWindowShown( + marker.markerId, + ); + expect(iwVisibleStatus, false); + + await controller.showMarkerInfoWindow(marker.markerId); + iwVisibleStatus = await controller.isMarkerInfoWindowShown(marker.markerId); + expect(iwVisibleStatus, true); + + await controller.hideMarkerInfoWindow(marker.markerId); + iwVisibleStatus = await controller.isMarkerInfoWindowShown(marker.markerId); + expect(iwVisibleStatus, false); + }); + + testWidgets('updating a marker does not hide its info window', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + const marker = Marker( + markerId: MarkerId('marker'), + infoWindow: InfoWindow(title: 'InfoWindow'), + ); + var markers = {marker}; + + const clusterManager = ClusterManager( + clusterManagerId: ClusterManagerId('cluster_manager'), + ); + final clusterManagers = {clusterManager}; + + final 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 controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final Uint8List? bytes = await controller.takeSnapshot(); + expect(bytes?.isNotEmpty, true); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets('set tileOverlay correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final tileOverlay1 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + transparency: 0.2, + ); + + final tileOverlay2 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_2'), + tileProvider: _DebugTileProvider(), + zIndex: 1, + visible: false, + transparency: 0.3, + fadeIn: false, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1, tileOverlay2}, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + final TileOverlay tileOverlayInfo1 = (await inspector.getTileOverlayInfo( + tileOverlay1.mapsId, + mapId: mapId, + ))!; + final TileOverlay tileOverlayInfo2 = (await inspector.getTileOverlayInfo( + tileOverlay2.mapsId, + mapId: mapId, + ))!; + + expect(tileOverlayInfo1.visible, isTrue); + expect(tileOverlayInfo1.fadeIn, isTrue); + expect( + tileOverlayInfo1.transparency, + moreOrLessEquals(0.2, epsilon: 0.001), + ); + expect(tileOverlayInfo1.zIndex, 2); + + expect(tileOverlayInfo2.visible, isFalse); + expect(tileOverlayInfo2.fadeIn, isFalse); + expect( + tileOverlayInfo2.transparency, + moreOrLessEquals(0.3, epsilon: 0.001), + ); + expect(tileOverlayInfo2.zIndex, 1); + }); + + testWidgets('update tileOverlays correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + final tileOverlay1 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + transparency: 0.2, + ); + + final tileOverlay2 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_2'), + tileProvider: _DebugTileProvider(), + zIndex: 3, + transparency: 0.5, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1, tileOverlay2}, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + final tileOverlay1New = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 1, + visible: false, + transparency: 0.3, + fadeIn: false, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1New}, + onMapCreated: (ExampleGoogleMapController controller) { + fail('update: OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final TileOverlay tileOverlayInfo1 = (await inspector.getTileOverlayInfo( + tileOverlay1.mapsId, + mapId: mapId, + ))!; + final TileOverlay? tileOverlayInfo2 = await inspector.getTileOverlayInfo( + tileOverlay2.mapsId, + mapId: mapId, + ); + + expect(tileOverlayInfo1.visible, isFalse); + expect(tileOverlayInfo1.fadeIn, isFalse); + expect( + tileOverlayInfo1.transparency, + moreOrLessEquals(0.3, epsilon: 0.001), + ); + expect(tileOverlayInfo1.zIndex, 1); + + expect(tileOverlayInfo2, isNull); + }); + + testWidgets('remove tileOverlays correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + final tileOverlay1 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + transparency: 0.2, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1}, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + final TileOverlay? tileOverlayInfo1 = await inspector.getTileOverlayInfo( + tileOverlay1.mapsId, + mapId: mapId, + ); + + expect(tileOverlayInfo1, isNull); + }); + + testWidgets('marker clustering', (WidgetTester tester) async { + final Key key = GlobalKey(); + const clusterManagersAmount = 2; + const markersPerClusterManager = 5; + final markers = {}; + final clusterManagers = {}; + + for (var i = 0; i < clusterManagersAmount; i++) { + final clusterManagerId = ClusterManagerId('cluster_manager_$i'); + final clusterManager = ClusterManager(clusterManagerId: clusterManagerId); + clusterManagers.add(clusterManager); + } + + for (final cm in clusterManagers) { + for (var i = 0; i < markersPerClusterManager; i++) { + final markerId = MarkerId('${cm.clusterManagerId.value}_marker_$i'); + final marker = Marker( + markerId: markerId, + clusterManagerId: cm.clusterManagerId, + position: LatLng( + _kInitialMapCenter.latitude + i, + _kInitialMapCenter.longitude, + ), + ); + markers[markerId] = marker; + } + } + + final controllerCompleter = Completer(); + + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + clusterManagers: clusterManagers, + markers: Set.of(markers.values), + onMapCreated: (ExampleGoogleMapController googleMapController) { + controllerCompleter.complete(googleMapController); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + for (final cm in clusterManagers) { + final List clusters = await inspector.getClusters( + mapId: controller.mapId, + clusterManagerId: cm.clusterManagerId, + ); + final int markersAmountForClusterManager = clusters + .map((Cluster cluster) => cluster.count) + .reduce((int value, int element) => value + element); + 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); + } + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + clusterManagers: clusterManagers, + markers: Set.of(markers.values), + ), + ), + ); + + for (final cm in clusterManagers) { + final List clusters = await inspector.getClusters( + mapId: controller.mapId, + clusterManagerId: cm.clusterManagerId, + ); + expect(clusters.length, 0); + } + }); + + testWidgets('testSetStyleMapId', (WidgetTester tester) async { + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + mapId: _kCloudMapId, + ), + ), + ); + }); + + testWidgets('getStyleError reports last error', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + style: '[[[this is an invalid style', + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final String? error = await controller.getStyleError(); + expect(error, isNotNull); + }); + + testWidgets('getStyleError returns null for a valid style', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + // An empty array is the simplest valid style. + style: '[]', + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final String? error = await controller.getStyleError(); + expect(error, isNull); + }); + + testWidgets('markerWithAssetMapBitmap', (WidgetTester tester) async { + final markers = { + Marker( + markerId: const MarkerId('1'), + icon: AssetMapBitmap('assets/red_square.png', imagePixelRatio: 1.0), + ), + }; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + ), + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithAssetMapBitmapCreate', (WidgetTester tester) async { + final imageConfiguration = ImageConfiguration( + devicePixelRatio: tester.view.devicePixelRatio, + ); + final markers = { + Marker( + markerId: const MarkerId('1'), + icon: await AssetMapBitmap.create( + imageConfiguration, + 'assets/red_square.png', + ), + ), + }; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + ), + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithBytesMapBitmap', (WidgetTester tester) async { + final Uint8List bytes = const Base64Decoder().convert(iconImageBase64); + final markers = { + Marker( + markerId: const MarkerId('1'), + icon: BytesMapBitmap( + bytes, + imagePixelRatio: tester.view.devicePixelRatio, + ), + ), + }; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + ), + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithLegacyAsset', (WidgetTester tester) async { + //tester.view.devicePixelRatio = 2.0; + const imageConfiguration = ImageConfiguration( + devicePixelRatio: 2.0, + size: Size(100, 100), + ); + final markers = { + Marker( + markerId: const MarkerId('1'), + // Intentionally testing the deprecated code path. + // ignore: deprecated_member_use + icon: await BitmapDescriptor.fromAssetImage( + imageConfiguration, + 'assets/red_square.png', + ), + ), + }; + final controllerCompleter = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + onMapCreated: (ExampleGoogleMapController controller) => + controllerCompleter.complete(controller), + ), + ), + ); + + await controllerCompleter.future; + }); + + testWidgets('markerWithLegacyBytes', (WidgetTester tester) async { + tester.view.devicePixelRatio = 2.0; + final Uint8List bytes = const Base64Decoder().convert(iconImageBase64); + // Intentionally testing the deprecated code path. + // ignore: deprecated_member_use + final BitmapDescriptor icon = BitmapDescriptor.fromBytes(bytes); + + final markers = {Marker(markerId: const MarkerId('1'), icon: icon)}; + final controllerCompleter = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + onMapCreated: (ExampleGoogleMapController controller) => + controllerCompleter.complete(controller), + ), + ), + ); + await controllerCompleter.future; + }); + + group('GroundOverlay', () { + final kGroundOverlayBounds = LatLngBounds( + southwest: const LatLng(37.77483, -122.41942), + northeast: const LatLng(37.78183, -122.39105), + ); + + final groundOverlayBounds1 = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('bounds_1'), + bounds: kGroundOverlayBounds, + image: AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ), + ); + + final groundOverlayPosition1 = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('position_1'), + position: kGroundOverlayBounds.northeast, + width: 100, + height: 100, + anchor: const Offset(0.1, 0.2), + zoomLevel: 14.0, + image: AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ), + ); + + void expectGroundOverlayEquals( + GroundOverlay source, + GroundOverlay response, + ) { + expect(response.groundOverlayId, source.groundOverlayId); + expect( + response.transparency, + moreOrLessEquals(source.transparency, epsilon: _floatTolerance), + ); + expect( + response.bearing, + moreOrLessEquals(source.bearing, epsilon: _floatTolerance), + ); + + // Only test bounds if it was given in the original object + if (source.bounds != null) { + expect(response.bounds, source.bounds); + } + + // Only test position if it was given in the original object + if (source.position != null) { + expect(response.position, source.position); + } + + expect(response.clickable, source.clickable); + expect(response.zIndex, source.zIndex); + expect(response.zoomLevel, source.zoomLevel); + expect( + response.anchor?.dx, + moreOrLessEquals(source.anchor!.dx, epsilon: _floatTolerance), + ); + expect( + response.anchor?.dy, + moreOrLessEquals(source.anchor!.dy, epsilon: _floatTolerance), + ); + } + + testWidgets('set ground overlays correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final groundOverlayBounds2 = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('bounds_2'), + bounds: groundOverlayBounds1.bounds!, + image: groundOverlayBounds1.image, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1, + groundOverlayBounds2, + groundOverlayPosition1, + }, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + if (inspector.supportsGettingGroundOverlayInfo()) { + final GroundOverlay groundOverlayBoundsInfo1 = (await inspector + .getGroundOverlayInfo(groundOverlayBounds1.mapsId, mapId: mapId))!; + final GroundOverlay groundOverlayBoundsInfo2 = (await inspector + .getGroundOverlayInfo(groundOverlayBounds2.mapsId, mapId: mapId))!; + final GroundOverlay groundOverlayPositionInfo1 = (await inspector + .getGroundOverlayInfo( + groundOverlayPosition1.mapsId, + mapId: mapId, + ))!; + + expectGroundOverlayEquals( + groundOverlayBounds1, + groundOverlayBoundsInfo1, + ); + expectGroundOverlayEquals( + groundOverlayBounds2, + groundOverlayBoundsInfo2, + ); + expectGroundOverlayEquals( + groundOverlayPosition1, + groundOverlayPositionInfo1, + ); + } + }); + + testWidgets('update ground overlays correctly', ( + WidgetTester tester, + ) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1, + groundOverlayPosition1, + }, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + final GroundOverlay groundOverlayBounds1New = groundOverlayBounds1 + .copyWith( + bearingParam: 10, + clickableParam: false, + transparencyParam: 0.5, + visibleParam: false, + zIndexParam: 10, + ); + + final GroundOverlay groundOverlayPosition1New = groundOverlayPosition1 + .copyWith( + bearingParam: 10, + clickableParam: false, + transparencyParam: 0.5, + visibleParam: false, + zIndexParam: 10, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1New, + groundOverlayPosition1New, + }, + onMapCreated: (ExampleGoogleMapController controller) { + fail('update: OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + if (inspector.supportsGettingGroundOverlayInfo()) { + final GroundOverlay groundOverlayBounds1Info = (await inspector + .getGroundOverlayInfo(groundOverlayBounds1.mapsId, mapId: mapId))!; + final GroundOverlay groundOverlayPosition1Info = (await inspector + .getGroundOverlayInfo( + groundOverlayPosition1.mapsId, + mapId: mapId, + ))!; + + expectGroundOverlayEquals( + groundOverlayBounds1New, + groundOverlayBounds1Info, + ); + expectGroundOverlayEquals( + groundOverlayPosition1New, + groundOverlayPosition1Info, + ); + } + }); + + testWidgets('remove ground overlays correctly', ( + WidgetTester tester, + ) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1, + groundOverlayPosition1, + }, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + if (inspector.supportsGettingGroundOverlayInfo()) { + final GroundOverlay? groundOverlayBounds1Info = await inspector + .getGroundOverlayInfo(groundOverlayBounds1.mapsId, mapId: mapId); + final GroundOverlay? groundOverlayPositionInfo = await inspector + .getGroundOverlayInfo(groundOverlayPosition1.mapsId, mapId: mapId); + + expect(groundOverlayBounds1Info, isNull); + expect(groundOverlayPositionInfo, isNull); + } + }); + }); + + testWidgets( + 'testAnimateCameraWithoutDuration', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + /// Completer to track when the camera has come to rest. + Completer? cameraIdleCompleter; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onCameraIdle: () { + if (cameraIdleCompleter != null && + !cameraIdleCompleter.isCompleted) { + cameraIdleCompleter.complete(); + } + }, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and + // `mapControllerCompleter.complete(controller)` above should happen in + // `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + // Create completer for camera idle event. + cameraIdleCompleter = Completer(); + + final CameraUpdate cameraUpdate = _getCameraUpdateForType( + _cameraUpdateTypeVariants.currentValue!, + ); + await controller.animateCamera(cameraUpdate); + + // Immediately after calling animateCamera, check that the camera hasn't + // reached its final position. This relies on the assumption that the + // camera move is animated and won't complete instantly. + final CameraPosition beforeFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + beforeFinishedPosition, + null, + controller, + (Matcher matcher) => isNot(matcher), + ); + + // Wait for the animation to complete (onCameraIdle). + expect(cameraIdleCompleter.isCompleted, isFalse); + await cameraIdleCompleter.future; + + // After onCameraIdle event, the camera should be at the final position. + final CameraPosition afterFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + afterFinishedPosition, + beforeFinishedPosition, + controller, + (Matcher matcher) => matcher, + ); + + await tester.pumpAndSettle(); + }, + variant: _cameraUpdateTypeVariants, + // Hanging in CI, https://github.com/flutter/flutter/issues/166139 + skip: true, + ); + + /// Tests animating the camera with specified durations to verify timing + /// behavior. + /// + /// This test checks two scenarios: short and long animation durations. + /// It uses a midpoint duration to ensure the short animation completes in + /// less time and the long animation takes more time than that midpoint. + /// This ensures that the animation duration is respected by the platform and + /// that the default camera animation duration does not affect the test + /// results. + testWidgets( + 'testAnimateCameraWithDuration', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + /// Completer to track when the camera has come to rest. + Completer? cameraIdleCompleter; + + const shortCameraAnimationDurationMS = 200; + const longCameraAnimationDurationMS = 1000; + + /// Calculate the midpoint duration of the animation test, which will + /// serve as a reference to verify that animations complete more quickly + /// with shorter durations and more slowly with longer durations. + const int animationDurationMiddlePoint = + (shortCameraAnimationDurationMS + longCameraAnimationDurationMS) ~/ 2; + + // Stopwatch to measure the time taken for the animation to complete. + final stopwatch = Stopwatch(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onCameraIdle: () { + if (cameraIdleCompleter != null && + !cameraIdleCompleter.isCompleted) { + stopwatch.stop(); + cameraIdleCompleter.complete(); + } + }, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and + // `mapControllerCompleter.complete(controller)` above should happen in + // `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + // Create completer for camera idle event. + cameraIdleCompleter = Completer(); + + // Start stopwatch to check the time taken for the animation to complete. + // Stopwatch is stopped on camera idle callback. + stopwatch.reset(); + stopwatch.start(); + + // First phase with shorter animation duration. + final CameraUpdate cameraUpdateShort = _getCameraUpdateForType( + _cameraUpdateTypeVariants.currentValue!, + ); + await controller.animateCamera( + cameraUpdateShort, + duration: const Duration(milliseconds: shortCameraAnimationDurationMS), + ); + + // Wait for the animation to complete (onCameraIdle). + expect(cameraIdleCompleter.isCompleted, isFalse); + await cameraIdleCompleter.future; + + // For short animation duration, check that the animation is completed + // faster than the midpoint benchmark. + expect( + stopwatch.elapsedMilliseconds, + lessThan(animationDurationMiddlePoint), + ); + + // Reset camera to initial position before testing long duration. + await controller.moveCamera( + CameraUpdate.newCameraPosition(_kInitialCameraPosition), + ); + await tester.pumpAndSettle(); + + // Create completer for camera idle event. + cameraIdleCompleter = Completer(); + + // Start stopwatch to check the time taken for the animation to complete. + // Stopwatch is stopped on camera idle callback. + stopwatch.reset(); + stopwatch.start(); + + // Second phase with longer animation duration. + final CameraUpdate cameraUpdateLong = _getCameraUpdateForType( + _cameraUpdateTypeVariants.currentValue!, + ); + await controller.animateCamera( + cameraUpdateLong, + duration: const Duration(milliseconds: longCameraAnimationDurationMS), + ); + + // Immediately after calling animateCamera, check that the camera hasn't + // reached its final position. This relies on the assumption that the + // camera move is animated and won't complete instantly. + final CameraPosition beforeFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + beforeFinishedPosition, + null, + controller, + (Matcher matcher) => isNot(matcher), + ); + + // Wait for the animation to complete (onCameraIdle). + expect(cameraIdleCompleter.isCompleted, isFalse); + await cameraIdleCompleter.future; + + // For longer animation duration, check that the animation is completed + // slower than the midpoint benchmark. + expect( + stopwatch.elapsedMilliseconds, + greaterThan(animationDurationMiddlePoint), + ); + + // Camera should be at the final position. + final CameraPosition afterFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + afterFinishedPosition, + beforeFinishedPosition, + controller, + (Matcher matcher) => matcher, + ); + + await tester.pumpAndSettle(); + }, + variant: _cameraUpdateTypeVariants, + // Hanging in CI, https://github.com/flutter/flutter/issues/166139 + skip: true, + ); +} + +class _DebugTileProvider implements TileProvider { + _DebugTileProvider() { + boxPaint.isAntiAlias = true; + boxPaint.color = Colors.blue; + boxPaint.strokeWidth = 2.0; + boxPaint.style = PaintingStyle.stroke; + } + + static const int width = 100; + static const int height = 100; + static final Paint boxPaint = Paint(); + static const TextStyle textStyle = TextStyle(color: Colors.red, fontSize: 20); + + @override + Future getTile(int x, int y, int? zoom) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final textSpan = TextSpan(text: '$x,$y', style: textStyle); + final textPainter = TextPainter( + text: textSpan, + textDirection: TextDirection.ltr, + ); + textPainter.layout(maxWidth: width.toDouble()); + textPainter.paint(canvas, Offset.zero); + canvas.drawRect( + Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), + boxPaint, + ); + final ui.Picture picture = recorder.endRecording(); + final Uint8List byteData = await picture + .toImage(width, height) + .then( + (ui.Image image) => image.toByteData(format: ui.ImageByteFormat.png), + ) + .then((ByteData? byteData) => byteData!.buffer.asUint8List()); + return Tile(width, height, byteData); + } +} + +Marker _copyMarkerWithClusterManagerId( + Marker marker, + ClusterManagerId? clusterManagerId, +) { + return Marker( + markerId: marker.markerId, + alpha: marker.alpha, + anchor: marker.anchor, + consumeTapEvents: marker.consumeTapEvents, + draggable: marker.draggable, + flat: marker.flat, + icon: marker.icon, + infoWindow: marker.infoWindow, + position: marker.position, + rotation: marker.rotation, + visible: marker.visible, + zIndexInt: marker.zIndexInt, + onTap: marker.onTap, + onDragStart: marker.onDragStart, + onDrag: marker.onDrag, + onDragEnd: marker.onDragEnd, + clusterManagerId: clusterManagerId, + ); +} + +CameraUpdate _getCameraUpdateForType(CameraUpdateType type) { + return switch (type) { + CameraUpdateType.newCameraPosition => CameraUpdate.newCameraPosition( + _kTestCameraPosition, + ), + CameraUpdateType.newLatLng => CameraUpdate.newLatLng(_kTestMapCenter), + CameraUpdateType.newLatLngBounds => CameraUpdate.newLatLngBounds( + _testCameraBounds, + 0, + ), + CameraUpdateType.newLatLngZoom => CameraUpdate.newLatLngZoom( + _kTestMapCenter, + _kTestCameraZoomLevel, + ), + CameraUpdateType.scrollBy => CameraUpdate.scrollBy(10, 10), + CameraUpdateType.zoomBy => CameraUpdate.zoomBy( + _kTestZoomByAmount, + const Offset(1, 1), + ), + CameraUpdateType.zoomTo => CameraUpdate.zoomTo(_kTestCameraZoomLevel), + CameraUpdateType.zoomIn => CameraUpdate.zoomIn(), + CameraUpdateType.zoomOut => CameraUpdate.zoomOut(), + }; +} + +Future _checkCameraUpdateByType( + CameraUpdateType type, + CameraPosition currentPosition, + CameraPosition? oldPosition, + ExampleGoogleMapController controller, + Matcher Function(Matcher matcher) wrapMatcher, +) async { + // As the target might differ a bit from the expected target, a threshold is + // used. + const latLngThreshold = 0.05; + + switch (type) { + case CameraUpdateType.newCameraPosition: + expect( + currentPosition.bearing, + wrapMatcher(equals(_kTestCameraPosition.bearing)), + ); + expect( + currentPosition.zoom, + wrapMatcher(equals(_kTestCameraPosition.zoom)), + ); + expect( + currentPosition.tilt, + wrapMatcher(equals(_kTestCameraPosition.tilt)), + ); + expect( + currentPosition.target.latitude, + wrapMatcher( + closeTo(_kTestCameraPosition.target.latitude, latLngThreshold), + ), + ); + expect( + currentPosition.target.longitude, + wrapMatcher( + closeTo(_kTestCameraPosition.target.longitude, latLngThreshold), + ), + ); + case CameraUpdateType.newLatLng: + expect( + currentPosition.target.latitude, + wrapMatcher(closeTo(_kTestMapCenter.latitude, latLngThreshold)), + ); + expect( + currentPosition.target.longitude, + wrapMatcher(closeTo(_kTestMapCenter.longitude, latLngThreshold)), + ); + case CameraUpdateType.newLatLngBounds: + final LatLngBounds bounds = await controller.getVisibleRegion(); + expect( + bounds.northeast.longitude, + wrapMatcher( + closeTo(_testCameraBounds.northeast.longitude, latLngThreshold), + ), + ); + expect( + bounds.southwest.longitude, + wrapMatcher( + closeTo(_testCameraBounds.southwest.longitude, latLngThreshold), + ), + ); + case CameraUpdateType.newLatLngZoom: + expect( + currentPosition.target.latitude, + wrapMatcher(closeTo(_kTestMapCenter.latitude, latLngThreshold)), + ); + expect( + currentPosition.target.longitude, + wrapMatcher(closeTo(_kTestMapCenter.longitude, latLngThreshold)), + ); + expect(currentPosition.zoom, wrapMatcher(equals(_kTestCameraZoomLevel))); + case CameraUpdateType.scrollBy: + // For scrollBy, just check that the location has changed. + if (oldPosition != null) { + expect( + currentPosition.target.latitude, + isNot(equals(oldPosition.target.latitude)), + ); + expect( + currentPosition.target.longitude, + isNot(equals(oldPosition.target.longitude)), + ); + } + case CameraUpdateType.zoomBy: + expect( + currentPosition.zoom, + wrapMatcher(equals(_kInitialZoomLevel + _kTestZoomByAmount)), + ); + case CameraUpdateType.zoomTo: + expect(currentPosition.zoom, wrapMatcher(equals(_kTestCameraZoomLevel))); + case CameraUpdateType.zoomIn: + expect(currentPosition.zoom, wrapMatcher(equals(_kInitialZoomLevel + 1))); + case CameraUpdateType.zoomOut: + expect(currentPosition.zoom, wrapMatcher(equals(_kInitialZoomLevel - 1))); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/integration_test/resources/icon_image_base64.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/integration_test/resources/icon_image_base64.dart new file mode 100644 index 000000000000..6b576e010572 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/integration_test/resources/icon_image_base64.dart @@ -0,0 +1,49 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// This constant holds the base64-encoded data of a 16x16 PNG image of the +/// Flutter logo. +/// +/// See `icon_image.png` source in the same directory. +/// +/// To create or update this image, follow these steps: +/// 1. Create or update a 16x16 PNG image. +/// 2. Convert the image to a base64 string using a script below. +/// 3. Replace the existing base64 string below with the new one. +/// +/// Example of converting an image to base64 in Dart: +/// ```dart +/// import 'dart:convert'; +/// import 'dart:io'; +/// +/// void main() async { +/// final bytes = await File('icon_image.png').readAsBytes(); +/// final base64String = base64Encode(bytes); +/// print(base64String); +/// } +/// ``` +const String iconImageBase64 = + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAIRlWElmTU' + '0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIA' + 'AIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQ' + 'AAABCgAwAEAAAAAQAAABAAAAAAx28c8QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1M' + 'OmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIH' + 'g6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8v' + 'd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcm' + 'lwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFk' + 'b2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk' + '9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6' + 'eG1wbWV0YT4KTMInWQAAAplJREFUOBF1k01ME1EQx2fe7tIPoGgTE6AJgQQSPaiH9oAtkFbsgX' + 'jygFcT0XjSkxcTDxtPJh6MR28ePMHBBA8cNLSIony0oBhEMVETP058tE132+7uG3cW24DAXN57' + '2fn9/zPz3iIcEdEl0nIxtNLr1IlVeoMadkubKmoL+u2SzAV8IjV5Ekt4GN+A8+VOUPwLarOI2G' + 'Vpqq0i4JQorwQxPtWHVZ1IKP8LNGDXGaSyqARFxDGo7MJBy4XVf3AyQ+qTHnTEXoF9cFUy3OkY' + '0oWxmWFtD5xNoc1sQ6AOn1+hCNTkkhKow8KFZV77tVs2O9dhFvBm0IA/U0RhZ7/ocEx23oUDlh' + 'h8HkNjZIN8Lb3gOU8gOp7AKJHCB2/aNZkTftHumNzzbtl2CBPZHqxw8mHhVZBeoz6w5DvhE2FZ' + 'lQYPjKdd2/qRyKZ6KsPv7TEk7EYEk0A0EUmJduHRy1i4oLKqgmC59ZggAdwrC9pFuWy1iUT2rA' + 'uv0h2UdNtNqxCBBkgqorjOMOgksN7CxQ90vEb00U3c3LIwyo9o8FXxQVNr8Coqyk+S5EPBXnjt' + 'xRmc4TegI7qWbvBkeeUbGMnTCd4nZnYeDOWIEtlC6cKK/JJepY3hZSvN33jovO6L0XFqPKqBTO' + 'FuapUoPr1lxDM7cmC2TAOz25cYSGa++feBew/cjpc0V+mNT29/HZp3KDFTNLvuTRPEHy5065lj' + 'Xn4y41XM+wP/AlcycRmdc3MUhvLm/J/ceu/3qUVT62oP2EZpjSylHybHSpDUVcjq9gEBVo0+Xt' + 'JyN2IWRO+3QUforRoKnZLVsglaMECW+YmMSj9M3SrC6Lg71CMiqWfUrJ6ywzefhnZ+G69BaKdB' + 'WhXQAn6wzDUpfUPw7MrmX/WhbfmKblw+AAAAAElFTkSuQmCC'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/Runner/AppDelegate.swift b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000000..a382ba8b736e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,21 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter +import GoogleMaps +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + var mapsApiKey = ProcessInfo.processInfo.environment["MAPS_API_KEY"] ?? "YOUR KEY HERE" + GMSServices.provideAPIKey(mapsApiKey) + + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/Runner/Runner-Bridging-Header.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000000..ba04211afd0a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1,5 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GeneratedPluginRegistrant.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/ExtractIconFromDataTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/ExtractIconFromDataTests.m new file mode 100644 index 000000000000..4d7da98cac59 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/ExtractIconFromDataTests.m @@ -0,0 +1,352 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; + +#import +#import + +@interface ExtractIconFromDataTests : XCTestCase +- (UIImage *)createOnePixelImage; +@end + +@implementation ExtractIconFromDataTests + +- (void)testExtractIconFromDataAssetAuto { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testExtractIconFromDataAssetAutoWithScale { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:10 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 10); + XCTAssertEqual(resultImage.size.width, 0.1); + XCTAssertEqual(resultImage.size.height, 0.1); +} + +- (void)testExtractIconFromDataAssetAutoAndSizeWithSameAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + XCTAssertEqual(testImage.scale, 1.0); + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + const CGFloat width = 15.0; + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(testImage.scale, 1.0); + + // As image has same aspect ratio as the original image, + // only image scale has been changed to match the target size. + CGFloat targetScale = testImage.scale * (testImage.size.width / width); + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(resultImage.scale, targetScale, accuracy); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, width); +} + +- (void)testExtractIconFromDataAssetAutoAndSizeWithDifferentAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + const CGFloat width = 15.0; + const CGFloat height = 45.0; + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:@(height)]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, screenScale); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, height); +} + +- (void)testExtractIconFromDataAssetNoScaling { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingNone + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testExtractIconFromDataBytesAuto { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testExtractIconFromDataBytesAutoWithScaling { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:10 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 10); + XCTAssertEqual(resultImage.size.width, 0.1); + XCTAssertEqual(resultImage.size.height, 0.1); +} + +- (void)testExtractIconFromDataBytesAutoAndSizeWithSameAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + const CGFloat width = 15.0; + const CGFloat height = 15.0; + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:@(height)]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(testImage.scale, 1.0); + + // As image has same aspect ratio as the original image, + // only image scale has been changed to match the target size. + CGFloat targetScale = testImage.scale * (testImage.size.width / width); + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(resultImage.scale, targetScale, accuracy); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, height); +} + +- (void)testExtractIconFromDataBytesAutoAndSizeWithDifferentAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + const CGFloat width = 15.0; + const CGFloat height = 45.0; + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:@(height)]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, screenScale); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, height); +} + +- (void)testExtractIconFromDataBytesNoScaling { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingNone + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testIsScalableWithScaleFactorFromSize100x100to10x100 { + CGSize originalSize = CGSizeMake(100.0, 100.0); + CGSize targetSize = CGSizeMake(10.0, 100.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize100x100to10x10 { + CGSize originalSize = CGSizeMake(100.0, 100.0); + CGSize targetSize = CGSizeMake(10.0, 10.0); + XCTAssertTrue(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize233x200to23x20 { + CGSize originalSize = CGSizeMake(233.0, 200.0); + CGSize targetSize = CGSizeMake(23.0, 20.0); + XCTAssertTrue(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize233x200to22x20 { + CGSize originalSize = CGSizeMake(233.0, 200.0); + CGSize targetSize = CGSizeMake(22.0, 20.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize200x233to20x23 { + CGSize originalSize = CGSizeMake(200.0, 233.0); + CGSize targetSize = CGSizeMake(20.0, 23.0); + XCTAssertTrue(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize200x233to20x22 { + CGSize originalSize = CGSizeMake(200.0, 233.0); + CGSize targetSize = CGSizeMake(20.0, 22.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize1024x768to500x250 { + CGSize originalSize = CGSizeMake(1024.0, 768.0); + CGSize targetSize = CGSizeMake(500.0, 250.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (UIImage *)createOnePixelImage { + CGSize size = CGSizeMake(1, 1); + UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat]; + format.scale = 1.0; + format.opaque = YES; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size + format:format]; + UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { + [UIColor.whiteColor setFill]; + [context fillRect:CGRectMake(0, 0, size.width, size.height)]; + }]; + return image; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMClusterManagersControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMClusterManagersControllerTests.m new file mode 100644 index 000000000000..f9baaa10184b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMClusterManagersControllerTests.m @@ -0,0 +1,145 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import +#import "PartiallyMockedMapView.h" + +@interface FGMClusterManagersControllerTests : XCTestCase +@end + +@implementation FGMClusterManagersControllerTests + +- (void)testClustering { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + CGRect frame = CGRectMake(0, 0, 100, 100); + + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + id handler = OCMClassMock([FGMMapsCallbackApi class]); + + FGMClusterManagersController *clusterManagersController = + [[FGMClusterManagersController alloc] initWithMapView:mapView callbackHandler:handler]; + + FLTMarkersController *markersController = + [[FLTMarkersController alloc] initWithMapView:mapView + callbackHandler:handler + clusterManagersController:clusterManagersController + registrar:registrar]; + + // Add cluster managers. + NSString *clusterManagerId = @"cm"; + FGMPlatformClusterManager *clusterManagerToAdd = + [FGMPlatformClusterManager makeWithIdentifier:clusterManagerId]; + [clusterManagersController addClusterManagers:@[ clusterManagerToAdd ]]; + + // Verify that cluster managers are available + GMUClusterManager *clusterManager = + [clusterManagersController clusterManagerWithIdentifier:clusterManagerId]; + XCTAssertNotNil(clusterManager, @"Cluster Manager should not be nil"); + + // Add markers + NSString *markerId1 = @"m1"; + NSString *markerId2 = @"m2"; + + FGMPlatformPoint *zeroPoint = [FGMPlatformPoint makeWithX:0 y:0]; + FGMPlatformLatLng *zeroLatLng = [FGMPlatformLatLng makeWithLatitude:0 longitude:0]; + FGMPlatformBitmap *bitmap = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + FGMPlatformInfoWindow *infoWindow = [FGMPlatformInfoWindow makeWithTitle:@"Info" + snippet:NULL + anchor:zeroPoint]; + FGMPlatformMarker *marker1 = [FGMPlatformMarker makeWithAlpha:1 + anchor:zeroPoint + consumeTapEvents:NO + draggable:NO + flat:NO + icon:bitmap + infoWindow:infoWindow + position:zeroLatLng + rotation:0 + visible:YES + zIndex:1 + markerId:markerId1 + clusterManagerId:clusterManagerId]; + FGMPlatformMarker *marker2 = [FGMPlatformMarker makeWithAlpha:1 + anchor:zeroPoint + consumeTapEvents:NO + draggable:NO + flat:NO + icon:bitmap + infoWindow:infoWindow + position:zeroLatLng + rotation:0 + visible:YES + zIndex:1 + markerId:markerId2 + clusterManagerId:clusterManagerId]; + + [markersController addMarkers:@[ marker1, marker2 ]]; + + FlutterError *error = nil; + + // Invoke clustering + [clusterManagersController invokeClusteringForEachClusterManager]; + + // Verify that the markers were added to the cluster manager + NSArray *clusters1 = + [clusterManagersController clustersWithIdentifier:clusterManagerId error:&error]; + XCTAssertNil(error, @"Error should be nil"); + for (FGMPlatformCluster *cluster in clusters1) { + NSString *cmId = cluster.clusterManagerId; + XCTAssertNotNil(cmId, @"Cluster Manager Identifier should not be nil"); + if ([cmId isEqualToString:clusterManagerId]) { + NSArray *markerIds = cluster.markerIds; + XCTAssertEqual(markerIds.count, 2, @"Cluster should contain two marker"); + XCTAssertTrue([markerIds containsObject:markerId1], @"Cluster should contain markerId1"); + XCTAssertTrue([markerIds containsObject:markerId2], @"Cluster should contain markerId2"); + return; + } + } + + [markersController removeMarkersWithIdentifiers:@[ markerId2 ]]; + + // Verify that the marker2 is removed from the clusterManager + NSArray *clusters2 = + [clusterManagersController clustersWithIdentifier:clusterManagerId error:&error]; + XCTAssertNil(error, @"Error should be nil"); + + for (FGMPlatformCluster *cluster in clusters2) { + NSString *cmId = cluster.clusterManagerId; + XCTAssertNotNil(cmId, @"Cluster Manager ID should not be nil"); + if ([cmId isEqualToString:clusterManagerId]) { + NSArray *markerIds = cluster.markerIds; + XCTAssertEqual(markerIds.count, 1, @"Cluster should contain one marker"); + XCTAssertTrue([markerIds containsObject:markerId1], @"Cluster should contain markerId1"); + return; + } + } + + [markersController removeMarkersWithIdentifiers:@[ markerId1 ]]; + + // Verify that all markers are removed from clusterManager + NSArray *clusters3 = + [clusterManagersController clustersWithIdentifier:clusterManagerId error:&error]; + XCTAssertNil(error, @"Error should be nil"); + XCTAssertEqual(clusters3.count, 0, @"Cluster Manager should not contain any clusters"); + + // Remove cluster manager + [clusterManagersController removeClusterManagersWithIdentifiers:@[ clusterManagerId ]]; + + // Verify that the cluster manager is removed + clusterManager = [clusterManagersController clusterManagerWithIdentifier:clusterManagerId]; + XCTAssertNil(clusterManager, @"Cluster Manager should be nil"); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMConversionsUtilsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMConversionsUtilsTests.m new file mode 100644 index 000000000000..ea39943cf571 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMConversionsUtilsTests.m @@ -0,0 +1,429 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +@interface FGMConversionUtilsTests : XCTestCase +@end + +@implementation FGMConversionUtilsTests + +- (void)testGetValueOrNilWithValue { + NSString *key = @"key"; + NSString *value = @"value"; + NSDictionary *dict = @{key : value}; + + XCTAssertEqual(FGMGetValueOrNilFromDict(dict, key), value); +} + +- (void)testGetValueOrNilWithNoEntry { + NSString *key = @"key"; + NSDictionary *dict = @{}; + + XCTAssertNil(FGMGetValueOrNilFromDict(dict, key)); +} + +- (void)testGetValueOrNilWithNSNull { + NSString *key = @"key"; + NSDictionary *dict = @{key : [NSNull null]}; + + XCTAssertNil(FGMGetValueOrNilFromDict(dict, key)); +} + +- (void)testColorFromPlatformColor { + double platformRed = 1 / 255.0; + double platformGreen = 2 / 255.0; + double platformBlue = 3 / 255.0; + double platformAlpha = 4 / 255.0; + UIColor *color = FGMGetColorForPigeonColor([FGMPlatformColor makeWithRed:platformRed + green:platformGreen + blue:platformBlue + alpha:platformAlpha]); + CGFloat red, green, blue, alpha; + BOOL success = [color getRed:&red green:&green blue:&blue alpha:&alpha]; + XCTAssertTrue(success); + const CGFloat accuracy = 0.0001; + XCTAssertEqualWithAccuracy(red, platformRed, accuracy); + XCTAssertEqualWithAccuracy(green, platformGreen, accuracy); + XCTAssertEqualWithAccuracy(blue, platformBlue, accuracy); + XCTAssertEqualWithAccuracy(alpha, platformAlpha, accuracy); +} + +- (void)testPlatformColorFromColor { + double red = 1 / 255.0; + double green = 2 / 255.0; + double blue = 3 / 255.0; + double alpha = 4 / 255.0; + UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; + FGMPlatformColor *platformColor = FGMGetPigeonColorForColor(color); + const CGFloat accuracy = 0.0001; + XCTAssertEqualWithAccuracy(red, platformColor.red, accuracy); + XCTAssertEqualWithAccuracy(green, platformColor.green, accuracy); + XCTAssertEqualWithAccuracy(blue, platformColor.blue, accuracy); + XCTAssertEqualWithAccuracy(alpha, platformColor.alpha, accuracy); +} + +- (void)testPointsFromLatLongs { + NSArray *latlongs = @[ + [FGMPlatformLatLng makeWithLatitude:1 longitude:2], [FGMPlatformLatLng makeWithLatitude:3 + longitude:4] + ]; + NSArray *locations = FGMGetPointsForPigeonLatLngs(latlongs); + XCTAssertEqual(locations.count, 2); + XCTAssertEqual(locations[0].coordinate.latitude, 1); + XCTAssertEqual(locations[0].coordinate.longitude, 2); + XCTAssertEqual(locations[1].coordinate.latitude, 3); + XCTAssertEqual(locations[1].coordinate.longitude, 4); +} + +- (void)testHolesFromPointsArray { + NSArray *> *pointsArray = @[ + @[ + [FGMPlatformLatLng makeWithLatitude:1 longitude:2], [FGMPlatformLatLng makeWithLatitude:3 + longitude:4] + ], + @[ + [FGMPlatformLatLng makeWithLatitude:5 longitude:6], [FGMPlatformLatLng makeWithLatitude:7 + longitude:8] + ] + ]; + NSArray *> *holes = FGMGetHolesForPigeonLatLngArrays(pointsArray); + XCTAssertEqual(holes.count, 2); + XCTAssertEqual(holes[0][0].coordinate.latitude, 1); + XCTAssertEqual(holes[0][0].coordinate.longitude, 2); + XCTAssertEqual(holes[0][1].coordinate.latitude, 3); + XCTAssertEqual(holes[0][1].coordinate.longitude, 4); + XCTAssertEqual(holes[1][0].coordinate.latitude, 5); + XCTAssertEqual(holes[1][0].coordinate.longitude, 6); + XCTAssertEqual(holes[1][1].coordinate.latitude, 7); + XCTAssertEqual(holes[1][1].coordinate.longitude, 8); +} + +- (void)testGetPigeonCameraPositionForPosition { + GMSCameraPosition *position = + [[GMSCameraPosition alloc] initWithTarget:CLLocationCoordinate2DMake(1, 2) + zoom:2.0 + bearing:3.0 + viewingAngle:75.0]; + FGMPlatformCameraPosition *pigeonPosition = FGMGetPigeonCameraPositionForPosition(position); + XCTAssertEqualWithAccuracy(pigeonPosition.target.latitude, position.target.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.target.longitude, position.target.longitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.zoom, position.zoom, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.bearing, position.bearing, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.tilt, position.viewingAngle, DBL_EPSILON); +} + +- (void)testPigeonPointForGCPoint { + CGPoint point = CGPointMake(10, 20); + FGMPlatformPoint *pigeonPoint = FGMGetPigeonPointForCGPoint(point); + XCTAssertEqualWithAccuracy(pigeonPoint.x, point.x, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPoint.y, point.y, DBL_EPSILON); +} + +- (void)testPigeonLatLngBoundsForCoordinateBounds { + GMSCoordinateBounds *bounds = + [[GMSCoordinateBounds alloc] initWithCoordinate:CLLocationCoordinate2DMake(10, 20) + coordinate:CLLocationCoordinate2DMake(30, 40)]; + FGMPlatformLatLngBounds *pigeonBounds = FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds); + XCTAssertEqualWithAccuracy(pigeonBounds.southwest.latitude, bounds.southWest.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonBounds.southwest.longitude, bounds.southWest.longitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonBounds.northeast.latitude, bounds.northEast.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonBounds.northeast.longitude, bounds.northEast.longitude, + DBL_EPSILON); +} + +- (void)testGetCameraPostionForPigeonCameraPosition { + FGMPlatformCameraPosition *pigeonCameraPosition = [FGMPlatformCameraPosition + makeWithBearing:1.0 + target:[FGMPlatformLatLng makeWithLatitude:2.0 longitude:3.0] + tilt:4.0 + zoom:5.0]; + + GMSCameraPosition *cameraPosition = + FGMGetCameraPositionForPigeonCameraPosition(pigeonCameraPosition); + + XCTAssertEqualWithAccuracy(cameraPosition.target.latitude, pigeonCameraPosition.target.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.target.longitude, pigeonCameraPosition.target.longitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.zoom, pigeonCameraPosition.zoom, DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.bearing, pigeonCameraPosition.bearing, DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.viewingAngle, pigeonCameraPosition.tilt, DBL_EPSILON); +} + +- (void)testCGPointForPigeonPoint { + FGMPlatformPoint *pigeonPoint = [FGMPlatformPoint makeWithX:1.0 y:2.0]; + + CGPoint point = FGMGetCGPointForPigeonPoint(pigeonPoint); + + XCTAssertEqualWithAccuracy(pigeonPoint.x, point.x, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPoint.y, point.y, DBL_EPSILON); +} + +- (void)testCoordinateBoundsFromLatLongs { + FGMPlatformLatLngBounds *pigeonBounds = [FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng makeWithLatitude:3 longitude:4] + southwest:[FGMPlatformLatLng makeWithLatitude:1 longitude:2]]; + + GMSCoordinateBounds *bounds = FGMGetCoordinateBoundsForPigeonLatLngBounds(pigeonBounds); + + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(bounds.southWest.latitude, 1, accuracy); + XCTAssertEqualWithAccuracy(bounds.southWest.longitude, 2, accuracy); + XCTAssertEqualWithAccuracy(bounds.northEast.latitude, 3, accuracy); + XCTAssertEqualWithAccuracy(bounds.northEast.longitude, 4, accuracy); +} + +- (void)testMapViewTypeFromPigeonType { + XCTAssertEqual(kGMSTypeNormal, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeNormal)); + XCTAssertEqual(kGMSTypeSatellite, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeSatellite)); + XCTAssertEqual(kGMSTypeTerrain, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeTerrain)); + XCTAssertEqual(kGMSTypeHybrid, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeHybrid)); + XCTAssertEqual(kGMSTypeNone, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeNone)); +} + +- (void)testCameraUpdateFromNewCameraPosition { + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMPlatformCameraUpdateNewCameraPosition *newPositionUpdate = + [FGMPlatformCameraUpdateNewCameraPosition + makeWithCameraPosition:[FGMPlatformCameraPosition + makeWithBearing:4 + target:[FGMPlatformLatLng makeWithLatitude:1 + longitude:2] + tilt:5 + zoom:3]]; + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:newPositionUpdate]); + [[classMockCameraUpdate expect] + setCamera:FGMGetCameraPositionForPigeonCameraPosition(newPositionUpdate.cameraPosition)]; + [classMockCameraUpdate stopMocking]; +} + +// TODO(cyanglaz): Fix the test for cameraUpdateFromArray with the "NewLatlng" key. +// 2 approaches have been tried and neither worked for the tests. +// +// 1. Use OCMock to vefiry that [GMSCameraUpdate setTarget:] is triggered with the correct value. +// This class method conflicts with certain category method in OCMock, causing OCMock not able to +// disambigious them. +// +// 2. Directly verify the GMSCameraUpdate object returned by the method. +// The GMSCameraUpdate object returned from the method doesn't have any accessors to the "target" +// property. It can be used to update the "camera" property in GMSMapView. However, [GMSMapView +// moveCamera:] doesn't update the camera immediately. Thus the GMSCameraUpdate object cannot be +// verified. +// +// The code in below test uses the 2nd approach. +- (void)skip_testCameraUpdateFromNewLatLong { + const CGFloat lat = 1; + const CGFloat lng = 2; + FGMPlatformCameraUpdateNewLatLng *platformUpdate = [FGMPlatformCameraUpdateNewLatLng + makeWithLatLng:[FGMPlatformLatLng makeWithLatitude:lat longitude:lng]]; + + GMSCameraUpdate *update = FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init]; + options.frame = CGRectZero; + options.camera = [GMSCameraPosition cameraWithTarget:CLLocationCoordinate2DMake(5, 6) zoom:1]; + GMSMapView *mapView = [[GMSMapView alloc] initWithOptions:options]; + [mapView moveCamera:update]; + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(mapView.camera.target.latitude, lat, + accuracy); // mapView.camera.target.latitude is still 5. + XCTAssertEqualWithAccuracy(mapView.camera.target.longitude, lng, + accuracy); // mapView.camera.target.longitude is still 6. +} + +- (void)testCameraUpdateFromNewLatLngBounds { + FGMPlatformLatLngBounds *pigeonBounds = [FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng makeWithLatitude:1 longitude:2] + southwest:[FGMPlatformLatLng makeWithLatitude:3 longitude:4]]; + GMSCoordinateBounds *bounds = FGMGetCoordinateBoundsForPigeonLatLngBounds(pigeonBounds); + + const CGFloat padding = 20; + FGMPlatformCameraUpdateNewLatLngBounds *platformUpdate = [FGMPlatformCameraUpdateNewLatLngBounds + makeWithBounds:FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds) + padding:padding]; + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] fitBounds:bounds withPadding:padding]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromNewLatLngZoom { + const CGFloat lat = 1; + const CGFloat lng = 2; + const CGFloat zoom = 3; + FGMPlatformCameraUpdateNewLatLngZoom *platformUpdate = [FGMPlatformCameraUpdateNewLatLngZoom + makeWithLatLng:[FGMPlatformLatLng makeWithLatitude:lat longitude:lng] + zoom:zoom]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] setTarget:CLLocationCoordinate2DMake(lat, lng) zoom:zoom]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromScrollBy { + const CGFloat x = 1; + const CGFloat y = 2; + FGMPlatformCameraUpdateScrollBy *platformUpdate = [FGMPlatformCameraUpdateScrollBy makeWithDx:x + dy:y]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] scrollByX:x Y:y]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomBy { + const CGFloat zoom = 1; + FGMPlatformCameraUpdateZoomBy *platformUpdateNoPoint = + [FGMPlatformCameraUpdateZoomBy makeWithAmount:zoom focus:nil]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdateNoPoint]); + + [[classMockCameraUpdate expect] zoomBy:zoom]; + + const CGFloat x = 2; + const CGFloat y = 3; + FGMPlatformCameraUpdateZoomBy *platformUpdate = + [FGMPlatformCameraUpdateZoomBy makeWithAmount:zoom focus:[FGMPlatformPoint makeWithX:x y:y]]; + + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomBy:zoom atPoint:CGPointMake(x, y)]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomIn { + FGMPlatformCameraUpdateZoom *platformUpdate = [FGMPlatformCameraUpdateZoom makeWithOut:NO]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomIn]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomOut { + FGMPlatformCameraUpdateZoom *platformUpdate = [FGMPlatformCameraUpdateZoom makeWithOut:YES]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomOut]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomTo { + const CGFloat zoom = 1; + FGMPlatformCameraUpdateZoomTo *platformUpdate = [FGMPlatformCameraUpdateZoomTo makeWithZoom:zoom]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomTo:zoom]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testStrokeStylesFromPatterns { + NSArray *patterns = @[ + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeGap length:@(1)], + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeDash length:@(1)] + ]; + UIColor *strokeColor = UIColor.redColor; + + NSArray *patternStrokeStyle = + FGMGetStrokeStylesFromPatterns(patterns, strokeColor); + + XCTAssertEqual(patternStrokeStyle.count, 2); + + // None of the parameters of `patternStrokeStyle` is observable, so we limit to testing + // the length of this output array. +} + +- (void)testLengthsFromPatterns { + const CGFloat gapLength = 10; + const CGFloat dashLength = 6.4; + NSArray *patterns = @[ + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeGap length:@(gapLength)], + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeDash length:@(dashLength)] + ]; + + NSArray *spanLengths = FGMGetSpanLengthsFromPatterns(patterns); + + XCTAssertEqual(spanLengths.count, 2); + + NSNumber *firstSpanLength = spanLengths[0]; + NSNumber *secondSpanLength = spanLengths[1]; + + XCTAssertEqual(firstSpanLength.doubleValue, gapLength); + XCTAssertEqual(secondSpanLength.doubleValue, dashLength); +} + +- (void)testWeightedDataFromPlatformWeightedData { + CGFloat intensity1 = 3.0; + CGFloat intensity2 = 6.0; + NSArray *data = @[ + [FGMPlatformWeightedLatLng makeWithPoint:[FGMPlatformLatLng makeWithLatitude:10 longitude:20] + weight:intensity1], + [FGMPlatformWeightedLatLng makeWithPoint:[FGMPlatformLatLng makeWithLatitude:30 longitude:40] + weight:intensity2], + ]; + + NSArray *weightedData = FGMGetWeightedDataForPigeonWeightedData(data); + XCTAssertEqual([weightedData[0] intensity], intensity1); + XCTAssertEqual([weightedData[1] intensity], intensity2); +} + +- (void)testGradientFromPlatformGradient { + CGFloat startPoint = 0.6; + CGFloat platformRed = 0.1; + CGFloat platformGreen = 0.2; + CGFloat platformBlue = 0.3; + CGFloat platformAlpha = 0.4; + NSInteger colorMapSize = 200; + FGMPlatformHeatmapGradient *platformGradient = + [FGMPlatformHeatmapGradient makeWithColors:@[ [FGMPlatformColor makeWithRed:platformRed + green:platformGreen + blue:platformBlue + alpha:platformAlpha] ] + startPoints:@[ @(startPoint) ] + colorMapSize:colorMapSize]; + + GMUGradient *gradient = FGMGetGradientForPigeonHeatmapGradient(platformGradient); + CGFloat red, green, blue, alpha; + [[gradient colors][0] getRed:&red green:&green blue:&blue alpha:&alpha]; + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(red, platformRed, accuracy); + XCTAssertEqualWithAccuracy(green, platformGreen, accuracy); + XCTAssertEqualWithAccuracy(blue, platformBlue, accuracy); + XCTAssertEqualWithAccuracy(alpha, platformAlpha, accuracy); + XCTAssertEqualWithAccuracy([[gradient startPoints][0] doubleValue], startPoint, accuracy); + XCTAssertEqual([gradient mapSize], colorMapSize); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m new file mode 100644 index 000000000000..2b0134d3ef9b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m @@ -0,0 +1,118 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; +@import GoogleMapsUtils; + +#import "PartiallyMockedMapView.h" + +@interface PropertyOrderValidatingHeatmap : GMUHeatmapTileLayer { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsHeatmapControllerTests : XCTestCase +@end + +@implementation GoogleMapsHeatmapControllerTests + +- (void)testUpdateHeatmapSetsVisibilityLast { + PropertyOrderValidatingHeatmap *heatmap = [[PropertyOrderValidatingHeatmap alloc] init]; + FGMPlatformHeatmapGradient *gradient = [FGMPlatformHeatmapGradient makeWithColors:@[ + [FGMPlatformColor makeWithRed:0 green:0 blue:0 alpha:0], + [FGMPlatformColor makeWithRed:1.0 green:1.0 blue:1.0 alpha:1.0], + ] + startPoints:@[ @(0), @(1) ] + colorMapSize:256]; + [FLTGoogleMapHeatmapController + updateHeatmap:heatmap + fromPlatformHeatmap:[FGMPlatformHeatmap + makeWithHeatmapId:@"heatmap" + data:@[ + [FGMPlatformWeightedLatLng + makeWithPoint:[FGMPlatformLatLng + makeWithLatitude:5.0 + longitude:5.0] + weight:0.5], + [FGMPlatformWeightedLatLng + makeWithPoint:[FGMPlatformLatLng + makeWithLatitude:10.0 + longitude:10.0] + weight:0.75], + ] + gradient:gradient + opacity:0.5 + radius:1 + minimumZoomIntensity:1 + maximumZoomIntensity:2] + withMapView:[GoogleMapsHeatmapControllerTests mapView]]; + XCTAssertTrue(heatmap.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingHeatmap + +- (void)setWeightedData:(NSArray *)weightedData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.weightedData = weightedData; +} + +- (void)setRadius:(NSUInteger)radius { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.radius = radius; +} + +- (void)setGradient:(GMUGradient *)gradient { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.gradient = gradient; +} + +- (void)setMinimumZoomIntensity:(NSUInteger)minimumZoomIntensity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.minimumZoomIntensity = minimumZoomIntensity; +} + +- (void)setMaximumZoomIntensity:(NSUInteger)maximumZoomIntensity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.maximumZoomIntensity = maximumZoomIntensity; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setTileSize:(NSInteger)tileSize { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tileSize = tileSize; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setFadeIn:(BOOL)fadeIn { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fadeIn = fadeIn; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTTileProviderControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTTileProviderControllerTests.m new file mode 100644 index 000000000000..3c7f43b3c206 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTTileProviderControllerTests.m @@ -0,0 +1,36 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import XCTest; +@import GoogleMaps; +@import google_maps_flutter_ios; + +#import + +@interface FLTTileProviderControllerTests : XCTestCase +@end + +@implementation FLTTileProviderControllerTests + +- (void)testCallChannelOnPlatformThread { + id handler = OCMClassMock([FGMMapsCallbackApi class]); + FLTTileProviderController *controller = + [[FLTTileProviderController alloc] initWithTileOverlayIdentifier:@"foo" + callbackHandler:handler]; + XCTAssertNotNil(controller); + XCTestExpectation *expectation = [self expectationWithDescription:@"invokeMethod"]; + OCMStub([handler tileWithOverlayIdentifier:[OCMArg any] + location:[OCMArg any] + zoom:0 + completion:[OCMArg any]]) + .andDo(^(NSInvocation *invocation) { + XCTAssertTrue([[NSThread currentThread] isMainThread]); + [expectation fulfill]; + }); + id receiver = OCMProtocolMock(@protocol(GMSTileReceiver)); + [controller requestTileForX:0 y:0 zoom:0 receiver:receiver]; + [self waitForExpectations:@[ expectation ] timeout:10.0]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m new file mode 100644 index 000000000000..7514a70704f5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m @@ -0,0 +1,104 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import "PartiallyMockedMapView.h" + +/// A GMSCircle that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingCircle : GMSCircle { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsCircleControllerTests : XCTestCase +@end + +@implementation GoogleMapsCircleControllerTests + +- (void)testUpdateCircleSetsVisibilityLast { + PropertyOrderValidatingCircle *circle = [[PropertyOrderValidatingCircle alloc] init]; + [FLTGoogleMapCircleController + updateCircle:circle + fromPlatformCircle:[FGMPlatformCircle + makeWithConsumeTapEvents:NO + fillColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + strokeColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + visible:YES + strokeWidth:0 + zIndex:0 + center:[FGMPlatformLatLng makeWithLatitude:0 + longitude:0] + radius:10 + circleId:@"circle"] + withMapView:[GoogleMapsCircleControllerTests mapView]]; + XCTAssertTrue(circle.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingCircle +- (void)setPosition:(CLLocationCoordinate2D)position { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.position = position; +} + +- (void)setRadius:(CLLocationDistance)radius { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.radius = radius; +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeWidth = strokeWidth; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeColor = strokeColor; +} + +- (void)setFillColor:(UIColor *)fillColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fillColor = fillColor; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m new file mode 100644 index 000000000000..9169d6064956 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -0,0 +1,281 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +/// A GMSGroundOverlay that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingGroundOverlay : GMSGroundOverlay { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsGroundOverlayControllerTests : XCTestCase +@end + +@implementation GoogleMapsGroundOverlayControllerTests + +/// Returns GoogleMapGroundOverlayController object instantiated with position and a mocked map +/// instance. +/// +/// @return An object of FLTGoogleMapGroundOverlayController ++ (FGMGroundOverlayController *)groundOverlayControllerWithPositionWithMockedMap { + NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"widegamut" + ofType:@"png" + inDirectory:@"assets"]; + UIImage *wideGamutImage = [UIImage imageWithContentsOfFile:imagePath]; + GMSGroundOverlay *groundOverlay = + [GMSGroundOverlay groundOverlayWithPosition:CLLocationCoordinate2DMake(52.4816, 3.1791) + icon:wideGamutImage + zoomLevel:14.0]; + + GMSMapView *mapView = [GoogleMapsGroundOverlayControllerTests mapView]; + + return [[FGMGroundOverlayController alloc] initWithGroundOverlay:groundOverlay + identifier:@"id_1" + mapView:mapView + isCreatedWithBounds:NO]; +} + +/// Returns GoogleMapGroundOverlayController object instantiated with bounds and a mocked map +/// instance. +/// +/// @return An object of FLTGoogleMapGroundOverlayController ++ (FGMGroundOverlayController *)groundOverlayControllerWithBoundsWithMockedMap { + NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"widegamut" + ofType:@"png" + inDirectory:@"assets"]; + UIImage *wideGamutImage = [UIImage imageWithContentsOfFile:imagePath]; + GMSGroundOverlay *groundOverlay = [GMSGroundOverlay + groundOverlayWithBounds:[[GMSCoordinateBounds alloc] + initWithCoordinate:CLLocationCoordinate2DMake(10, 20) + coordinate:CLLocationCoordinate2DMake(30, 40)] + icon:wideGamutImage]; + + GMSMapView *mapView = [GoogleMapsGroundOverlayControllerTests mapView]; + + return [[FGMGroundOverlayController alloc] initWithGroundOverlay:groundOverlay + identifier:@"id_1" + mapView:mapView + isCreatedWithBounds:YES]; +} + +- (void)testUpdatingGroundOverlayWithPosition { + FGMGroundOverlayController *groundOverlayController = + [GoogleMapsGroundOverlayControllerTests groundOverlayControllerWithPositionWithMockedMap]; + + FGMPlatformLatLng *position = [FGMPlatformLatLng makeWithLatitude:52.4816 longitude:3.1791]; + + FGMPlatformBitmap *bitmap = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + + FGMPlatformGroundOverlay *platformGroundOverlay = + [FGMPlatformGroundOverlay makeWithGroundOverlayId:@"id_1" + image:bitmap + position:position + bounds:nil + anchor:[FGMPlatformPoint makeWithX:0.5 y:0.5] + transparency:0.5 + bearing:65.0 + zIndex:2.0 + visible:true + clickable:true + zoomLevel:@14.0]; + + [groundOverlayController updateFromPlatformGroundOverlay:platformGroundOverlay + registrar:mockRegistrar + screenScale:1.0]; + + XCTAssertNotNil(groundOverlayController.groundOverlay.icon); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.position.latitude, + position.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.position.longitude, + position.longitude, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.opacity, platformGroundOverlay.transparency); + XCTAssertEqual(groundOverlayController.groundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.zIndex, platformGroundOverlay.zIndex); + + FGMPlatformGroundOverlay *convertedPlatformGroundOverlay = + FGMGetPigeonGroundOverlay(groundOverlayController.groundOverlay, @"id_1", NO, @14.0); + XCTAssertEqualObjects(convertedPlatformGroundOverlay.groundOverlayId, @"id_1"); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.position.latitude, position.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.position.longitude, position.longitude, + DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.zoomLevel.doubleValue, 14.0); + XCTAssertEqual(convertedPlatformGroundOverlay.transparency, platformGroundOverlay.transparency); + XCTAssertEqual(convertedPlatformGroundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.zIndex, platformGroundOverlay.zIndex); +} + +- (void)testUpdatingGroundOverlayWithBounds { + FGMGroundOverlayController *groundOverlayController = + [GoogleMapsGroundOverlayControllerTests groundOverlayControllerWithBoundsWithMockedMap]; + + FGMPlatformLatLngBounds *bounds = [FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng makeWithLatitude:54.4816 longitude:5.1791] + southwest:[FGMPlatformLatLng makeWithLatitude:52.4816 longitude:3.1791]]; + + FGMPlatformBitmap *bitmap = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + + FGMPlatformGroundOverlay *platformGroundOverlay = + [FGMPlatformGroundOverlay makeWithGroundOverlayId:@"id_1" + image:bitmap + position:nil + bounds:bounds + anchor:[FGMPlatformPoint makeWithX:0.5 y:0.5] + transparency:0.5 + bearing:65.0 + zIndex:2.0 + visible:true + clickable:true + zoomLevel:nil]; + + [groundOverlayController updateFromPlatformGroundOverlay:platformGroundOverlay + registrar:mockRegistrar + screenScale:1.0]; + + XCTAssertNotNil(groundOverlayController.groundOverlay.icon); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.northEast.latitude, + bounds.northeast.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.northEast.longitude, + bounds.northeast.longitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.southWest.latitude, + bounds.southwest.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.southWest.longitude, + bounds.southwest.longitude, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.opacity, platformGroundOverlay.transparency); + XCTAssertEqual(groundOverlayController.groundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.zIndex, platformGroundOverlay.zIndex); + + FGMPlatformGroundOverlay *convertedPlatformGroundOverlay = + FGMGetPigeonGroundOverlay(groundOverlayController.groundOverlay, @"id_1", YES, nil); + XCTAssertEqualObjects(convertedPlatformGroundOverlay.groundOverlayId, @"id_1"); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.northeast.latitude, + bounds.northeast.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.northeast.longitude, + bounds.northeast.longitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.southwest.latitude, + bounds.southwest.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.southwest.longitude, + bounds.southwest.longitude, DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.transparency, platformGroundOverlay.transparency); + XCTAssertEqual(convertedPlatformGroundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.zIndex, platformGroundOverlay.zIndex); +} + +- (void)testUpdateGroundOverlaySetsVisibilityLast { + PropertyOrderValidatingGroundOverlay *groundOverlay = + [[PropertyOrderValidatingGroundOverlay alloc] init]; + [FGMGroundOverlayController + updateGroundOverlay:groundOverlay + fromPlatformGroundOverlay: + [FGMPlatformGroundOverlay + makeWithGroundOverlayId:@"groundOverlay" + image:[FGMPlatformBitmap + makeWithBitmap:[FGMPlatformBitmapDefaultMarker + makeWithHue:@0]] + position:[FGMPlatformLatLng makeWithLatitude:0 longitude:0] + bounds:[FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng + makeWithLatitude:54.4816 + longitude:5.1791] + southwest:[FGMPlatformLatLng + makeWithLatitude:52.4816 + longitude:3.1791]] + anchor:[FGMPlatformPoint makeWithX:0.5 y:0.5] + transparency:0.5 + bearing:65.0 + zIndex:2.0 + visible:YES + clickable:YES + zoomLevel:nil] + withMapView:[GoogleMapsGroundOverlayControllerTests mapView] + registrar:nil + screenScale:1.0 + usingBounds:YES]; + XCTAssertTrue(groundOverlay.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingGroundOverlay + +- (void)setPosition:(CLLocationCoordinate2D)position { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.position = position; +} + +- (void)setAnchor:(CGPoint)anchor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.anchor = anchor; +} + +- (void)setIcon:(UIImage *)icon { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.icon = icon; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setBearing:(CLLocationDirection)bearing { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.bearing = bearing; +} + +- (void)setBounds:(GMSCoordinateBounds *)bounds { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.bounds = bounds; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m new file mode 100644 index 000000000000..bac3fb2cc84e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -0,0 +1,361 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import + +#import "PartiallyMockedMapView.h" + +/// A GMSMarker that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingMarker : GMSMarker { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsMarkerControllerTests : XCTestCase +@end + +@implementation GoogleMapsMarkerControllerTests + +/// Returns a simple map view for use with marker controllers. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +/// Returns a FLTMarkersController instance instantiated with the given map view. +/// +/// The mapView should outlive the controller, as the controller keeps a weak reference to it. +- (FLTMarkersController *)markersControllerWithMapView:(GMSMapView *)mapView { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + return [[FLTMarkersController alloc] initWithMapView:mapView + callbackHandler:[[FGMMapsCallbackApi alloc] init] + clusterManagersController:nil + registrar:mockRegistrar]; +} + +- (FGMPlatformBitmap *)placeholderBitmap { + return [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:@0]]; +} + +- (void)testSetsMarkerNumericProperties { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + double anchorX = 3.14; + double anchorY = 2.718; + double alpha = 0.4; + double rotation = 90.0; + double zIndex = 3.0; + double latitutde = 10.0; + double longitude = 20.0; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:alpha + anchor:[FGMPlatformPoint makeWithX:anchorX y:anchorY] + consumeTapEvents:YES + draggable:YES + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:latitutde + longitude:longitude] + rotation:rotation + visible:YES + zIndex:zIndex + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + const double delta = 0.0001; + XCTAssertEqualWithAccuracy(marker.opacity, alpha, delta); + XCTAssertEqualWithAccuracy(marker.rotation, rotation, delta); + XCTAssertEqualWithAccuracy(marker.zIndex, zIndex, delta); + XCTAssertEqualWithAccuracy(marker.groundAnchor.x, anchorX, delta); + XCTAssertEqualWithAccuracy(marker.groundAnchor.y, anchorY, delta); + XCTAssertEqualWithAccuracy(marker.position.latitude, latitutde, delta); + XCTAssertEqualWithAccuracy(marker.position.longitude, longitude, delta); +} + +// Boolean properties are tested individually to ensure they aren't accidentally cross-assigned from +// another property. +- (void)testSetsDraggable { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:NO + draggable:YES + flat:NO + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0.0 longitude:0.0] + rotation:0 + visible:NO + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + XCTAssertTrue(marker.draggable); +} + +// Boolean properties are tested individually to ensure they aren't accidentally cross-assigned from +// another property. +- (void)testSetsFlat { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:NO + draggable:NO + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0.0 longitude:0.0] + rotation:0 + visible:NO + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + XCTAssertTrue(marker.flat); +} + +// Boolean properties are tested individually to ensure they aren't accidentally cross-assigned from +// another property. +- (void)testSetsVisible { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:NO + draggable:NO + flat:NO + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0.0 longitude:0.0] + rotation:0 + visible:YES + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + // Visibility is controlled by being set to a map. + XCTAssertNotNil(marker.map); +} + +- (void)testSetsMarkerInfoWindowProperties { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + NSString *title = @"info title"; + NSString *snippet = @"info snippet"; + double anchorX = 3.14; + double anchorY = 2.718; + [controller + addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:YES + draggable:YES + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:title + snippet:snippet + anchor:[FGMPlatformPoint makeWithX:anchorX + y:anchorY]] + position:[FGMPlatformLatLng makeWithLatitude:0 longitude:0] + rotation:0 + visible:YES + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + const double delta = 0.0001; + XCTAssertEqualWithAccuracy(marker.infoWindowAnchor.x, anchorX, delta); + XCTAssertEqualWithAccuracy(marker.infoWindowAnchor.y, anchorY, delta); + XCTAssertEqual(marker.title, title); + XCTAssertEqual(marker.snippet, snippet); +} + +- (void)testUpdateMarkerSetsVisibilityLast { + PropertyOrderValidatingMarker *marker = [[PropertyOrderValidatingMarker alloc] init]; + [FLTGoogleMapMarkerController + updateMarker:marker + fromPlatformMarker:[FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:YES + draggable:YES + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint + makeWithX:0 + y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0 + longitude:0] + rotation:0 + visible:YES + zIndex:0 + markerId:@"marker" + clusterManagerId:nil] + withMapView:[GoogleMapsMarkerControllerTests mapView] + registrar:nil + screenScale:1 + usingOpacityForVisibility:NO]; + XCTAssertTrue(marker.hasSetMap); +} + +@end + +@implementation PropertyOrderValidatingMarker + +- (void)setPosition:(CLLocationCoordinate2D)position { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.position = position; +} + +- (void)setSnippet:(NSString *)snippet { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.snippet = snippet; +} + +- (void)setIcon:(UIImage *)icon { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.icon = icon; +} + +- (void)setIconView:(UIView *)iconView { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.iconView = iconView; +} + +- (void)setTracksViewChanges:(BOOL)tracksViewChanges { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tracksViewChanges = tracksViewChanges; +} + +- (void)setTracksInfoWindowChanges:(BOOL)tracksInfoWindowChanges { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tracksInfoWindowChanges = tracksInfoWindowChanges; +} + +- (void)setGroundAnchor:(CGPoint)groundAnchor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.groundAnchor = groundAnchor; +} + +- (void)setInfoWindowAnchor:(CGPoint)infoWindowAnchor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.infoWindowAnchor = infoWindowAnchor; +} + +- (void)setAppearAnimation:(GMSMarkerAnimation)appearAnimation { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.appearAnimation = appearAnimation; +} + +- (void)setDraggable:(BOOL)draggable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.draggable = draggable; +} + +- (void)setFlat:(BOOL)flat { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.flat = flat; +} + +- (void)setRotation:(CLLocationDegrees)rotation { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.rotation = rotation; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setPanoramaView:(GMSPanoramaView *)panoramaView { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.panoramaView = panoramaView; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setUserData:(id)userData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.userData = userData; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m new file mode 100644 index 000000000000..2cb386e0fc55 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m @@ -0,0 +1,112 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +/// A GMSPolygon that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingPolygon : GMSPolygon { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsPolygonControllerTests : XCTestCase +@end + +@implementation GoogleMapsPolygonControllerTests + +- (void)testUpdatePolygonSetsVisibilityLast { + PropertyOrderValidatingPolygon *polygon = [[PropertyOrderValidatingPolygon alloc] init]; + [FLTGoogleMapPolygonController + updatePolygon:polygon + fromPlatformPolygon:[FGMPlatformPolygon + makeWithConsumeTapEvents:NO + fillColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + geodesic:NO + holes:@[] + strokeColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + strokeWidth:0 + visible:YES + zIndex:0 + points:@[] + polygonId:@"polygon"] + withMapView:[GoogleMapsPolygonControllerTests mapView]]; + XCTAssertTrue(polygon.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingPolygon +- (void)setPath:(GMSPath *)path { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.path = path; +} + +- (void)setHoles:(NSArray *)holes { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.holes = holes; +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeWidth = strokeWidth; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeColor = strokeColor; +} + +- (void)setFillColor:(UIColor *)fillColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fillColor = fillColor; +} + +- (void)setGeodesic:(BOOL)geodesic { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.geodesic = geodesic; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setUserData:(id)userData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.userData = userData; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m new file mode 100644 index 000000000000..19ca6e84a266 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m @@ -0,0 +1,181 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +/// A GMSPolyline that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingPolyline : GMSPolyline { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsPolylineControllerTests : XCTestCase +@end + +@implementation GoogleMapsPolylineControllerTests + +/// Returns GoogleMapPolylineController object instantiated with a mocked map instance +/// +/// @return An object of FLTGoogleMapPolylineController +- (FLTGoogleMapPolylineController *)polylineControllerWithMockedMap { + FGMPlatformPolyline *polyline = [FGMPlatformPolyline + makeWithPolylineId:@"polyline_id_0" + consumesTapEvents:NO + color:[FGMPlatformColor makeWithRed:0 green:0 blue:0 alpha:0] + geodesic:NO + jointType:FGMPlatformJointTypeRound + patterns:@[] + points:[GoogleMapsPolylineControllerTests polylinePoints] + visible:NO + width:1 + zIndex:0]; + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSCameraPosition *camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + mapViewOptions.camera = camera; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + GMSMutablePath *path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(polyline.points)); + + FLTGoogleMapPolylineController *polylineControllerWithMockedMap = + [[FLTGoogleMapPolylineController alloc] initWithPath:path + identifier:polyline.polylineId + mapView:mapView]; + + return polylineControllerWithMockedMap; +} + +- (void)testPatternsSetSpans { + FLTGoogleMapPolylineController *polylineController = [self polylineControllerWithMockedMap]; + + XCTAssertNil(polylineController.polyline.spans); + + [polylineController + updateFromPlatformPolyline:[FGMPlatformPolyline + makeWithPolylineId:@"polyline_id_0" + consumesTapEvents:NO + color:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + geodesic:NO + jointType:FGMPlatformJointTypeRound + patterns:@[ + [FGMPlatformPatternItem + makeWithType:FGMPlatformPatternItemTypeDot + length:@(10)], + [FGMPlatformPatternItem + makeWithType:FGMPlatformPatternItemTypeDash + length:@(10)] + ] + points:[GoogleMapsPolylineControllerTests + polylinePoints] + visible:YES + width:1 + zIndex:0]]; + + // `GMSStyleSpan` doesn't implement `isEqual` so cannot be compared by value at present. + XCTAssertNotNil(polylineController.polyline.spans); +} + +- (void)testUpdatePolylineSetsVisibilityLast { + PropertyOrderValidatingPolyline *polyline = [[PropertyOrderValidatingPolyline alloc] init]; + [FLTGoogleMapPolylineController + updatePolyline:polyline + fromPlatformPolyline:[FGMPlatformPolyline + makeWithPolylineId:@"polyline" + consumesTapEvents:NO + color:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + geodesic:NO + jointType:FGMPlatformJointTypeRound + patterns:@[] + points:[GoogleMapsPolylineControllerTests polylinePoints] + visible:YES + width:1 + zIndex:0] + withMapView:[GoogleMapsPolylineControllerTests mapView]]; + XCTAssertTrue(polyline.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +/// Returns a set of points to use for tests that need a valid but arbitrary line. ++ (NSArray *)polylinePoints { + return @[ + [FGMPlatformLatLng makeWithLatitude:52.4816 longitude:-3.1791], + [FGMPlatformLatLng makeWithLatitude:54.043 longitude:-2.9925], + [FGMPlatformLatLng makeWithLatitude:54.1396 longitude:-4.2739], + [FGMPlatformLatLng makeWithLatitude:53.4153 longitude:-4.0829], + ]; +} + +@end + +@implementation PropertyOrderValidatingPolyline + +- (void)setPath:(GMSPath *)path { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.path = path; +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeWidth = strokeWidth; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeColor = strokeColor; +} + +- (void)setGeodesic:(BOOL)geodesic { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.geodesic = geodesic; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setUserData:(id)userData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.userData = userData; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.m new file mode 100644 index 000000000000..ecbef7b3924e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.m @@ -0,0 +1,212 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "FGMCATransactionWrapper.h" +#import "PartiallyMockedMapView.h" + +@interface FLTGoogleMapFactory (Test) +@property(strong, nonatomic, readonly) id sharedMapServices; +@end + +@interface GoogleMapsTests : XCTestCase +@end + +@interface FLTTileProviderController (Testing) +- (UIImage *)handleResultTile:(nullable UIImage *)tileImage; +@end + +@implementation GoogleMapsTests + +- (void)testPlugin { + FLTGoogleMapsPlugin *plugin = [[FLTGoogleMapsPlugin alloc] init]; + XCTAssertNotNil(plugin); +} + +- (void)testFrameObserver { + id registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init]; + options.frame = frame; + options.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:options]; + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + for (NSInteger i = 0; i < 10; ++i) { + [controller view]; + } + XCTAssertEqual(mapView.frameObserverCount, 1); + + mapView.frame = frame; + XCTAssertEqual(mapView.frameObserverCount, 0); +} + +- (void)testMapsServiceSync { + id registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + FLTGoogleMapFactory *factory1 = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + XCTAssertNotNil(factory1.sharedMapServices); + FLTGoogleMapFactory *factory2 = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + // Test pointer equality, should be same retained singleton +[GMSServices sharedServices] object. + // Retaining the opaque object should be enough to avoid multiple internal initializations, + // but don't test the internals of the GoogleMaps API. Assume that it does what is documented. + // https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_services#a436e03c32b1c0be74e072310a7158831 + XCTAssertEqual(factory1.sharedMapServices, factory2.sharedMapServices); +} + +- (void)testHandleResultTileDownsamplesWideGamutImages { + FLTTileProviderController *controller = [[FLTTileProviderController alloc] init]; + + NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"widegamut" + ofType:@"png" + inDirectory:@"assets"]; + UIImage *wideGamutImage = [UIImage imageWithContentsOfFile:imagePath]; + + XCTAssertNotNil(wideGamutImage, @"The image should be loaded."); + + UIImage *downsampledImage = [controller handleResultTile:wideGamutImage]; + + CGImageRef imageRef = downsampledImage.CGImage; + size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); + + // non wide gamut images use 8 bit format + XCTAssertEqual(bitsPerComponent, 8); + XCTAssertEqual(CGImageGetAlphaInfo(imageRef), kCGImageAlphaPremultipliedLast); +} + +- (void)testAnimateCameraWithUpdate { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + + // Init camera with zero zoom. + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + id mapViewMock = OCMPartialMock(mapView); + id mockTransactionWrapper = OCMProtocolMock(@protocol(FGMCATransactionProtocol)); + controller.callHandler.transactionWrapper = mockTransactionWrapper; + + FGMPlatformCameraUpdateZoomTo *zoomTo = [FGMPlatformCameraUpdateZoomTo makeWithZoom:10.0]; + FGMPlatformCameraUpdate *cameraUpdate = [FGMPlatformCameraUpdate makeWithCameraUpdate:zoomTo]; + FlutterError *error = nil; + + OCMReject([mockTransactionWrapper begin]); + OCMReject([mockTransactionWrapper commit]); + OCMExpect([mapViewMock animateWithCameraUpdate:[OCMArg any]]); + [controller.callHandler animateCameraWithUpdate:cameraUpdate duration:nil error:&error]; + OCMVerifyAll(mapViewMock); + OCMVerifyAll(mockTransactionWrapper); +} + +- (void)testAnimateCameraWithUpdateAndDuration { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + + // Init camera with zero zoom. + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + id mapViewMock = OCMPartialMock(mapView); + id mockTransactionWrapper = OCMProtocolMock(@protocol(FGMCATransactionProtocol)); + controller.callHandler.transactionWrapper = mockTransactionWrapper; + + FGMPlatformCameraUpdateZoomTo *zoomTo = [FGMPlatformCameraUpdateZoomTo makeWithZoom:10.0]; + FGMPlatformCameraUpdate *cameraUpdate = [FGMPlatformCameraUpdate makeWithCameraUpdate:zoomTo]; + FlutterError *error = nil; + + NSNumber *durationMilliseconds = @100; + OCMExpect([mockTransactionWrapper begin]); + OCMExpect( + [mockTransactionWrapper setAnimationDuration:[durationMilliseconds doubleValue] / 1000]); + OCMExpect([mockTransactionWrapper commit]); + OCMExpect([mapViewMock animateWithCameraUpdate:[OCMArg any]]); + [controller.callHandler animateCameraWithUpdate:cameraUpdate + duration:durationMilliseconds + error:&error]; + OCMVerifyAll(mapViewMock); + OCMVerifyAll(mockTransactionWrapper); +} + +- (void)testInspectorAPICameraPosition { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + + // Init camera with specific position. + GMSCameraPosition *initialCameraPosition = [[GMSCameraPosition alloc] initWithLatitude:37.7749 + longitude:-122.4194 + zoom:10]; + mapViewOptions.camera = initialCameraPosition; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + FGMMapInspector *inspector = [[FGMMapInspector alloc] initWithMapController:controller + messenger:registrar.messenger + pigeonSuffix:@"0"]; + + FlutterError *error = nil; + FGMPlatformCameraPosition *cameraPosition = [inspector cameraPosition:&error]; + + XCTAssertEqual(cameraPosition.target.latitude, initialCameraPosition.target.latitude); + XCTAssertEqual(cameraPosition.target.longitude, initialCameraPosition.target.longitude); + XCTAssertEqual(cameraPosition.zoom, initialCameraPosition.zoom); +} + +/// Creates an empty creation paramaters object for tests where the values don't matter, just that +/// there's a valid object to pass in. +- (FGMPlatformMapViewCreationParams *)emptyCreationParameters { + return [FGMPlatformMapViewCreationParams + makeWithInitialCameraPosition:[FGMPlatformCameraPosition + makeWithBearing:0.0 + target:[FGMPlatformLatLng makeWithLatitude:0.0 + longitude:0.0] + tilt:0.0 + zoom:0.0] + mapConfiguration:[[FGMPlatformMapConfiguration alloc] init] + initialCircles:@[] + initialMarkers:@[] + initialPolygons:@[] + initialPolylines:@[] + initialHeatmaps:@[] + initialTileOverlays:@[] + initialClusterManagers:@[] + initialGroundOverlays:@[]]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m new file mode 100644 index 000000000000..e7b1118a8d56 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m @@ -0,0 +1,73 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import "PartiallyMockedMapView.h" + +/// A GMSTileOverlay that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingTileLayer : GMSTileLayer +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsTileOverlayControllerTests : XCTestCase +@end + +@implementation GoogleMapsTileOverlayControllerTests + +- (void)testUpdateTileOverlaySetsVisibilityLast { + PropertyOrderValidatingTileLayer *tileLayer = [[PropertyOrderValidatingTileLayer alloc] init]; + [FLTGoogleMapTileOverlayController + updateTileLayer:tileLayer + fromPlatformTileOverlay:[FGMPlatformTileOverlay makeWithTileOverlayId:@"overlay" + fadeIn:NO + transparency:0.5 + zIndex:0 + visible:YES + tileSize:1] + withMapView:[GoogleMapsTileOverlayControllerTests mapView]]; + XCTAssertTrue(tileLayer.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingTileLayer + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setTileSize:(NSInteger)tileSize { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tileSize = tileSize; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setFadeIn:(BOOL)fadeIn { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fadeIn = fadeIn; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/PartiallyMockedMapView.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/PartiallyMockedMapView.h new file mode 100644 index 000000000000..9a04ae84ab24 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/PartiallyMockedMapView.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import GoogleMaps; + +/** + * Defines a map view used for testing key-value observing. + */ +@interface PartiallyMockedMapView : GMSMapView + +/** + * The number of times that the `frame` KVO has been added. + */ +@property(nonatomic, assign, readonly) NSInteger frameObserverCount; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/PartiallyMockedMapView.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/PartiallyMockedMapView.m new file mode 100644 index 000000000000..47d48d2e07fc --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/PartiallyMockedMapView.m @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "PartiallyMockedMapView.h" + +@interface PartiallyMockedMapView () + +@property(nonatomic, assign) NSInteger frameObserverCount; + +@end + +@implementation PartiallyMockedMapView + +- (void)addObserver:(NSObject *)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + [super addObserver:observer forKeyPath:keyPath options:options context:context]; + + if ([keyPath isEqualToString:@"frame"]) { + ++self.frameObserverCount; + } +} + +- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { + [super removeObserver:observer forKeyPath:keyPath]; + + if ([keyPath isEqualToString:@"frame"]) { + --self.frameObserverCount; + } +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.m new file mode 100644 index 000000000000..cb7fbc196b40 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerUITests/GoogleMapsUITests.m @@ -0,0 +1,288 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import CoreLocation; +@import XCTest; +@import os.log; + +static const NSTimeInterval kWaitTime = 60; + +// TODO(bparrishMines): Remove once https://github.com/flutter/flutter/issues/154641 is fixed. +static const BOOL skipFor154641 = YES; + +@interface GoogleMapsUITests : XCTestCase +@property(nonatomic, strong) XCUIApplication *app; +@end + +@implementation GoogleMapsUITests + +- (void)setUp { + self.continueAfterFailure = NO; + + self.app = [[XCUIApplication alloc] init]; + [self.app launch]; + + [self + addUIInterruptionMonitorWithDescription:@"Permission popups" + handler:^BOOL(XCUIElement *_Nonnull interruptingElement) { + if (@available(iOS 14, *)) { + XCUIElement *locationPermission = + interruptingElement.buttons[@"Allow While Using App"]; + if (![locationPermission + waitForExistenceWithTimeout:kWaitTime]) { + XCTFail(@"Failed due to not able to find " + @"locationPermission button"); + } + [locationPermission tap]; + + } else { + XCUIElement *allow = + interruptingElement.buttons[@"Allow"]; + if (![allow waitForExistenceWithTimeout:kWaitTime]) { + XCTFail(@"Failed due to not able to find Allow button"); + } + [allow tap]; + } + return YES; + }]; +} + +- (void)testUserInterface { + XCTSkipIf(skipFor154641); + + XCUIApplication *app = self.app; + XCUIElement *userInteface = app.staticTexts[@"User interface"]; + if (![userInteface waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find User interface"); + } + [userInteface tap]; + + XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; + if (![platformView waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find platform view"); + } + + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button + // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app + // instead. + XCUICoordinate *coordinate = [app coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; + [coordinate tap]; + XCUIElement *compass = app.buttons[@"disable compass"]; + if (![compass waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find disable compass button"); + } + + [self forceTap:compass]; +} + +- (void)testMapCoordinatesPage { + XCTSkipIf(skipFor154641); + + XCUIApplication *app = self.app; + XCUIElement *mapCoordinates = app.staticTexts[@"Map coordinates"]; + if (![mapCoordinates waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'Map coordinates''"); + } + [mapCoordinates tap]; + + XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; + if (![platformView waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find platform view"); + } + + XCUIElement *titleBar = app.otherElements[@"Map coordinates"]; + if (![titleBar waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find title bar"); + } + + NSPredicate *visibleRegionPredicate = + [NSPredicate predicateWithFormat:@"label BEGINSWITH 'VisibleRegion'"]; + XCUIElement *visibleRegionText = + [app.staticTexts elementMatchingPredicate:visibleRegionPredicate]; + if (![visibleRegionText waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find Visible Region label'"); + } + + // Validate visible region does not change when scrolled under safe areas. + // https://github.com/flutter/flutter/issues/107913 + + // Example -33.79495661816674, 151.313996873796 + CLLocationCoordinate2D originalNortheast; + // Example -33.90900557679571, 151.10800322145224 + CLLocationCoordinate2D originalSouthwest; + [self validateVisibleRegion:visibleRegionText.label + northeast:&originalNortheast + southwest:&originalSouthwest]; + XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude); + XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude); + + XCTAssertLessThan(originalNortheast.latitude, 0); + XCTAssertLessThan(originalSouthwest.latitude, 0); + XCTAssertGreaterThan(originalNortheast.longitude, 0); + XCTAssertGreaterThan(originalSouthwest.longitude, 0); + + // Drag the map upward to under the title bar. + [platformView pressForDuration:0 thenDragToElement:titleBar]; + + CLLocationCoordinate2D draggedNortheast; + CLLocationCoordinate2D draggedSouthwest; + [self validateVisibleRegion:visibleRegionText.label + northeast:&draggedNortheast + southwest:&draggedSouthwest]; + XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude); + XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude); + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); +} + +- (void)validateVisibleRegion:(NSString *)label + northeast:(CLLocationCoordinate2D *)northeast + southwest:(CLLocationCoordinate2D *)southwest { + // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, + // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" + NSScanner *scan = [NSScanner scannerWithString:label]; + + // northeast + [scan scanString:@"VisibleRegion:\nnortheast: LatLng(" intoString:NULL]; + double northeastLatitude; + [scan scanDouble:&northeastLatitude]; + [scan scanString:@", " intoString:NULL]; + XCTAssertNotEqual(northeastLatitude, 0); + double northeastLongitude; + [scan scanDouble:&northeastLongitude]; + XCTAssertNotEqual(northeastLongitude, 0); + + [scan scanString:@"),\nsouthwest: LatLng(" intoString:NULL]; + double southwestLatitude; + [scan scanDouble:&southwestLatitude]; + XCTAssertNotEqual(southwestLatitude, 0); + [scan scanString:@", " intoString:NULL]; + double southwestLongitude; + [scan scanDouble:&southwestLongitude]; + XCTAssertNotEqual(southwestLongitude, 0); + *northeast = CLLocationCoordinate2DMake(northeastLatitude, northeastLongitude); + *southwest = CLLocationCoordinate2DMake(southwestLatitude, southwestLongitude); +} + +- (void)testMapClickPage { + XCTSkipIf(skipFor154641); + + XCUIApplication *app = self.app; + XCUIElement *mapClick = app.staticTexts[@"Map click"]; + if (![mapClick waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'Map click''"); + } + [mapClick tap]; + + XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; + if (![platformView waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find platform view"); + } + + [platformView tap]; + + XCUIElement *tapped = app.staticTexts[@"Tapped"]; + if (![tapped waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'tapped''"); + } + + [platformView pressForDuration:5.0]; + + XCUIElement *longPressed = app.staticTexts[@"Long pressed"]; + if (![longPressed waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'longPressed''"); + } +} + +- (void)forceTap:(XCUIElement *)button { + // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the + // button if that is the case. It is likely similar to + // https://github.com/flutter/flutter/issues/113377. + if (button.isHittable) { + [button tap]; + return; + } + XCUICoordinate *coordinate = [button coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; + [coordinate tap]; +} + +- (void)testMarkerDraggingCallbacks { + XCTSkipIf(skipFor154641); + + XCUIApplication *application = [[XCUIApplication alloc] init]; + [application launch]; + XCUIElement *placeMarkerButton = application.staticTexts[@"Place marker"]; + if (![placeMarkerButton waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the Place marker button."); + } + [placeMarkerButton tap]; + + XCUIElement *Add = application.buttons[@"Add"]; + if (![Add waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the Add button."); + } + [Add tap]; + + XCUIElement *marker = application.buttons[@"marker_id_1"]; + if (![marker waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the marker."); + } + [marker tap]; + + XCUIElement *toggleDraggable = application.buttons[@"toggle draggable"]; + if (![toggleDraggable waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the toggle draggable."); + } + [toggleDraggable tap]; + + // Drag marker to center + [marker pressForDuration:5 thenDragToElement:application]; + + NSPredicate *predicateDragStart = + [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragStart"]; + NSPredicate *predicateDrag = + [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDrag called"]; + NSPredicate *predicateDragEnd = + [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragEnd"]; + + XCUIElement *dragStart = [application.staticTexts matchingPredicate:predicateDragStart].element; + if (![dragStart waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the _onMarkerDragStart."); + } + XCTAssertTrue(dragStart.exists); + + XCUIElement *drag = [application.staticTexts matchingPredicate:predicateDrag].element; + if (![drag waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the _onMarkerDrag."); + } + XCTAssertTrue(drag.exists); + + XCUIElement *dragEnd = [application.staticTexts matchingPredicate:predicateDragEnd].element; + if (![dragEnd waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the _onMarkerDragEnd."); + } + XCTAssertTrue(dragEnd.exists); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/animate_camera.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/animate_camera.dart new file mode 100644 index 000000000000..a7c515c36928 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/animate_camera.dart @@ -0,0 +1,204 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class AnimateCameraPage extends GoogleMapExampleAppPage { + const AnimateCameraPage({Key? key}) + : super(const Icon(Icons.map), 'Camera control, animated', key: key); + + @override + Widget build(BuildContext context) { + return const AnimateCamera(); + } +} + +class AnimateCamera extends StatefulWidget { + const AnimateCamera({super.key}); + @override + State createState() => AnimateCameraState(); +} + +// Animation duration for a animation configuration. +const int _durationSeconds = 10; + +class AnimateCameraState extends State { + ExampleGoogleMapController? mapController; + Duration? _cameraUpdateAnimationDuration; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + mapController = controller; + } + + void _toggleAnimationDuration() { + setState(() { + _cameraUpdateAnimationDuration = _cameraUpdateAnimationDuration != null + ? null + : const Duration(seconds: _durationSeconds); + }); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(0.0, 0.0), + ), + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newCameraPosition( + const CameraPosition( + bearing: 270.0, + target: LatLng(51.5160895, -0.1294527), + tilt: 30.0, + zoom: 17.0, + ), + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newCameraPosition'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newLatLng( + const LatLng(56.1725505, 10.1850512), + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newLatLng'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newLatLngBounds( + LatLngBounds( + southwest: const LatLng(-38.483935, 113.248673), + northeast: const LatLng(-8.982446, 153.823821), + ), + 10.0, + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newLatLngBounds'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newLatLngZoom( + const LatLng(37.4231613, -122.087159), + 11.0, + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newLatLngZoom'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.scrollBy(150.0, -225.0), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('scrollBy'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomBy(-0.5, const Offset(30.0, 20.0)), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomBy with focus'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomBy(-0.5), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomBy'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomIn(), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomIn'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomOut(), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomOut'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomTo(16.0), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomTo'), + ), + ], + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('With 10 second duration', textAlign: TextAlign.right), + const SizedBox(width: 5), + Switch( + value: _cameraUpdateAnimationDuration != null, + onChanged: (bool value) { + _toggleAnimationDuration(); + }, + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/clustering.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/clustering.dart new file mode 100644 index 000000000000..5757717c215b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/clustering.dart @@ -0,0 +1,288 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +/// Page for demonstrating marker clustering support. +class ClusteringPage extends GoogleMapExampleAppPage { + /// Default Constructor. + const ClusteringPage({Key? key}) + : super(const Icon(Icons.place), 'Manage clustering', key: key); + + @override + Widget build(BuildContext context) { + return const ClusteringBody(); + } +} + +/// Body of the clustering page. +class ClusteringBody extends StatefulWidget { + /// Default Constructor. + const ClusteringBody({super.key}); + + @override + State createState() => ClusteringBodyState(); +} + +/// State of the clustering page. +class ClusteringBodyState extends State { + /// Default Constructor. + ClusteringBodyState(); + + /// Starting point from where markers are added. + static const LatLng center = LatLng(-33.86, 151.1547171); + + /// Marker offset factor for randomizing marker placing. + static const double _markerOffsetFactor = 0.05; + + /// Offset for longitude when placing markers to different cluster managers. + static const double _clusterManagerLongitudeOffset = 0.1; + + /// Maximum amount of cluster managers. + static const int _clusterManagerMaxCount = 3; + + /// Amount of markers to be added to the cluster manager at once. + static const int _markersToAddToClusterManagerCount = 10; + + /// Fully visible alpha value. + static const double _fullyVisibleAlpha = 1.0; + + /// Half visible alpha value. + static const double _halfVisibleAlpha = 0.5; + + /// Google map controller. + ExampleGoogleMapController? controller; + + /// Map of clusterManagers with identifier as the key. + Map clusterManagers = + {}; + + /// Map of markers with identifier as the key. + Map markers = {}; + + /// Id of the currently selected marker. + MarkerId? selectedMarker; + + /// Counter for added cluster manager ids. + int _clusterManagerIdCounter = 1; + + /// Counter for added markers ids. + int _markerIdCounter = 1; + + /// Cluster that was tapped most recently. + Cluster? lastCluster; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onMarkerTapped(MarkerId markerId) { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + final MarkerId? previousMarkerId = selectedMarker; + if (previousMarkerId != null && markers.containsKey(previousMarkerId)) { + final Marker resetOld = markers[previousMarkerId]!.copyWith( + iconParam: BitmapDescriptor.defaultMarker, + ); + markers[previousMarkerId] = resetOld; + } + selectedMarker = markerId; + final Marker newMarker = tappedMarker.copyWith( + iconParam: BitmapDescriptor.defaultMarkerWithHue( + BitmapDescriptor.hueGreen, + ), + ); + markers[markerId] = newMarker; + }); + } + } + + void _addClusterManager() { + if (clusterManagers.length == _clusterManagerMaxCount) { + return; + } + + final clusterManagerIdVal = 'cluster_manager_id_$_clusterManagerIdCounter'; + _clusterManagerIdCounter++; + final clusterManagerId = ClusterManagerId(clusterManagerIdVal); + + final clusterManager = ClusterManager( + clusterManagerId: clusterManagerId, + onClusterTap: (Cluster cluster) => setState(() { + lastCluster = cluster; + }), + ); + + setState(() { + clusterManagers[clusterManagerId] = clusterManager; + }); + _addMarkersToCluster(clusterManager); + } + + void _removeClusterManager(ClusterManager clusterManager) { + setState(() { + // Remove markers managed by cluster manager to be removed. + markers.removeWhere( + (MarkerId key, Marker marker) => + marker.clusterManagerId == clusterManager.clusterManagerId, + ); + // Remove cluster manager. + clusterManagers.remove(clusterManager.clusterManagerId); + }); + } + + void _addMarkersToCluster(ClusterManager clusterManager) { + for (var i = 0; i < _markersToAddToClusterManagerCount; i++) { + final markerIdVal = + '${clusterManager.clusterManagerId.value}_marker_id_$_markerIdCounter'; + _markerIdCounter++; + final markerId = MarkerId(markerIdVal); + + final int clusterManagerIndex = clusterManagers.values.toList().indexOf( + clusterManager, + ); + + // Add additional offset to longitude for each cluster manager to space + // out markers in different cluster managers. + final double clusterManagerLongitudeOffset = + clusterManagerIndex * _clusterManagerLongitudeOffset; + + final marker = Marker( + clusterManagerId: clusterManager.clusterManagerId, + markerId: markerId, + position: LatLng( + center.latitude + _getRandomOffset(), + center.longitude + _getRandomOffset() + clusterManagerLongitudeOffset, + ), + infoWindow: InfoWindow(title: markerIdVal, snippet: '*'), + onTap: () => _onMarkerTapped(markerId), + ); + markers[markerId] = marker; + } + setState(() {}); + } + + double _getRandomOffset() { + return (Random().nextDouble() - 0.5) * _markerOffsetFactor; + } + + void _remove(MarkerId markerId) { + setState(() { + if (markers.containsKey(markerId)) { + markers.remove(markerId); + } + }); + } + + void _changeMarkersAlpha() { + for (final MarkerId markerId in markers.keys) { + final Marker marker = markers[markerId]!; + final double current = marker.alpha; + markers[markerId] = marker.copyWith( + alphaParam: current == _fullyVisibleAlpha + ? _halfVisibleAlpha + : _fullyVisibleAlpha, + ); + } + setState(() {}); + } + + @override + Widget build(BuildContext context) { + final MarkerId? selectedId = selectedMarker; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox( + height: 300.0, + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(-33.852, 151.25), + zoom: 11.0, + ), + markers: Set.of(markers.values), + clusterManagers: Set.of(clusterManagers.values), + ), + ), + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: clusterManagers.length >= _clusterManagerMaxCount + ? null + : () => _addClusterManager(), + child: const Text('Add cluster manager'), + ), + TextButton( + onPressed: clusterManagers.isEmpty + ? null + : () => + _removeClusterManager(clusterManagers.values.last), + child: const Text('Remove cluster manager'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + for (final MapEntry + clusterEntry + in clusterManagers.entries) + TextButton( + onPressed: () => _addMarkersToCluster(clusterEntry.value), + child: Text('Add markers to ${clusterEntry.key.value}'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: selectedId == null + ? null + : () { + _remove(selectedId); + setState(() { + selectedMarker = null; + }); + }, + child: const Text('Remove selected marker'), + ), + TextButton( + onPressed: markers.isEmpty + ? null + : () => _changeMarkersAlpha(), + child: const Text('Change all markers alpha'), + ), + ], + ), + if (lastCluster != null) + Padding( + padding: const EdgeInsets.all(10), + child: Text( + 'Cluster with ${lastCluster!.count} markers clicked at ${lastCluster!.position}', + ), + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/custom_marker_icon.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/custom_marker_icon.dart new file mode 100644 index 000000000000..548146c6206c --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/custom_marker_icon.dart @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +/// Returns a generated png image in [ByteData] format with the requested size. +Future createCustomMarkerIconImage({required Size size}) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final painter = _MarkerPainter(); + + painter.paint(canvas, size); + + final ui.Image image = await recorder.endRecording().toImage( + size.width.floor(), + size.height.floor(), + ); + + final ByteData? bytes = await image.toByteData( + format: ui.ImageByteFormat.png, + ); + return bytes!; +} + +class _MarkerPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Rect rect = Offset.zero & size; + const gradient = RadialGradient( + colors: [Colors.yellow, Colors.red], + stops: [0.4, 1.0], + ); + + // Draw radial gradient + canvas.drawRect(rect, Paint()..shader = gradient.createShader(rect)); + + // Draw diagonal black line + canvas.drawLine( + Offset.zero, + Offset(size.width, size.height), + Paint() + ..color = Colors.black + ..strokeWidth = 1, + ); + } + + @override + bool shouldRepaint(_MarkerPainter oldDelegate) => false; + @override + bool shouldRebuildSemantics(_MarkerPainter oldDelegate) => false; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/example_google_map.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/example_google_map.dart new file mode 100644 index 000000000000..152f83c16f38 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/example_google_map.dart @@ -0,0 +1,676 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +// This is a pared down version of the Dart code from the app-facing package, +// to allow running the same examples for package-local testing. +// TODO(stuartmorgan): Consider extracting this to a shared package. See also +// https://github.com/flutter/flutter/issues/46716. + +/// Controller for a single ExampleGoogleMap instance running on the host platform. +class ExampleGoogleMapController { + ExampleGoogleMapController._(this._googleMapState, {required this.mapId}) { + _connectStreams(mapId); + } + + /// The mapId for this controller + final int mapId; + + /// Initialize control of a [ExampleGoogleMap] with [id]. + /// + /// Mainly for internal use when instantiating a [ExampleGoogleMapController] passed + /// in [ExampleGoogleMap.onMapCreated] callback. + static Future _init( + int id, + CameraPosition initialCameraPosition, + _ExampleGoogleMapState googleMapState, + ) async { + await GoogleMapsFlutterPlatform.instance.init(id); + return ExampleGoogleMapController._(googleMapState, mapId: id); + } + + final _ExampleGoogleMapState _googleMapState; + + void _connectStreams(int mapId) { + if (_googleMapState.widget.onCameraMoveStarted != null) { + GoogleMapsFlutterPlatform.instance + .onCameraMoveStarted(mapId: mapId) + .listen((_) => _googleMapState.widget.onCameraMoveStarted!()); + } + if (_googleMapState.widget.onCameraMove != null) { + GoogleMapsFlutterPlatform.instance + .onCameraMove(mapId: mapId) + .listen( + (CameraMoveEvent e) => + _googleMapState.widget.onCameraMove!(e.value), + ); + } + if (_googleMapState.widget.onCameraIdle != null) { + GoogleMapsFlutterPlatform.instance + .onCameraIdle(mapId: mapId) + .listen((_) => _googleMapState.widget.onCameraIdle!()); + } + GoogleMapsFlutterPlatform.instance + .onMarkerTap(mapId: mapId) + .listen((MarkerTapEvent e) => _googleMapState.onMarkerTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onMarkerDragStart(mapId: mapId) + .listen( + (MarkerDragStartEvent e) => + _googleMapState.onMarkerDragStart(e.value, e.position), + ); + GoogleMapsFlutterPlatform.instance + .onMarkerDrag(mapId: mapId) + .listen( + (MarkerDragEvent e) => + _googleMapState.onMarkerDrag(e.value, e.position), + ); + GoogleMapsFlutterPlatform.instance + .onMarkerDragEnd(mapId: mapId) + .listen( + (MarkerDragEndEvent e) => + _googleMapState.onMarkerDragEnd(e.value, e.position), + ); + GoogleMapsFlutterPlatform.instance + .onInfoWindowTap(mapId: mapId) + .listen( + (InfoWindowTapEvent e) => _googleMapState.onInfoWindowTap(e.value), + ); + GoogleMapsFlutterPlatform.instance + .onPolylineTap(mapId: mapId) + .listen((PolylineTapEvent e) => _googleMapState.onPolylineTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onPolygonTap(mapId: mapId) + .listen((PolygonTapEvent e) => _googleMapState.onPolygonTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onCircleTap(mapId: mapId) + .listen((CircleTapEvent e) => _googleMapState.onCircleTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onGroundOverlayTap(mapId: mapId) + .listen( + (GroundOverlayTapEvent e) => + _googleMapState.onGroundOverlayTap(e.value), + ); + GoogleMapsFlutterPlatform.instance + .onTap(mapId: mapId) + .listen((MapTapEvent e) => _googleMapState.onTap(e.position)); + GoogleMapsFlutterPlatform.instance + .onLongPress(mapId: mapId) + .listen( + (MapLongPressEvent e) => _googleMapState.onLongPress(e.position), + ); + GoogleMapsFlutterPlatform.instance + .onClusterTap(mapId: mapId) + .listen((ClusterTapEvent e) => _googleMapState.onClusterTap(e.value)); + } + + /// Updates configuration options of the map user interface. + Future _updateMapConfiguration(MapConfiguration update) { + return GoogleMapsFlutterPlatform.instance.updateMapConfiguration( + update, + mapId: mapId, + ); + } + + /// Updates marker configuration. + Future _updateMarkers(MarkerUpdates markerUpdates) { + return GoogleMapsFlutterPlatform.instance.updateMarkers( + markerUpdates, + mapId: mapId, + ); + } + + /// Updates cluster manager configuration. + Future _updateClusterManagers( + ClusterManagerUpdates clusterManagerUpdates, + ) { + return GoogleMapsFlutterPlatform.instance.updateClusterManagers( + clusterManagerUpdates, + mapId: mapId, + ); + } + + /// Updates ground overlay configuration. + Future _updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, + ) { + return GoogleMapsFlutterPlatform.instance.updateGroundOverlays( + groundOverlayUpdates, + mapId: mapId, + ); + } + + /// Updates polygon configuration. + Future _updatePolygons(PolygonUpdates polygonUpdates) { + return GoogleMapsFlutterPlatform.instance.updatePolygons( + polygonUpdates, + mapId: mapId, + ); + } + + /// Updates polyline configuration. + Future _updatePolylines(PolylineUpdates polylineUpdates) { + return GoogleMapsFlutterPlatform.instance.updatePolylines( + polylineUpdates, + mapId: mapId, + ); + } + + /// Updates circle configuration. + Future _updateCircles(CircleUpdates circleUpdates) { + return GoogleMapsFlutterPlatform.instance.updateCircles( + circleUpdates, + mapId: mapId, + ); + } + + /// Updates tile overlays configuration. + Future _updateTileOverlays(Set newTileOverlays) { + return GoogleMapsFlutterPlatform.instance.updateTileOverlays( + newTileOverlays: newTileOverlays, + mapId: mapId, + ); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. + Future clearTileCache(TileOverlayId tileOverlayId) async { + return GoogleMapsFlutterPlatform.instance.clearTileCache( + tileOverlayId, + mapId: mapId, + ); + } + + /// Starts an animated change of the map camera position. + Future animateCamera(CameraUpdate cameraUpdate, {Duration? duration}) { + return GoogleMapsFlutterPlatform.instance.animateCameraWithConfiguration( + cameraUpdate, + CameraUpdateAnimationConfiguration(duration: duration), + mapId: mapId, + ); + } + + /// Changes the map camera position. + Future moveCamera(CameraUpdate cameraUpdate) { + return GoogleMapsFlutterPlatform.instance.moveCamera( + cameraUpdate, + mapId: mapId, + ); + } + + /// Return [LatLngBounds] defining the region that is visible in a map. + Future getVisibleRegion() { + return GoogleMapsFlutterPlatform.instance.getVisibleRegion(mapId: mapId); + } + + /// Return [ScreenCoordinate] of the [LatLng] in the current map view. + Future getScreenCoordinate(LatLng latLng) { + return GoogleMapsFlutterPlatform.instance.getScreenCoordinate( + latLng, + mapId: mapId, + ); + } + + /// Returns [LatLng] corresponding to the [ScreenCoordinate] in the current map view. + Future getLatLng(ScreenCoordinate screenCoordinate) { + return GoogleMapsFlutterPlatform.instance.getLatLng( + screenCoordinate, + mapId: mapId, + ); + } + + /// Programmatically show the Info Window for a [Marker]. + Future showMarkerInfoWindow(MarkerId markerId) { + return GoogleMapsFlutterPlatform.instance.showMarkerInfoWindow( + markerId, + mapId: mapId, + ); + } + + /// Programmatically hide the Info Window for a [Marker]. + Future hideMarkerInfoWindow(MarkerId markerId) { + return GoogleMapsFlutterPlatform.instance.hideMarkerInfoWindow( + markerId, + mapId: mapId, + ); + } + + /// Returns `true` when the [InfoWindow] is showing, `false` otherwise. + Future isMarkerInfoWindowShown(MarkerId markerId) { + return GoogleMapsFlutterPlatform.instance.isMarkerInfoWindowShown( + markerId, + mapId: mapId, + ); + } + + /// Returns the current zoom level of the map + Future getZoomLevel() { + return GoogleMapsFlutterPlatform.instance.getZoomLevel(mapId: mapId); + } + + /// Returns the image bytes of the map + Future takeSnapshot() { + return GoogleMapsFlutterPlatform.instance.takeSnapshot(mapId: mapId); + } + + /// Returns the last style error, if any. + Future getStyleError() { + return GoogleMapsFlutterPlatform.instance.getStyleError(mapId: mapId); + } + + /// Disposes of the platform resources + void dispose() { + GoogleMapsFlutterPlatform.instance.dispose(mapId: mapId); + } +} + +// The next map ID to create. +int _nextMapCreationId = 0; + +/// A widget which displays a map with data obtained from the Google Maps service. +class ExampleGoogleMap extends StatefulWidget { + /// Creates a widget displaying data from Google Maps services. + /// + /// [AssertionError] will be thrown if [initialCameraPosition] is null; + const ExampleGoogleMap({ + super.key, + required this.initialCameraPosition, + this.onMapCreated, + this.gestureRecognizers = const >{}, + this.compassEnabled = true, + this.cameraTargetBounds = CameraTargetBounds.unbounded, + this.mapType = MapType.normal, + this.minMaxZoomPreference = MinMaxZoomPreference.unbounded, + this.rotateGesturesEnabled = true, + this.scrollGesturesEnabled = true, + this.zoomControlsEnabled = true, + this.zoomGesturesEnabled = true, + this.tiltGesturesEnabled = true, + this.myLocationEnabled = false, + this.myLocationButtonEnabled = true, + this.layoutDirection, + + /// If no padding is specified default padding will be 0. + this.padding = EdgeInsets.zero, + this.indoorViewEnabled = false, + this.trafficEnabled = false, + this.buildingsEnabled = true, + this.markers = const {}, + this.polygons = const {}, + this.polylines = const {}, + this.circles = const {}, + this.clusterManagers = const {}, + this.onCameraMoveStarted, + this.tileOverlays = const {}, + this.groundOverlays = const {}, + this.onCameraMove, + this.onCameraIdle, + this.onTap, + this.onLongPress, + this.mapId, + this.style, + }); + + /// Callback method for when the map is ready to be used. + /// + /// Used to receive a [ExampleGoogleMapController] for this [ExampleGoogleMap]. + final void Function(ExampleGoogleMapController controller)? onMapCreated; + + /// The initial position of the map's camera. + final CameraPosition initialCameraPosition; + + /// True if the map should show a compass when rotated. + final bool compassEnabled; + + /// Geographical bounding box for the camera target. + final CameraTargetBounds cameraTargetBounds; + + /// Type of map tiles to be rendered. + final MapType mapType; + + /// The layout direction to use for the embedded view. + final TextDirection? layoutDirection; + + /// Preferred bounds for the camera zoom level. + /// + /// Actual bounds depend on map data and device. + final MinMaxZoomPreference minMaxZoomPreference; + + /// True if the map view should respond to rotate gestures. + final bool rotateGesturesEnabled; + + /// True if the map view should respond to scroll gestures. + final bool scrollGesturesEnabled; + + /// True if the map view should show zoom controls. This includes two buttons + /// to zoom in and zoom out. The default value is to show zoom controls. + final bool zoomControlsEnabled; + + /// True if the map view should respond to zoom gestures. + final bool zoomGesturesEnabled; + + /// True if the map view should respond to tilt gestures. + final bool tiltGesturesEnabled; + + /// Padding to be set on map. + final EdgeInsets padding; + + /// Markers to be placed on the map. + final Set markers; + + /// Polygons to be placed on the map. + final Set polygons; + + /// Polylines to be placed on the map. + final Set polylines; + + /// Circles to be placed on the map. + final Set circles; + + /// Tile overlays to be placed on the map. + final Set tileOverlays; + + /// Cluster Managers to be placed for the map. + final Set clusterManagers; + + /// Ground overlays to be initialized for the map. + final Set groundOverlays; + + /// Called when the camera starts moving. + final VoidCallback? onCameraMoveStarted; + + /// Called repeatedly as the camera continues to move after an + /// onCameraMoveStarted call. + final CameraPositionCallback? onCameraMove; + + /// Called when camera movement has ended, there are no pending + /// animations and the user has stopped interacting with the map. + final VoidCallback? onCameraIdle; + + /// Called every time a [ExampleGoogleMap] is tapped. + final ArgumentCallback? onTap; + + /// Called every time a [ExampleGoogleMap] is long pressed. + final ArgumentCallback? onLongPress; + + /// True if a "My Location" layer should be shown on the map. + final bool myLocationEnabled; + + /// Enables or disables the my-location button. + final bool myLocationButtonEnabled; + + /// Enables or disables the indoor view from the map + final bool indoorViewEnabled; + + /// Enables or disables the traffic layer of the map + final bool trafficEnabled; + + /// Enables or disables showing 3D buildings where available + final bool buildingsEnabled; + + /// Which gestures should be consumed by the map. + final Set> gestureRecognizers; + + /// Identifier that's associated with a specific cloud-based map style. + /// + /// See https://developers.google.com/maps/documentation/get-map-id + /// for more details. + final String? mapId; + + /// The locally configured style for the map. + final String? style; + + /// Creates a [State] for this [ExampleGoogleMap]. + @override + State createState() => _ExampleGoogleMapState(); +} + +class _ExampleGoogleMapState extends State { + final int _mapId = _nextMapCreationId++; + + final Completer _controller = + Completer(); + + Map _markers = {}; + Map _polygons = {}; + Map _polylines = {}; + Map _circles = {}; + Map _clusterManagers = + {}; + Map _groundOverlays = + {}; + late MapConfiguration _mapConfiguration; + + @override + Widget build(BuildContext context) { + return GoogleMapsFlutterPlatform.instance.buildViewWithConfiguration( + _mapId, + onPlatformViewCreated, + widgetConfiguration: MapWidgetConfiguration( + textDirection: + widget.layoutDirection ?? + Directionality.maybeOf(context) ?? + TextDirection.ltr, + initialCameraPosition: widget.initialCameraPosition, + gestureRecognizers: widget.gestureRecognizers, + ), + mapObjects: MapObjects( + markers: widget.markers, + polygons: widget.polygons, + polylines: widget.polylines, + circles: widget.circles, + clusterManagers: widget.clusterManagers, + groundOverlays: widget.groundOverlays, + ), + mapConfiguration: _mapConfiguration, + ); + } + + @override + void initState() { + super.initState(); + _mapConfiguration = _configurationFromMapWidget(widget); + _clusterManagers = keyByClusterManagerId(widget.clusterManagers); + _markers = keyByMarkerId(widget.markers); + _polygons = keyByPolygonId(widget.polygons); + _polylines = keyByPolylineId(widget.polylines); + _circles = keyByCircleId(widget.circles); + _groundOverlays = keyByGroundOverlayId(widget.groundOverlays); + } + + @override + void dispose() { + _controller.future.then( + (ExampleGoogleMapController controller) => controller.dispose(), + ); + super.dispose(); + } + + @override + void didUpdateWidget(ExampleGoogleMap oldWidget) { + super.didUpdateWidget(oldWidget); + _updateOptions(); + _updateClusterManagers(); + _updateMarkers(); + _updatePolygons(); + _updatePolylines(); + _updateCircles(); + _updateTileOverlays(); + _updateGroundOverlays(); + } + + Future _updateOptions() async { + final MapConfiguration newConfig = _configurationFromMapWidget(widget); + final MapConfiguration updates = newConfig.diffFrom(_mapConfiguration); + if (updates.isEmpty) { + return; + } + final ExampleGoogleMapController controller = await _controller.future; + unawaited(controller._updateMapConfiguration(updates)); + _mapConfiguration = newConfig; + } + + Future _updateMarkers() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateMarkers( + MarkerUpdates.from(_markers.values.toSet(), widget.markers), + ), + ); + _markers = keyByMarkerId(widget.markers); + } + + Future _updateClusterManagers() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateClusterManagers( + ClusterManagerUpdates.from( + _clusterManagers.values.toSet(), + widget.clusterManagers, + ), + ), + ); + _clusterManagers = keyByClusterManagerId(widget.clusterManagers); + } + + Future _updateGroundOverlays() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateGroundOverlays( + GroundOverlayUpdates.from( + _groundOverlays.values.toSet(), + widget.groundOverlays, + ), + ), + ); + _groundOverlays = keyByGroundOverlayId(widget.groundOverlays); + } + + Future _updatePolygons() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updatePolygons( + PolygonUpdates.from(_polygons.values.toSet(), widget.polygons), + ), + ); + _polygons = keyByPolygonId(widget.polygons); + } + + Future _updatePolylines() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updatePolylines( + PolylineUpdates.from(_polylines.values.toSet(), widget.polylines), + ), + ); + _polylines = keyByPolylineId(widget.polylines); + } + + Future _updateCircles() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateCircles( + CircleUpdates.from(_circles.values.toSet(), widget.circles), + ), + ); + _circles = keyByCircleId(widget.circles); + } + + Future _updateTileOverlays() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited(controller._updateTileOverlays(widget.tileOverlays)); + } + + Future onPlatformViewCreated(int id) async { + final ExampleGoogleMapController controller = + await ExampleGoogleMapController._init( + id, + widget.initialCameraPosition, + this, + ); + _controller.complete(controller); + unawaited(_updateTileOverlays()); + widget.onMapCreated?.call(controller); + } + + void onMarkerTap(MarkerId markerId) { + _markers[markerId]!.onTap?.call(); + } + + void onMarkerDragStart(MarkerId markerId, LatLng position) { + _markers[markerId]!.onDragStart?.call(position); + } + + void onMarkerDrag(MarkerId markerId, LatLng position) { + _markers[markerId]!.onDrag?.call(position); + } + + void onMarkerDragEnd(MarkerId markerId, LatLng position) { + _markers[markerId]!.onDragEnd?.call(position); + } + + void onPolygonTap(PolygonId polygonId) { + _polygons[polygonId]!.onTap?.call(); + } + + void onPolylineTap(PolylineId polylineId) { + _polylines[polylineId]!.onTap?.call(); + } + + void onCircleTap(CircleId circleId) { + _circles[circleId]!.onTap?.call(); + } + + void onGroundOverlayTap(GroundOverlayId groundOverlayId) { + _groundOverlays[groundOverlayId]!.onTap?.call(); + } + + void onInfoWindowTap(MarkerId markerId) { + _markers[markerId]!.infoWindow.onTap?.call(); + } + + void onTap(LatLng position) { + widget.onTap?.call(position); + } + + void onLongPress(LatLng position) { + widget.onLongPress?.call(position); + } + + void onClusterTap(Cluster cluster) { + final ClusterManager? clusterManager = + _clusterManagers[cluster.clusterManagerId]; + clusterManager?.onClusterTap?.call(cluster); + } +} + +/// Builds a [MapConfiguration] from the given [map]. +MapConfiguration _configurationFromMapWidget(ExampleGoogleMap map) { + return MapConfiguration( + compassEnabled: map.compassEnabled, + cameraTargetBounds: map.cameraTargetBounds, + mapType: map.mapType, + minMaxZoomPreference: map.minMaxZoomPreference, + rotateGesturesEnabled: map.rotateGesturesEnabled, + scrollGesturesEnabled: map.scrollGesturesEnabled, + tiltGesturesEnabled: map.tiltGesturesEnabled, + trackCameraPosition: map.onCameraMove != null, + zoomControlsEnabled: map.zoomControlsEnabled, + zoomGesturesEnabled: map.zoomGesturesEnabled, + myLocationEnabled: map.myLocationEnabled, + myLocationButtonEnabled: map.myLocationButtonEnabled, + padding: map.padding, + indoorViewEnabled: map.indoorViewEnabled, + trafficEnabled: map.trafficEnabled, + buildingsEnabled: map.buildingsEnabled, + mapId: map.mapId, + style: map.style, + ); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/ground_overlay.dart new file mode 100644 index 000000000000..d8f474eb7d5e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/ground_overlay.dart @@ -0,0 +1,311 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +enum _GroundOverlayPlacing { position, bounds } + +class GroundOverlayPage extends GoogleMapExampleAppPage { + const GroundOverlayPage({Key? key}) + : super(const Icon(Icons.map), 'Ground overlay', key: key); + + @override + Widget build(BuildContext context) { + return const GroundOverlayBody(); + } +} + +class GroundOverlayBody extends StatefulWidget { + const GroundOverlayBody({super.key}); + + @override + State createState() => GroundOverlayBodyState(); +} + +class GroundOverlayBodyState extends State { + GroundOverlayBodyState(); + + ExampleGoogleMapController? controller; + GroundOverlay? _groundOverlay; + + final LatLng _mapCenter = const LatLng(37.422026, -122.085329); + + _GroundOverlayPlacing _placingType = _GroundOverlayPlacing.bounds; + + // Positions for demonstranting placing ground overlays with position, and + // changing positions. + final LatLng _groundOverlayPos1 = const LatLng(37.422026, -122.085329); + final LatLng _groundOverlayPos2 = const LatLng(37.42, -122.08); + late LatLng _currentGroundOverlayPos; + + // Bounds for demonstranting placing ground overlays with bounds, and + // changing bounds. + final LatLngBounds _groundOverlayBounds1 = LatLngBounds( + southwest: const LatLng(37.42, -122.09), + northeast: const LatLng(37.423, -122.084), + ); + final LatLngBounds _groundOverlayBounds2 = LatLngBounds( + southwest: const LatLng(37.421, -122.091), + northeast: const LatLng(37.424, -122.08), + ); + late LatLngBounds _currentGroundOverlayBounds; + + Offset _anchor = const Offset(0.5, 0.5); + + // Index to be used as identifier for the ground overlay. + // If position is changed to bounds and vice versa, the ground overlay will + // be removed and added again with the new type. Also anchor can be given only + // when the ground overlay is created with position and cannot be changed + // after the ground overlay is created. + int _groundOverlayIndex = 0; + + @override + void initState() { + _currentGroundOverlayPos = _groundOverlayPos1; + _currentGroundOverlayBounds = _groundOverlayBounds1; + super.initState(); + } + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + void _removeGroundOverlay() { + setState(() { + _groundOverlay = null; + }); + } + + Future _addGroundOverlay() async { + final AssetMapBitmap assetMapBitmap = await AssetMapBitmap.create( + createLocalImageConfiguration(context), + 'assets/red_square.png', + bitmapScaling: MapBitmapScaling.none, + ); + + _groundOverlayIndex += 1; + + final id = GroundOverlayId('ground_overlay_$_groundOverlayIndex'); + + final GroundOverlay groundOverlay = switch (_placingType) { + _GroundOverlayPlacing.position => GroundOverlay.fromPosition( + groundOverlayId: id, + image: assetMapBitmap, + position: _currentGroundOverlayPos, + anchor: _anchor, + onTap: () { + _onGroundOverlayTapped(); + }, + zoomLevel: 14.0, + ), + _GroundOverlayPlacing.bounds => GroundOverlay.fromBounds( + groundOverlayId: id, + image: assetMapBitmap, + bounds: _currentGroundOverlayBounds, + anchor: _anchor, + onTap: () { + _onGroundOverlayTapped(); + }, + ), + }; + + setState(() { + _groundOverlay = groundOverlay; + }); + } + + void _onGroundOverlayTapped() { + _changePosition(); + } + + void _setBearing() { + assert(_groundOverlay != null); + setState(() { + // Adjusts the bearing by 10 degrees, wrapping around at 360 degrees. + // 10 is the increment, 350 degrees of the full circle -10. + _groundOverlay = _groundOverlay!.copyWith( + bearingParam: _groundOverlay!.bearing >= 350 + ? 0 + : _groundOverlay!.bearing + 10, + ); + }); + } + + void _changeTransparency() { + assert(_groundOverlay != null); + setState(() { + final transparency = _groundOverlay!.transparency == 0.0 ? 0.5 : 0.0; + _groundOverlay = _groundOverlay!.copyWith( + transparencyParam: transparency, + ); + }); + } + + Future _changePosition() async { + assert(_groundOverlay != null); + assert(_placingType == _GroundOverlayPlacing.position); + setState(() { + _currentGroundOverlayPos = _currentGroundOverlayPos == _groundOverlayPos1 + ? _groundOverlayPos2 + : _groundOverlayPos1; + }); + + // Re-add the ground overlay to apply the new position, as the position + // cannot be changed after the ground overlay is created on all platforms. + await _addGroundOverlay(); + } + + Future _changeBounds() async { + assert(_groundOverlay != null); + assert(_placingType == _GroundOverlayPlacing.bounds); + setState(() { + _currentGroundOverlayBounds = + _currentGroundOverlayBounds == _groundOverlayBounds1 + ? _groundOverlayBounds2 + : _groundOverlayBounds1; + }); + + // Re-add the ground overlay to apply the new position, as the position + // cannot be changed after the ground overlay is created on all platforms. + await _addGroundOverlay(); + } + + void _toggleVisible() { + assert(_groundOverlay != null); + setState(() { + _groundOverlay = _groundOverlay!.copyWith( + visibleParam: !_groundOverlay!.visible, + ); + }); + } + + void _changeZIndex() { + assert(_groundOverlay != null); + final int current = _groundOverlay!.zIndex; + final int zIndex = current == 12 ? 0 : current + 1; + setState(() { + _groundOverlay = _groundOverlay!.copyWith(zIndexParam: zIndex); + }); + } + + Future _changeType() async { + setState(() { + _placingType = _placingType == _GroundOverlayPlacing.position + ? _GroundOverlayPlacing.bounds + : _GroundOverlayPlacing.position; + }); + + // Re-add the ground overlay to apply the new position, as the position + // cannot be changed after the ground overlay is created on all platforms. + await _addGroundOverlay(); + } + + Future _changeAnchor() async { + assert(_groundOverlay != null); + setState(() { + _anchor = _groundOverlay!.anchor == const Offset(0.5, 0.5) + ? const Offset(1.0, 1.0) + : const Offset(0.5, 0.5); + }); + + // Re-add the ground overlay to apply the new anchor, as anchor cannot be + // changed after the ground overlay is created. + await _addGroundOverlay(); + } + + @override + Widget build(BuildContext context) { + final overlays = { + if (_groundOverlay != null) _groundOverlay!, + }; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: ExampleGoogleMap( + initialCameraPosition: CameraPosition( + target: _mapCenter, + zoom: 14.0, + ), + groundOverlays: overlays, + onMapCreated: _onMapCreated, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: _groundOverlay == null ? _addGroundOverlay : null, + child: const Text('Add'), + ), + TextButton( + onPressed: _groundOverlay != null ? _removeGroundOverlay : null, + child: const Text('Remove'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: _groundOverlay == null + ? null + : () => _changeTransparency(), + child: const Text('change transparency'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _setBearing(), + child: const Text('change bearing'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _toggleVisible(), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _changeZIndex(), + child: const Text('change zIndex'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _changeAnchor(), + child: const Text('change anchor'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _changeType(), + child: Text( + _placingType == _GroundOverlayPlacing.position + ? 'use bounds' + : 'use position', + ), + ), + TextButton( + onPressed: + _placingType != _GroundOverlayPlacing.position || + _groundOverlay == null + ? null + : () => _changePosition(), + child: const Text('change position'), + ), + TextButton( + onPressed: + _placingType != _GroundOverlayPlacing.bounds || + _groundOverlay == null + ? null + : () => _changeBounds(), + child: const Text('change bounds'), + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/lite_mode.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/lite_mode.dart new file mode 100644 index 000000000000..e6359e19acc2 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/lite_mode.dart @@ -0,0 +1,46 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class LiteModePage extends GoogleMapExampleAppPage { + const LiteModePage({Key? key}) + : super(const Icon(Icons.map), 'Lite mode', key: key); + + @override + Widget build(BuildContext context) { + return const _LiteModeBody(); + } +} + +class _LiteModeBody extends StatelessWidget { + const _LiteModeBody(); + + @override + Widget build(BuildContext context) { + return const Card( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 30.0), + child: Center( + child: SizedBox( + width: 300.0, + height: 300.0, + child: ExampleGoogleMap(initialCameraPosition: _kInitialPosition), + ), + ), + ), + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/main.dart new file mode 100644 index 000000000000..605e4e3a57ec --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/main.dart @@ -0,0 +1,53 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'animate_camera.dart'; +import 'clustering.dart'; +import 'ground_overlay.dart'; +import 'lite_mode.dart'; +import 'map_click.dart'; +import 'map_coordinates.dart'; +import 'map_map_id.dart'; +import 'map_ui.dart'; +import 'maps_demo.dart'; +import 'marker_icons.dart'; +import 'move_camera.dart'; +import 'padding.dart'; +import 'page.dart'; +import 'place_circle.dart'; +import 'place_marker.dart'; +import 'place_polygon.dart'; +import 'place_polyline.dart'; +import 'scrolling_map.dart'; +import 'snapshot.dart'; +import 'tile_overlay.dart'; + +void main() { + runApp( + const MaterialApp( + home: MapsDemo([ + MapUiPage(), + MapCoordinatesPage(), + MapClickPage(), + AnimateCameraPage(), + MoveCameraPage(), + PlaceMarkerPage(), + MarkerIconsPage(), + ScrollingMapPage(), + PlacePolylinePage(), + PlacePolygonPage(), + PlaceCirclePage(), + PaddingPage(), + SnapshotPage(), + LiteModePage(), + TileOverlayPage(), + GroundOverlayPage(), + ClusteringPage(), + MapIdPage(), + ]), + ), + ); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_click.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_click.dart new file mode 100644 index 000000000000..4d45e961d63e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_click.dart @@ -0,0 +1,105 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class MapClickPage extends GoogleMapExampleAppPage { + const MapClickPage({Key? key}) + : super(const Icon(Icons.mouse), 'Map click', key: key); + + @override + Widget build(BuildContext context) { + return const _MapClickBody(); + } +} + +class _MapClickBody extends StatefulWidget { + const _MapClickBody(); + + @override + State createState() => _MapClickBodyState(); +} + +class _MapClickBodyState extends State<_MapClickBody> { + _MapClickBodyState(); + + ExampleGoogleMapController? mapController; + LatLng? _lastTap; + LatLng? _lastLongPress; + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + onTap: (LatLng pos) { + setState(() { + _lastTap = pos; + }); + }, + onLongPress: (LatLng pos) { + setState(() { + _lastLongPress = pos; + }); + }, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + ]; + + if (mapController != null) { + final lastTap = 'Tap:\n${_lastTap ?? ""}\n'; + final lastLongPress = 'Long press:\n${_lastLongPress ?? ""}'; + columnChildren.add( + Center(child: Text(lastTap, textAlign: TextAlign.center)), + ); + columnChildren.add( + Center( + child: Text( + _lastTap != null ? 'Tapped' : '', + textAlign: TextAlign.center, + ), + ), + ); + columnChildren.add( + Center(child: Text(lastLongPress, textAlign: TextAlign.center)), + ); + columnChildren.add( + Center( + child: Text( + _lastLongPress != null ? 'Long pressed' : '', + textAlign: TextAlign.center, + ), + ), + ); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + Future onMapCreated(ExampleGoogleMapController controller) async { + setState(() { + mapController = controller; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_coordinates.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_coordinates.dart new file mode 100644 index 000000000000..3a93b0db93b7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_coordinates.dart @@ -0,0 +1,105 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class MapCoordinatesPage extends GoogleMapExampleAppPage { + const MapCoordinatesPage({Key? key}) + : super(const Icon(Icons.map), 'Map coordinates', key: key); + + @override + Widget build(BuildContext context) { + return const _MapCoordinatesBody(); + } +} + +class _MapCoordinatesBody extends StatefulWidget { + const _MapCoordinatesBody(); + + @override + State createState() => _MapCoordinatesBodyState(); +} + +class _MapCoordinatesBodyState extends State<_MapCoordinatesBody> { + _MapCoordinatesBodyState(); + + ExampleGoogleMapController? mapController; + LatLngBounds _visibleRegion = LatLngBounds( + southwest: const LatLng(0, 0), + northeast: const LatLng(0, 0), + ); + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + onCameraIdle: + _updateVisibleRegion, // https://github.com/flutter/flutter/issues/54758 + ); + + return NotificationListener( + onNotification: (ScrollNotification scrollState) { + _updateVisibleRegion(); + return true; + }, + child: Stack( + children: [ + ListView( + children: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: googleMap, + ), + ), + ), + // Add a block at the bottom of this list to allow validation that the visible region of the map + // does not change when scrolled under the safe view on iOS. + // https://github.com/flutter/flutter/issues/107913 + const SizedBox(width: 300, height: 1000), + ], + ), + if (mapController != null) + Center( + child: Text( + 'VisibleRegion:' + '\nnortheast: ${_visibleRegion.northeast},' + '\nsouthwest: ${_visibleRegion.southwest}', + ), + ), + ], + ), + ); + } + + Future onMapCreated(ExampleGoogleMapController controller) async { + final LatLngBounds visibleRegion = await controller.getVisibleRegion(); + setState(() { + mapController = controller; + _visibleRegion = visibleRegion; + }); + } + + Future _updateVisibleRegion() async { + final LatLngBounds visibleRegion = await mapController!.getVisibleRegion(); + setState(() { + _visibleRegion = visibleRegion; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_map_id.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_map_id.dart new file mode 100644 index 000000000000..c62152f149d0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_map_id.dart @@ -0,0 +1,100 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class MapIdPage extends GoogleMapExampleAppPage { + const MapIdPage({Key? key}) + : super(const Icon(Icons.map), 'Cloud-based maps styling', key: key); + + @override + Widget build(BuildContext context) { + return const MapIdBody(); + } +} + +class MapIdBody extends StatefulWidget { + const MapIdBody({super.key}); + + @override + State createState() => MapIdBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +class MapIdBodyState extends State { + ExampleGoogleMapController? controller; + + Key _key = const Key('mapId#'); + String? _mapId; + final TextEditingController _mapIdController = TextEditingController(); + + void _setMapId() { + setState(() { + _mapId = _mapIdController.text; + + // Change key to initialize new map instance for new mapId. + _key = Key(_mapId ?? 'mapId#'); + }); + } + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + key: _key, + mapId: _mapId, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: TextField( + controller: _mapIdController, + decoration: const InputDecoration(hintText: 'Map Id'), + ), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: ElevatedButton( + onPressed: () => _setMapId(), + child: const Text('Press to use specified map Id'), + ), + ), + ]; + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + @override + void dispose() { + _mapIdController.dispose(); + super.dispose(); + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_ui.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_ui.dart new file mode 100644 index 000000000000..46fa320ad3a0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/map_ui.dart @@ -0,0 +1,341 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart' show rootBundle; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +final LatLngBounds sydneyBounds = LatLngBounds( + southwest: const LatLng(-34.022631, 150.620685), + northeast: const LatLng(-33.571835, 151.325952), +); + +class MapUiPage extends GoogleMapExampleAppPage { + const MapUiPage({Key? key}) + : super(const Icon(Icons.map), 'User interface', key: key); + + @override + Widget build(BuildContext context) { + return const MapUiBody(); + } +} + +class MapUiBody extends StatefulWidget { + const MapUiBody({super.key}); + + @override + State createState() => MapUiBodyState(); +} + +class MapUiBodyState extends State { + MapUiBodyState(); + + static const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, + ); + + CameraPosition _position = _kInitialPosition; + bool _isMapCreated = false; + final bool _isMoving = false; + bool _compassEnabled = true; + CameraTargetBounds _cameraTargetBounds = CameraTargetBounds.unbounded; + MinMaxZoomPreference _minMaxZoomPreference = MinMaxZoomPreference.unbounded; + MapType _mapType = MapType.normal; + bool _rotateGesturesEnabled = true; + bool _scrollGesturesEnabled = true; + bool _tiltGesturesEnabled = true; + bool _zoomControlsEnabled = false; + bool _zoomGesturesEnabled = true; + bool _indoorViewEnabled = true; + bool _myLocationEnabled = true; + bool _myTrafficEnabled = false; + bool _myLocationButtonEnabled = true; + late ExampleGoogleMapController _controller; + bool _nightMode = false; + String _mapStyle = ''; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + Widget _compassToggler() { + return TextButton( + child: Text('${_compassEnabled ? 'disable' : 'enable'} compass'), + onPressed: () { + setState(() { + _compassEnabled = !_compassEnabled; + }); + }, + ); + } + + Widget _latLngBoundsToggler() { + return TextButton( + child: Text( + _cameraTargetBounds.bounds == null + ? 'bound camera target' + : 'release camera target', + ), + onPressed: () { + setState(() { + _cameraTargetBounds = _cameraTargetBounds.bounds == null + ? CameraTargetBounds(sydneyBounds) + : CameraTargetBounds.unbounded; + }); + }, + ); + } + + Widget _zoomBoundsToggler() { + return TextButton( + child: Text( + _minMaxZoomPreference.minZoom == null ? 'bound zoom' : 'release zoom', + ), + onPressed: () { + setState(() { + _minMaxZoomPreference = _minMaxZoomPreference.minZoom == null + ? const MinMaxZoomPreference(12.0, 16.0) + : MinMaxZoomPreference.unbounded; + }); + }, + ); + } + + Widget _mapTypeCycler() { + final MapType nextType = + MapType.values[(_mapType.index + 1) % MapType.values.length]; + return TextButton( + child: Text('change map type to $nextType'), + onPressed: () { + setState(() { + _mapType = nextType; + }); + }, + ); + } + + Widget _rotateToggler() { + return TextButton( + child: Text('${_rotateGesturesEnabled ? 'disable' : 'enable'} rotate'), + onPressed: () { + setState(() { + _rotateGesturesEnabled = !_rotateGesturesEnabled; + }); + }, + ); + } + + Widget _scrollToggler() { + return TextButton( + child: Text('${_scrollGesturesEnabled ? 'disable' : 'enable'} scroll'), + onPressed: () { + setState(() { + _scrollGesturesEnabled = !_scrollGesturesEnabled; + }); + }, + ); + } + + Widget _tiltToggler() { + return TextButton( + child: Text('${_tiltGesturesEnabled ? 'disable' : 'enable'} tilt'), + onPressed: () { + setState(() { + _tiltGesturesEnabled = !_tiltGesturesEnabled; + }); + }, + ); + } + + Widget _zoomToggler() { + return TextButton( + child: Text('${_zoomGesturesEnabled ? 'disable' : 'enable'} zoom'), + onPressed: () { + setState(() { + _zoomGesturesEnabled = !_zoomGesturesEnabled; + }); + }, + ); + } + + Widget _zoomControlsToggler() { + return TextButton( + child: Text( + '${_zoomControlsEnabled ? 'disable' : 'enable'} zoom controls', + ), + onPressed: () { + setState(() { + _zoomControlsEnabled = !_zoomControlsEnabled; + }); + }, + ); + } + + Widget _indoorViewToggler() { + return TextButton( + child: Text('${_indoorViewEnabled ? 'disable' : 'enable'} indoor'), + onPressed: () { + setState(() { + _indoorViewEnabled = !_indoorViewEnabled; + }); + }, + ); + } + + Widget _myLocationToggler() { + return TextButton( + child: Text( + '${_myLocationEnabled ? 'disable' : 'enable'} my location marker', + ), + onPressed: () { + setState(() { + _myLocationEnabled = !_myLocationEnabled; + }); + }, + ); + } + + Widget _myLocationButtonToggler() { + return TextButton( + child: Text( + '${_myLocationButtonEnabled ? 'disable' : 'enable'} my location button', + ), + onPressed: () { + setState(() { + _myLocationButtonEnabled = !_myLocationButtonEnabled; + }); + }, + ); + } + + Widget _myTrafficToggler() { + return TextButton( + child: Text('${_myTrafficEnabled ? 'disable' : 'enable'} my traffic'), + onPressed: () { + setState(() { + _myTrafficEnabled = !_myTrafficEnabled; + }); + }, + ); + } + + Future _getFileData(String path) async { + return rootBundle.loadString(path); + } + + Widget _nightModeToggler() { + return TextButton( + child: Text('${_nightMode ? 'disable' : 'enable'} night mode'), + onPressed: () async { + _nightMode = !_nightMode; + final String style = _nightMode + ? await _getFileData('assets/night_mode.json') + : ''; + setState(() { + _mapStyle = style; + }); + }, + ); + } + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + compassEnabled: _compassEnabled, + cameraTargetBounds: _cameraTargetBounds, + minMaxZoomPreference: _minMaxZoomPreference, + mapType: _mapType, + style: _mapStyle, + rotateGesturesEnabled: _rotateGesturesEnabled, + scrollGesturesEnabled: _scrollGesturesEnabled, + tiltGesturesEnabled: _tiltGesturesEnabled, + zoomGesturesEnabled: _zoomGesturesEnabled, + zoomControlsEnabled: _zoomControlsEnabled, + indoorViewEnabled: _indoorViewEnabled, + myLocationEnabled: _myLocationEnabled, + myLocationButtonEnabled: _myLocationButtonEnabled, + trafficEnabled: _myTrafficEnabled, + onCameraMove: _updateCameraPosition, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + ]; + + if (_isMapCreated) { + columnChildren.add( + Expanded( + child: ListView( + children: [ + Text('camera bearing: ${_position.bearing}'), + Text( + 'camera target: ${_position.target.latitude.toStringAsFixed(4)},' + '${_position.target.longitude.toStringAsFixed(4)}', + ), + Text('camera zoom: ${_position.zoom}'), + Text('camera tilt: ${_position.tilt}'), + Text(_isMoving ? '(Camera moving)' : '(Camera idle)'), + _compassToggler(), + _latLngBoundsToggler(), + _mapTypeCycler(), + _zoomBoundsToggler(), + _rotateToggler(), + _scrollToggler(), + _tiltToggler(), + _zoomToggler(), + _zoomControlsToggler(), + _indoorViewToggler(), + _myLocationToggler(), + _myLocationButtonToggler(), + _myTrafficToggler(), + _nightModeToggler(), + ], + ), + ), + ); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + void _updateCameraPosition(CameraPosition position) { + setState(() { + _position = position; + }); + } + + void onMapCreated(ExampleGoogleMapController controller) { + setState(() { + _controller = controller; + _isMapCreated = true; + }); + // Log any style errors to the console for debugging. + _controller.getStyleError().then((String? error) { + if (error != null) { + debugPrint(error); + } + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/maps_demo.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/maps_demo.dart new file mode 100644 index 000000000000..6d21ab3b91e9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/maps_demo.dart @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'page.dart'; + +/// MapsDemo is the Main Application. +class MapsDemo extends StatelessWidget { + /// Default Constructor + const MapsDemo(this.pages, {super.key}); + + /// The list of demo pages. + final List pages; + + void _pushPage(BuildContext context, GoogleMapExampleAppPage page) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + appBar: AppBar(title: Text(page.title)), + body: page, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('GoogleMaps examples')), + body: ListView.builder( + itemCount: pages.length, + itemBuilder: (_, int index) => ListTile( + leading: pages[index].leading, + title: Text(pages[index].title), + onTap: () => _pushPage(context, pages[index]), + ), + ), + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/marker_icons.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/marker_icons.dart new file mode 100644 index 000000000000..2959c7c0dcf0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/marker_icons.dart @@ -0,0 +1,355 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs +// ignore_for_file: unawaited_futures + +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'custom_marker_icon.dart'; +import 'example_google_map.dart'; +import 'page.dart'; + +class MarkerIconsPage extends GoogleMapExampleAppPage { + const MarkerIconsPage({Key? key}) + : super(const Icon(Icons.image), 'Marker icons', key: key); + + @override + Widget build(BuildContext context) { + return const MarkerIconsBody(); + } +} + +class MarkerIconsBody extends StatefulWidget { + const MarkerIconsBody({super.key}); + + @override + State createState() => MarkerIconsBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +enum _MarkerSizeOption { original, width30, height40, size30x60, size120x60 } + +class MarkerIconsBodyState extends State { + final Size _markerAssetImageSize = const Size(48, 48); + _MarkerSizeOption _currentSizeOption = _MarkerSizeOption.original; + Set _markers = {}; + bool _scalingEnabled = true; + bool _mipMapsEnabled = true; + ExampleGoogleMapController? controller; + AssetMapBitmap? _markerIconAsset; + BytesMapBitmap? _markerIconBytes; + final int _markersAmountPerType = 15; + bool get _customSizeEnabled => + _currentSizeOption != _MarkerSizeOption.original; + + @override + Widget build(BuildContext context) { + _createCustomMarkerIconImages(context); + final Size referenceSize = _getMarkerReferenceSize(); + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Column( + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + markers: _markers, + onMapCreated: _onMapCreated, + ), + ), + ), + TextButton( + onPressed: () => _toggleScaling(context), + child: Text( + _scalingEnabled + ? 'Disable auto scaling' + : 'Enable auto scaling', + ), + ), + if (_scalingEnabled) ...[ + Container( + width: referenceSize.width, + height: referenceSize.height, + decoration: BoxDecoration(border: Border.all()), + ), + Text( + 'Reference box with size of ${referenceSize.width} x ${referenceSize.height} in logical pixels.', + ), + const SizedBox(height: 10), + Image.asset( + 'assets/red_square.png', + scale: _mipMapsEnabled ? null : 1.0, + ), + const Text('Asset image rendered with flutter'), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Marker size:'), + const SizedBox(width: 10), + DropdownButton<_MarkerSizeOption>( + value: _currentSizeOption, + onChanged: (_MarkerSizeOption? newValue) { + if (newValue != null) { + setState(() { + _currentSizeOption = newValue; + _updateMarkerImages(context); + }); + } + }, + items: _MarkerSizeOption.values.map(( + _MarkerSizeOption option, + ) { + return DropdownMenuItem<_MarkerSizeOption>( + value: option, + child: Text(_getMarkerSizeOptionName(option)), + ); + }).toList(), + ), + ], + ), + ], + TextButton( + onPressed: () => _toggleMipMaps(context), + child: Text( + _mipMapsEnabled ? 'Disable mipmaps' : 'Enable mipmaps', + ), + ), + ], + ), + ], + ); + } + + String _getMarkerSizeOptionName(_MarkerSizeOption option) { + switch (option) { + case _MarkerSizeOption.original: + return 'Original'; + case _MarkerSizeOption.width30: + return 'Width 30'; + case _MarkerSizeOption.height40: + return 'Height 40'; + case _MarkerSizeOption.size30x60: + return '30x60'; + case _MarkerSizeOption.size120x60: + return '120x60'; + } + } + + (double? width, double? height) _getCurrentMarkerSize() { + if (_scalingEnabled) { + switch (_currentSizeOption) { + case _MarkerSizeOption.width30: + return (30, null); + case _MarkerSizeOption.height40: + return (null, 40); + case _MarkerSizeOption.size30x60: + return (30, 60); + case _MarkerSizeOption.size120x60: + return (120, 60); + case _MarkerSizeOption.original: + return (_markerAssetImageSize.width, _markerAssetImageSize.height); + } + } else { + return (_markerAssetImageSize.width, _markerAssetImageSize.height); + } + } + + // Helper method to calculate reference size for custom marker size. + Size _getMarkerReferenceSize() { + final (double? width, double? height) = _getCurrentMarkerSize(); + + // Calculates reference size using _markerAssetImageSize aspect ration: + + if (width != null && height != null) { + return Size(width, height); + } else if (width != null) { + return Size( + width, + width * _markerAssetImageSize.height / _markerAssetImageSize.width, + ); + } else if (height != null) { + return Size( + height * _markerAssetImageSize.width / _markerAssetImageSize.height, + height, + ); + } else { + return _markerAssetImageSize; + } + } + + void _toggleMipMaps(BuildContext context) { + _mipMapsEnabled = !_mipMapsEnabled; + _updateMarkerImages(context); + } + + void _toggleScaling(BuildContext context) { + _scalingEnabled = !_scalingEnabled; + _updateMarkerImages(context); + } + + void _updateMarkerImages(BuildContext context) { + _updateMarkerAssetImage(context); + _updateMarkerBytesImage(context); + _updateMarkers(); + } + + Marker _createAssetMarker(int index) { + final position = LatLng( + _kMapCenter.latitude - (index * 0.5), + _kMapCenter.longitude - 1, + ); + + return Marker( + markerId: MarkerId('marker_asset_$index'), + position: position, + icon: _markerIconAsset!, + ); + } + + Marker _createBytesMarker(int index) { + final position = LatLng( + _kMapCenter.latitude - (index * 0.5), + _kMapCenter.longitude + 1, + ); + + return Marker( + markerId: MarkerId('marker_bytes_$index'), + position: position, + icon: _markerIconBytes!, + ); + } + + void _updateMarkers() { + final markers = {}; + for (var i = 0; i < _markersAmountPerType; i++) { + if (_markerIconAsset != null) { + markers.add(_createAssetMarker(i)); + } + if (_markerIconBytes != null) { + markers.add(_createBytesMarker(i)); + } + } + setState(() { + _markers = markers; + }); + } + + Future _updateMarkerAssetImage(BuildContext context) async { + // Width and height are used only for custom size. + final ( + double? width, + double? height, + ) = _scalingEnabled && _customSizeEnabled + ? _getCurrentMarkerSize() + : (null, null); + + AssetMapBitmap assetMapBitmap; + if (_mipMapsEnabled) { + final ImageConfiguration imageConfiguration = + createLocalImageConfiguration(context); + + assetMapBitmap = await AssetMapBitmap.create( + imageConfiguration, + 'assets/red_square.png', + width: width, + height: height, + bitmapScaling: _scalingEnabled + ? MapBitmapScaling.auto + : MapBitmapScaling.none, + ); + } else { + // Uses hardcoded asset path + // This bypasses the asset resolving logic and allows to load the asset + // with precise path. + assetMapBitmap = AssetMapBitmap( + 'assets/red_square.png', + width: width, + height: height, + bitmapScaling: _scalingEnabled + ? MapBitmapScaling.auto + : MapBitmapScaling.none, + ); + } + + _updateAssetBitmap(assetMapBitmap); + } + + Future _updateMarkerBytesImage(BuildContext context) async { + final double? devicePixelRatio = MediaQuery.maybeDevicePixelRatioOf( + context, + ); + + final Size bitmapLogicalSize = _getMarkerReferenceSize(); + final double? imagePixelRatio = _scalingEnabled ? devicePixelRatio : null; + + // Create canvasSize with physical marker size + final canvasSize = Size( + bitmapLogicalSize.width * (imagePixelRatio ?? 1.0), + bitmapLogicalSize.height * (imagePixelRatio ?? 1.0), + ); + + final ByteData bytes = await createCustomMarkerIconImage(size: canvasSize); + + // Width and height are used only for custom size. + final ( + double? width, + double? height, + ) = _scalingEnabled && _customSizeEnabled + ? _getCurrentMarkerSize() + : (null, null); + + final bitmap = BytesMapBitmap( + bytes.buffer.asUint8List(), + imagePixelRatio: imagePixelRatio, + width: width, + height: height, + bitmapScaling: _scalingEnabled + ? MapBitmapScaling.auto + : MapBitmapScaling.none, + ); + + _updateBytesBitmap(bitmap); + } + + void _updateAssetBitmap(AssetMapBitmap bitmap) { + _markerIconAsset = bitmap; + _updateMarkers(); + } + + void _updateBytesBitmap(BytesMapBitmap bitmap) { + _markerIconBytes = bitmap; + _updateMarkers(); + } + + void _createCustomMarkerIconImages(BuildContext context) { + if (_markerIconAsset == null) { + _updateMarkerAssetImage(context); + } + + if (_markerIconBytes == null) { + _updateMarkerBytesImage(context); + } + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/move_camera.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/move_camera.dart new file mode 100644 index 000000000000..bc6fcdea2651 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/move_camera.dart @@ -0,0 +1,161 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class MoveCameraPage extends GoogleMapExampleAppPage { + const MoveCameraPage({Key? key}) + : super(const Icon(Icons.map), 'Camera control', key: key); + + @override + Widget build(BuildContext context) { + return const MoveCamera(); + } +} + +class MoveCamera extends StatefulWidget { + const MoveCamera({super.key}); + @override + State createState() => MoveCameraState(); +} + +class MoveCameraState extends State { + ExampleGoogleMapController? mapController; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + mapController = controller; + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(0.0, 0.0), + ), + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newCameraPosition( + const CameraPosition( + bearing: 270.0, + target: LatLng(51.5160895, -0.1294527), + tilt: 30.0, + zoom: 17.0, + ), + ), + ); + }, + child: const Text('newCameraPosition'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newLatLng( + const LatLng(56.1725505, 10.1850512), + ), + ); + }, + child: const Text('newLatLng'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newLatLngBounds( + LatLngBounds( + southwest: const LatLng(-38.483935, 113.248673), + northeast: const LatLng(-8.982446, 153.823821), + ), + 10.0, + ), + ); + }, + child: const Text('newLatLngBounds'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newLatLngZoom( + const LatLng(37.4231613, -122.087159), + 11.0, + ), + ); + }, + child: const Text('newLatLngZoom'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.scrollBy(150.0, -225.0), + ); + }, + child: const Text('scrollBy'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.zoomBy(-0.5, const Offset(30.0, 20.0)), + ); + }, + child: const Text('zoomBy with focus'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomBy(-0.5)); + }, + child: const Text('zoomBy'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomIn()); + }, + child: const Text('zoomIn'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomOut()); + }, + child: const Text('zoomOut'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomTo(16.0)); + }, + child: const Text('zoomTo'), + ), + ], + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/padding.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/padding.dart new file mode 100644 index 000000000000..beb39b305f58 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/padding.dart @@ -0,0 +1,169 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PaddingPage extends GoogleMapExampleAppPage { + const PaddingPage({Key? key}) + : super(const Icon(Icons.map), 'Add padding to the map', key: key); + + @override + Widget build(BuildContext context) { + return const MarkerIconsBody(); + } +} + +class MarkerIconsBody extends StatefulWidget { + const MarkerIconsBody({super.key}); + + @override + State createState() => MarkerIconsBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +class MarkerIconsBodyState extends State { + ExampleGoogleMapController? controller; + + EdgeInsets _padding = EdgeInsets.zero; + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + padding: _padding, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + const Padding( + padding: EdgeInsets.only(top: 20), + child: Center( + child: Text( + 'Enter Padding Below', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + ), + ]; + + columnChildren.addAll([_paddingInput(), _buttons()]); + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } + + final TextEditingController _topController = TextEditingController(); + final TextEditingController _bottomController = TextEditingController(); + final TextEditingController _leftController = TextEditingController(); + final TextEditingController _rightController = TextEditingController(); + + Widget _paddingInput() { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Flexible( + flex: 2, + child: TextField( + controller: _topController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Top'), + ), + ), + const Spacer(), + Flexible( + flex: 2, + child: TextField( + controller: _bottomController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Bottom'), + ), + ), + const Spacer(), + Flexible( + flex: 2, + child: TextField( + controller: _leftController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Left'), + ), + ), + const Spacer(), + Flexible( + flex: 2, + child: TextField( + controller: _rightController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Right'), + ), + ), + ], + ), + ); + } + + Widget _buttons() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + child: const Text('Set Padding'), + onPressed: () { + setState(() { + _padding = EdgeInsets.fromLTRB( + double.tryParse(_leftController.value.text) ?? 0, + double.tryParse(_topController.value.text) ?? 0, + double.tryParse(_rightController.value.text) ?? 0, + double.tryParse(_bottomController.value.text) ?? 0, + ); + }); + }, + ), + TextButton( + child: const Text('Reset Padding'), + onPressed: () { + setState(() { + _topController.clear(); + _bottomController.clear(); + _leftController.clear(); + _rightController.clear(); + _padding = EdgeInsets.zero; + }); + }, + ), + ], + ), + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/page.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/page.dart new file mode 100644 index 000000000000..2793b9d10edb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/page.dart @@ -0,0 +1,14 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; + +abstract class GoogleMapExampleAppPage extends StatelessWidget { + const GoogleMapExampleAppPage(this.leading, this.title, {super.key}); + + final Widget leading; + final String title; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_circle.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_circle.dart new file mode 100644 index 000000000000..88c84c79e124 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_circle.dart @@ -0,0 +1,227 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PlaceCirclePage extends GoogleMapExampleAppPage { + const PlaceCirclePage({Key? key}) + : super(const Icon(Icons.linear_scale), 'Place circle', key: key); + + @override + Widget build(BuildContext context) { + return const PlaceCircleBody(); + } +} + +class PlaceCircleBody extends StatefulWidget { + const PlaceCircleBody({super.key}); + + @override + State createState() => PlaceCircleBodyState(); +} + +class PlaceCircleBodyState extends State { + PlaceCircleBodyState(); + + ExampleGoogleMapController? controller; + Map circles = {}; + int _circleIdCounter = 1; + CircleId? selectedCircle; + + // Values when toggling circle color + int fillColorsIndex = 0; + int strokeColorsIndex = 0; + List colors = [ + Colors.purple, + Colors.red, + Colors.green, + Colors.pink, + ]; + + // Values when toggling circle stroke width + int widthsIndex = 0; + List widths = [10, 20, 5]; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onCircleTapped(CircleId circleId) { + setState(() { + selectedCircle = circleId; + }); + } + + void _remove(CircleId circleId) { + setState(() { + if (circles.containsKey(circleId)) { + circles.remove(circleId); + } + if (circleId == selectedCircle) { + selectedCircle = null; + } + }); + } + + void _add() { + final int circleCount = circles.length; + + if (circleCount == 12) { + return; + } + + final circleIdVal = 'circle_id_$_circleIdCounter'; + _circleIdCounter++; + final circleId = CircleId(circleIdVal); + + final circle = Circle( + circleId: circleId, + consumeTapEvents: true, + strokeColor: Colors.orange, + fillColor: Colors.green, + strokeWidth: 5, + center: _createCenter(), + radius: 50000, + onTap: () { + _onCircleTapped(circleId); + }, + ); + + setState(() { + circles[circleId] = circle; + }); + } + + void _toggleVisible(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith(visibleParam: !circle.visible); + }); + } + + void _changeFillColor(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith( + fillColorParam: colors[++fillColorsIndex % colors.length], + ); + }); + } + + void _changeStrokeColor(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith( + strokeColorParam: colors[++strokeColorsIndex % colors.length], + ); + }); + } + + void _changeStrokeWidth(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith( + strokeWidthParam: widths[++widthsIndex % widths.length], + ); + }); + } + + @override + Widget build(BuildContext context) { + final CircleId? selectedId = selectedCircle; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(52.4478, -3.5402), + zoom: 7.0, + ), + circles: Set.of(circles.values), + onMapCreated: _onMapCreated, + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + TextButton(onPressed: _add, child: const Text('add')), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), + child: const Text('remove'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeStrokeWidth(selectedId), + child: const Text('change stroke width'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeStrokeColor(selectedId), + child: const Text('change stroke color'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeFillColor(selectedId), + child: const Text('change fill color'), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ); + } + + LatLng _createCenter() { + final double offset = _circleIdCounter.ceilToDouble(); + return _createLatLng(51.4816 + offset * 0.2, -3.1791); + } + + LatLng _createLatLng(double lat, double lng) { + return LatLng(lat, lng); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_marker.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_marker.dart new file mode 100644 index 000000000000..926c2db2e426 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_marker.dart @@ -0,0 +1,417 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:async'; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'custom_marker_icon.dart'; +import 'example_google_map.dart'; +import 'page.dart'; + +class PlaceMarkerPage extends GoogleMapExampleAppPage { + const PlaceMarkerPage({Key? key}) + : super(const Icon(Icons.place), 'Place marker', key: key); + + @override + Widget build(BuildContext context) { + return const PlaceMarkerBody(); + } +} + +class PlaceMarkerBody extends StatefulWidget { + const PlaceMarkerBody({super.key}); + + @override + State createState() => PlaceMarkerBodyState(); +} + +typedef MarkerUpdateAction = Marker Function(Marker marker); + +class PlaceMarkerBodyState extends State { + PlaceMarkerBodyState(); + static const LatLng center = LatLng(-33.86711, 151.1947171); + + ExampleGoogleMapController? controller; + Map markers = {}; + MarkerId? selectedMarker; + int _markerIdCounter = 1; + LatLng? markerPosition; + // A helper text for Xcode UITests. + String _onDragXcodeUITestHelperText = ''; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onMarkerTapped(MarkerId markerId) { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + final MarkerId? previousMarkerId = selectedMarker; + if (previousMarkerId != null && markers.containsKey(previousMarkerId)) { + final Marker resetOld = markers[previousMarkerId]!.copyWith( + iconParam: BitmapDescriptor.defaultMarker, + ); + markers[previousMarkerId] = resetOld; + } + selectedMarker = markerId; + final Marker newMarker = tappedMarker.copyWith( + iconParam: BitmapDescriptor.defaultMarkerWithHue( + BitmapDescriptor.hueGreen, + ), + ); + markers[markerId] = newMarker; + + markerPosition = null; + }); + } + } + + Future _onMarkerDrag(MarkerId markerId, LatLng newPosition) async { + setState(() { + markerPosition = newPosition; + if (!_onDragXcodeUITestHelperText.contains('\n_onMarkerDrag called')) { + // _onMarkerDrag can be called multiple times during a single drag. + // Only log _onMarkerDrag once per dragging action to reduce noises in UI. + _onDragXcodeUITestHelperText += '\n_onMarkerDrag called'; + } + }); + } + + Future _onMarkerDragStart(MarkerId markerId, LatLng newPosition) async { + setState(() { + _onDragXcodeUITestHelperText += '\n_onMarkerDragStart'; + }); + } + + Future _onMarkerDragEnd(MarkerId markerId, LatLng newPosition) async { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + _onDragXcodeUITestHelperText += '\n_onMarkerDragEnd'; + markerPosition = null; + }); + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + actions: [ + TextButton( + child: const Text('OK'), + onPressed: () { + _onDragXcodeUITestHelperText = ''; + Navigator.of(context).pop(); + }, + ), + ], + content: Padding( + padding: const EdgeInsets.symmetric(vertical: 66), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('iOS delegate called: \n $_onDragXcodeUITestHelperText'), + Text('Old position: ${tappedMarker.position}'), + Text('New position: $newPosition'), + ], + ), + ), + ); + }, + ); + } + } + + void _add() { + final int markerCount = markers.length; + + if (markerCount == 12) { + return; + } + + final markerIdVal = 'marker_id_$_markerIdCounter'; + _markerIdCounter++; + final markerId = MarkerId(markerIdVal); + + final marker = Marker( + markerId: markerId, + position: LatLng( + center.latitude + sin(_markerIdCounter * pi / 6.0) / 20.0, + center.longitude + cos(_markerIdCounter * pi / 6.0) / 20.0, + ), + infoWindow: InfoWindow(title: markerIdVal, snippet: '*'), + onTap: () => _onMarkerTapped(markerId), + onDragStart: (LatLng position) => _onMarkerDragStart(markerId, position), + onDragEnd: (LatLng position) => _onMarkerDragEnd(markerId, position), + onDrag: (LatLng position) => _onMarkerDrag(markerId, position), + ); + + setState(() { + markers[markerId] = marker; + }); + } + + void _remove(MarkerId markerId) { + setState(() { + if (markers.containsKey(markerId)) { + markers.remove(markerId); + } + }); + } + + void _changePosition(MarkerId markerId) { + final Marker marker = markers[markerId]!; + final LatLng current = marker.position; + final offset = Offset( + center.latitude - current.latitude, + center.longitude - current.longitude, + ); + setState(() { + markers[markerId] = marker.copyWith( + positionParam: LatLng( + center.latitude + offset.dy, + center.longitude + offset.dx, + ), + ); + }); + } + + void _changeAnchor(MarkerId markerId) { + final Marker marker = markers[markerId]!; + final Offset currentAnchor = marker.anchor; + final newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); + setState(() { + markers[markerId] = marker.copyWith(anchorParam: newAnchor); + }); + } + + Future _changeInfoAnchor(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final Offset currentAnchor = marker.infoWindow.anchor; + final newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); + setState(() { + markers[markerId] = marker.copyWith( + infoWindowParam: marker.infoWindow.copyWith(anchorParam: newAnchor), + ); + }); + } + + Future _toggleDraggable(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(draggableParam: !marker.draggable); + }); + } + + Future _toggleFlat(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(flatParam: !marker.flat); + }); + } + + Future _changeInfo(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final newSnippet = '${marker.infoWindow.snippet!}*'; + setState(() { + markers[markerId] = marker.copyWith( + infoWindowParam: marker.infoWindow.copyWith(snippetParam: newSnippet), + ); + }); + } + + Future _changeAlpha(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final double current = marker.alpha; + setState(() { + markers[markerId] = marker.copyWith( + alphaParam: current < 0.1 ? 1.0 : current * 0.75, + ); + }); + } + + Future _changeRotation(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final double current = marker.rotation; + setState(() { + markers[markerId] = marker.copyWith( + rotationParam: current == 330.0 ? 0.0 : current + 30.0, + ); + }); + } + + Future _toggleVisible(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(visibleParam: !marker.visible); + }); + } + + Future _changeZIndex(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final int current = marker.zIndexInt; + setState(() { + markers[markerId] = marker.copyWith( + zIndexIntParam: current == 12 ? 0 : current + 1, + ); + }); + } + + void _setMarkerIcon(MarkerId markerId, BitmapDescriptor assetIcon) { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(iconParam: assetIcon); + }); + } + + Future _getMarkerIcon(BuildContext context) async { + const canvasSize = Size(48, 48); + final ByteData bytes = await createCustomMarkerIconImage(size: canvasSize); + return BytesMapBitmap(bytes.buffer.asUint8List()); + } + + @override + Widget build(BuildContext context) { + final MarkerId? selectedId = selectedMarker; + return Stack( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, + ), + markers: Set.of(markers.values), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton(onPressed: _add, child: const Text('Add')), + TextButton( + onPressed: selectedId == null + ? null + : () => _remove(selectedId), + child: const Text('Remove'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: selectedId == null + ? null + : () => _changeInfo(selectedId), + child: const Text('change info'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeInfoAnchor(selectedId), + child: const Text('change info anchor'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeAlpha(selectedId), + child: const Text('change alpha'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeAnchor(selectedId), + child: const Text('change anchor'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _toggleDraggable(selectedId), + child: const Text('toggle draggable'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _toggleFlat(selectedId), + child: const Text('toggle flat'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changePosition(selectedId), + child: const Text('change position'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeRotation(selectedId), + child: const Text('change rotation'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeZIndex(selectedId), + child: const Text('change zIndex'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () { + _getMarkerIcon(context).then((BitmapDescriptor icon) { + _setMarkerIcon(selectedId, icon); + }); + }, + child: const Text('set marker icon'), + ), + ], + ), + ], + ), + Visibility( + visible: markerPosition != null, + child: Container( + color: Colors.white70, + height: 30, + padding: const EdgeInsets.only(left: 12, right: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + if (markerPosition == null) + Container() + else + Expanded(child: Text('lat: ${markerPosition!.latitude}')), + if (markerPosition == null) + Container() + else + Expanded(child: Text('lng: ${markerPosition!.longitude}')), + ], + ), + ), + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_polygon.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_polygon.dart new file mode 100644 index 000000000000..ff9eac82210c --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_polygon.dart @@ -0,0 +1,298 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PlacePolygonPage extends GoogleMapExampleAppPage { + const PlacePolygonPage({Key? key}) + : super(const Icon(Icons.linear_scale), 'Place polygon', key: key); + + @override + Widget build(BuildContext context) { + return const PlacePolygonBody(); + } +} + +class PlacePolygonBody extends StatefulWidget { + const PlacePolygonBody({super.key}); + + @override + State createState() => PlacePolygonBodyState(); +} + +class PlacePolygonBodyState extends State { + PlacePolygonBodyState(); + + ExampleGoogleMapController? controller; + Map polygons = {}; + Map polygonOffsets = {}; + int _polygonIdCounter = 0; + PolygonId? selectedPolygon; + + // Values when toggling polygon color + int strokeColorsIndex = 0; + int fillColorsIndex = 0; + List colors = [ + Colors.purple, + Colors.red, + Colors.green, + Colors.pink, + ]; + + // Values when toggling polygon width + int widthsIndex = 0; + List widths = [10, 20, 5]; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onPolygonTapped(PolygonId polygonId) { + setState(() { + selectedPolygon = polygonId; + }); + } + + void _remove(PolygonId polygonId) { + setState(() { + if (polygons.containsKey(polygonId)) { + polygons.remove(polygonId); + } + selectedPolygon = null; + }); + } + + void _add() { + final int polygonCount = polygons.length; + + if (polygonCount == 12) { + return; + } + + final polygonIdVal = 'polygon_id_$_polygonIdCounter'; + final polygonId = PolygonId(polygonIdVal); + + final polygon = Polygon( + polygonId: polygonId, + consumeTapEvents: true, + strokeColor: Colors.orange, + strokeWidth: 5, + fillColor: Colors.green, + points: _createPoints(), + onTap: () { + _onPolygonTapped(polygonId); + }, + ); + + setState(() { + polygons[polygonId] = polygon; + polygonOffsets[polygonId] = _polygonIdCounter.ceilToDouble(); + // increment _polygonIdCounter to have unique polygon id each time + _polygonIdCounter++; + }); + } + + void _toggleGeodesic(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith(geodesicParam: !polygon.geodesic); + }); + } + + void _toggleVisible(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith(visibleParam: !polygon.visible); + }); + } + + void _changeStrokeColor(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + strokeColorParam: colors[++strokeColorsIndex % colors.length], + ); + }); + } + + void _changeFillColor(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + fillColorParam: colors[++fillColorsIndex % colors.length], + ); + }); + } + + void _changeWidth(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + strokeWidthParam: widths[++widthsIndex % widths.length], + ); + }); + } + + void _addHoles(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + holesParam: _createHoles(polygonId), + ); + }); + } + + void _removeHoles(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith(holesParam: >[]); + }); + } + + @override + Widget build(BuildContext context) { + final PolygonId? selectedId = selectedPolygon; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(52.4478, -3.5402), + zoom: 7.0, + ), + polygons: Set.of(polygons.values), + onMapCreated: _onMapCreated, + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + TextButton(onPressed: _add, child: const Text('add')), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), + child: const Text('remove'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleGeodesic(selectedId), + child: const Text('toggle geodesic'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: (selectedId == null) + ? null + : (polygons[selectedId]!.holes.isNotEmpty + ? null + : () => _addHoles(selectedId)), + child: const Text('add holes'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : (polygons[selectedId]!.holes.isEmpty + ? null + : () => _removeHoles(selectedId)), + child: const Text('remove holes'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeWidth(selectedId), + child: const Text('change stroke width'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeStrokeColor(selectedId), + child: const Text('change stroke color'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeFillColor(selectedId), + child: const Text('change fill color'), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ); + } + + List _createPoints() { + final points = []; + final double offset = _polygonIdCounter.ceilToDouble(); + points.add(_createLatLng(51.2395 + offset, -3.4314)); + points.add(_createLatLng(53.5234 + offset, -3.5314)); + points.add(_createLatLng(52.4351 + offset, -4.5235)); + points.add(_createLatLng(52.1231 + offset, -5.0829)); + return points; + } + + List> _createHoles(PolygonId polygonId) { + final holes = >[]; + final double offset = polygonOffsets[polygonId]!; + + final hole1 = []; + hole1.add(_createLatLng(51.8395 + offset, -3.8814)); + hole1.add(_createLatLng(52.0234 + offset, -3.9914)); + hole1.add(_createLatLng(52.1351 + offset, -4.4435)); + hole1.add(_createLatLng(52.0231 + offset, -4.5829)); + holes.add(hole1); + + final hole2 = []; + hole2.add(_createLatLng(52.2395 + offset, -3.6814)); + hole2.add(_createLatLng(52.4234 + offset, -3.7914)); + hole2.add(_createLatLng(52.5351 + offset, -4.2435)); + hole2.add(_createLatLng(52.4231 + offset, -4.3829)); + holes.add(hole2); + + return holes; + } + + LatLng _createLatLng(double lat, double lng) { + return LatLng(lat, lng); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_polyline.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_polyline.dart new file mode 100644 index 000000000000..f749cac5f268 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/place_polyline.dart @@ -0,0 +1,322 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PlacePolylinePage extends GoogleMapExampleAppPage { + const PlacePolylinePage({Key? key}) + : super(const Icon(Icons.linear_scale), 'Place polyline', key: key); + + @override + Widget build(BuildContext context) { + return const PlacePolylineBody(); + } +} + +class PlacePolylineBody extends StatefulWidget { + const PlacePolylineBody({super.key}); + + @override + State createState() => PlacePolylineBodyState(); +} + +class PlacePolylineBodyState extends State { + PlacePolylineBodyState(); + + ExampleGoogleMapController? controller; + Map polylines = {}; + int _polylineIdCounter = 0; + PolylineId? selectedPolyline; + + // Values when toggling polyline color + int colorsIndex = 0; + List colors = [ + Colors.purple, + Colors.red, + Colors.green, + Colors.pink, + ]; + + // Values when toggling polyline width + int widthsIndex = 0; + List widths = [10, 20, 5]; + + int jointTypesIndex = 0; + List jointTypes = [ + JointType.mitered, + JointType.bevel, + JointType.round, + ]; + + // Values when toggling polyline end cap type + int endCapsIndex = 0; + List endCaps = [Cap.buttCap, Cap.squareCap, Cap.roundCap]; + + // Values when toggling polyline start cap type + int startCapsIndex = 0; + List startCaps = [Cap.buttCap, Cap.squareCap, Cap.roundCap]; + + // Values when toggling polyline pattern + int patternsIndex = 0; + List> patterns = >[ + [], + [ + PatternItem.dash(30.0), + PatternItem.gap(20.0), + PatternItem.dot, + PatternItem.gap(20.0), + ], + [PatternItem.dash(30.0), PatternItem.gap(20.0)], + [PatternItem.dot, PatternItem.gap(10.0)], + ]; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onPolylineTapped(PolylineId polylineId) { + setState(() { + selectedPolyline = polylineId; + }); + } + + void _remove(PolylineId polylineId) { + setState(() { + if (polylines.containsKey(polylineId)) { + polylines.remove(polylineId); + } + selectedPolyline = null; + }); + } + + void _add() { + final int polylineCount = polylines.length; + + if (polylineCount == 12) { + return; + } + + final polylineIdVal = 'polyline_id_$_polylineIdCounter'; + _polylineIdCounter++; + final polylineId = PolylineId(polylineIdVal); + + final polyline = Polyline( + polylineId: polylineId, + consumeTapEvents: true, + color: Colors.orange, + width: 5, + points: _createPoints(), + onTap: () { + _onPolylineTapped(polylineId); + }, + ); + + setState(() { + polylines[polylineId] = polyline; + }); + } + + void _toggleGeodesic(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + geodesicParam: !polyline.geodesic, + ); + }); + } + + void _toggleVisible(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + visibleParam: !polyline.visible, + ); + }); + } + + void _changeColor(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + colorParam: colors[++colorsIndex % colors.length], + ); + }); + } + + void _changeWidth(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + widthParam: widths[++widthsIndex % widths.length], + ); + }); + } + + void _changeJointType(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + jointTypeParam: jointTypes[++jointTypesIndex % jointTypes.length], + ); + }); + } + + void _changeEndCap(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + endCapParam: endCaps[++endCapsIndex % endCaps.length], + ); + }); + } + + void _changeStartCap(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + startCapParam: startCaps[++startCapsIndex % startCaps.length], + ); + }); + } + + void _changePattern(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + patternsParam: patterns[++patternsIndex % patterns.length], + ); + }); + } + + @override + Widget build(BuildContext context) { + final bool isIOS = !kIsWeb && defaultTargetPlatform == TargetPlatform.iOS; + + final PolylineId? selectedId = selectedPolyline; + + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(53.1721, -3.5402), + zoom: 7.0, + ), + polylines: Set.of(polylines.values), + onMapCreated: _onMapCreated, + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + TextButton(onPressed: _add, child: const Text('add')), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), + child: const Text('remove'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleGeodesic(selectedId), + child: const Text('toggle geodesic'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeWidth(selectedId), + child: const Text('change width'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeColor(selectedId), + child: const Text('change color'), + ), + TextButton( + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeStartCap(selectedId), + child: const Text('change start cap [Android only]'), + ), + TextButton( + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeEndCap(selectedId), + child: const Text('change end cap [Android only]'), + ), + TextButton( + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeJointType(selectedId), + child: const Text('change joint type [Android only]'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changePattern(selectedId), + child: const Text('change pattern'), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ); + } + + List _createPoints() { + final points = []; + final double offset = _polylineIdCounter.ceilToDouble(); + points.add(_createLatLng(51.4816 + offset, -3.1791)); + points.add(_createLatLng(53.0430 + offset, -2.9925)); + points.add(_createLatLng(53.1396 + offset, -4.2739)); + points.add(_createLatLng(52.4153 + offset, -4.0829)); + return points; + } + + LatLng _createLatLng(double lat, double lng) { + return LatLng(lat, lng); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/scrolling_map.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/scrolling_map.dart new file mode 100644 index 000000000000..57d8cd6d9ff4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/scrolling_map.dart @@ -0,0 +1,112 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const LatLng _center = LatLng(32.080664, 34.9563837); + +class ScrollingMapPage extends GoogleMapExampleAppPage { + const ScrollingMapPage({Key? key}) + : super(const Icon(Icons.map), 'Scrolling map', key: key); + + @override + Widget build(BuildContext context) { + return const ScrollingMapBody(); + } +} + +class ScrollingMapBody extends StatelessWidget { + const ScrollingMapBody({super.key}); + + @override + Widget build(BuildContext context) { + return ListView( + children: [ + Card( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 30.0), + child: Column( + children: [ + const Padding( + padding: EdgeInsets.only(bottom: 12.0), + child: Text('This map consumes all touch events.'), + ), + Center( + child: SizedBox( + width: 300.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: _center, + zoom: 11.0, + ), + gestureRecognizers: // + >{ + Factory( + () => EagerGestureRecognizer(), + ), + }, + ), + ), + ), + ], + ), + ), + ), + Card( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 30.0), + child: Column( + children: [ + const Text("This map doesn't consume the vertical drags."), + const Padding( + padding: EdgeInsets.only(bottom: 12.0), + child: Text( + 'It still gets other gestures (e.g scale or tap).', + ), + ), + Center( + child: SizedBox( + width: 300.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: _center, + zoom: 11.0, + ), + markers: { + Marker( + markerId: const MarkerId('test_marker_id'), + position: LatLng(_center.latitude, _center.longitude), + infoWindow: const InfoWindow( + title: 'An interesting location', + snippet: '*', + ), + ), + }, + gestureRecognizers: + >{ + Factory( + () => ScaleGestureRecognizer(), + ), + }, + ), + ), + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/snapshot.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/snapshot.dart new file mode 100644 index 000000000000..8fa4d67b6422 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/snapshot.dart @@ -0,0 +1,81 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class SnapshotPage extends GoogleMapExampleAppPage { + const SnapshotPage({Key? key}) + : super( + const Icon(Icons.camera_alt), + 'Take a snapshot of the map', + key: key, + ); + + @override + Widget build(BuildContext context) { + return _SnapshotBody(); + } +} + +class _SnapshotBody extends StatefulWidget { + @override + _SnapshotBodyState createState() => _SnapshotBodyState(); +} + +class _SnapshotBodyState extends State<_SnapshotBody> { + ExampleGoogleMapController? _mapController; + Uint8List? _imageBytes; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox( + height: 180, + child: ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + ), + ), + TextButton( + child: const Text('Take a snapshot'), + onPressed: () async { + final Uint8List? imageBytes = await _mapController + ?.takeSnapshot(); + setState(() { + _imageBytes = imageBytes; + }); + }, + ), + Container( + decoration: BoxDecoration(color: Colors.blueGrey[50]), + height: 180, + child: _imageBytes != null ? Image.memory(_imageBytes!) : null, + ), + ], + ), + ); + } + + // ignore: use_setters_to_change_properties + void onMapCreated(ExampleGoogleMapController controller) { + _mapController = controller; + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/tile_overlay.dart new file mode 100644 index 000000000000..bcce3b5f387b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/lib/tile_overlay.dart @@ -0,0 +1,147 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class TileOverlayPage extends GoogleMapExampleAppPage { + const TileOverlayPage({Key? key}) + : super(const Icon(Icons.map), 'Tile overlay', key: key); + + @override + Widget build(BuildContext context) { + return const TileOverlayBody(); + } +} + +class TileOverlayBody extends StatefulWidget { + const TileOverlayBody({super.key}); + + @override + State createState() => TileOverlayBodyState(); +} + +class TileOverlayBodyState extends State { + TileOverlayBodyState(); + + ExampleGoogleMapController? controller; + TileOverlay? _tileOverlay; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _removeTileOverlay() { + setState(() { + _tileOverlay = null; + }); + } + + void _addTileOverlay() { + final tileOverlay = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + ); + setState(() { + _tileOverlay = tileOverlay; + }); + } + + void _clearTileCache() { + if (_tileOverlay != null && controller != null) { + controller!.clearTileCache(_tileOverlay!.tileOverlayId); + } + } + + @override + Widget build(BuildContext context) { + final overlays = {if (_tileOverlay != null) _tileOverlay!}; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(59.935460, 30.325177), + zoom: 7.0, + ), + tileOverlays: overlays, + onMapCreated: _onMapCreated, + ), + ), + ), + TextButton( + onPressed: _addTileOverlay, + child: const Text('Add tile overlay'), + ), + TextButton( + onPressed: _removeTileOverlay, + child: const Text('Remove tile overlay'), + ), + TextButton( + onPressed: _clearTileCache, + child: const Text('Clear tile cache'), + ), + ], + ); + } +} + +class _DebugTileProvider implements TileProvider { + _DebugTileProvider() { + boxPaint.isAntiAlias = true; + boxPaint.color = Colors.blue; + boxPaint.strokeWidth = 2.0; + boxPaint.style = PaintingStyle.stroke; + } + + static const int width = 100; + static const int height = 100; + static final Paint boxPaint = Paint(); + static const TextStyle textStyle = TextStyle(color: Colors.red, fontSize: 20); + + @override + Future getTile(int x, int y, int? zoom) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final textSpan = TextSpan(text: '$x,$y', style: textStyle); + final textPainter = TextPainter( + text: textSpan, + textDirection: TextDirection.ltr, + ); + textPainter.layout(maxWidth: width.toDouble()); + textPainter.paint(canvas, Offset.zero); + canvas.drawRect( + Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), + boxPaint, + ); + final ui.Picture picture = recorder.endRecording(); + final Uint8List byteData = await picture + .toImage(width, height) + .then( + (ui.Image image) => image.toByteData(format: ui.ImageByteFormat.png), + ) + .then((ByteData? byteData) => byteData!.buffer.asUint8List()); + return Tile(width, height, byteData); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/example_google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/example_google_map_test.dart new file mode 100644 index 000000000000..261fc473e8bb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/example_google_map_test.dart @@ -0,0 +1,176 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_example/example_google_map.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'fake_google_maps_flutter_platform.dart'; + +Widget _mapWithObjects({ + Set circles = const {}, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set tileOverlays = const {}, +}) { + return Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + circles: circles, + markers: markers, + polygons: polygons, + polylines: polylines, + tileOverlays: tileOverlays, + ), + ); +} + +void main() { + late FakeGoogleMapsFlutterPlatform platform; + + setUp(() { + platform = FakeGoogleMapsFlutterPlatform(); + GoogleMapsFlutterPlatform.instance = platform; + }); + + testWidgets('circle updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const c1 = Circle(circleId: CircleId('circle_1')); + const c2 = Circle(circleId: CircleId('circle_2')); + const c3 = Circle(circleId: CircleId('circle_3'), radius: 1); + const c3updated = Circle(circleId: CircleId('circle_3'), radius: 10); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(circles: {c1, c2})); + await tester.pumpWidget(_mapWithObjects(circles: {c1, c3})); + await tester.pumpWidget(_mapWithObjects(circles: {c1, c3updated})); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.circleUpdates.length, 3); + + expect(map.circleUpdates[0].circlesToChange.isEmpty, true); + expect(map.circleUpdates[0].circlesToAdd, {c1, c2}); + expect(map.circleUpdates[0].circleIdsToRemove.isEmpty, true); + + expect(map.circleUpdates[1].circlesToChange.isEmpty, true); + expect(map.circleUpdates[1].circlesToAdd, {c3}); + expect(map.circleUpdates[1].circleIdsToRemove, {c2.circleId}); + + expect(map.circleUpdates[2].circlesToChange, {c3updated}); + expect(map.circleUpdates[2].circlesToAdd.isEmpty, true); + expect(map.circleUpdates[2].circleIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); + + testWidgets('marker updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const m1 = Marker(markerId: MarkerId('marker_1')); + const m2 = Marker(markerId: MarkerId('marker_2')); + const m3 = Marker(markerId: MarkerId('marker_3')); + const m3updated = Marker(markerId: MarkerId('marker_3'), draggable: true); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(markers: {m1, m2})); + await tester.pumpWidget(_mapWithObjects(markers: {m1, m3})); + await tester.pumpWidget(_mapWithObjects(markers: {m1, m3updated})); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.markerUpdates.length, 3); + + expect(map.markerUpdates[0].markersToChange.isEmpty, true); + expect(map.markerUpdates[0].markersToAdd, {m1, m2}); + expect(map.markerUpdates[0].markerIdsToRemove.isEmpty, true); + + expect(map.markerUpdates[1].markersToChange.isEmpty, true); + expect(map.markerUpdates[1].markersToAdd, {m3}); + expect(map.markerUpdates[1].markerIdsToRemove, {m2.markerId}); + + expect(map.markerUpdates[2].markersToChange, {m3updated}); + expect(map.markerUpdates[2].markersToAdd.isEmpty, true); + expect(map.markerUpdates[2].markerIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); + + testWidgets('polygon updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const p1 = Polygon(polygonId: PolygonId('polygon_1')); + const p2 = Polygon(polygonId: PolygonId('polygon_2')); + const p3 = Polygon(polygonId: PolygonId('polygon_3'), strokeWidth: 1); + const p3updated = Polygon( + polygonId: PolygonId('polygon_3'), + strokeWidth: 2, + ); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(polygons: {p1, p2})); + await tester.pumpWidget(_mapWithObjects(polygons: {p1, p3})); + await tester.pumpWidget( + _mapWithObjects(polygons: {p1, p3updated}), + ); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.polygonUpdates.length, 3); + + expect(map.polygonUpdates[0].polygonsToChange.isEmpty, true); + expect(map.polygonUpdates[0].polygonsToAdd, {p1, p2}); + expect(map.polygonUpdates[0].polygonIdsToRemove.isEmpty, true); + + expect(map.polygonUpdates[1].polygonsToChange.isEmpty, true); + expect(map.polygonUpdates[1].polygonsToAdd, {p3}); + expect(map.polygonUpdates[1].polygonIdsToRemove, {p2.polygonId}); + + expect(map.polygonUpdates[2].polygonsToChange, {p3updated}); + expect(map.polygonUpdates[2].polygonsToAdd.isEmpty, true); + expect(map.polygonUpdates[2].polygonIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); + + testWidgets('polyline updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const p1 = Polyline(polylineId: PolylineId('polyline_1')); + const p2 = Polyline(polylineId: PolylineId('polyline_2')); + const p3 = Polyline(polylineId: PolylineId('polyline_3'), width: 1); + const p3updated = Polyline(polylineId: PolylineId('polyline_3'), width: 2); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(polylines: {p1, p2})); + await tester.pumpWidget(_mapWithObjects(polylines: {p1, p3})); + await tester.pumpWidget( + _mapWithObjects(polylines: {p1, p3updated}), + ); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.polylineUpdates.length, 3); + + expect(map.polylineUpdates[0].polylinesToChange.isEmpty, true); + expect(map.polylineUpdates[0].polylinesToAdd, {p1, p2}); + expect(map.polylineUpdates[0].polylineIdsToRemove.isEmpty, true); + + expect(map.polylineUpdates[1].polylinesToChange.isEmpty, true); + expect(map.polylineUpdates[1].polylinesToAdd, {p3}); + expect(map.polylineUpdates[1].polylineIdsToRemove, { + p2.polylineId, + }); + + expect(map.polylineUpdates[2].polylinesToChange, {p3updated}); + expect(map.polylineUpdates[2].polylinesToAdd.isEmpty, true); + expect(map.polylineUpdates[2].polylineIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); +} 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 new file mode 100644 index 000000000000..899a7709c548 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test/fake_google_maps_flutter_platform.dart @@ -0,0 +1,350 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:stream_transform/stream_transform.dart'; + +// A dummy implementation of the platform interface for tests. +class FakeGoogleMapsFlutterPlatform extends GoogleMapsFlutterPlatform { + FakeGoogleMapsFlutterPlatform(); + + /// The IDs passed to each call to buildView, in call order. + List createdIds = []; + + /// A map of creation IDs to fake map instances. + Map mapInstances = + {}; + + PlatformMapStateRecorder get lastCreatedMap => mapInstances[createdIds.last]!; + + /// Whether to add a small delay to async calls to simulate more realistic + /// async behavior (simulating the platform channel calls most + /// implementations will do). + /// + /// When true, requires tests to `pumpAndSettle` at the end of the test + /// to avoid exceptions. + bool simulatePlatformDelay = false; + + /// Whether `dispose` has been called. + bool disposed = false; + + /// Stream controller to inject events for testing. + final StreamController> mapEventStreamController = + StreamController>.broadcast(); + + @override + Future init(int mapId) async {} + + @override + Future updateMapConfiguration( + MapConfiguration update, { + required int mapId, + }) async { + mapInstances[mapId]?.mapConfiguration = update; + await _fakeDelay(); + } + + @override + Future updateMarkers( + MarkerUpdates markerUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.markerUpdates.add(markerUpdates); + await _fakeDelay(); + } + + @override + Future updatePolygons( + PolygonUpdates polygonUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.polygonUpdates.add(polygonUpdates); + await _fakeDelay(); + } + + @override + Future updatePolylines( + PolylineUpdates polylineUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.polylineUpdates.add(polylineUpdates); + await _fakeDelay(); + } + + @override + Future updateCircles( + CircleUpdates circleUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.circleUpdates.add(circleUpdates); + await _fakeDelay(); + } + + @override + Future updateTileOverlays({ + required Set newTileOverlays, + required int mapId, + }) async { + mapInstances[mapId]?.tileOverlaySets.add(newTileOverlays); + await _fakeDelay(); + } + + @override + Future updateClusterManagers( + ClusterManagerUpdates clusterManagerUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.clusterManagerUpdates.add(clusterManagerUpdates); + await _fakeDelay(); + } + + @override + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.groundOverlayUpdates.add(groundOverlayUpdates); + await _fakeDelay(); + } + + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + required int mapId, + }) async {} + + @override + Future animateCamera( + CameraUpdate cameraUpdate, { + required int mapId, + }) async {} + + @override + Future animateCameraWithConfiguration( + CameraUpdate cameraUpdate, + CameraUpdateAnimationConfiguration configuration, { + required int mapId, + }) async {} + + @override + Future moveCamera( + CameraUpdate cameraUpdate, { + required int mapId, + }) async {} + + @override + Future setMapStyle(String? mapStyle, {required int mapId}) async {} + + @override + Future getVisibleRegion({required int mapId}) async { + return LatLngBounds( + southwest: const LatLng(0, 0), + northeast: const LatLng(0, 0), + ); + } + + @override + Future getScreenCoordinate( + LatLng latLng, { + required int mapId, + }) async { + return const ScreenCoordinate(x: 0, y: 0); + } + + @override + Future getLatLng( + ScreenCoordinate screenCoordinate, { + required int mapId, + }) async { + return const LatLng(0, 0); + } + + @override + Future showMarkerInfoWindow( + MarkerId markerId, { + required int mapId, + }) async {} + + @override + Future hideMarkerInfoWindow( + MarkerId markerId, { + required int mapId, + }) async {} + + @override + Future isMarkerInfoWindowShown( + MarkerId markerId, { + required int mapId, + }) async { + return false; + } + + @override + Future getZoomLevel({required int mapId}) async { + return 0.0; + } + + @override + Future takeSnapshot({required int mapId}) async { + return null; + } + + @override + Stream onCameraMoveStarted({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCameraMove({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCameraIdle({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onInfoWindowTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDragStart({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDrag({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDragEnd({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onPolylineTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onPolygonTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCircleTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onLongPress({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onClusterTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onGroundOverlayTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + void dispose({required int mapId}) { + disposed = true; + } + + @override + Widget buildViewWithConfiguration( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required MapWidgetConfiguration widgetConfiguration, + MapObjects mapObjects = const MapObjects(), + MapConfiguration mapConfiguration = const MapConfiguration(), + }) { + final PlatformMapStateRecorder? instance = mapInstances[creationId]; + if (instance == null) { + createdIds.add(creationId); + mapInstances[creationId] = PlatformMapStateRecorder( + widgetConfiguration: widgetConfiguration, + mapConfiguration: mapConfiguration, + mapObjects: mapObjects, + ); + onPlatformViewCreated(creationId); + } + return Container(); + } + + Future _fakeDelay() async { + if (!simulatePlatformDelay) { + return; + } + return Future.delayed(const Duration(microseconds: 1)); + } +} + +/// A fake implementation of a native map, which stores all the updates it is +/// sent for inspection in tests. +class PlatformMapStateRecorder { + PlatformMapStateRecorder({ + required this.widgetConfiguration, + this.mapObjects = const MapObjects(), + this.mapConfiguration = const MapConfiguration(), + }) { + clusterManagerUpdates.add( + ClusterManagerUpdates.from( + const {}, + mapObjects.clusterManagers, + ), + ); + groundOverlayUpdates.add( + GroundOverlayUpdates.from( + const {}, + mapObjects.groundOverlays, + ), + ); + markerUpdates.add(MarkerUpdates.from(const {}, mapObjects.markers)); + polygonUpdates.add( + PolygonUpdates.from(const {}, mapObjects.polygons), + ); + polylineUpdates.add( + PolylineUpdates.from(const {}, mapObjects.polylines), + ); + circleUpdates.add(CircleUpdates.from(const {}, mapObjects.circles)); + tileOverlaySets.add(mapObjects.tileOverlays); + } + + MapWidgetConfiguration widgetConfiguration; + MapObjects mapObjects; + MapConfiguration mapConfiguration; + + final List markerUpdates = []; + final List polygonUpdates = []; + final List polylineUpdates = []; + final List circleUpdates = []; + final List> tileOverlaySets = >[]; + final List clusterManagerUpdates = + []; + final List groundOverlayUpdates = + []; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test_driver/integration_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test_driver/integration_test.dart new file mode 100644 index 000000000000..fb3dec00bee9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/test_driver/integration_test.dart @@ -0,0 +1,7 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMCATransactionWrapper.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMCATransactionWrapper.m new file mode 100644 index 000000000000..5fb79de8b17a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMCATransactionWrapper.m @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMCATransactionWrapper.h" + +@import QuartzCore; + +@implementation FGMCATransactionWrapper + +- (void)begin { + [CATransaction begin]; +} + +- (void)commit { + [CATransaction commit]; +} + +- (void)setAnimationDuration:(CFTimeInterval)duration { + [CATransaction setAnimationDuration:duration]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMClusterManagersController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMClusterManagersController.m new file mode 100644 index 000000000000..04c3f04c9285 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMClusterManagersController.m @@ -0,0 +1,128 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMClusterManagersController.h" + +#import "FGMConversionUtils.h" +#import "FGMMarkerUserData.h" + +@interface FGMClusterManagersController () + +/// A dictionary mapping unique cluster manager identifiers to their corresponding cluster managers. +@property(strong, nonatomic) + NSMutableDictionary *clusterManagerIdentifierToManagers; + +/// The callback handler interface for calls to Flutter. +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; + +/// The current map instance on which the cluster managers are operating. +@property(strong, nonatomic) GMSMapView *mapView; + +@end + +@implementation FGMClusterManagersController +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _clusterManagerIdentifierToManagers = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)addClusterManagers:(NSArray *)clusterManagersToAdd { + for (FGMPlatformClusterManager *clusterManager in clusterManagersToAdd) { + NSString *identifier = clusterManager.identifier; + [self addClusterManager:identifier]; + } +} + +- (void)addClusterManager:(NSString *)identifier { + id algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init]; + id iconGenerator = [[GMUDefaultClusterIconGenerator alloc] init]; + id renderer = + [[GMUDefaultClusterRenderer alloc] initWithMapView:self.mapView + clusterIconGenerator:iconGenerator]; + self.clusterManagerIdentifierToManagers[identifier] = + [[GMUClusterManager alloc] initWithMap:self.mapView algorithm:algorithm renderer:renderer]; + ; +} + +- (void)removeClusterManagersWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + GMUClusterManager *clusterManager = + [self.clusterManagerIdentifierToManagers objectForKey:identifier]; + if (!clusterManager) { + continue; + } + [clusterManager clearItems]; + [self.clusterManagerIdentifierToManagers removeObjectForKey:identifier]; + } +} + +- (nullable GMUClusterManager *)clusterManagerWithIdentifier:(NSString *)identifier { + return [self.clusterManagerIdentifierToManagers objectForKey:identifier]; +} + +- (void)invokeClusteringForEachClusterManager { + for (GMUClusterManager *clusterManager in [self.clusterManagerIdentifierToManagers allValues]) { + [clusterManager cluster]; + } +} + +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMUClusterManager *clusterManager = + [self.clusterManagerIdentifierToManagers objectForKey:identifier]; + + if (!clusterManager) { + *error = [FlutterError + errorWithCode:@"Invalid clusterManagerId" + message:@"getClusters called with invalid clusterManagerId" + details:[NSString stringWithFormat:@"clusterManagerId was: '%@'", identifier]]; + return nil; + } + + // Ref: + // https://github.com/googlemaps/google-maps-ios-utils/blob/0e7ed81f1bbd9d29e4529c40ae39b0791b0a0eb8/src/Clustering/GMUClusterManager.m#L94. + NSUInteger integralZoom = (NSUInteger)floorf(_mapView.camera.zoom + 0.5f); + NSArray> *clusters = [clusterManager.algorithm clustersAtZoom:integralZoom]; + NSMutableArray *response = + [[NSMutableArray alloc] initWithCapacity:clusters.count]; + for (id cluster in clusters) { + FGMPlatformCluster *platFormCluster = FGMGetPigeonCluster(cluster, identifier); + [response addObject:platFormCluster]; + } + return response; +} + +- (void)didTapCluster:(GMUStaticCluster *)cluster { + NSString *clusterManagerId = [self clusterManagerIdentifierForCluster:cluster]; + if (!clusterManagerId) { + return; + } + FGMPlatformCluster *platFormCluster = FGMGetPigeonCluster(cluster, clusterManagerId); + [self.callbackHandler didTapCluster:platFormCluster + completion:^(FlutterError *_Nullable _){ + }]; +} + +#pragma mark - Private methods + +/// Returns the cluster manager identifier for given cluster. +/// +/// @return The cluster manager identifier if found; otherwise, nil. +- (nullable NSString *)clusterManagerIdentifierForCluster:(GMUStaticCluster *)cluster { + if ([cluster.items.firstObject isKindOfClass:[GMSMarker class]]) { + GMSMarker *firstMarker = (GMSMarker *)cluster.items.firstObject; + return FGMGetClusterManagerIdentifierFromMarker(firstMarker); + } + + return nil; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMConversionUtils.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMConversionUtils.m new file mode 100644 index 000000000000..876ec0d1e4aa --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMConversionUtils.m @@ -0,0 +1,288 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMConversionUtils.h" + +#import "FGMMarkerUserData.h" + +/// Returns dict[key], or nil if dict[key] is NSNull. +id FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key) { + id value = dict[key]; + return value == [NSNull null] ? nil : value; +} + +CGPoint FGMGetCGPointForPigeonPoint(FGMPlatformPoint *point) { + return CGPointMake(point.x, point.y); +} + +FGMPlatformPoint *FGMGetPigeonPointForCGPoint(CGPoint point) { + return [FGMPlatformPoint makeWithX:point.x y:point.y]; +} + +CLLocationCoordinate2D FGMGetCoordinateForPigeonLatLng(FGMPlatformLatLng *latLng) { + return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude); +} + +FGMPlatformLatLng *FGMGetPigeonLatLngForCoordinate(CLLocationCoordinate2D coord) { + return [FGMPlatformLatLng makeWithLatitude:coord.latitude longitude:coord.longitude]; +} + +GMSCoordinateBounds *FGMGetCoordinateBoundsForPigeonLatLngBounds(FGMPlatformLatLngBounds *bounds) { + return [[GMSCoordinateBounds alloc] + initWithCoordinate:FGMGetCoordinateForPigeonLatLng(bounds.northeast) + coordinate:FGMGetCoordinateForPigeonLatLng(bounds.southwest)]; +} + +FGMPlatformLatLngBounds *FGMGetPigeonLatLngBoundsForCoordinateBounds(GMSCoordinateBounds *bounds) { + return + [FGMPlatformLatLngBounds makeWithNortheast:FGMGetPigeonLatLngForCoordinate(bounds.northEast) + southwest:FGMGetPigeonLatLngForCoordinate(bounds.southWest)]; +} + +FGMPlatformCameraPosition *FGMGetPigeonCameraPositionForPosition(GMSCameraPosition *position) { + return [FGMPlatformCameraPosition makeWithBearing:position.bearing + target:FGMGetPigeonLatLngForCoordinate(position.target) + tilt:position.viewingAngle + zoom:position.zoom]; +} + +GMSCameraPosition *FGMGetCameraPositionForPigeonCameraPosition( + FGMPlatformCameraPosition *position) { + return [GMSCameraPosition cameraWithTarget:FGMGetCoordinateForPigeonLatLng(position.target) + zoom:position.zoom + bearing:position.bearing + viewingAngle:position.tilt]; +} + +NSArray *FGMGetPointsForPigeonLatLngs(NSArray *pigeonPoints) { + NSMutableArray *points = [[NSMutableArray alloc] initWithCapacity:pigeonPoints.count]; + for (FGMPlatformLatLng *point in pigeonPoints) { + [points addObject:[[CLLocation alloc] initWithLatitude:point.latitude + longitude:point.longitude]]; + } + return points; +} + +NSArray *> *FGMGetHolesForPigeonLatLngArrays( + NSArray *> *pigeonHolePoints) { + NSMutableArray *> *holes = + [[NSMutableArray alloc] initWithCapacity:pigeonHolePoints.count]; + for (NSArray *holePoints in pigeonHolePoints) { + [holes addObject:FGMGetPointsForPigeonLatLngs(holePoints)]; + } + return holes; +} + +GMSMutablePath *FGMGetPathFromPoints(NSArray *points) { + GMSMutablePath *path = [GMSMutablePath path]; + for (CLLocation *location in points) { + [path addCoordinate:location.coordinate]; + } + return path; +} + +GMSMapViewType FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapType type) { + switch (type) { + case FGMPlatformMapTypeNone: + return kGMSTypeNone; + case FGMPlatformMapTypeNormal: + return kGMSTypeNormal; + case FGMPlatformMapTypeSatellite: + return kGMSTypeSatellite; + case FGMPlatformMapTypeTerrain: + return kGMSTypeTerrain; + case FGMPlatformMapTypeHybrid: + return kGMSTypeHybrid; + } +} + +FGMPlatformCluster *FGMGetPigeonCluster(GMUStaticCluster *cluster, + NSString *clusterManagerIdentifier) { + NSMutableArray *markerIDs = [[NSMutableArray alloc] initWithCapacity:cluster.items.count]; + GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] init]; + + for (GMSMarker *marker in cluster.items) { + [markerIDs addObject:FGMGetMarkerIdentifierFromMarker(marker)]; + bounds = [bounds includingCoordinate:marker.position]; + } + + return [FGMPlatformCluster + makeWithClusterManagerId:clusterManagerIdentifier + position:FGMGetPigeonLatLngForCoordinate(cluster.position) + bounds:FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds) + markerIds:markerIDs]; +} + +FGMPlatformGroundOverlay *FGMGetPigeonGroundOverlay(GMSGroundOverlay *groundOverlay, + NSString *overlayId, BOOL isCreatedWithBounds, + NSNumber *zoomLevel) { + // Image is mandatory field on FGMPlatformGroundOverlay (and it should be kept + // non-nullable), therefore image must be set for the object. The image is + // description either contains set of bytes, or path to asset. This info is + // converted to format google maps uses (BitmapDescription), and the original + // data is not stored on native code. Therefore placeholder image is used for + // the image field. + FGMPlatformBitmap *placeholderImage = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + if (isCreatedWithBounds) { + return [FGMPlatformGroundOverlay + makeWithGroundOverlayId:overlayId + image:placeholderImage + position:nil + bounds:[FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng + makeWithLatitude:groundOverlay.bounds + .northEast.latitude + longitude:groundOverlay.bounds + .northEast.longitude] + southwest:[FGMPlatformLatLng + makeWithLatitude:groundOverlay.bounds + .southWest.latitude + longitude:groundOverlay.bounds + .southWest + .longitude]] + anchor:[FGMPlatformPoint makeWithX:groundOverlay.anchor.x + y:groundOverlay.anchor.y] + transparency:1.0f - groundOverlay.opacity + bearing:groundOverlay.bearing + zIndex:groundOverlay.zIndex + visible:groundOverlay.map != nil + clickable:groundOverlay.isTappable + zoomLevel:zoomLevel]; + } else { + return [FGMPlatformGroundOverlay + makeWithGroundOverlayId:overlayId + image:placeholderImage + position:[FGMPlatformLatLng + makeWithLatitude:groundOverlay.position.latitude + longitude:groundOverlay.position.longitude] + bounds:nil + anchor:[FGMPlatformPoint makeWithX:groundOverlay.anchor.x + y:groundOverlay.anchor.y] + transparency:1.0f - groundOverlay.opacity + bearing:groundOverlay.bearing + zIndex:groundOverlay.zIndex + visible:groundOverlay.map != nil + clickable:groundOverlay.isTappable + zoomLevel:zoomLevel]; + } +} + +GMUGradient *FGMGetGradientForPigeonHeatmapGradient(FGMPlatformHeatmapGradient *gradient) { + NSMutableArray *colors = [[NSMutableArray alloc] initWithCapacity:gradient.colors.count]; + for (FGMPlatformColor *color in gradient.colors) { + [colors addObject:FGMGetColorForPigeonColor(color)]; + } + return [[GMUGradient alloc] initWithColors:colors + startPoints:gradient.startPoints + colorMapSize:gradient.colorMapSize]; +} + +FGMPlatformHeatmapGradient *FGMGetPigeonHeatmapGradientForGradient(GMUGradient *gradient) { + NSMutableArray *colors = [[NSMutableArray alloc] initWithCapacity:gradient.colors.count]; + for (UIColor *color in gradient.colors) { + [colors addObject:FGMGetPigeonColorForColor(color)]; + } + return [FGMPlatformHeatmapGradient makeWithColors:colors + startPoints:gradient.startPoints + colorMapSize:gradient.mapSize]; +} + +NSArray *FGMGetWeightedDataForPigeonWeightedData( + NSArray *weightedLatLngs) { + NSMutableArray *weightedData = [[NSMutableArray alloc] initWithCapacity:weightedLatLngs.count]; + for (FGMPlatformWeightedLatLng *weightedLatLng in weightedLatLngs) { + [weightedData + addObject:[[GMUWeightedLatLng alloc] + initWithCoordinate:FGMGetCoordinateForPigeonLatLng(weightedLatLng.point) + intensity:weightedLatLng.weight]]; + } + return weightedData; +} + +NSArray *FGMGetPigeonWeightedDataForWeightedData( + NSArray *weightedLatLngs) { + NSMutableArray *weightedData = [[NSMutableArray alloc] initWithCapacity:weightedLatLngs.count]; + for (GMUWeightedLatLng *weightedLatLng in weightedLatLngs) { + GMSMapPoint point = {weightedLatLng.point.x, weightedLatLng.point.y}; + [weightedData addObject:[FGMPlatformWeightedLatLng + makeWithPoint:FGMGetPigeonLatLngForCoordinate(GMSUnproject(point)) + weight:weightedLatLng.intensity]]; + } + return weightedData; +} + +GMSCameraUpdate *FGMGetCameraUpdateForPigeonCameraUpdate(FGMPlatformCameraUpdate *cameraUpdate) { + // See note in messages.dart for why this is so loosely typed. + id update = cameraUpdate.cameraUpdate; + if ([update isKindOfClass:[FGMPlatformCameraUpdateNewCameraPosition class]]) { + return [GMSCameraUpdate + setCamera:FGMGetCameraPositionForPigeonCameraPosition( + ((FGMPlatformCameraUpdateNewCameraPosition *)update).cameraPosition)]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateNewLatLng class]]) { + return [GMSCameraUpdate setTarget:FGMGetCoordinateForPigeonLatLng( + ((FGMPlatformCameraUpdateNewLatLng *)update).latLng)]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateNewLatLngBounds class]]) { + FGMPlatformCameraUpdateNewLatLngBounds *typedUpdate = + (FGMPlatformCameraUpdateNewLatLngBounds *)update; + return + [GMSCameraUpdate fitBounds:FGMGetCoordinateBoundsForPigeonLatLngBounds(typedUpdate.bounds) + withPadding:typedUpdate.padding]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateNewLatLngZoom class]]) { + FGMPlatformCameraUpdateNewLatLngZoom *typedUpdate = + (FGMPlatformCameraUpdateNewLatLngZoom *)update; + return [GMSCameraUpdate setTarget:FGMGetCoordinateForPigeonLatLng(typedUpdate.latLng) + zoom:typedUpdate.zoom]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateScrollBy class]]) { + FGMPlatformCameraUpdateScrollBy *typedUpdate = (FGMPlatformCameraUpdateScrollBy *)update; + return [GMSCameraUpdate scrollByX:typedUpdate.dx Y:typedUpdate.dy]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateZoomBy class]]) { + FGMPlatformCameraUpdateZoomBy *typedUpdate = (FGMPlatformCameraUpdateZoomBy *)update; + if (typedUpdate.focus) { + return [GMSCameraUpdate zoomBy:typedUpdate.amount + atPoint:FGMGetCGPointForPigeonPoint(typedUpdate.focus)]; + } else { + return [GMSCameraUpdate zoomBy:typedUpdate.amount]; + } + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateZoom class]]) { + if (((FGMPlatformCameraUpdateZoom *)update).out) { + return [GMSCameraUpdate zoomOut]; + } else { + return [GMSCameraUpdate zoomIn]; + } + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateZoomTo class]]) { + return [GMSCameraUpdate zoomTo:((FGMPlatformCameraUpdateZoomTo *)update).zoom]; + } + return nil; +} + +UIColor *FGMGetColorForPigeonColor(FGMPlatformColor *color) { + return [UIColor colorWithRed:color.red green:color.green blue:color.blue alpha:color.alpha]; +} + +FGMPlatformColor *FGMGetPigeonColorForColor(UIColor *color) { + double red, green, blue, alpha; + [color getRed:&red green:&green blue:&blue alpha:&alpha]; + return [FGMPlatformColor makeWithRed:red green:green blue:blue alpha:alpha]; +} + +NSArray *FGMGetStrokeStylesFromPatterns( + NSArray *patterns, UIColor *strokeColor) { + NSMutableArray *strokeStyles = [[NSMutableArray alloc] initWithCapacity:[patterns count]]; + for (FGMPlatformPatternItem *pattern in patterns) { + UIColor *color = + pattern.type == FGMPlatformPatternItemTypeGap ? UIColor.clearColor : strokeColor; + [strokeStyles addObject:[GMSStrokeStyle solidColor:color]]; + } + return strokeStyles; +} + +NSArray *FGMGetSpanLengthsFromPatterns(NSArray *patterns) { + NSMutableArray *lengths = [[NSMutableArray alloc] initWithCapacity:[patterns count]]; + for (FGMPlatformPatternItem *pattern in patterns) { + NSNumber *length = pattern.length ?: @0; + [lengths addObject:length]; + } + return lengths; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMGroundOverlayController.m new file mode 100644 index 000000000000..624f43032c53 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMGroundOverlayController.m @@ -0,0 +1,211 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMGroundOverlayController.h" +#import "FGMGroundOverlayController_Test.h" + +#import "FGMConversionUtils.h" +#import "FGMImageUtils.h" + +@interface FGMGroundOverlayController () + +/// The GMSMapView to which the ground overlays are added. +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FGMGroundOverlayController + +- (instancetype)initWithGroundOverlay:(GMSGroundOverlay *)groundOverlay + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView + isCreatedWithBounds:(BOOL)isCreatedWithBounds { + self = [super init]; + if (self) { + _groundOverlay = groundOverlay; + _mapView = mapView; + _groundOverlay.userData = @[ identifier ]; + _createdWithBounds = isCreatedWithBounds; + } + return self; +} + +- (void)removeGroundOverlay { + self.groundOverlay.map = nil; +} + +- (void)updateFromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)groundOverlay + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale { + [FGMGroundOverlayController updateGroundOverlay:self.groundOverlay + fromPlatformGroundOverlay:groundOverlay + withMapView:self.mapView + registrar:registrar + screenScale:screenScale + usingBounds:self.createdWithBounds]; +} + ++ (void)updateGroundOverlay:(GMSGroundOverlay *)groundOverlay + fromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)platformGroundOverlay + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingBounds:(BOOL)useBounds { + groundOverlay.tappable = platformGroundOverlay.clickable; + groundOverlay.zIndex = (int)platformGroundOverlay.zIndex; + groundOverlay.anchor = + CGPointMake(platformGroundOverlay.anchor.x, platformGroundOverlay.anchor.y); + UIImage *image = FGMIconFromBitmap(platformGroundOverlay.image, registrar, screenScale); + groundOverlay.icon = image; + groundOverlay.bearing = platformGroundOverlay.bearing; + groundOverlay.opacity = 1.0 - platformGroundOverlay.transparency; + if (useBounds) { + groundOverlay.bounds = [[GMSCoordinateBounds alloc] + initWithCoordinate:CLLocationCoordinate2DMake( + platformGroundOverlay.bounds.northeast.latitude, + platformGroundOverlay.bounds.northeast.longitude) + coordinate:CLLocationCoordinate2DMake( + platformGroundOverlay.bounds.southwest.latitude, + platformGroundOverlay.bounds.southwest.longitude)]; + } else { + groundOverlay.position = CLLocationCoordinate2DMake(platformGroundOverlay.position.latitude, + platformGroundOverlay.position.longitude); + } + + // This must be done last, to avoid visual flickers of default property values. + groundOverlay.map = platformGroundOverlay.visible ? mapView : nil; +} + +@end + +@interface FLTGroundOverlaysController () + +/// A map from ground overlay id to the controller that manages it. +@property(strong, nonatomic) NSMutableDictionary + *groundOverlayControllerByIdentifier; + +/// A callback api for the map interactions. +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; + +/// Flutter Plugin Registrar used to load images. +@property(weak, nonatomic) NSObject *registrar; + +/// The map view used to generate the controllers. +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGroundOverlaysController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _groundOverlayControllerByIdentifier = [[NSMutableDictionary alloc] init]; + _registrar = registrar; + } + return self; +} + +- (void)addGroundOverlays:(NSArray *)groundOverlaysToAdd { + for (FGMPlatformGroundOverlay *groundOverlay in groundOverlaysToAdd) { + NSString *identifier = groundOverlay.groundOverlayId; + GMSGroundOverlay *gmsOverlay; + BOOL isCreatedWithBounds = NO; + if (groundOverlay.position == nil) { + isCreatedWithBounds = YES; + NSAssert(groundOverlay.bounds != nil, + @"If ground overlay is initialized without position, bounds are required"); + gmsOverlay = [GMSGroundOverlay + groundOverlayWithBounds: + [[GMSCoordinateBounds alloc] + initWithCoordinate:CLLocationCoordinate2DMake( + groundOverlay.bounds.northeast.latitude, + groundOverlay.bounds.northeast.longitude) + coordinate:CLLocationCoordinate2DMake( + groundOverlay.bounds.southwest.latitude, + groundOverlay.bounds.southwest.longitude)] + icon:FGMIconFromBitmap(groundOverlay.image, self.registrar, + [self getScreenScale])]; + } else { + NSAssert(groundOverlay.zoomLevel != nil, + @"If ground overlay is initialized with position, zoomLevel is required"); + gmsOverlay = [GMSGroundOverlay + groundOverlayWithPosition:CLLocationCoordinate2DMake(groundOverlay.position.latitude, + groundOverlay.position.longitude) + icon:FGMIconFromBitmap(groundOverlay.image, self.registrar, + [self getScreenScale]) + zoomLevel:[groundOverlay.zoomLevel doubleValue]]; + } + FGMGroundOverlayController *controller = + [[FGMGroundOverlayController alloc] initWithGroundOverlay:gmsOverlay + identifier:identifier + mapView:self.mapView + isCreatedWithBounds:isCreatedWithBounds]; + controller.zoomLevel = groundOverlay.zoomLevel; + [controller updateFromPlatformGroundOverlay:groundOverlay + registrar:self.registrar + screenScale:[self getScreenScale]]; + self.groundOverlayControllerByIdentifier[identifier] = controller; + } +} + +- (void)changeGroundOverlays:(NSArray *)groundOverlaysToChange { + for (FGMPlatformGroundOverlay *groundOverlay in groundOverlaysToChange) { + NSString *identifier = groundOverlay.groundOverlayId; + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + [controller updateFromPlatformGroundOverlay:groundOverlay + registrar:self.registrar + screenScale:[self getScreenScale]]; + } +} + +- (void)removeGroundOverlaysWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + if (!controller) { + continue; + } + [controller removeGroundOverlay]; + [self.groundOverlayControllerByIdentifier removeObjectForKey:identifier]; + } +} + +- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier { + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapGroundOverlayWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (bool)hasGroundOverlaysWithIdentifier:(NSString *)identifier { + return self.groundOverlayControllerByIdentifier[identifier] != nil; +} + +- (CGFloat)getScreenScale { + // TODO(jokerttu): This method is called on marker creation, which, for initial markers, is done + // before the view is added to the view hierarchy. This means that the traitCollection values may + // not be matching the right display where the map is finally shown. The solution should be + // revisited after the proper way to fetch the display scale is resolved for platform views. This + // should be done under the context of the following issue: + // https://github.com/flutter/flutter/issues/125496. + return self.mapView.traitCollection.displayScale; +} + +- (nullable FGMPlatformGroundOverlay *)groundOverlayWithIdentifier:(NSString *)identifier { + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + if (!controller) { + return nil; + } + return FGMGetPigeonGroundOverlay(controller.groundOverlay, identifier, + controller.isCreatedWithBounds, controller.zoomLevel); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMImageUtils.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMImageUtils.m new file mode 100644 index 000000000000..7bd5192c2377 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMImageUtils.m @@ -0,0 +1,235 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMImageUtils.h" + +@import Foundation; + +/// This method is deprecated within the context of `BitmapDescriptor.fromBytes` handling in the +/// flutter google_maps_flutter_platform_interface package which has been replaced by 'bytes' +/// message handling. It will be removed when the deprecated image bitmap description type +/// 'fromBytes' is removed from the platform interface. +static UIImage *scaledImage(UIImage *image, double scale); + +/// Creates a scaled version of the provided UIImage based on a specified scale factor. If the +/// scale factor differs from the image's current scale by more than a small epsilon-delta (to +/// account for minor floating-point inaccuracies), a new UIImage object is created with the +/// specified scale. Otherwise, the original image is returned. +/// +/// @param image The UIImage to scale. +/// @param scale The factor by which to scale the image. +/// @return UIImage Returns the scaled UIImage. +static UIImage *scaledImageWithScale(UIImage *image, CGFloat scale); + +/// Scales an input UIImage to a specified size. If the aspect ratio of the input image +/// closely matches the target size, indicated by a small epsilon-delta, the image's scale +/// property is updated instead of resizing the image. If the aspect ratios differ beyond this +/// threshold, the method redraws the image at the target size. +/// +/// @param image The UIImage to scale. +/// @param size The target CGSize to scale the image to. +/// @return UIImage Returns the scaled UIImage. +static UIImage *scaledImageWithSize(UIImage *image, CGSize size); + +/// Scales an input UIImage to a specified width and height preserving aspect ratio if both +/// widht and height are not given.. +/// +/// @param image The UIImage to scale. +/// @param width The target width to scale the image to. +/// @param height The target height to scale the image to. +/// @param screenScale The current screen scale. +/// @return UIImage Returns the scaled UIImage. +static UIImage *scaledImageWithWidthHeight(UIImage *image, NSNumber *width, NSNumber *height, + CGFloat screenScale); + +UIImage *FGMIconFromBitmap(FGMPlatformBitmap *platformBitmap, + NSObject *registrar, CGFloat screenScale) { + assert(screenScale > 0 && "Screen scale must be greater than 0"); + // See comment in messages.dart for why this is so loosely typed. See also + // https://github.com/flutter/flutter/issues/117819. + id bitmap = platformBitmap.bitmap; + UIImage *image; + if ([bitmap isKindOfClass:[FGMPlatformBitmapDefaultMarker class]]) { + FGMPlatformBitmapDefaultMarker *bitmapDefaultMarker = bitmap; + CGFloat hue = bitmapDefaultMarker.hue.doubleValue; + image = [GMSMarker markerImageWithColor:[UIColor colorWithHue:hue / 360.0 + saturation:1.0 + brightness:0.7 + alpha:1.0]]; + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapAsset class]]) { + // Deprecated: This message handling for 'fromAsset' has been replaced by 'asset'. + // Refer to the flutter google_maps_flutter_platform_interface package for details. + FGMPlatformBitmapAsset *bitmapAsset = bitmap; + if (bitmapAsset.pkg) { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAsset.name + fromPackage:bitmapAsset.pkg]]; + } else { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAsset.name]]; + } + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapAssetImage class]]) { + // Deprecated: This message handling for 'fromAssetImage' has been replaced by 'asset'. + // Refer to the flutter google_maps_flutter_platform_interface package for details. + FGMPlatformBitmapAssetImage *bitmapAssetImage = bitmap; + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAssetImage.name]]; + image = scaledImage(image, bitmapAssetImage.scale); + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapBytes class]]) { + // Deprecated: This message handling for 'fromBytes' has been replaced by 'bytes'. + // Refer to the flutter google_maps_flutter_platform_interface package for details. + FGMPlatformBitmapBytes *bitmapBytes = bitmap; + @try { + CGFloat mainScreenScale = [[UIScreen mainScreen] scale]; + image = [UIImage imageWithData:bitmapBytes.byteData.data scale:mainScreenScale]; + } @catch (NSException *exception) { + @throw [NSException exceptionWithName:@"InvalidByteDescriptor" + reason:@"Unable to interpret bytes as a valid image." + userInfo:nil]; + } + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapAssetMap class]]) { + FGMPlatformBitmapAssetMap *bitmapAssetMap = bitmap; + + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAssetMap.assetName]]; + + if (bitmapAssetMap.bitmapScaling == FGMPlatformMapBitmapScalingAuto) { + NSNumber *width = bitmapAssetMap.width; + NSNumber *height = bitmapAssetMap.height; + if (width || height) { + image = scaledImageWithScale(image, screenScale); + image = scaledImageWithWidthHeight(image, width, height, screenScale); + } else { + image = scaledImageWithScale(image, bitmapAssetMap.imagePixelRatio); + } + } + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapBytesMap class]]) { + FGMPlatformBitmapBytesMap *bitmapBytesMap = bitmap; + FlutterStandardTypedData *bytes = bitmapBytesMap.byteData; + + @try { + image = [UIImage imageWithData:bytes.data scale:screenScale]; + if (bitmapBytesMap.bitmapScaling == FGMPlatformMapBitmapScalingAuto) { + NSNumber *width = bitmapBytesMap.width; + NSNumber *height = bitmapBytesMap.height; + + if (width || height) { + // Before scaling the image, image must be in screenScale. + image = scaledImageWithScale(image, screenScale); + image = scaledImageWithWidthHeight(image, width, height, screenScale); + } else { + image = scaledImageWithScale(image, bitmapBytesMap.imagePixelRatio); + } + } else { + // No scaling, load image from bytes without scale parameter. + image = [UIImage imageWithData:bytes.data]; + } + } @catch (NSException *exception) { + @throw [NSException exceptionWithName:@"InvalidByteDescriptor" + reason:@"Unable to interpret bytes as a valid image." + userInfo:nil]; + } + } + + return image; +} + +UIImage *scaledImage(UIImage *image, double scale) { + if (fabs(scale - 1) > 1e-3) { + return [UIImage imageWithCGImage:[image CGImage] + scale:(image.scale * scale) + orientation:(image.imageOrientation)]; + } + return image; +} + +UIImage *scaledImageWithScale(UIImage *image, CGFloat scale) { + if (fabs(scale - image.scale) > DBL_EPSILON) { + return [UIImage imageWithCGImage:[image CGImage] + scale:scale + orientation:(image.imageOrientation)]; + } + return image; +} + +UIImage *scaledImageWithSize(UIImage *image, CGSize size) { + CGFloat originalPixelWidth = image.size.width * image.scale; + CGFloat originalPixelHeight = image.size.height * image.scale; + + // Return original image if either original image size or target size is so small that + // image cannot be resized or displayed. + if (originalPixelWidth <= 0 || originalPixelHeight <= 0 || size.width <= 0 || size.height <= 0) { + return image; + } + + // Check if the image's size, accounting for scale, matches the target size. + if (fabs(originalPixelWidth - size.width) <= DBL_EPSILON && + fabs(originalPixelHeight - size.height) <= DBL_EPSILON) { + // No need for resizing, return the original image + return image; + } + + // Check if the aspect ratios are approximately equal. + CGSize originalPixelSize = CGSizeMake(originalPixelWidth, originalPixelHeight); + if (FGMIsScalableWithScaleFactorFromSize(originalPixelSize, size)) { + // Scaled image has close to same aspect ratio, + // updating image scale instead of resizing image. + CGFloat factor = originalPixelWidth / size.width; + return scaledImageWithScale(image, image.scale * factor); + } else { + // Aspect ratios differ significantly, resize the image. + UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat]; + format.scale = 1.0; + format.opaque = NO; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size + format:format]; + UIImage *newImage = + [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { + [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; + }]; + + // Return image with proper scaling. + return scaledImageWithScale(newImage, image.scale); + } +} + +UIImage *scaledImageWithWidthHeight(UIImage *image, NSNumber *width, NSNumber *height, + CGFloat screenScale) { + if ((width == nil) && (height == nil)) { + return image; + } + + CGFloat targetWidth = width == nil ? image.size.width : width.doubleValue; + CGFloat targetHeight = height == nil ? image.size.height : height.doubleValue; + + if ((width != nil) && (height == nil)) { + // Calculate height based on aspect ratio if only width is provided. + double aspectRatio = image.size.height / image.size.width; + targetHeight = round(targetWidth * aspectRatio); + } else if ((width == nil) && (height != nil)) { + // Calculate width based on aspect ratio if only height is provided. + double aspectRatio = image.size.width / image.size.height; + targetWidth = round(targetHeight * aspectRatio); + } + + CGSize targetSize = + CGSizeMake(round(targetWidth * screenScale), round(targetHeight * screenScale)); + return scaledImageWithSize(image, targetSize); +} + +BOOL FGMIsScalableWithScaleFactorFromSize(CGSize originalSize, CGSize targetSize) { + // Select the scaling factor based on the longer side to have good precision. + CGFloat scaleFactor = (originalSize.width > originalSize.height) + ? (targetSize.width / originalSize.width) + : (targetSize.height / originalSize.height); + + // Calculate the scaled dimensions. + CGFloat scaledWidth = originalSize.width * scaleFactor; + CGFloat scaledHeight = originalSize.height * scaleFactor; + + // Check if the scaled dimensions are within a one-pixel + // threshold of the target dimensions. + BOOL widthWithinThreshold = fabs(scaledWidth - targetSize.width) <= 1.0; + BOOL heightWithinThreshold = fabs(scaledHeight - targetSize.height) <= 1.0; + + // The image is considered scalable with scale factor + // if both dimensions are within the threshold. + return widthWithinThreshold && heightWithinThreshold; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMMarkerUserData.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMMarkerUserData.m new file mode 100644 index 000000000000..22b100e34102 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMMarkerUserData.m @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMMarkerUserData.h" + +@implementation FGMMarkerUserData + +@end + +void FGMSetIdentifiersToMarkerUserData(NSString *markerIdentifier, + NSString *_Nullable clusterManagerIdentifier, + GMSMarker *marker) { + FGMMarkerUserData *userData = [[FGMMarkerUserData alloc] init]; + userData.markerIdentifier = markerIdentifier; + userData.clusterManagerIdentifier = clusterManagerIdentifier; + marker.userData = userData; +}; + +NSString *_Nullable FGMGetMarkerIdentifierFromMarker(GMSMarker *marker) { + if ([marker.userData isKindOfClass:[FGMMarkerUserData class]]) { + FGMMarkerUserData *userData = (FGMMarkerUserData *)marker.userData; + return userData.markerIdentifier; + } + return nil; +}; + +NSString *_Nullable FGMGetClusterManagerIdentifierFromMarker(GMSMarker *marker) { + if ([marker.userData isKindOfClass:[FGMMarkerUserData class]]) { + FGMMarkerUserData *userData = (FGMMarkerUserData *)marker.userData; + return userData.clusterManagerIdentifier; + } + return nil; +}; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapHeatmapController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapHeatmapController.m new file mode 100644 index 000000000000..91c93933308d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapHeatmapController.m @@ -0,0 +1,140 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapHeatmapController.h" +#import "FLTGoogleMapHeatmapController_Test.h" + +@import GoogleMapsUtils; + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapHeatmapController () + +/// The heatmap tile layer this controller handles. +@property(nonatomic, strong) GMUHeatmapTileLayer *heatmapTileLayer; + +/// The GMSMapView to which the heatmaps are added. +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapHeatmapController +- (instancetype)initWithHeatmap:(FGMPlatformHeatmap *)heatmap + tileLayer:(GMUHeatmapTileLayer *)heatmapTileLayer + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _heatmapTileLayer = heatmapTileLayer; + _mapView = mapView; + + [FLTGoogleMapHeatmapController updateHeatmap:_heatmapTileLayer + fromPlatformHeatmap:heatmap + withMapView:_mapView]; + } + return self; +} + +- (void)removeHeatmap { + _heatmapTileLayer.map = nil; +} + +- (void)clearTileCache { + [_heatmapTileLayer clearTileCache]; +} + +- (void)updateFromPlatformHeatmap:(FGMPlatformHeatmap *)platformHeatmap { + [FLTGoogleMapHeatmapController updateHeatmap:_heatmapTileLayer + fromPlatformHeatmap:platformHeatmap + withMapView:_mapView]; +} + ++ (void)updateHeatmap:(GMUHeatmapTileLayer *)heatmapTileLayer + fromPlatformHeatmap:(FGMPlatformHeatmap *)platformHeatmap + withMapView:(GMSMapView *)mapView { + heatmapTileLayer.weightedData = FGMGetWeightedDataForPigeonWeightedData(platformHeatmap.data); + if (platformHeatmap.gradient) { + heatmapTileLayer.gradient = FGMGetGradientForPigeonHeatmapGradient(platformHeatmap.gradient); + } + heatmapTileLayer.opacity = platformHeatmap.opacity; + heatmapTileLayer.radius = platformHeatmap.radius; + heatmapTileLayer.minimumZoomIntensity = platformHeatmap.minimumZoomIntensity; + heatmapTileLayer.maximumZoomIntensity = platformHeatmap.maximumZoomIntensity; + + // The map must be set each time for options to update. + // This must be done last, to avoid visual flickers of default property values. + heatmapTileLayer.map = mapView; +} +@end + +@interface FLTHeatmapsController () + +/// A map from heatmapId to the controller that manages it. +@property(nonatomic, strong) + NSMutableDictionary *heatmapIdToController; + +/// The map view owned by GoogmeMapController. +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTHeatmapsController +- (instancetype)initWithMapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _mapView = mapView; + _heatmapIdToController = [NSMutableDictionary dictionary]; + } + return self; +} + +- (void)addHeatmaps:(NSArray *)heatmapsToAdd { + for (FGMPlatformHeatmap *heatmap in heatmapsToAdd) { + GMUHeatmapTileLayer *heatmapTileLayer = [[GMUHeatmapTileLayer alloc] init]; + FLTGoogleMapHeatmapController *controller = + [[FLTGoogleMapHeatmapController alloc] initWithHeatmap:heatmap + tileLayer:heatmapTileLayer + mapView:_mapView]; + _heatmapIdToController[heatmap.heatmapId] = controller; + } +} + +- (void)changeHeatmaps:(NSArray *)heatmapsToChange { + for (FGMPlatformHeatmap *heatmap in heatmapsToChange) { + FLTGoogleMapHeatmapController *controller = _heatmapIdToController[heatmap.heatmapId]; + + [controller updateFromPlatformHeatmap:heatmap]; + [controller clearTileCache]; + } +} + +- (void)removeHeatmapsWithIdentifiers:(NSArray *)identifiers { + for (NSString *heatmapId in identifiers) { + FLTGoogleMapHeatmapController *controller = _heatmapIdToController[heatmapId]; + if (!controller) { + continue; + } + [controller removeHeatmap]; + [_heatmapIdToController removeObjectForKey:heatmapId]; + } +} + +- (BOOL)hasHeatmapWithIdentifier:(NSString *)identifier { + return _heatmapIdToController[identifier] != nil; +} + +- (FGMPlatformHeatmap *)heatmapWithIdentifier:(NSString *)identifier { + GMUHeatmapTileLayer *heatmap = self.heatmapIdToController[identifier].heatmapTileLayer; + if (!heatmap) { + return nil; + } + return [FGMPlatformHeatmap + makeWithHeatmapId:identifier + data:FGMGetPigeonWeightedDataForWeightedData(heatmap.weightedData) + gradient:FGMGetPigeonHeatmapGradientForGradient(heatmap.gradient) + opacity:heatmap.opacity + radius:heatmap.radius + minimumZoomIntensity:heatmap.minimumZoomIntensity + maximumZoomIntensity:heatmap.maximumZoomIntensity]; +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapTileOverlayController.m new file mode 100644 index 000000000000..c4cce14ed247 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapTileOverlayController.m @@ -0,0 +1,199 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapTileOverlayController.h" +#import "FLTGoogleMapTileOverlayController_Test.h" + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapTileOverlayController () + +@property(strong, nonatomic) GMSTileLayer *layer; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapTileOverlayController + +- (instancetype)initWithTileOverlay:(FGMPlatformTileOverlay *)tileOverlay + tileLayer:(GMSTileLayer *)tileLayer + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _layer = tileLayer; + _mapView = mapView; + [FLTGoogleMapTileOverlayController updateTileLayer:tileLayer + fromPlatformTileOverlay:tileOverlay + withMapView:mapView]; + } + return self; +} + +- (void)removeTileOverlay { + self.layer.map = nil; +} + +- (void)clearTileCache { + [self.layer clearTileCache]; +} + +- (void)updateFromPlatformTileOverlay:(FGMPlatformTileOverlay *)overlay { + [FLTGoogleMapTileOverlayController updateTileLayer:self.layer + fromPlatformTileOverlay:overlay + withMapView:self.mapView]; +} + ++ (void)updateTileLayer:(GMSTileLayer *)tileLayer + fromPlatformTileOverlay:(FGMPlatformTileOverlay *)platformOverlay + withMapView:(GMSMapView *)mapView { + tileLayer.opacity = 1.0 - platformOverlay.transparency; + tileLayer.zIndex = (int)platformOverlay.zIndex; + tileLayer.fadeIn = platformOverlay.fadeIn; + tileLayer.tileSize = platformOverlay.tileSize; + + // This must be done last, to avoid visual flickers of default property values. + tileLayer.map = platformOverlay.visible ? mapView : nil; +} + +@end + +@interface FLTTileProviderController () + +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; + +@end + +@implementation FLTTileProviderController + +- (instancetype)initWithTileOverlayIdentifier:(NSString *)identifier + callbackHandler:(FGMMapsCallbackApi *)callbackHandler { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _tileOverlayIdentifier = identifier; + } + return self; +} + +#pragma mark - GMSTileLayer method + +- (UIImage *)handleResultTile:(nullable UIImage *)tile { + CGImageRef imageRef = tile.CGImage; + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + BOOL isFloat = bitmapInfo && kCGBitmapFloatComponents; + size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); + + // Engine use f16 pixel format for wide gamut images + // If it is wide gamut, we want to downsample it + if (isFloat & (bitsPerComponent == 16)) { + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = + CGBitmapContextCreate(nil, tile.size.width, tile.size.height, 8, 0, colorSpace, + (kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast)); + CGContextDrawImage(context, CGRectMake(0, 0, tile.size.width, tile.size.height), tile.CGImage); + CGImageRef image = CGBitmapContextCreateImage(context); + tile = [UIImage imageWithCGImage:image]; + + CGImageRelease(image); + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + } + return tile; +} + +- (void)requestTileForX:(NSUInteger)x + y:(NSUInteger)y + zoom:(NSUInteger)zoom + receiver:(id)receiver { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.callbackHandler + tileWithOverlayIdentifier:self.tileOverlayIdentifier + location:[FGMPlatformPoint makeWithX:x y:y] + zoom:zoom + completion:^(FGMPlatformTile *_Nullable tile, + FlutterError *_Nullable error) { + FlutterStandardTypedData *typedData = tile.data; + UIImage *tileImage = + typedData + ? [self handleResultTile:[UIImage imageWithData:typedData.data]] + : kGMSTileLayerNoTile; + if (error) { + NSLog(@"Can't get tile: errorCode = %@, errorMessage = %@, details = %@", + [error code], [error message], [error details]); + } + [receiver receiveTileWithX:x y:y zoom:zoom image:tileImage]; + }]; + }); +} + +@end + +@interface FLTTileOverlaysController () + +@property(strong, nonatomic) NSMutableDictionary + *tileOverlayIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTTileOverlaysController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _tileOverlayIdentifierToController = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd { + for (FGMPlatformTileOverlay *tileOverlay in tileOverlaysToAdd) { + NSString *identifier = tileOverlay.tileOverlayId; + FLTTileProviderController *tileProvider = + [[FLTTileProviderController alloc] initWithTileOverlayIdentifier:identifier + callbackHandler:self.callbackHandler]; + FLTGoogleMapTileOverlayController *controller = + [[FLTGoogleMapTileOverlayController alloc] initWithTileOverlay:tileOverlay + tileLayer:tileProvider + mapView:self.mapView]; + self.tileOverlayIdentifierToController[identifier] = controller; + } +} + +- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange { + for (FGMPlatformTileOverlay *tileOverlay in tileOverlaysToChange) { + NSString *identifier = tileOverlay.tileOverlayId; + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; + [controller updateFromPlatformTileOverlay:tileOverlay]; + } +} +- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; + if (!controller) { + continue; + } + [controller removeTileOverlay]; + [self.tileOverlayIdentifierToController removeObjectForKey:identifier]; + } +} + +- (void)clearTileCacheWithIdentifier:(NSString *)identifier { + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; + [controller clearTileCache]; +} + +- (nullable FLTGoogleMapTileOverlayController *)tileOverlayWithIdentifier:(NSString *)identifier { + return self.tileOverlayIdentifierToController[identifier]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapsPlugin.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapsPlugin.m new file mode 100644 index 000000000000..86391b40892e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FLTGoogleMapsPlugin.m @@ -0,0 +1,19 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapsPlugin.h" + +#pragma mark - GoogleMaps plugin implementation + +@implementation FLTGoogleMapsPlugin + ++ (void)registerWithRegistrar:(NSObject *)registrar { + FLTGoogleMapFactory *googleMapFactory = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + [registrar registerViewFactory:googleMapFactory + withId:@"plugins.flutter.dev/google_maps_ios" + gestureRecognizersBlockingPolicy: + FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapCircleController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapCircleController.m new file mode 100644 index 000000000000..d2d0130dc64a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapCircleController.m @@ -0,0 +1,130 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapCircleController.h" +#import "GoogleMapCircleController_Test.h" + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapCircleController () + +@property(nonatomic, strong) GMSCircle *circle; +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapCircleController + +- (instancetype)initCircleWithPlatformCircle:(FGMPlatformCircle *)circle + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _circle = [GMSCircle circleWithPosition:FGMGetCoordinateForPigeonLatLng(circle.center) + radius:circle.radius]; + _mapView = mapView; + _circle.userData = @[ circle.circleId ]; + [FLTGoogleMapCircleController updateCircle:_circle + fromPlatformCircle:circle + withMapView:mapView]; + } + return self; +} + +- (void)removeCircle { + self.circle.map = nil; +} + +- (void)updateFromPlatformCircle:(FGMPlatformCircle *)platformCircle { + [FLTGoogleMapCircleController updateCircle:self.circle + fromPlatformCircle:platformCircle + withMapView:self.mapView]; +} + ++ (void)updateCircle:(GMSCircle *)circle + fromPlatformCircle:(FGMPlatformCircle *)platformCircle + withMapView:(GMSMapView *)mapView { + circle.tappable = platformCircle.consumeTapEvents; + circle.zIndex = platformCircle.zIndex; + circle.position = FGMGetCoordinateForPigeonLatLng(platformCircle.center); + circle.radius = platformCircle.radius; + circle.strokeColor = FGMGetColorForPigeonColor(platformCircle.strokeColor); + circle.strokeWidth = platformCircle.strokeWidth; + circle.fillColor = FGMGetColorForPigeonColor(platformCircle.fillColor); + + // This must be done last, to avoid visual flickers of default property values. + circle.map = platformCircle.visible ? mapView : nil; +} + +@end + +@interface FLTCirclesController () + +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) GMSMapView *mapView; +@property(strong, nonatomic) NSMutableDictionary *circleIdToController; + +@end + +@implementation FLTCirclesController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _circleIdToController = [NSMutableDictionary dictionaryWithCapacity:1]; + } + return self; +} + +- (void)addCircles:(NSArray *)circlesToAdd { + for (FGMPlatformCircle *circle in circlesToAdd) { + FLTGoogleMapCircleController *controller = + [[FLTGoogleMapCircleController alloc] initCircleWithPlatformCircle:circle + mapView:self.mapView]; + self.circleIdToController[circle.circleId] = controller; + } +} + +- (void)changeCircles:(NSArray *)circlesToChange { + for (FGMPlatformCircle *circle in circlesToChange) { + FLTGoogleMapCircleController *controller = self.circleIdToController[circle.circleId]; + [controller updateFromPlatformCircle:circle]; + } +} + +- (void)removeCirclesWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapCircleController *controller = self.circleIdToController[identifier]; + if (!controller) { + continue; + } + [controller removeCircle]; + [self.circleIdToController removeObjectForKey:identifier]; + } +} + +- (bool)hasCircleWithIdentifier:(NSString *)identifier { + if (!identifier) { + return false; + } + return self.circleIdToController[identifier] != nil; +} + +- (void)didTapCircleWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapCircleController *controller = self.circleIdToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapCircleWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapController.m new file mode 100644 index 000000000000..0537d48ba9ce --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapController.m @@ -0,0 +1,838 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import GoogleMapsUtils; + +#import "GoogleMapController.h" +#import "GoogleMapController_Test.h" + +#import "FGMConversionUtils.h" +#import "FGMGroundOverlayController.h" +#import "FGMMarkerUserData.h" +#import "FLTGoogleMapHeatmapController.h" +#import "FLTGoogleMapTileOverlayController.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +#pragma mark - Conversion of JSON-like values sent via platform channels. Forward declarations. + +@interface FLTGoogleMapFactory () + +@property(weak, nonatomic) NSObject *registrar; +@property(strong, nonatomic, readonly) id sharedMapServices; + +@end + +@implementation FLTGoogleMapFactory + +@synthesize sharedMapServices = _sharedMapServices; + +- (instancetype)initWithRegistrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _registrar = registrar; + } + return self; +} + +- (NSObject *)createArgsCodec { + return FGMGetGoogleMapsFlutterPigeonMessagesCodec(); +} + +- (NSObject *)createWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + arguments:(id _Nullable)args { + // Precache shared map services, if needed. + // Retain the shared map services singleton, don't use the result for anything. + (void)[self sharedMapServices]; + + return [[FLTGoogleMapController alloc] initWithFrame:frame + viewIdentifier:viewId + creationParameters:args + registrar:self.registrar]; +} + +- (id)sharedMapServices { + if (_sharedMapServices == nil) { + // Calling this prepares GMSServices on a background thread controlled + // by the GoogleMaps framework. + // Retain the singleton to cache the initialization work across all map views. + _sharedMapServices = [GMSServices sharedServices]; + } + return _sharedMapServices; +} + +@end + +#pragma mark - + +/// Private declarations of the FGMMapCallHandler. +@interface FGMMapCallHandler () +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix; + +/// The map controller this inspector corresponds to. +@property(nonatomic, weak) FLTGoogleMapController *controller; +/// The messenger this instance was registered with by Pigeon. +@property(nonatomic, copy) NSObject *messenger; +/// The suffix this instance was registered under with Pigeon. +@property(nonatomic, copy) NSString *pigeonSuffix; +@end + +#pragma mark - + +/// Private declarations of the FGMMapInspector. +@interface FGMMapInspector () + +/// The map controller this inspector corresponds to. +@property(nonatomic, weak) FLTGoogleMapController *controller; +/// The messenger this instance was registered with by Pigeon. +@property(nonatomic, copy) NSObject *messenger; +/// The suffix this instance was registered under with Pigeon. +@property(nonatomic, copy) NSString *pigeonSuffix; +@end + +#pragma mark - + +@interface FLTGoogleMapController () + +@property(nonatomic, strong) GMSMapView *mapView; +@property(nonatomic, strong) FGMMapsCallbackApi *dartCallbackHandler; +@property(nonatomic, assign) BOOL trackCameraPosition; +@property(nonatomic, weak) NSObject *registrar; +@property(nonatomic, strong) FGMClusterManagersController *clusterManagersController; +@property(nonatomic, strong) FLTMarkersController *markersController; +@property(nonatomic, strong) FLTPolygonsController *polygonsController; +@property(nonatomic, strong) FLTPolylinesController *polylinesController; +@property(nonatomic, strong) FLTCirclesController *circlesController; + +// The controller that handles heatmaps +@property(nonatomic, strong) FLTHeatmapsController *heatmapsController; +@property(nonatomic, strong) FLTTileOverlaysController *tileOverlaysController; +@property(nonatomic, strong) FLTGroundOverlaysController *groundOverlaysController; +// The resulting error message, if any, from the last attempt to set the map style. +// This is used to provide access to errors after the fact, since the map style is generally set at +// creation time and there's no mechanism to return non-fatal error details during platform view +// initialization. +@property(nonatomic, copy) NSString *styleError; +// The main Pigeon API implementation, separate to avoid lifetime extension. +@property(nonatomic, strong) FGMMapCallHandler *callHandler; +// The inspector API implementation, separate to avoid lifetime extension. +@property(nonatomic, strong) FGMMapInspector *inspector; + +@end + +@implementation FLTGoogleMapController + +- (instancetype)initWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *)registrar { + GMSCameraPosition *camera = + FGMGetCameraPositionForPigeonCameraPosition(creationParameters.initialCameraPosition); + + GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init]; + options.frame = frame; + options.camera = camera; + NSString *cloudMapId = creationParameters.mapConfiguration.mapId; + if (cloudMapId) { + options.mapID = [GMSMapID mapIDWithIdentifier:cloudMapId]; + } + + GMSMapView *mapView = [[GMSMapView alloc] initWithOptions:options]; + + return [self initWithMapView:mapView + viewIdentifier:viewId + creationParameters:creationParameters + registrar:registrar]; +} + +- (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *_Nonnull)registrar { + if (self = [super init]) { + _mapView = mapView; + + _mapView.accessibilityElementsHidden = NO; + // TODO(cyanglaz): avoid sending message to self in the middle of the init method. + // https://github.com/flutter/flutter/issues/104121 + [self interpretMapConfiguration:creationParameters.mapConfiguration]; + NSString *pigeonSuffix = [NSString stringWithFormat:@"%lld", viewId]; + _dartCallbackHandler = [[FGMMapsCallbackApi alloc] initWithBinaryMessenger:registrar.messenger + messageChannelSuffix:pigeonSuffix]; + _mapView.delegate = self; + _mapView.paddingAdjustmentBehavior = kGMSMapViewPaddingAdjustmentBehaviorNever; + _registrar = registrar; + _clusterManagersController = + [[FGMClusterManagersController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler]; + _markersController = [[FLTMarkersController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + clusterManagersController:_clusterManagersController + registrar:registrar]; + _polygonsController = [[FLTPolygonsController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _polylinesController = [[FLTPolylinesController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _circlesController = [[FLTCirclesController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _heatmapsController = [[FLTHeatmapsController alloc] initWithMapView:_mapView]; + _tileOverlaysController = + [[FLTTileOverlaysController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _groundOverlaysController = + [[FLTGroundOverlaysController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + [_clusterManagersController addClusterManagers:creationParameters.initialClusterManagers]; + [_markersController addMarkers:creationParameters.initialMarkers]; + [_polygonsController addPolygons:creationParameters.initialPolygons]; + [_polylinesController addPolylines:creationParameters.initialPolylines]; + [_circlesController addCircles:creationParameters.initialCircles]; + [_heatmapsController addHeatmaps:creationParameters.initialHeatmaps]; + [_tileOverlaysController addTileOverlays:creationParameters.initialTileOverlays]; + [_groundOverlaysController addGroundOverlays:creationParameters.initialGroundOverlays]; + + // Invoke clustering after markers are added. + [_clusterManagersController invokeClusteringForEachClusterManager]; + + [_mapView addObserver:self forKeyPath:@"frame" options:0 context:nil]; + + _callHandler = [[FGMMapCallHandler alloc] initWithMapController:self + messenger:registrar.messenger + pigeonSuffix:pigeonSuffix]; + SetUpFGMMapsApiWithSuffix(registrar.messenger, _callHandler, pigeonSuffix); + _inspector = [[FGMMapInspector alloc] initWithMapController:self + messenger:registrar.messenger + pigeonSuffix:pigeonSuffix]; + SetUpFGMMapsInspectorApiWithSuffix(registrar.messenger, _inspector, pigeonSuffix); + } + return self; +} + +- (void)dealloc { + // Unregister the API implementations so that they can be released; the registration created an + // owning reference. + SetUpFGMMapsApiWithSuffix(_callHandler.messenger, nil, _callHandler.pigeonSuffix); + SetUpFGMMapsInspectorApiWithSuffix(_inspector.messenger, nil, _inspector.pigeonSuffix); +} + +- (UIView *)view { + return self.mapView; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if (object == self.mapView && [keyPath isEqualToString:@"frame"]) { + CGRect bounds = self.mapView.bounds; + if (CGRectEqualToRect(bounds, CGRectZero)) { + // The workaround is to fix an issue that the camera location is not current when + // the size of the map is zero at initialization. + // So We only care about the size of the `self.mapView`, ignore the frame changes when the + // size is zero. + return; + } + // We only observe the frame for initial setup. + [self.mapView removeObserver:self forKeyPath:@"frame"]; + [self.mapView moveCamera:[GMSCameraUpdate setCamera:self.mapView.camera]]; + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +- (void)showAtOrigin:(CGPoint)origin { + CGRect frame = {origin, self.mapView.frame.size}; + self.mapView.frame = frame; + self.mapView.hidden = NO; +} + +- (void)hide { + self.mapView.hidden = YES; +} + +- (GMSCameraPosition *)cameraPosition { + if (self.trackCameraPosition) { + return self.mapView.camera; + } else { + return nil; + } +} + +- (void)setCamera:(GMSCameraPosition *)camera { + self.mapView.camera = camera; +} + +- (void)setCameraTargetBounds:(GMSCoordinateBounds *)bounds { + self.mapView.cameraTargetBounds = bounds; +} + +- (void)setCompassEnabled:(BOOL)enabled { + self.mapView.settings.compassButton = enabled; +} + +- (void)setIndoorEnabled:(BOOL)enabled { + self.mapView.indoorEnabled = enabled; +} + +- (void)setTrafficEnabled:(BOOL)enabled { + self.mapView.trafficEnabled = enabled; +} + +- (void)setBuildingsEnabled:(BOOL)enabled { + self.mapView.buildingsEnabled = enabled; +} + +- (void)setMapType:(GMSMapViewType)mapType { + self.mapView.mapType = mapType; +} + +- (void)setMinZoom:(float)minZoom maxZoom:(float)maxZoom { + [self.mapView setMinZoom:minZoom maxZoom:maxZoom]; +} + +- (void)setPaddingTop:(float)top left:(float)left bottom:(float)bottom right:(float)right { + self.mapView.padding = UIEdgeInsetsMake(top, left, bottom, right); +} + +- (void)setRotateGesturesEnabled:(BOOL)enabled { + self.mapView.settings.rotateGestures = enabled; +} + +- (void)setScrollGesturesEnabled:(BOOL)enabled { + self.mapView.settings.scrollGestures = enabled; +} + +- (void)setTiltGesturesEnabled:(BOOL)enabled { + self.mapView.settings.tiltGestures = enabled; +} + +- (void)setTrackCameraPosition:(BOOL)enabled { + _trackCameraPosition = enabled; +} + +- (void)setZoomGesturesEnabled:(BOOL)enabled { + self.mapView.settings.zoomGestures = enabled; +} + +- (void)setMyLocationEnabled:(BOOL)enabled { + self.mapView.myLocationEnabled = enabled; +} + +- (void)setMyLocationButtonEnabled:(BOOL)enabled { + self.mapView.settings.myLocationButton = enabled; +} + +/// Sets the map style, returing any error string as well as storing that error in `mapStyle` for +/// later access. +- (NSString *)setMapStyle:(NSString *)mapStyle { + NSString *errorString = nil; + if (mapStyle.length == 0) { + self.mapView.mapStyle = nil; + } else { + NSError *error; + GMSMapStyle *style = [GMSMapStyle styleWithJSONString:mapStyle error:&error]; + if (style) { + self.mapView.mapStyle = style; + } else { + errorString = [error localizedDescription]; + } + } + self.styleError = errorString; + return errorString; +} + +#pragma mark - GMSMapViewDelegate methods + +- (void)mapView:(GMSMapView *)mapView willMove:(BOOL)gesture { + [self.dartCallbackHandler didStartCameraMoveWithCompletion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position { + if (self.trackCameraPosition) { + [self.dartCallbackHandler + didMoveCameraToPosition:FGMGetPigeonCameraPositionForPosition(position) + completion:^(FlutterError *_Nullable _){ + }]; + } +} + +- (void)mapView:(GMSMapView *)mapView idleAtCameraPosition:(GMSCameraPosition *)position { + [self.dartCallbackHandler didIdleCameraWithCompletion:^(FlutterError *_Nullable _){ + }]; +} + +- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker { + if ([marker.userData isKindOfClass:[GMUStaticCluster class]]) { + GMUStaticCluster *cluster = marker.userData; + [self.clusterManagersController didTapCluster:cluster]; + // When NO is returned, the map will focus on the cluster. + return NO; + } + return + [self.markersController didTapMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker)]; +} + +- (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker { + [self.markersController + didEndDraggingMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker) + location:marker.position]; +} + +- (void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker { + [self.markersController + didStartDraggingMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker) + location:marker.position]; +} + +- (void)mapView:(GMSMapView *)mapView didDragMarker:(GMSMarker *)marker { + [self.markersController didDragMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker) + location:marker.position]; +} + +- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker { + [self.markersController + didTapInfoWindowOfMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker)]; +} +- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay { + NSString *overlayId = overlay.userData[0]; + if ([self.polylinesController hasPolylineWithIdentifier:overlayId]) { + [self.polylinesController didTapPolylineWithIdentifier:overlayId]; + } else if ([self.polygonsController hasPolygonWithIdentifier:overlayId]) { + [self.polygonsController didTapPolygonWithIdentifier:overlayId]; + } else if ([self.circlesController hasCircleWithIdentifier:overlayId]) { + [self.circlesController didTapCircleWithIdentifier:overlayId]; + } else if ([self.groundOverlaysController hasGroundOverlaysWithIdentifier:overlayId]) { + [self.groundOverlaysController didTapGroundOverlayWithIdentifier:overlayId]; + } +} + +- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { + [self.dartCallbackHandler didTapAtPosition:FGMGetPigeonLatLngForCoordinate(coordinate) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate { + [self.dartCallbackHandler didLongPressAtPosition:FGMGetPigeonLatLngForCoordinate(coordinate) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)interpretMapConfiguration:(FGMPlatformMapConfiguration *)config { + FGMPlatformCameraTargetBounds *cameraTargetBounds = config.cameraTargetBounds; + if (cameraTargetBounds) { + [self setCameraTargetBounds:cameraTargetBounds.bounds + ? FGMGetCoordinateBoundsForPigeonLatLngBounds( + cameraTargetBounds.bounds) + : nil]; + } + NSNumber *compassEnabled = config.compassEnabled; + if (compassEnabled != nil) { + [self setCompassEnabled:compassEnabled.boolValue]; + } + NSNumber *indoorEnabled = config.indoorViewEnabled; + if (indoorEnabled != nil) { + [self setIndoorEnabled:indoorEnabled.boolValue]; + } + NSNumber *trafficEnabled = config.trafficEnabled; + if (trafficEnabled != nil) { + [self setTrafficEnabled:trafficEnabled.boolValue]; + } + NSNumber *buildingsEnabled = config.buildingsEnabled; + if (buildingsEnabled != nil) { + [self setBuildingsEnabled:buildingsEnabled.boolValue]; + } + FGMPlatformMapTypeBox *mapType = config.mapType; + if (mapType) { + [self setMapType:FGMGetMapViewTypeForPigeonMapType(mapType.value)]; + } + FGMPlatformZoomRange *zoomData = config.minMaxZoomPreference; + if (zoomData) { + float minZoom = zoomData.min != nil ? zoomData.min.floatValue : kGMSMinZoomLevel; + float maxZoom = zoomData.max != nil ? zoomData.max.floatValue : kGMSMaxZoomLevel; + [self setMinZoom:minZoom maxZoom:maxZoom]; + } + FGMPlatformEdgeInsets *padding = config.padding; + if (padding) { + [self setPaddingTop:padding.top left:padding.left bottom:padding.bottom right:padding.right]; + } + + NSNumber *rotateGesturesEnabled = config.rotateGesturesEnabled; + if (rotateGesturesEnabled != nil) { + [self setRotateGesturesEnabled:rotateGesturesEnabled.boolValue]; + } + NSNumber *scrollGesturesEnabled = config.scrollGesturesEnabled; + if (scrollGesturesEnabled != nil) { + [self setScrollGesturesEnabled:scrollGesturesEnabled.boolValue]; + } + NSNumber *tiltGesturesEnabled = config.tiltGesturesEnabled; + if (tiltGesturesEnabled != nil) { + [self setTiltGesturesEnabled:tiltGesturesEnabled.boolValue]; + } + NSNumber *trackCameraPosition = config.trackCameraPosition; + if (trackCameraPosition != nil) { + [self setTrackCameraPosition:trackCameraPosition.boolValue]; + } + NSNumber *zoomGesturesEnabled = config.zoomGesturesEnabled; + if (zoomGesturesEnabled != nil) { + [self setZoomGesturesEnabled:zoomGesturesEnabled.boolValue]; + } + NSNumber *myLocationEnabled = config.myLocationEnabled; + if (myLocationEnabled != nil) { + [self setMyLocationEnabled:myLocationEnabled.boolValue]; + } + NSNumber *myLocationButtonEnabled = config.myLocationButtonEnabled; + if (myLocationButtonEnabled != nil) { + [self setMyLocationButtonEnabled:myLocationButtonEnabled.boolValue]; + } + NSString *style = config.style; + if (style) { + [self setMapStyle:style]; + } +} + +@end + +#pragma mark - + +/// Private declarations of the FGMMapCallHandler. +@implementation FGMMapCallHandler + +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix { + self = [super init]; + if (self) { + _controller = controller; + _messenger = messenger; + _pigeonSuffix = suffix; + _transactionWrapper = [[FGMCATransactionWrapper alloc] init]; + } + return self; +} + +- (void)waitForMapWithError:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + // No-op; this call just ensures synchronization with the platform thread. +} + +- (void)updateCirclesByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.circlesController addCircles:toAdd]; + [self.controller.circlesController changeCircles:toChange]; + [self.controller.circlesController removeCirclesWithIdentifiers:idsToRemove]; +} + +- (void)updateHeatmapsByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.heatmapsController addHeatmaps:toAdd]; + [self.controller.heatmapsController changeHeatmaps:toChange]; + [self.controller.heatmapsController removeHeatmapsWithIdentifiers:idsToRemove]; +} + +- (void)updateWithMapConfiguration:(nonnull FGMPlatformMapConfiguration *)configuration + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller interpretMapConfiguration:configuration]; +} + +- (void)updateMarkersByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.markersController addMarkers:toAdd]; + [self.controller.markersController changeMarkers:toChange]; + [self.controller.markersController removeMarkersWithIdentifiers:idsToRemove]; + + // Invoke clustering after markers are added. + [self.controller.clusterManagersController invokeClusteringForEachClusterManager]; +} + +- (void)updateClusterManagersByAdding:(nonnull NSArray *)toAdd + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.clusterManagersController addClusterManagers:toAdd]; + [self.controller.clusterManagersController removeClusterManagersWithIdentifiers:idsToRemove]; +} + +- (void)updatePolygonsByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.polygonsController addPolygons:toAdd]; + [self.controller.polygonsController changePolygons:toChange]; + [self.controller.polygonsController removePolygonWithIdentifiers:idsToRemove]; +} + +- (void)updatePolylinesByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.polylinesController addPolylines:toAdd]; + [self.controller.polylinesController changePolylines:toChange]; + [self.controller.polylinesController removePolylineWithIdentifiers:idsToRemove]; +} + +- (void)updateTileOverlaysByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.tileOverlaysController addTileOverlays:toAdd]; + [self.controller.tileOverlaysController changeTileOverlays:toChange]; + [self.controller.tileOverlaysController removeTileOverlayWithIdentifiers:idsToRemove]; +} + +- (void)updateGroundOverlaysByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.groundOverlaysController addGroundOverlays:toAdd]; + [self.controller.groundOverlaysController changeGroundOverlays:toChange]; + [self.controller.groundOverlaysController removeGroundOverlaysWithIdentifiers:idsToRemove]; +} + +- (nullable FGMPlatformLatLng *) + latLngForScreenCoordinate:(nonnull FGMPlatformPoint *)screenCoordinate + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + if (!self.controller.mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"getLatLng called prior to map initialization" + details:nil]; + return nil; + } + CGPoint point = FGMGetCGPointForPigeonPoint(screenCoordinate); + CLLocationCoordinate2D latlng = [self.controller.mapView.projection coordinateForPoint:point]; + return FGMGetPigeonLatLngForCoordinate(latlng); +} + +- (nullable FGMPlatformPoint *) + screenCoordinatesForLatLng:(nonnull FGMPlatformLatLng *)latLng + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + if (!self.controller.mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"getScreenCoordinate called prior to map initialization" + details:nil]; + return nil; + } + CLLocationCoordinate2D location = FGMGetCoordinateForPigeonLatLng(latLng); + CGPoint point = [self.controller.mapView.projection pointForCoordinate:location]; + return FGMGetPigeonPointForCGPoint(point); +} + +- (nullable FGMPlatformLatLngBounds *)visibleMapRegion: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + if (!self.controller.mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"getVisibleRegion called prior to map initialization" + details:nil]; + return nil; + } + GMSVisibleRegion visibleRegion = self.controller.mapView.projection.visibleRegion; + GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithRegion:visibleRegion]; + return FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds); +} + +- (void)moveCameraWithUpdate:(nonnull FGMPlatformCameraUpdate *)cameraUpdate + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSCameraUpdate *update = FGMGetCameraUpdateForPigeonCameraUpdate(cameraUpdate); + if (!update) { + *error = [FlutterError errorWithCode:@"Invalid update" + message:@"Unrecognized camera update" + details:nil]; + return; + } + [self.controller.mapView moveCamera:update]; +} + +- (void)animateCameraWithUpdate:(nonnull FGMPlatformCameraUpdate *)cameraUpdate + duration:(nullable NSNumber *)durationMilliseconds + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSCameraUpdate *update = FGMGetCameraUpdateForPigeonCameraUpdate(cameraUpdate); + if (!update) { + *error = [FlutterError errorWithCode:@"Invalid update" + message:@"Unrecognized camera update" + details:nil]; + return; + } + FGMCATransactionWrapper *transaction = + durationMilliseconds != nil ? self.transactionWrapper : nil; + [transaction begin]; + [transaction setAnimationDuration:[durationMilliseconds doubleValue] / 1000]; + [self.controller.mapView animateWithCameraUpdate:update]; + [transaction commit]; +} + +- (nullable NSNumber *)currentZoomLevel:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.camera.zoom); +} + +- (void)showInfoWindowForMarkerWithIdentifier:(nonnull NSString *)markerId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + [self.controller.markersController showMarkerInfoWindowWithIdentifier:markerId error:error]; +} + +- (void)hideInfoWindowForMarkerWithIdentifier:(nonnull NSString *)markerId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + [self.controller.markersController hideMarkerInfoWindowWithIdentifier:markerId error:error]; +} + +- (nullable NSNumber *) + isShowingInfoWindowForMarkerWithIdentifier:(nonnull NSString *)markerId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + return [self.controller.markersController isInfoWindowShownForMarkerWithIdentifier:markerId + error:error]; +} + +- (nullable NSString *)setStyle:(nonnull NSString *)style + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [self.controller setMapStyle:style]; +} + +- (nullable NSString *)lastStyleError:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return self.controller.styleError; +} + +- (void)clearTileCacheForOverlayWithIdentifier:(nonnull NSString *)tileOverlayId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + [self.controller.tileOverlaysController clearTileCacheWithIdentifier:tileOverlayId]; +} + +- (nullable FlutterStandardTypedData *)takeSnapshotWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSMapView *mapView = self.controller.mapView; + if (!mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"takeSnapshot called prior to map initialization" + details:nil]; + return nil; + } + UIGraphicsImageRenderer *renderer = + [[UIGraphicsImageRenderer alloc] initWithSize:mapView.bounds.size]; + // For some unknown reason mapView.layer::renderInContext API returns a blank image on iOS 17. + // So we have to use drawViewHierarchyInRect API. + UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *context) { + [mapView drawViewHierarchyInRect:mapView.bounds afterScreenUpdates:YES]; + }]; + NSData *imageData = UIImagePNGRepresentation(image); + return imageData ? [FlutterStandardTypedData typedDataWithBytes:imageData] : nil; +} + +@end + +#pragma mark - + +/// Private declarations of the FGMMapInspector. +@implementation FGMMapInspector + +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix { + self = [super init]; + if (self) { + _controller = controller; + _messenger = messenger; + _pigeonSuffix = suffix; + } + return self; +} + +- (nullable NSNumber *)areBuildingsEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.buildingsEnabled); +} + +- (nullable NSNumber *)areRotateGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.rotateGestures); +} + +- (nullable NSNumber *)areScrollGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.scrollGestures); +} + +- (nullable NSNumber *)areTiltGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.tiltGestures); +} + +- (nullable NSNumber *)areZoomGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.zoomGestures); +} + +- (nullable FGMPlatformTileLayer *) + tileOverlayWithIdentifier:(nonnull NSString *)tileOverlayId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSTileLayer *layer = + [self.controller.tileOverlaysController tileOverlayWithIdentifier:tileOverlayId].layer; + if (!layer) { + return nil; + } + return [FGMPlatformTileLayer makeWithVisible:(layer.map != nil) + fadeIn:layer.fadeIn + opacity:layer.opacity + zIndex:layer.zIndex]; +} + +- (nullable FGMPlatformHeatmap *) + heatmapWithIdentifier:(nonnull NSString *)heatmapId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [self.controller.heatmapsController heatmapWithIdentifier:heatmapId]; +} + +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)clusterManagerId + error:(FlutterError *_Nullable *_Nonnull)error { + return [self.controller.clusterManagersController clustersWithIdentifier:clusterManagerId + error:error]; +} + +- (nullable NSNumber *)isCompassEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.compassButton); +} + +- (nullable NSNumber *)isMyLocationButtonEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.myLocationButton); +} + +- (nullable NSNumber *)isTrafficEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.trafficEnabled); +} + +- (nullable FGMPlatformZoomRange *)zoomRange: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [FGMPlatformZoomRange makeWithMin:@(self.controller.mapView.minZoom) + max:@(self.controller.mapView.maxZoom)]; +} + +- (nullable FGMPlatformGroundOverlay *) + groundOverlayWithIdentifier:(NSString *)groundOverlayId + error:(FlutterError *_Nullable __autoreleasing *)error { + return [self.controller.groundOverlaysController groundOverlayWithIdentifier:groundOverlayId]; +} + +- (nullable FGMPlatformCameraPosition *)cameraPosition: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return FGMGetPigeonCameraPositionForPosition(self.controller.mapView.camera); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapMarkerController.m new file mode 100644 index 000000000000..ed3aabd7fc10 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapMarkerController.m @@ -0,0 +1,343 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapMarkerController.h" +#import "GoogleMapMarkerController_Test.h" + +#import "FGMConversionUtils.h" +#import "FGMImageUtils.h" +#import "FGMMarkerUserData.h" + +@interface FLTGoogleMapMarkerController () + +@property(strong, nonatomic, readwrite) GMSMarker *marker; +@property(weak, nonatomic) GMSMapView *mapView; +@property(assign, nonatomic, readwrite) BOOL consumeTapEvents; +/// The unique identifier for the cluster manager. +@property(copy, nonatomic, nullable) NSString *clusterManagerIdentifier; +/// The unique identifier for the marker. +@property(copy, nonatomic) NSString *markerIdentifier; + +@end + +@implementation FLTGoogleMapMarkerController + +- (instancetype)initWithMarker:(GMSMarker *)marker + markerIdentifier:(NSString *)markerIdentifier + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _marker = marker; + _markerIdentifier = [markerIdentifier copy]; + _mapView = mapView; + } + return self; +} + +- (void)showInfoWindow { + self.mapView.selectedMarker = self.marker; +} + +- (void)hideInfoWindow { + if (self.mapView.selectedMarker == self.marker) { + self.mapView.selectedMarker = nil; + } +} + +- (BOOL)isInfoWindowShown { + return self.mapView.selectedMarker == self.marker; +} + +- (void)removeMarker { + self.marker.map = nil; +} + +- (void)updateFromPlatformMarker:(FGMPlatformMarker *)platformMarker + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale { + self.clusterManagerIdentifier = platformMarker.clusterManagerId; + self.consumeTapEvents = platformMarker.consumeTapEvents; + + // Set the marker's user data with current identifiers. + FGMSetIdentifiersToMarkerUserData(self.markerIdentifier, self.clusterManagerIdentifier, + self.marker); + + // If marker belongs the cluster manager, visibility need to be controlled with the opacity + // as the cluster manager controls when marker is on the map and when not. + BOOL useOpacityForVisibility = self.clusterManagerIdentifier != nil; + [FLTGoogleMapMarkerController updateMarker:self.marker + fromPlatformMarker:platformMarker + withMapView:self.mapView + registrar:registrar + screenScale:screenScale + usingOpacityForVisibility:useOpacityForVisibility]; +} + ++ (void)updateMarker:(GMSMarker *)marker + fromPlatformMarker:(FGMPlatformMarker *)platformMarker + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingOpacityForVisibility:(BOOL)useOpacityForVisibility { + marker.groundAnchor = FGMGetCGPointForPigeonPoint(platformMarker.anchor); + marker.draggable = platformMarker.draggable; + UIImage *image = FGMIconFromBitmap(platformMarker.icon, registrar, screenScale); + marker.icon = image; + marker.flat = platformMarker.flat; + marker.position = FGMGetCoordinateForPigeonLatLng(platformMarker.position); + marker.rotation = platformMarker.rotation; + marker.zIndex = (int)platformMarker.zIndex; + FGMPlatformInfoWindow *infoWindow = platformMarker.infoWindow; + marker.infoWindowAnchor = FGMGetCGPointForPigeonPoint(infoWindow.anchor); + if (infoWindow.title) { + marker.title = infoWindow.title; + marker.snippet = infoWindow.snippet; + } + + // This must be done last, to avoid visual flickers of default property values. + if (useOpacityForVisibility) { + marker.opacity = platformMarker.visible ? platformMarker.alpha : 0.0f; + } else { + marker.opacity = platformMarker.alpha; + marker.map = platformMarker.visible ? mapView : nil; + } +} + +@end + +@interface FLTMarkersController () + +@property(strong, nonatomic, readwrite) NSMutableDictionary *markerIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +/// Controller for adding/removing/fetching cluster managers +@property(weak, nonatomic, nullable) FGMClusterManagersController *clusterManagersController; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTMarkersController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + clusterManagersController:(nullable FGMClusterManagersController *)clusterManagersController + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _clusterManagersController = clusterManagersController; + _markerIdentifierToController = [[NSMutableDictionary alloc] init]; + _registrar = registrar; + } + return self; +} + +- (void)addMarkers:(NSArray *)markersToAdd { + for (FGMPlatformMarker *marker in markersToAdd) { + [self addMarker:marker]; + } +} + +- (void)addMarker:(FGMPlatformMarker *)markerToAdd { + CLLocationCoordinate2D position = FGMGetCoordinateForPigeonLatLng(markerToAdd.position); + NSString *markerIdentifier = markerToAdd.markerId; + NSString *clusterManagerIdentifier = markerToAdd.clusterManagerId; + GMSMarker *marker = [GMSMarker markerWithPosition:position]; + FLTGoogleMapMarkerController *controller = + [[FLTGoogleMapMarkerController alloc] initWithMarker:marker + markerIdentifier:markerIdentifier + mapView:self.mapView]; + [controller updateFromPlatformMarker:markerToAdd + registrar:self.registrar + screenScale:[self getScreenScale]]; + if (clusterManagerIdentifier) { + GMUClusterManager *clusterManager = + [_clusterManagersController clusterManagerWithIdentifier:clusterManagerIdentifier]; + if ([marker conformsToProtocol:@protocol(GMUClusterItem)]) { + [clusterManager addItem:(id)marker]; + } + } + self.markerIdentifierToController[markerIdentifier] = controller; +} + +- (void)changeMarkers:(NSArray *)markersToChange { + for (FGMPlatformMarker *marker in markersToChange) { + [self changeMarker:marker]; + } +} + +- (void)changeMarker:(FGMPlatformMarker *)markerToChange { + NSString *markerIdentifier = markerToChange.markerId; + + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[markerIdentifier]; + if (!controller) { + return; + } + + NSString *clusterManagerIdentifier = markerToChange.clusterManagerId; + NSString *previousClusterManagerIdentifier = [controller clusterManagerIdentifier]; + [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]; + } + } +} + +- (void)removeMarkersWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + [self removeMarker:identifier]; + } +} + +- (void)removeMarker:(NSString *)identifier { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + NSString *clusterManagerIdentifier = [controller clusterManagerIdentifier]; + if (clusterManagerIdentifier) { + GMUClusterManager *clusterManager = + [_clusterManagersController clusterManagerWithIdentifier:clusterManagerIdentifier]; + [clusterManager removeItem:(id)controller.marker]; + } else { + [controller removeMarker]; + } + [self.markerIdentifierToController removeObjectForKey:identifier]; +} + +- (BOOL)didTapMarkerWithIdentifier:(NSString *)identifier { + if (!identifier) { + return NO; + } + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return NO; + } + [self.callbackHandler didTapMarkerWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; + return controller.consumeTapEvents; +} + +- (void)didStartDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + if (!identifier) { + return; + } + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler + didStartDragForMarkerWithIdentifier:identifier + atPosition:FGMGetPigeonLatLngForCoordinate(location) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)didDragMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + if (!identifier) { + return; + } + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didDragMarkerWithIdentifier:identifier + atPosition:FGMGetPigeonLatLngForCoordinate(location) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)didEndDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didEndDragForMarkerWithIdentifier:identifier + atPosition:FGMGetPigeonLatLngForCoordinate(location) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)identifier { + if (identifier && self.markerIdentifierToController[identifier]) { + [self.callbackHandler didTapInfoWindowOfMarkerWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; + } +} + +- (void)showMarkerInfoWindowWithIdentifier:(NSString *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (controller) { + [controller showInfoWindow]; + } else { + *error = [FlutterError errorWithCode:@"Invalid markerId" + message:@"showInfoWindow called with invalid markerId" + details:nil]; + } +} + +- (void)hideMarkerInfoWindowWithIdentifier:(NSString *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (controller) { + [controller hideInfoWindow]; + } else { + *error = [FlutterError errorWithCode:@"Invalid markerId" + message:@"hideInfoWindow called with invalid markerId" + details:nil]; + } +} + +- (nullable NSNumber *) + isInfoWindowShownForMarkerWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (controller) { + return @([controller isInfoWindowShown]); + } else { + *error = [FlutterError errorWithCode:@"Invalid markerId" + message:@"isInfoWindowShown called with invalid markerId" + details:nil]; + return nil; + } +} + +- (CGFloat)getScreenScale { + // TODO(jokerttu): This method is called on marker creation, which, for initial markers, is done + // before the view is added to the view hierarchy. This means that the traitCollection values may + // not be matching the right display where the map is finally shown. The solution should be + // revisited after the proper way to fetch the display scale is resolved for platform views. This + // should be done under the context of the following issue: + // https://github.com/flutter/flutter/issues/125496. + return self.mapView.traitCollection.displayScale; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapPolygonController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapPolygonController.m new file mode 100644 index 000000000000..12cbfeefecd7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapPolygonController.m @@ -0,0 +1,146 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolygonController.h" +#import "GoogleMapPolygonController_Test.h" + +#import "FGMConversionUtils.h" + +/// Converts a list of holes represented as CLLocation lists to GMSMutablePath lists. +static NSArray *FMGPathHolesFromLocationHoles( + NSArray *> *locationHoles) { + NSMutableArray *pathHoles = + [NSMutableArray arrayWithCapacity:locationHoles.count]; + for (NSArray *hole in locationHoles) { + [pathHoles addObject:FGMGetPathFromPoints(hole)]; + } + return pathHoles; +} + +@interface FLTGoogleMapPolygonController () + +@property(strong, nonatomic) GMSPolygon *polygon; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapPolygonController + +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _polygon = [GMSPolygon polygonWithPath:path]; + _mapView = mapView; + _polygon.userData = @[ identifier ]; + } + return self; +} + +- (void)removePolygon { + self.polygon.map = nil; +} + +- (void)updateFromPlatformPolygon:(FGMPlatformPolygon *)polygon { + [FLTGoogleMapPolygonController updatePolygon:self.polygon + fromPlatformPolygon:polygon + withMapView:self.mapView]; +} + ++ (void)updatePolygon:(GMSPolygon *)polygon + fromPlatformPolygon:(FGMPlatformPolygon *)platformPolygon + withMapView:(GMSMapView *)mapView { + polygon.tappable = platformPolygon.consumesTapEvents; + polygon.zIndex = (int)platformPolygon.zIndex; + polygon.path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(platformPolygon.points)); + polygon.holes = + FMGPathHolesFromLocationHoles(FGMGetHolesForPigeonLatLngArrays(platformPolygon.holes)); + polygon.fillColor = FGMGetColorForPigeonColor(platformPolygon.fillColor); + polygon.strokeColor = FGMGetColorForPigeonColor(platformPolygon.strokeColor); + polygon.strokeWidth = platformPolygon.strokeWidth; + + // This must be done last, to avoid visual flickers of default property values. + polygon.map = platformPolygon.visible ? mapView : nil; +} + +@end + +@interface FLTPolygonsController () + +@property(strong, nonatomic) NSMutableDictionary *polygonIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTPolygonsController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _polygonIdentifierToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _registrar = registrar; + } + return self; +} + +- (void)addPolygons:(NSArray *)polygonsToAdd { + for (FGMPlatformPolygon *polygon in polygonsToAdd) { + GMSMutablePath *path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(polygon.points)); + NSString *identifier = polygon.polygonId; + FLTGoogleMapPolygonController *controller = + [[FLTGoogleMapPolygonController alloc] initWithPath:path + identifier:identifier + mapView:self.mapView]; + [controller updateFromPlatformPolygon:polygon]; + self.polygonIdentifierToController[identifier] = controller; + } +} + +- (void)changePolygons:(NSArray *)polygonsToChange { + for (FGMPlatformPolygon *polygon in polygonsToChange) { + NSString *identifier = polygon.polygonId; + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; + [controller updateFromPlatformPolygon:polygon]; + } +} + +- (void)removePolygonWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; + if (!controller) { + continue; + } + [controller removePolygon]; + [self.polygonIdentifierToController removeObjectForKey:identifier]; + } +} + +- (void)didTapPolygonWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapPolygonWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (bool)hasPolygonWithIdentifier:(NSString *)identifier { + if (!identifier) { + return false; + } + return self.polygonIdentifierToController[identifier] != nil; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapPolylineController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapPolylineController.m new file mode 100644 index 000000000000..63a7f7b7b0fc --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapPolylineController.m @@ -0,0 +1,140 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolylineController.h" +#import "GoogleMapPolylineController_Test.h" + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapPolylineController () + +@property(strong, nonatomic) GMSPolyline *polyline; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapPolylineController + +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _polyline = [GMSPolyline polylineWithPath:path]; + _mapView = mapView; + _polyline.userData = @[ identifier ]; + } + return self; +} + +- (void)removePolyline { + self.polyline.map = nil; +} + +- (void)updateFromPlatformPolyline:(FGMPlatformPolyline *)polyline { + [FLTGoogleMapPolylineController updatePolyline:self.polyline + fromPlatformPolyline:polyline + withMapView:self.mapView]; +} + ++ (void)updatePolyline:(GMSPolyline *)polyline + fromPlatformPolyline:(FGMPlatformPolyline *)platformPolyline + withMapView:(GMSMapView *)mapView { + polyline.tappable = platformPolyline.consumesTapEvents; + polyline.zIndex = (int)platformPolyline.zIndex; + GMSMutablePath *path = + FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(platformPolyline.points)); + polyline.path = path; + UIColor *strokeColor = FGMGetColorForPigeonColor(platformPolyline.color); + polyline.strokeColor = strokeColor; + polyline.strokeWidth = platformPolyline.width; + polyline.geodesic = platformPolyline.geodesic; + polyline.spans = + GMSStyleSpans(path, FGMGetStrokeStylesFromPatterns(platformPolyline.patterns, strokeColor), + FGMGetSpanLengthsFromPatterns(platformPolyline.patterns), kGMSLengthRhumb); + + // This must be done last, to avoid visual flickers of default property values. + polyline.map = platformPolyline.visible ? mapView : nil; +} + +@end + +@interface FLTPolylinesController () + +@property(strong, nonatomic) NSMutableDictionary *polylineIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end +; + +@implementation FLTPolylinesController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _polylineIdentifierToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _registrar = registrar; + } + return self; +} + +- (void)addPolylines:(NSArray *)polylinesToAdd { + for (FGMPlatformPolyline *polyline in polylinesToAdd) { + GMSMutablePath *path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(polyline.points)); + NSString *identifier = polyline.polylineId; + FLTGoogleMapPolylineController *controller = + [[FLTGoogleMapPolylineController alloc] initWithPath:path + identifier:identifier + mapView:self.mapView]; + [controller updateFromPlatformPolyline:polyline]; + self.polylineIdentifierToController[identifier] = controller; + } +} + +- (void)changePolylines:(NSArray *)polylinesToChange { + for (FGMPlatformPolyline *polyline in polylinesToChange) { + NSString *identifier = polyline.polylineId; + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; + [controller updateFromPlatformPolyline:polyline]; + } +} + +- (void)removePolylineWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; + if (!controller) { + continue; + } + [controller removePolyline]; + [self.polylineIdentifierToController removeObjectForKey:identifier]; + } +} + +- (void)didTapPolylineWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapPolylineWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (bool)hasPolylineWithIdentifier:(NSString *)identifier { + if (!identifier) { + return false; + } + return self.polylineIdentifierToController[identifier] != nil; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.m new file mode 100644 index 000000000000..e833e2f24f42 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.m @@ -0,0 +1,3446 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#import "google_maps_flutter_pigeon_messages.g.h" + +#if TARGET_OS_OSX +#import +#else +#import +#endif + +#if !__has_feature(objc_arc) +#error File requires ARC to be enabled. +#endif + +static NSArray *wrapResult(id result, FlutterError *error) { + if (error) { + return @[ + error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null] + ]; + } + return @[ result ?: [NSNull null] ]; +} + +static FlutterError *createConnectionError(NSString *channelName) { + return [FlutterError + errorWithCode:@"channel-error" + message:[NSString stringWithFormat:@"%@/%@/%@", + @"Unable to establish connection on channel: '", + channelName, @"'."] + details:@""]; +} + +static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { + id result = array[key]; + return (result == [NSNull null]) ? nil : result; +} + +/// Pigeon equivalent of MapType +@implementation FGMPlatformMapTypeBox +- (instancetype)initWithValue:(FGMPlatformMapType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +/// Join types for polyline joints. +@implementation FGMPlatformJointTypeBox +- (instancetype)initWithValue:(FGMPlatformJointType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +/// Enumeration of possible types for PatternItem. +@implementation FGMPlatformPatternItemTypeBox +- (instancetype)initWithValue:(FGMPlatformPatternItemType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +/// Pigeon equivalent of [MapBitmapScaling]. +@implementation FGMPlatformMapBitmapScalingBox +- (instancetype)initWithValue:(FGMPlatformMapBitmapScaling)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +@interface FGMPlatformCameraPosition () ++ (FGMPlatformCameraPosition *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraPosition *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdate () ++ (FGMPlatformCameraUpdate *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdate *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewCameraPosition () ++ (FGMPlatformCameraUpdateNewCameraPosition *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewCameraPosition *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewLatLng () ++ (FGMPlatformCameraUpdateNewLatLng *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewLatLng *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewLatLngBounds () ++ (FGMPlatformCameraUpdateNewLatLngBounds *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewLatLngBounds *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewLatLngZoom () ++ (FGMPlatformCameraUpdateNewLatLngZoom *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewLatLngZoom *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateScrollBy () ++ (FGMPlatformCameraUpdateScrollBy *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateScrollBy *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateZoomBy () ++ (FGMPlatformCameraUpdateZoomBy *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateZoomBy *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateZoom () ++ (FGMPlatformCameraUpdateZoom *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateZoom *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateZoomTo () ++ (FGMPlatformCameraUpdateZoomTo *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateZoomTo *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCircle () ++ (FGMPlatformCircle *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCircle *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformHeatmap () ++ (FGMPlatformHeatmap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformHeatmap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformHeatmapGradient () ++ (FGMPlatformHeatmapGradient *)fromList:(NSArray *)list; ++ (nullable FGMPlatformHeatmapGradient *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformWeightedLatLng () ++ (FGMPlatformWeightedLatLng *)fromList:(NSArray *)list; ++ (nullable FGMPlatformWeightedLatLng *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformInfoWindow () ++ (FGMPlatformInfoWindow *)fromList:(NSArray *)list; ++ (nullable FGMPlatformInfoWindow *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCluster () ++ (FGMPlatformCluster *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCluster *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformClusterManager () ++ (FGMPlatformClusterManager *)fromList:(NSArray *)list; ++ (nullable FGMPlatformClusterManager *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformMarker () ++ (FGMPlatformMarker *)fromList:(NSArray *)list; ++ (nullable FGMPlatformMarker *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPolygon () ++ (FGMPlatformPolygon *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPolygon *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPolyline () ++ (FGMPlatformPolyline *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPolyline *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPatternItem () ++ (FGMPlatformPatternItem *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPatternItem *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformTile () ++ (FGMPlatformTile *)fromList:(NSArray *)list; ++ (nullable FGMPlatformTile *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformTileOverlay () ++ (FGMPlatformTileOverlay *)fromList:(NSArray *)list; ++ (nullable FGMPlatformTileOverlay *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformEdgeInsets () ++ (FGMPlatformEdgeInsets *)fromList:(NSArray *)list; ++ (nullable FGMPlatformEdgeInsets *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformLatLng () ++ (FGMPlatformLatLng *)fromList:(NSArray *)list; ++ (nullable FGMPlatformLatLng *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformLatLngBounds () ++ (FGMPlatformLatLngBounds *)fromList:(NSArray *)list; ++ (nullable FGMPlatformLatLngBounds *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraTargetBounds () ++ (FGMPlatformCameraTargetBounds *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraTargetBounds *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformGroundOverlay () ++ (FGMPlatformGroundOverlay *)fromList:(NSArray *)list; ++ (nullable FGMPlatformGroundOverlay *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformMapViewCreationParams () ++ (FGMPlatformMapViewCreationParams *)fromList:(NSArray *)list; ++ (nullable FGMPlatformMapViewCreationParams *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformMapConfiguration () ++ (FGMPlatformMapConfiguration *)fromList:(NSArray *)list; ++ (nullable FGMPlatformMapConfiguration *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPoint () ++ (FGMPlatformPoint *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPoint *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformSize () ++ (FGMPlatformSize *)fromList:(NSArray *)list; ++ (nullable FGMPlatformSize *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformColor () ++ (FGMPlatformColor *)fromList:(NSArray *)list; ++ (nullable FGMPlatformColor *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformTileLayer () ++ (FGMPlatformTileLayer *)fromList:(NSArray *)list; ++ (nullable FGMPlatformTileLayer *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformZoomRange () ++ (FGMPlatformZoomRange *)fromList:(NSArray *)list; ++ (nullable FGMPlatformZoomRange *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmap () ++ (FGMPlatformBitmap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapDefaultMarker () ++ (FGMPlatformBitmapDefaultMarker *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapDefaultMarker *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapBytes () ++ (FGMPlatformBitmapBytes *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapBytes *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapAsset () ++ (FGMPlatformBitmapAsset *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapAsset *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapAssetImage () ++ (FGMPlatformBitmapAssetImage *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapAssetImage *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapAssetMap () ++ (FGMPlatformBitmapAssetMap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapAssetMap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapBytesMap () ++ (FGMPlatformBitmapBytesMap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapBytesMap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@implementation FGMPlatformCameraPosition ++ (instancetype)makeWithBearing:(double)bearing + target:(FGMPlatformLatLng *)target + tilt:(double)tilt + zoom:(double)zoom { + FGMPlatformCameraPosition *pigeonResult = [[FGMPlatformCameraPosition alloc] init]; + pigeonResult.bearing = bearing; + pigeonResult.target = target; + pigeonResult.tilt = tilt; + pigeonResult.zoom = zoom; + return pigeonResult; +} ++ (FGMPlatformCameraPosition *)fromList:(NSArray *)list { + FGMPlatformCameraPosition *pigeonResult = [[FGMPlatformCameraPosition alloc] init]; + pigeonResult.bearing = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.target = GetNullableObjectAtIndex(list, 1); + pigeonResult.tilt = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.zoom = [GetNullableObjectAtIndex(list, 3) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraPosition *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraPosition fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.bearing), + self.target ?: [NSNull null], + @(self.tilt), + @(self.zoom), + ]; +} +@end + +@implementation FGMPlatformCameraUpdate ++ (instancetype)makeWithCameraUpdate:(id)cameraUpdate { + FGMPlatformCameraUpdate *pigeonResult = [[FGMPlatformCameraUpdate alloc] init]; + pigeonResult.cameraUpdate = cameraUpdate; + return pigeonResult; +} ++ (FGMPlatformCameraUpdate *)fromList:(NSArray *)list { + FGMPlatformCameraUpdate *pigeonResult = [[FGMPlatformCameraUpdate alloc] init]; + pigeonResult.cameraUpdate = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdate *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdate fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.cameraUpdate ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewCameraPosition ++ (instancetype)makeWithCameraPosition:(FGMPlatformCameraPosition *)cameraPosition { + FGMPlatformCameraUpdateNewCameraPosition *pigeonResult = + [[FGMPlatformCameraUpdateNewCameraPosition alloc] init]; + pigeonResult.cameraPosition = cameraPosition; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewCameraPosition *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewCameraPosition *pigeonResult = + [[FGMPlatformCameraUpdateNewCameraPosition alloc] init]; + pigeonResult.cameraPosition = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewCameraPosition *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewCameraPosition fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.cameraPosition ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewLatLng ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng { + FGMPlatformCameraUpdateNewLatLng *pigeonResult = [[FGMPlatformCameraUpdateNewLatLng alloc] init]; + pigeonResult.latLng = latLng; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewLatLng *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewLatLng *pigeonResult = [[FGMPlatformCameraUpdateNewLatLng alloc] init]; + pigeonResult.latLng = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewLatLng *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewLatLng fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.latLng ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewLatLngBounds ++ (instancetype)makeWithBounds:(FGMPlatformLatLngBounds *)bounds padding:(double)padding { + FGMPlatformCameraUpdateNewLatLngBounds *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngBounds alloc] init]; + pigeonResult.bounds = bounds; + pigeonResult.padding = padding; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewLatLngBounds *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewLatLngBounds *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngBounds alloc] init]; + pigeonResult.bounds = GetNullableObjectAtIndex(list, 0); + pigeonResult.padding = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewLatLngBounds *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewLatLngBounds fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.bounds ?: [NSNull null], + @(self.padding), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewLatLngZoom ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng zoom:(double)zoom { + FGMPlatformCameraUpdateNewLatLngZoom *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngZoom alloc] init]; + pigeonResult.latLng = latLng; + pigeonResult.zoom = zoom; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewLatLngZoom *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewLatLngZoom *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngZoom alloc] init]; + pigeonResult.latLng = GetNullableObjectAtIndex(list, 0); + pigeonResult.zoom = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewLatLngZoom *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewLatLngZoom fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.latLng ?: [NSNull null], + @(self.zoom), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateScrollBy ++ (instancetype)makeWithDx:(double)dx dy:(double)dy { + FGMPlatformCameraUpdateScrollBy *pigeonResult = [[FGMPlatformCameraUpdateScrollBy alloc] init]; + pigeonResult.dx = dx; + pigeonResult.dy = dy; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateScrollBy *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateScrollBy *pigeonResult = [[FGMPlatformCameraUpdateScrollBy alloc] init]; + pigeonResult.dx = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.dy = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateScrollBy *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateScrollBy fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.dx), + @(self.dy), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateZoomBy ++ (instancetype)makeWithAmount:(double)amount focus:(nullable FGMPlatformPoint *)focus { + FGMPlatformCameraUpdateZoomBy *pigeonResult = [[FGMPlatformCameraUpdateZoomBy alloc] init]; + pigeonResult.amount = amount; + pigeonResult.focus = focus; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateZoomBy *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateZoomBy *pigeonResult = [[FGMPlatformCameraUpdateZoomBy alloc] init]; + pigeonResult.amount = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.focus = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateZoomBy *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateZoomBy fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.amount), + self.focus ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateZoom ++ (instancetype)makeWithOut:(BOOL)out { + FGMPlatformCameraUpdateZoom *pigeonResult = [[FGMPlatformCameraUpdateZoom alloc] init]; + pigeonResult.out = out; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateZoom *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateZoom *pigeonResult = [[FGMPlatformCameraUpdateZoom alloc] init]; + pigeonResult.out = [GetNullableObjectAtIndex(list, 0) boolValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateZoom *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateZoom fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.out), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateZoomTo ++ (instancetype)makeWithZoom:(double)zoom { + FGMPlatformCameraUpdateZoomTo *pigeonResult = [[FGMPlatformCameraUpdateZoomTo alloc] init]; + pigeonResult.zoom = zoom; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateZoomTo *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateZoomTo *pigeonResult = [[FGMPlatformCameraUpdateZoomTo alloc] init]; + pigeonResult.zoom = [GetNullableObjectAtIndex(list, 0) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateZoomTo *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateZoomTo fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.zoom), + ]; +} +@end + +@implementation FGMPlatformCircle ++ (instancetype)makeWithConsumeTapEvents:(BOOL)consumeTapEvents + fillColor:(FGMPlatformColor *)fillColor + strokeColor:(FGMPlatformColor *)strokeColor + visible:(BOOL)visible + strokeWidth:(NSInteger)strokeWidth + zIndex:(double)zIndex + center:(FGMPlatformLatLng *)center + radius:(double)radius + circleId:(NSString *)circleId { + FGMPlatformCircle *pigeonResult = [[FGMPlatformCircle alloc] init]; + pigeonResult.consumeTapEvents = consumeTapEvents; + pigeonResult.fillColor = fillColor; + pigeonResult.strokeColor = strokeColor; + pigeonResult.visible = visible; + pigeonResult.strokeWidth = strokeWidth; + pigeonResult.zIndex = zIndex; + pigeonResult.center = center; + pigeonResult.radius = radius; + pigeonResult.circleId = circleId; + return pigeonResult; +} ++ (FGMPlatformCircle *)fromList:(NSArray *)list { + FGMPlatformCircle *pigeonResult = [[FGMPlatformCircle alloc] init]; + pigeonResult.consumeTapEvents = [GetNullableObjectAtIndex(list, 0) boolValue]; + pigeonResult.fillColor = GetNullableObjectAtIndex(list, 1); + pigeonResult.strokeColor = GetNullableObjectAtIndex(list, 2); + pigeonResult.visible = [GetNullableObjectAtIndex(list, 3) boolValue]; + pigeonResult.strokeWidth = [GetNullableObjectAtIndex(list, 4) integerValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 5) doubleValue]; + pigeonResult.center = GetNullableObjectAtIndex(list, 6); + pigeonResult.radius = [GetNullableObjectAtIndex(list, 7) doubleValue]; + pigeonResult.circleId = GetNullableObjectAtIndex(list, 8); + return pigeonResult; +} ++ (nullable FGMPlatformCircle *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCircle fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.consumeTapEvents), + self.fillColor ?: [NSNull null], + self.strokeColor ?: [NSNull null], + @(self.visible), + @(self.strokeWidth), + @(self.zIndex), + self.center ?: [NSNull null], + @(self.radius), + self.circleId ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformHeatmap ++ (instancetype)makeWithHeatmapId:(NSString *)heatmapId + data:(NSArray *)data + gradient:(nullable FGMPlatformHeatmapGradient *)gradient + opacity:(double)opacity + radius:(NSInteger)radius + minimumZoomIntensity:(NSInteger)minimumZoomIntensity + maximumZoomIntensity:(NSInteger)maximumZoomIntensity { + FGMPlatformHeatmap *pigeonResult = [[FGMPlatformHeatmap alloc] init]; + pigeonResult.heatmapId = heatmapId; + pigeonResult.data = data; + pigeonResult.gradient = gradient; + pigeonResult.opacity = opacity; + pigeonResult.radius = radius; + pigeonResult.minimumZoomIntensity = minimumZoomIntensity; + pigeonResult.maximumZoomIntensity = maximumZoomIntensity; + return pigeonResult; +} ++ (FGMPlatformHeatmap *)fromList:(NSArray *)list { + FGMPlatformHeatmap *pigeonResult = [[FGMPlatformHeatmap alloc] init]; + pigeonResult.heatmapId = GetNullableObjectAtIndex(list, 0); + pigeonResult.data = GetNullableObjectAtIndex(list, 1); + pigeonResult.gradient = GetNullableObjectAtIndex(list, 2); + pigeonResult.opacity = [GetNullableObjectAtIndex(list, 3) doubleValue]; + pigeonResult.radius = [GetNullableObjectAtIndex(list, 4) integerValue]; + pigeonResult.minimumZoomIntensity = [GetNullableObjectAtIndex(list, 5) integerValue]; + pigeonResult.maximumZoomIntensity = [GetNullableObjectAtIndex(list, 6) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformHeatmap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformHeatmap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.heatmapId ?: [NSNull null], + self.data ?: [NSNull null], + self.gradient ?: [NSNull null], + @(self.opacity), + @(self.radius), + @(self.minimumZoomIntensity), + @(self.maximumZoomIntensity), + ]; +} +@end + +@implementation FGMPlatformHeatmapGradient ++ (instancetype)makeWithColors:(NSArray *)colors + startPoints:(NSArray *)startPoints + colorMapSize:(NSInteger)colorMapSize { + FGMPlatformHeatmapGradient *pigeonResult = [[FGMPlatformHeatmapGradient alloc] init]; + pigeonResult.colors = colors; + pigeonResult.startPoints = startPoints; + pigeonResult.colorMapSize = colorMapSize; + return pigeonResult; +} ++ (FGMPlatformHeatmapGradient *)fromList:(NSArray *)list { + FGMPlatformHeatmapGradient *pigeonResult = [[FGMPlatformHeatmapGradient alloc] init]; + pigeonResult.colors = GetNullableObjectAtIndex(list, 0); + pigeonResult.startPoints = GetNullableObjectAtIndex(list, 1); + pigeonResult.colorMapSize = [GetNullableObjectAtIndex(list, 2) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformHeatmapGradient *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformHeatmapGradient fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.colors ?: [NSNull null], + self.startPoints ?: [NSNull null], + @(self.colorMapSize), + ]; +} +@end + +@implementation FGMPlatformWeightedLatLng ++ (instancetype)makeWithPoint:(FGMPlatformLatLng *)point weight:(double)weight { + FGMPlatformWeightedLatLng *pigeonResult = [[FGMPlatformWeightedLatLng alloc] init]; + pigeonResult.point = point; + pigeonResult.weight = weight; + return pigeonResult; +} ++ (FGMPlatformWeightedLatLng *)fromList:(NSArray *)list { + FGMPlatformWeightedLatLng *pigeonResult = [[FGMPlatformWeightedLatLng alloc] init]; + pigeonResult.point = GetNullableObjectAtIndex(list, 0); + pigeonResult.weight = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformWeightedLatLng *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformWeightedLatLng fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.point ?: [NSNull null], + @(self.weight), + ]; +} +@end + +@implementation FGMPlatformInfoWindow ++ (instancetype)makeWithTitle:(nullable NSString *)title + snippet:(nullable NSString *)snippet + anchor:(FGMPlatformPoint *)anchor { + FGMPlatformInfoWindow *pigeonResult = [[FGMPlatformInfoWindow alloc] init]; + pigeonResult.title = title; + pigeonResult.snippet = snippet; + pigeonResult.anchor = anchor; + return pigeonResult; +} ++ (FGMPlatformInfoWindow *)fromList:(NSArray *)list { + FGMPlatformInfoWindow *pigeonResult = [[FGMPlatformInfoWindow alloc] init]; + pigeonResult.title = GetNullableObjectAtIndex(list, 0); + pigeonResult.snippet = GetNullableObjectAtIndex(list, 1); + pigeonResult.anchor = GetNullableObjectAtIndex(list, 2); + return pigeonResult; +} ++ (nullable FGMPlatformInfoWindow *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformInfoWindow fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.title ?: [NSNull null], + self.snippet ?: [NSNull null], + self.anchor ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCluster ++ (instancetype)makeWithClusterManagerId:(NSString *)clusterManagerId + position:(FGMPlatformLatLng *)position + bounds:(FGMPlatformLatLngBounds *)bounds + markerIds:(NSArray *)markerIds { + FGMPlatformCluster *pigeonResult = [[FGMPlatformCluster alloc] init]; + pigeonResult.clusterManagerId = clusterManagerId; + pigeonResult.position = position; + pigeonResult.bounds = bounds; + pigeonResult.markerIds = markerIds; + return pigeonResult; +} ++ (FGMPlatformCluster *)fromList:(NSArray *)list { + FGMPlatformCluster *pigeonResult = [[FGMPlatformCluster alloc] init]; + pigeonResult.clusterManagerId = GetNullableObjectAtIndex(list, 0); + pigeonResult.position = GetNullableObjectAtIndex(list, 1); + pigeonResult.bounds = GetNullableObjectAtIndex(list, 2); + pigeonResult.markerIds = GetNullableObjectAtIndex(list, 3); + return pigeonResult; +} ++ (nullable FGMPlatformCluster *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCluster fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.clusterManagerId ?: [NSNull null], + self.position ?: [NSNull null], + self.bounds ?: [NSNull null], + self.markerIds ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformClusterManager ++ (instancetype)makeWithIdentifier:(NSString *)identifier { + FGMPlatformClusterManager *pigeonResult = [[FGMPlatformClusterManager alloc] init]; + pigeonResult.identifier = identifier; + return pigeonResult; +} ++ (FGMPlatformClusterManager *)fromList:(NSArray *)list { + FGMPlatformClusterManager *pigeonResult = [[FGMPlatformClusterManager alloc] init]; + pigeonResult.identifier = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformClusterManager *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformClusterManager fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.identifier ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformMarker ++ (instancetype)makeWithAlpha:(double)alpha + anchor:(FGMPlatformPoint *)anchor + consumeTapEvents:(BOOL)consumeTapEvents + draggable:(BOOL)draggable + flat:(BOOL)flat + icon:(FGMPlatformBitmap *)icon + infoWindow:(FGMPlatformInfoWindow *)infoWindow + position:(FGMPlatformLatLng *)position + rotation:(double)rotation + visible:(BOOL)visible + zIndex:(NSInteger)zIndex + markerId:(NSString *)markerId + clusterManagerId:(nullable NSString *)clusterManagerId { + FGMPlatformMarker *pigeonResult = [[FGMPlatformMarker alloc] init]; + pigeonResult.alpha = alpha; + pigeonResult.anchor = anchor; + pigeonResult.consumeTapEvents = consumeTapEvents; + pigeonResult.draggable = draggable; + pigeonResult.flat = flat; + pigeonResult.icon = icon; + pigeonResult.infoWindow = infoWindow; + pigeonResult.position = position; + pigeonResult.rotation = rotation; + pigeonResult.visible = visible; + pigeonResult.zIndex = zIndex; + pigeonResult.markerId = markerId; + pigeonResult.clusterManagerId = clusterManagerId; + return pigeonResult; +} ++ (FGMPlatformMarker *)fromList:(NSArray *)list { + FGMPlatformMarker *pigeonResult = [[FGMPlatformMarker alloc] init]; + pigeonResult.alpha = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.anchor = GetNullableObjectAtIndex(list, 1); + pigeonResult.consumeTapEvents = [GetNullableObjectAtIndex(list, 2) boolValue]; + pigeonResult.draggable = [GetNullableObjectAtIndex(list, 3) boolValue]; + pigeonResult.flat = [GetNullableObjectAtIndex(list, 4) boolValue]; + pigeonResult.icon = GetNullableObjectAtIndex(list, 5); + pigeonResult.infoWindow = GetNullableObjectAtIndex(list, 6); + pigeonResult.position = GetNullableObjectAtIndex(list, 7); + pigeonResult.rotation = [GetNullableObjectAtIndex(list, 8) doubleValue]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 9) boolValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 10) integerValue]; + pigeonResult.markerId = GetNullableObjectAtIndex(list, 11); + pigeonResult.clusterManagerId = GetNullableObjectAtIndex(list, 12); + return pigeonResult; +} ++ (nullable FGMPlatformMarker *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformMarker fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.alpha), + self.anchor ?: [NSNull null], + @(self.consumeTapEvents), + @(self.draggable), + @(self.flat), + self.icon ?: [NSNull null], + self.infoWindow ?: [NSNull null], + self.position ?: [NSNull null], + @(self.rotation), + @(self.visible), + @(self.zIndex), + self.markerId ?: [NSNull null], + self.clusterManagerId ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformPolygon ++ (instancetype)makeWithPolygonId:(NSString *)polygonId + consumesTapEvents:(BOOL)consumesTapEvents + fillColor:(FGMPlatformColor *)fillColor + geodesic:(BOOL)geodesic + points:(NSArray *)points + holes:(NSArray *> *)holes + visible:(BOOL)visible + strokeColor:(FGMPlatformColor *)strokeColor + strokeWidth:(NSInteger)strokeWidth + zIndex:(NSInteger)zIndex { + FGMPlatformPolygon *pigeonResult = [[FGMPlatformPolygon alloc] init]; + pigeonResult.polygonId = polygonId; + pigeonResult.consumesTapEvents = consumesTapEvents; + pigeonResult.fillColor = fillColor; + pigeonResult.geodesic = geodesic; + pigeonResult.points = points; + pigeonResult.holes = holes; + pigeonResult.visible = visible; + pigeonResult.strokeColor = strokeColor; + pigeonResult.strokeWidth = strokeWidth; + pigeonResult.zIndex = zIndex; + return pigeonResult; +} ++ (FGMPlatformPolygon *)fromList:(NSArray *)list { + FGMPlatformPolygon *pigeonResult = [[FGMPlatformPolygon alloc] init]; + pigeonResult.polygonId = GetNullableObjectAtIndex(list, 0); + pigeonResult.consumesTapEvents = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.fillColor = GetNullableObjectAtIndex(list, 2); + pigeonResult.geodesic = [GetNullableObjectAtIndex(list, 3) boolValue]; + pigeonResult.points = GetNullableObjectAtIndex(list, 4); + pigeonResult.holes = GetNullableObjectAtIndex(list, 5); + pigeonResult.visible = [GetNullableObjectAtIndex(list, 6) boolValue]; + pigeonResult.strokeColor = GetNullableObjectAtIndex(list, 7); + pigeonResult.strokeWidth = [GetNullableObjectAtIndex(list, 8) integerValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 9) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformPolygon *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPolygon fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.polygonId ?: [NSNull null], + @(self.consumesTapEvents), + self.fillColor ?: [NSNull null], + @(self.geodesic), + self.points ?: [NSNull null], + self.holes ?: [NSNull null], + @(self.visible), + self.strokeColor ?: [NSNull null], + @(self.strokeWidth), + @(self.zIndex), + ]; +} +@end + +@implementation FGMPlatformPolyline ++ (instancetype)makeWithPolylineId:(NSString *)polylineId + consumesTapEvents:(BOOL)consumesTapEvents + color:(FGMPlatformColor *)color + geodesic:(BOOL)geodesic + jointType:(FGMPlatformJointType)jointType + patterns:(NSArray *)patterns + points:(NSArray *)points + visible:(BOOL)visible + width:(NSInteger)width + zIndex:(NSInteger)zIndex { + FGMPlatformPolyline *pigeonResult = [[FGMPlatformPolyline alloc] init]; + pigeonResult.polylineId = polylineId; + pigeonResult.consumesTapEvents = consumesTapEvents; + pigeonResult.color = color; + pigeonResult.geodesic = geodesic; + pigeonResult.jointType = jointType; + pigeonResult.patterns = patterns; + pigeonResult.points = points; + pigeonResult.visible = visible; + pigeonResult.width = width; + pigeonResult.zIndex = zIndex; + return pigeonResult; +} ++ (FGMPlatformPolyline *)fromList:(NSArray *)list { + FGMPlatformPolyline *pigeonResult = [[FGMPlatformPolyline alloc] init]; + pigeonResult.polylineId = GetNullableObjectAtIndex(list, 0); + pigeonResult.consumesTapEvents = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.color = GetNullableObjectAtIndex(list, 2); + pigeonResult.geodesic = [GetNullableObjectAtIndex(list, 3) boolValue]; + FGMPlatformJointTypeBox *boxedFGMPlatformJointType = GetNullableObjectAtIndex(list, 4); + pigeonResult.jointType = boxedFGMPlatformJointType.value; + pigeonResult.patterns = GetNullableObjectAtIndex(list, 5); + pigeonResult.points = GetNullableObjectAtIndex(list, 6); + pigeonResult.visible = [GetNullableObjectAtIndex(list, 7) boolValue]; + pigeonResult.width = [GetNullableObjectAtIndex(list, 8) integerValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 9) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformPolyline *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPolyline fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.polylineId ?: [NSNull null], + @(self.consumesTapEvents), + self.color ?: [NSNull null], + @(self.geodesic), + [[FGMPlatformJointTypeBox alloc] initWithValue:self.jointType], + self.patterns ?: [NSNull null], + self.points ?: [NSNull null], + @(self.visible), + @(self.width), + @(self.zIndex), + ]; +} +@end + +@implementation FGMPlatformPatternItem ++ (instancetype)makeWithType:(FGMPlatformPatternItemType)type length:(nullable NSNumber *)length { + FGMPlatformPatternItem *pigeonResult = [[FGMPlatformPatternItem alloc] init]; + pigeonResult.type = type; + pigeonResult.length = length; + return pigeonResult; +} ++ (FGMPlatformPatternItem *)fromList:(NSArray *)list { + FGMPlatformPatternItem *pigeonResult = [[FGMPlatformPatternItem alloc] init]; + FGMPlatformPatternItemTypeBox *boxedFGMPlatformPatternItemType = + GetNullableObjectAtIndex(list, 0); + pigeonResult.type = boxedFGMPlatformPatternItemType.value; + pigeonResult.length = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformPatternItem *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPatternItem fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + [[FGMPlatformPatternItemTypeBox alloc] initWithValue:self.type], + self.length ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformTile ++ (instancetype)makeWithWidth:(NSInteger)width + height:(NSInteger)height + data:(nullable FlutterStandardTypedData *)data { + FGMPlatformTile *pigeonResult = [[FGMPlatformTile alloc] init]; + pigeonResult.width = width; + pigeonResult.height = height; + pigeonResult.data = data; + return pigeonResult; +} ++ (FGMPlatformTile *)fromList:(NSArray *)list { + FGMPlatformTile *pigeonResult = [[FGMPlatformTile alloc] init]; + pigeonResult.width = [GetNullableObjectAtIndex(list, 0) integerValue]; + pigeonResult.height = [GetNullableObjectAtIndex(list, 1) integerValue]; + pigeonResult.data = GetNullableObjectAtIndex(list, 2); + return pigeonResult; +} ++ (nullable FGMPlatformTile *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformTile fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.width), + @(self.height), + self.data ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformTileOverlay ++ (instancetype)makeWithTileOverlayId:(NSString *)tileOverlayId + fadeIn:(BOOL)fadeIn + transparency:(double)transparency + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + tileSize:(NSInteger)tileSize { + FGMPlatformTileOverlay *pigeonResult = [[FGMPlatformTileOverlay alloc] init]; + pigeonResult.tileOverlayId = tileOverlayId; + pigeonResult.fadeIn = fadeIn; + pigeonResult.transparency = transparency; + pigeonResult.zIndex = zIndex; + pigeonResult.visible = visible; + pigeonResult.tileSize = tileSize; + return pigeonResult; +} ++ (FGMPlatformTileOverlay *)fromList:(NSArray *)list { + FGMPlatformTileOverlay *pigeonResult = [[FGMPlatformTileOverlay alloc] init]; + pigeonResult.tileOverlayId = GetNullableObjectAtIndex(list, 0); + pigeonResult.fadeIn = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.transparency = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 3) integerValue]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 4) boolValue]; + pigeonResult.tileSize = [GetNullableObjectAtIndex(list, 5) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformTileOverlay *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformTileOverlay fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.tileOverlayId ?: [NSNull null], + @(self.fadeIn), + @(self.transparency), + @(self.zIndex), + @(self.visible), + @(self.tileSize), + ]; +} +@end + +@implementation FGMPlatformEdgeInsets ++ (instancetype)makeWithTop:(double)top + bottom:(double)bottom + left:(double)left + right:(double)right { + FGMPlatformEdgeInsets *pigeonResult = [[FGMPlatformEdgeInsets alloc] init]; + pigeonResult.top = top; + pigeonResult.bottom = bottom; + pigeonResult.left = left; + pigeonResult.right = right; + return pigeonResult; +} ++ (FGMPlatformEdgeInsets *)fromList:(NSArray *)list { + FGMPlatformEdgeInsets *pigeonResult = [[FGMPlatformEdgeInsets alloc] init]; + pigeonResult.top = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.bottom = [GetNullableObjectAtIndex(list, 1) doubleValue]; + pigeonResult.left = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.right = [GetNullableObjectAtIndex(list, 3) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformEdgeInsets *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformEdgeInsets fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.top), + @(self.bottom), + @(self.left), + @(self.right), + ]; +} +@end + +@implementation FGMPlatformLatLng ++ (instancetype)makeWithLatitude:(double)latitude longitude:(double)longitude { + FGMPlatformLatLng *pigeonResult = [[FGMPlatformLatLng alloc] init]; + pigeonResult.latitude = latitude; + pigeonResult.longitude = longitude; + return pigeonResult; +} ++ (FGMPlatformLatLng *)fromList:(NSArray *)list { + FGMPlatformLatLng *pigeonResult = [[FGMPlatformLatLng alloc] init]; + pigeonResult.latitude = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.longitude = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformLatLng *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformLatLng fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.latitude), + @(self.longitude), + ]; +} +@end + +@implementation FGMPlatformLatLngBounds ++ (instancetype)makeWithNortheast:(FGMPlatformLatLng *)northeast + southwest:(FGMPlatformLatLng *)southwest { + FGMPlatformLatLngBounds *pigeonResult = [[FGMPlatformLatLngBounds alloc] init]; + pigeonResult.northeast = northeast; + pigeonResult.southwest = southwest; + return pigeonResult; +} ++ (FGMPlatformLatLngBounds *)fromList:(NSArray *)list { + FGMPlatformLatLngBounds *pigeonResult = [[FGMPlatformLatLngBounds alloc] init]; + pigeonResult.northeast = GetNullableObjectAtIndex(list, 0); + pigeonResult.southwest = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformLatLngBounds *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformLatLngBounds fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.northeast ?: [NSNull null], + self.southwest ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraTargetBounds ++ (instancetype)makeWithBounds:(nullable FGMPlatformLatLngBounds *)bounds { + FGMPlatformCameraTargetBounds *pigeonResult = [[FGMPlatformCameraTargetBounds alloc] init]; + pigeonResult.bounds = bounds; + return pigeonResult; +} ++ (FGMPlatformCameraTargetBounds *)fromList:(NSArray *)list { + FGMPlatformCameraTargetBounds *pigeonResult = [[FGMPlatformCameraTargetBounds alloc] init]; + pigeonResult.bounds = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraTargetBounds *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraTargetBounds fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.bounds ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformGroundOverlay ++ (instancetype)makeWithGroundOverlayId:(NSString *)groundOverlayId + image:(FGMPlatformBitmap *)image + position:(nullable FGMPlatformLatLng *)position + bounds:(nullable FGMPlatformLatLngBounds *)bounds + anchor:(nullable FGMPlatformPoint *)anchor + transparency:(double)transparency + bearing:(double)bearing + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + clickable:(BOOL)clickable + zoomLevel:(nullable NSNumber *)zoomLevel { + FGMPlatformGroundOverlay *pigeonResult = [[FGMPlatformGroundOverlay alloc] init]; + pigeonResult.groundOverlayId = groundOverlayId; + pigeonResult.image = image; + pigeonResult.position = position; + pigeonResult.bounds = bounds; + pigeonResult.anchor = anchor; + pigeonResult.transparency = transparency; + pigeonResult.bearing = bearing; + pigeonResult.zIndex = zIndex; + pigeonResult.visible = visible; + pigeonResult.clickable = clickable; + pigeonResult.zoomLevel = zoomLevel; + return pigeonResult; +} ++ (FGMPlatformGroundOverlay *)fromList:(NSArray *)list { + FGMPlatformGroundOverlay *pigeonResult = [[FGMPlatformGroundOverlay alloc] init]; + pigeonResult.groundOverlayId = GetNullableObjectAtIndex(list, 0); + pigeonResult.image = GetNullableObjectAtIndex(list, 1); + pigeonResult.position = GetNullableObjectAtIndex(list, 2); + pigeonResult.bounds = GetNullableObjectAtIndex(list, 3); + pigeonResult.anchor = GetNullableObjectAtIndex(list, 4); + pigeonResult.transparency = [GetNullableObjectAtIndex(list, 5) doubleValue]; + pigeonResult.bearing = [GetNullableObjectAtIndex(list, 6) doubleValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 7) integerValue]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 8) boolValue]; + pigeonResult.clickable = [GetNullableObjectAtIndex(list, 9) boolValue]; + pigeonResult.zoomLevel = GetNullableObjectAtIndex(list, 10); + return pigeonResult; +} ++ (nullable FGMPlatformGroundOverlay *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformGroundOverlay fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.groundOverlayId ?: [NSNull null], + self.image ?: [NSNull null], + self.position ?: [NSNull null], + self.bounds ?: [NSNull null], + self.anchor ?: [NSNull null], + @(self.transparency), + @(self.bearing), + @(self.zIndex), + @(self.visible), + @(self.clickable), + self.zoomLevel ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformMapViewCreationParams ++ (instancetype) + makeWithInitialCameraPosition:(FGMPlatformCameraPosition *)initialCameraPosition + mapConfiguration:(FGMPlatformMapConfiguration *)mapConfiguration + initialCircles:(NSArray *)initialCircles + initialMarkers:(NSArray *)initialMarkers + initialPolygons:(NSArray *)initialPolygons + initialPolylines:(NSArray *)initialPolylines + initialHeatmaps:(NSArray *)initialHeatmaps + initialTileOverlays:(NSArray *)initialTileOverlays + initialClusterManagers:(NSArray *)initialClusterManagers + initialGroundOverlays:(NSArray *)initialGroundOverlays { + FGMPlatformMapViewCreationParams *pigeonResult = [[FGMPlatformMapViewCreationParams alloc] init]; + pigeonResult.initialCameraPosition = initialCameraPosition; + pigeonResult.mapConfiguration = mapConfiguration; + pigeonResult.initialCircles = initialCircles; + pigeonResult.initialMarkers = initialMarkers; + pigeonResult.initialPolygons = initialPolygons; + pigeonResult.initialPolylines = initialPolylines; + pigeonResult.initialHeatmaps = initialHeatmaps; + pigeonResult.initialTileOverlays = initialTileOverlays; + pigeonResult.initialClusterManagers = initialClusterManagers; + pigeonResult.initialGroundOverlays = initialGroundOverlays; + return pigeonResult; +} ++ (FGMPlatformMapViewCreationParams *)fromList:(NSArray *)list { + FGMPlatformMapViewCreationParams *pigeonResult = [[FGMPlatformMapViewCreationParams alloc] init]; + pigeonResult.initialCameraPosition = GetNullableObjectAtIndex(list, 0); + pigeonResult.mapConfiguration = GetNullableObjectAtIndex(list, 1); + pigeonResult.initialCircles = GetNullableObjectAtIndex(list, 2); + pigeonResult.initialMarkers = GetNullableObjectAtIndex(list, 3); + pigeonResult.initialPolygons = GetNullableObjectAtIndex(list, 4); + pigeonResult.initialPolylines = GetNullableObjectAtIndex(list, 5); + pigeonResult.initialHeatmaps = GetNullableObjectAtIndex(list, 6); + pigeonResult.initialTileOverlays = GetNullableObjectAtIndex(list, 7); + pigeonResult.initialClusterManagers = GetNullableObjectAtIndex(list, 8); + pigeonResult.initialGroundOverlays = GetNullableObjectAtIndex(list, 9); + return pigeonResult; +} ++ (nullable FGMPlatformMapViewCreationParams *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformMapViewCreationParams fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.initialCameraPosition ?: [NSNull null], + self.mapConfiguration ?: [NSNull null], + self.initialCircles ?: [NSNull null], + self.initialMarkers ?: [NSNull null], + self.initialPolygons ?: [NSNull null], + self.initialPolylines ?: [NSNull null], + self.initialHeatmaps ?: [NSNull null], + self.initialTileOverlays ?: [NSNull null], + self.initialClusterManagers ?: [NSNull null], + self.initialGroundOverlays ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformMapConfiguration ++ (instancetype)makeWithCompassEnabled:(nullable NSNumber *)compassEnabled + cameraTargetBounds:(nullable FGMPlatformCameraTargetBounds *)cameraTargetBounds + mapType:(nullable FGMPlatformMapTypeBox *)mapType + minMaxZoomPreference:(nullable FGMPlatformZoomRange *)minMaxZoomPreference + rotateGesturesEnabled:(nullable NSNumber *)rotateGesturesEnabled + scrollGesturesEnabled:(nullable NSNumber *)scrollGesturesEnabled + tiltGesturesEnabled:(nullable NSNumber *)tiltGesturesEnabled + trackCameraPosition:(nullable NSNumber *)trackCameraPosition + zoomGesturesEnabled:(nullable NSNumber *)zoomGesturesEnabled + myLocationEnabled:(nullable NSNumber *)myLocationEnabled + myLocationButtonEnabled:(nullable NSNumber *)myLocationButtonEnabled + padding:(nullable FGMPlatformEdgeInsets *)padding + indoorViewEnabled:(nullable NSNumber *)indoorViewEnabled + trafficEnabled:(nullable NSNumber *)trafficEnabled + buildingsEnabled:(nullable NSNumber *)buildingsEnabled + mapId:(nullable NSString *)mapId + style:(nullable NSString *)style { + FGMPlatformMapConfiguration *pigeonResult = [[FGMPlatformMapConfiguration alloc] init]; + pigeonResult.compassEnabled = compassEnabled; + pigeonResult.cameraTargetBounds = cameraTargetBounds; + pigeonResult.mapType = mapType; + pigeonResult.minMaxZoomPreference = minMaxZoomPreference; + pigeonResult.rotateGesturesEnabled = rotateGesturesEnabled; + pigeonResult.scrollGesturesEnabled = scrollGesturesEnabled; + pigeonResult.tiltGesturesEnabled = tiltGesturesEnabled; + pigeonResult.trackCameraPosition = trackCameraPosition; + pigeonResult.zoomGesturesEnabled = zoomGesturesEnabled; + pigeonResult.myLocationEnabled = myLocationEnabled; + pigeonResult.myLocationButtonEnabled = myLocationButtonEnabled; + pigeonResult.padding = padding; + pigeonResult.indoorViewEnabled = indoorViewEnabled; + pigeonResult.trafficEnabled = trafficEnabled; + pigeonResult.buildingsEnabled = buildingsEnabled; + pigeonResult.mapId = mapId; + pigeonResult.style = style; + return pigeonResult; +} ++ (FGMPlatformMapConfiguration *)fromList:(NSArray *)list { + FGMPlatformMapConfiguration *pigeonResult = [[FGMPlatformMapConfiguration alloc] init]; + pigeonResult.compassEnabled = GetNullableObjectAtIndex(list, 0); + pigeonResult.cameraTargetBounds = GetNullableObjectAtIndex(list, 1); + pigeonResult.mapType = GetNullableObjectAtIndex(list, 2); + pigeonResult.minMaxZoomPreference = GetNullableObjectAtIndex(list, 3); + pigeonResult.rotateGesturesEnabled = GetNullableObjectAtIndex(list, 4); + pigeonResult.scrollGesturesEnabled = GetNullableObjectAtIndex(list, 5); + pigeonResult.tiltGesturesEnabled = GetNullableObjectAtIndex(list, 6); + pigeonResult.trackCameraPosition = GetNullableObjectAtIndex(list, 7); + pigeonResult.zoomGesturesEnabled = GetNullableObjectAtIndex(list, 8); + pigeonResult.myLocationEnabled = GetNullableObjectAtIndex(list, 9); + pigeonResult.myLocationButtonEnabled = GetNullableObjectAtIndex(list, 10); + pigeonResult.padding = GetNullableObjectAtIndex(list, 11); + pigeonResult.indoorViewEnabled = GetNullableObjectAtIndex(list, 12); + pigeonResult.trafficEnabled = GetNullableObjectAtIndex(list, 13); + pigeonResult.buildingsEnabled = GetNullableObjectAtIndex(list, 14); + pigeonResult.mapId = GetNullableObjectAtIndex(list, 15); + pigeonResult.style = GetNullableObjectAtIndex(list, 16); + return pigeonResult; +} ++ (nullable FGMPlatformMapConfiguration *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformMapConfiguration fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.compassEnabled ?: [NSNull null], + self.cameraTargetBounds ?: [NSNull null], + self.mapType ?: [NSNull null], + self.minMaxZoomPreference ?: [NSNull null], + self.rotateGesturesEnabled ?: [NSNull null], + self.scrollGesturesEnabled ?: [NSNull null], + self.tiltGesturesEnabled ?: [NSNull null], + self.trackCameraPosition ?: [NSNull null], + self.zoomGesturesEnabled ?: [NSNull null], + self.myLocationEnabled ?: [NSNull null], + self.myLocationButtonEnabled ?: [NSNull null], + self.padding ?: [NSNull null], + self.indoorViewEnabled ?: [NSNull null], + self.trafficEnabled ?: [NSNull null], + self.buildingsEnabled ?: [NSNull null], + self.mapId ?: [NSNull null], + self.style ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformPoint ++ (instancetype)makeWithX:(double)x y:(double)y { + FGMPlatformPoint *pigeonResult = [[FGMPlatformPoint alloc] init]; + pigeonResult.x = x; + pigeonResult.y = y; + return pigeonResult; +} ++ (FGMPlatformPoint *)fromList:(NSArray *)list { + FGMPlatformPoint *pigeonResult = [[FGMPlatformPoint alloc] init]; + pigeonResult.x = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.y = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformPoint *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPoint fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.x), + @(self.y), + ]; +} +@end + +@implementation FGMPlatformSize ++ (instancetype)makeWithWidth:(double)width height:(double)height { + FGMPlatformSize *pigeonResult = [[FGMPlatformSize alloc] init]; + pigeonResult.width = width; + pigeonResult.height = height; + return pigeonResult; +} ++ (FGMPlatformSize *)fromList:(NSArray *)list { + FGMPlatformSize *pigeonResult = [[FGMPlatformSize alloc] init]; + pigeonResult.width = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.height = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformSize *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformSize fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.width), + @(self.height), + ]; +} +@end + +@implementation FGMPlatformColor ++ (instancetype)makeWithRed:(double)red green:(double)green blue:(double)blue alpha:(double)alpha { + FGMPlatformColor *pigeonResult = [[FGMPlatformColor alloc] init]; + pigeonResult.red = red; + pigeonResult.green = green; + pigeonResult.blue = blue; + pigeonResult.alpha = alpha; + return pigeonResult; +} ++ (FGMPlatformColor *)fromList:(NSArray *)list { + FGMPlatformColor *pigeonResult = [[FGMPlatformColor alloc] init]; + pigeonResult.red = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.green = [GetNullableObjectAtIndex(list, 1) doubleValue]; + pigeonResult.blue = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.alpha = [GetNullableObjectAtIndex(list, 3) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformColor *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformColor fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.red), + @(self.green), + @(self.blue), + @(self.alpha), + ]; +} +@end + +@implementation FGMPlatformTileLayer ++ (instancetype)makeWithVisible:(BOOL)visible + fadeIn:(BOOL)fadeIn + opacity:(double)opacity + zIndex:(NSInteger)zIndex { + FGMPlatformTileLayer *pigeonResult = [[FGMPlatformTileLayer alloc] init]; + pigeonResult.visible = visible; + pigeonResult.fadeIn = fadeIn; + pigeonResult.opacity = opacity; + pigeonResult.zIndex = zIndex; + return pigeonResult; +} ++ (FGMPlatformTileLayer *)fromList:(NSArray *)list { + FGMPlatformTileLayer *pigeonResult = [[FGMPlatformTileLayer alloc] init]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 0) boolValue]; + pigeonResult.fadeIn = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.opacity = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 3) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformTileLayer *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformTileLayer fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.visible), + @(self.fadeIn), + @(self.opacity), + @(self.zIndex), + ]; +} +@end + +@implementation FGMPlatformZoomRange ++ (instancetype)makeWithMin:(nullable NSNumber *)min max:(nullable NSNumber *)max { + FGMPlatformZoomRange *pigeonResult = [[FGMPlatformZoomRange alloc] init]; + pigeonResult.min = min; + pigeonResult.max = max; + return pigeonResult; +} ++ (FGMPlatformZoomRange *)fromList:(NSArray *)list { + FGMPlatformZoomRange *pigeonResult = [[FGMPlatformZoomRange alloc] init]; + pigeonResult.min = GetNullableObjectAtIndex(list, 0); + pigeonResult.max = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformZoomRange *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformZoomRange fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.min ?: [NSNull null], + self.max ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmap ++ (instancetype)makeWithBitmap:(id)bitmap { + FGMPlatformBitmap *pigeonResult = [[FGMPlatformBitmap alloc] init]; + pigeonResult.bitmap = bitmap; + return pigeonResult; +} ++ (FGMPlatformBitmap *)fromList:(NSArray *)list { + FGMPlatformBitmap *pigeonResult = [[FGMPlatformBitmap alloc] init]; + pigeonResult.bitmap = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformBitmap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.bitmap ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapDefaultMarker ++ (instancetype)makeWithHue:(nullable NSNumber *)hue { + FGMPlatformBitmapDefaultMarker *pigeonResult = [[FGMPlatformBitmapDefaultMarker alloc] init]; + pigeonResult.hue = hue; + return pigeonResult; +} ++ (FGMPlatformBitmapDefaultMarker *)fromList:(NSArray *)list { + FGMPlatformBitmapDefaultMarker *pigeonResult = [[FGMPlatformBitmapDefaultMarker alloc] init]; + pigeonResult.hue = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapDefaultMarker *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapDefaultMarker fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.hue ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapBytes ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + size:(nullable FGMPlatformSize *)size { + FGMPlatformBitmapBytes *pigeonResult = [[FGMPlatformBitmapBytes alloc] init]; + pigeonResult.byteData = byteData; + pigeonResult.size = size; + return pigeonResult; +} ++ (FGMPlatformBitmapBytes *)fromList:(NSArray *)list { + FGMPlatformBitmapBytes *pigeonResult = [[FGMPlatformBitmapBytes alloc] init]; + pigeonResult.byteData = GetNullableObjectAtIndex(list, 0); + pigeonResult.size = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapBytes *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapBytes fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.byteData ?: [NSNull null], + self.size ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapAsset ++ (instancetype)makeWithName:(NSString *)name pkg:(nullable NSString *)pkg { + FGMPlatformBitmapAsset *pigeonResult = [[FGMPlatformBitmapAsset alloc] init]; + pigeonResult.name = name; + pigeonResult.pkg = pkg; + return pigeonResult; +} ++ (FGMPlatformBitmapAsset *)fromList:(NSArray *)list { + FGMPlatformBitmapAsset *pigeonResult = [[FGMPlatformBitmapAsset alloc] init]; + pigeonResult.name = GetNullableObjectAtIndex(list, 0); + pigeonResult.pkg = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapAsset *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapAsset fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.name ?: [NSNull null], + self.pkg ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapAssetImage ++ (instancetype)makeWithName:(NSString *)name + scale:(double)scale + size:(nullable FGMPlatformSize *)size { + FGMPlatformBitmapAssetImage *pigeonResult = [[FGMPlatformBitmapAssetImage alloc] init]; + pigeonResult.name = name; + pigeonResult.scale = scale; + pigeonResult.size = size; + return pigeonResult; +} ++ (FGMPlatformBitmapAssetImage *)fromList:(NSArray *)list { + FGMPlatformBitmapAssetImage *pigeonResult = [[FGMPlatformBitmapAssetImage alloc] init]; + pigeonResult.name = GetNullableObjectAtIndex(list, 0); + pigeonResult.scale = [GetNullableObjectAtIndex(list, 1) doubleValue]; + pigeonResult.size = GetNullableObjectAtIndex(list, 2); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapAssetImage *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapAssetImage fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.name ?: [NSNull null], + @(self.scale), + self.size ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapAssetMap ++ (instancetype)makeWithAssetName:(NSString *)assetName + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height { + FGMPlatformBitmapAssetMap *pigeonResult = [[FGMPlatformBitmapAssetMap alloc] init]; + pigeonResult.assetName = assetName; + pigeonResult.bitmapScaling = bitmapScaling; + pigeonResult.imagePixelRatio = imagePixelRatio; + pigeonResult.width = width; + pigeonResult.height = height; + return pigeonResult; +} ++ (FGMPlatformBitmapAssetMap *)fromList:(NSArray *)list { + FGMPlatformBitmapAssetMap *pigeonResult = [[FGMPlatformBitmapAssetMap alloc] init]; + pigeonResult.assetName = GetNullableObjectAtIndex(list, 0); + FGMPlatformMapBitmapScalingBox *boxedFGMPlatformMapBitmapScaling = + GetNullableObjectAtIndex(list, 1); + pigeonResult.bitmapScaling = boxedFGMPlatformMapBitmapScaling.value; + pigeonResult.imagePixelRatio = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.width = GetNullableObjectAtIndex(list, 3); + pigeonResult.height = GetNullableObjectAtIndex(list, 4); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapAssetMap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapAssetMap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.assetName ?: [NSNull null], + [[FGMPlatformMapBitmapScalingBox alloc] initWithValue:self.bitmapScaling], + @(self.imagePixelRatio), + self.width ?: [NSNull null], + self.height ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapBytesMap ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height { + FGMPlatformBitmapBytesMap *pigeonResult = [[FGMPlatformBitmapBytesMap alloc] init]; + pigeonResult.byteData = byteData; + pigeonResult.bitmapScaling = bitmapScaling; + pigeonResult.imagePixelRatio = imagePixelRatio; + pigeonResult.width = width; + pigeonResult.height = height; + return pigeonResult; +} ++ (FGMPlatformBitmapBytesMap *)fromList:(NSArray *)list { + FGMPlatformBitmapBytesMap *pigeonResult = [[FGMPlatformBitmapBytesMap alloc] init]; + pigeonResult.byteData = GetNullableObjectAtIndex(list, 0); + FGMPlatformMapBitmapScalingBox *boxedFGMPlatformMapBitmapScaling = + GetNullableObjectAtIndex(list, 1); + pigeonResult.bitmapScaling = boxedFGMPlatformMapBitmapScaling.value; + pigeonResult.imagePixelRatio = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.width = GetNullableObjectAtIndex(list, 3); + pigeonResult.height = GetNullableObjectAtIndex(list, 4); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapBytesMap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapBytesMap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.byteData ?: [NSNull null], + [[FGMPlatformMapBitmapScalingBox alloc] initWithValue:self.bitmapScaling], + @(self.imagePixelRatio), + self.width ?: [NSNull null], + self.height ?: [NSNull null], + ]; +} +@end + +@interface FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReader : FlutterStandardReader +@end +@implementation FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReader +- (nullable id)readValueOfType:(UInt8)type { + switch (type) { + case 129: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil + ? nil + : [[FGMPlatformMapTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; + } + case 130: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil + ? nil + : [[FGMPlatformJointTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; + } + case 131: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil ? nil + : [[FGMPlatformPatternItemTypeBox alloc] + initWithValue:[enumAsNumber integerValue]]; + } + case 132: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil ? nil + : [[FGMPlatformMapBitmapScalingBox alloc] + initWithValue:[enumAsNumber integerValue]]; + } + case 133: + return [FGMPlatformCameraPosition fromList:[self readValue]]; + case 134: + return [FGMPlatformCameraUpdate fromList:[self readValue]]; + case 135: + return [FGMPlatformCameraUpdateNewCameraPosition fromList:[self readValue]]; + case 136: + return [FGMPlatformCameraUpdateNewLatLng fromList:[self readValue]]; + case 137: + return [FGMPlatformCameraUpdateNewLatLngBounds fromList:[self readValue]]; + case 138: + return [FGMPlatformCameraUpdateNewLatLngZoom fromList:[self readValue]]; + case 139: + return [FGMPlatformCameraUpdateScrollBy fromList:[self readValue]]; + case 140: + return [FGMPlatformCameraUpdateZoomBy fromList:[self readValue]]; + case 141: + return [FGMPlatformCameraUpdateZoom fromList:[self readValue]]; + case 142: + return [FGMPlatformCameraUpdateZoomTo fromList:[self readValue]]; + case 143: + return [FGMPlatformCircle fromList:[self readValue]]; + case 144: + return [FGMPlatformHeatmap fromList:[self readValue]]; + case 145: + return [FGMPlatformHeatmapGradient fromList:[self readValue]]; + case 146: + return [FGMPlatformWeightedLatLng fromList:[self readValue]]; + case 147: + return [FGMPlatformInfoWindow fromList:[self readValue]]; + case 148: + return [FGMPlatformCluster fromList:[self readValue]]; + case 149: + return [FGMPlatformClusterManager fromList:[self readValue]]; + case 150: + return [FGMPlatformMarker fromList:[self readValue]]; + case 151: + return [FGMPlatformPolygon fromList:[self readValue]]; + case 152: + return [FGMPlatformPolyline fromList:[self readValue]]; + case 153: + return [FGMPlatformPatternItem fromList:[self readValue]]; + case 154: + return [FGMPlatformTile fromList:[self readValue]]; + case 155: + return [FGMPlatformTileOverlay fromList:[self readValue]]; + case 156: + return [FGMPlatformEdgeInsets fromList:[self readValue]]; + case 157: + return [FGMPlatformLatLng fromList:[self readValue]]; + case 158: + return [FGMPlatformLatLngBounds fromList:[self readValue]]; + case 159: + return [FGMPlatformCameraTargetBounds fromList:[self readValue]]; + case 160: + return [FGMPlatformGroundOverlay fromList:[self readValue]]; + case 161: + return [FGMPlatformMapViewCreationParams fromList:[self readValue]]; + case 162: + return [FGMPlatformMapConfiguration fromList:[self readValue]]; + case 163: + return [FGMPlatformPoint fromList:[self readValue]]; + case 164: + return [FGMPlatformSize fromList:[self readValue]]; + case 165: + return [FGMPlatformColor fromList:[self readValue]]; + case 166: + return [FGMPlatformTileLayer fromList:[self readValue]]; + case 167: + return [FGMPlatformZoomRange fromList:[self readValue]]; + case 168: + return [FGMPlatformBitmap fromList:[self readValue]]; + case 169: + return [FGMPlatformBitmapDefaultMarker fromList:[self readValue]]; + case 170: + return [FGMPlatformBitmapBytes fromList:[self readValue]]; + case 171: + return [FGMPlatformBitmapAsset fromList:[self readValue]]; + case 172: + return [FGMPlatformBitmapAssetImage fromList:[self readValue]]; + case 173: + return [FGMPlatformBitmapAssetMap fromList:[self readValue]]; + case 174: + return [FGMPlatformBitmapBytesMap fromList:[self readValue]]; + default: + return [super readValueOfType:type]; + } +} +@end + +@interface FGMGoogleMapsFlutterPigeonMessagesPigeonCodecWriter : FlutterStandardWriter +@end +@implementation FGMGoogleMapsFlutterPigeonMessagesPigeonCodecWriter +- (void)writeValue:(id)value { + if ([value isKindOfClass:[FGMPlatformMapTypeBox class]]) { + FGMPlatformMapTypeBox *box = (FGMPlatformMapTypeBox *)value; + [self writeByte:129]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformJointTypeBox class]]) { + FGMPlatformJointTypeBox *box = (FGMPlatformJointTypeBox *)value; + [self writeByte:130]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformPatternItemTypeBox class]]) { + FGMPlatformPatternItemTypeBox *box = (FGMPlatformPatternItemTypeBox *)value; + [self writeByte:131]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformMapBitmapScalingBox class]]) { + FGMPlatformMapBitmapScalingBox *box = (FGMPlatformMapBitmapScalingBox *)value; + [self writeByte:132]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformCameraPosition class]]) { + [self writeByte:133]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdate class]]) { + [self writeByte:134]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewCameraPosition class]]) { + [self writeByte:135]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewLatLng class]]) { + [self writeByte:136]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewLatLngBounds class]]) { + [self writeByte:137]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewLatLngZoom class]]) { + [self writeByte:138]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateScrollBy class]]) { + [self writeByte:139]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateZoomBy class]]) { + [self writeByte:140]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateZoom class]]) { + [self writeByte:141]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateZoomTo class]]) { + [self writeByte:142]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCircle class]]) { + [self writeByte:143]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformHeatmap class]]) { + [self writeByte:144]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformHeatmapGradient class]]) { + [self writeByte:145]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformWeightedLatLng class]]) { + [self writeByte:146]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformInfoWindow class]]) { + [self writeByte:147]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCluster class]]) { + [self writeByte:148]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformClusterManager class]]) { + [self writeByte:149]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformMarker class]]) { + [self writeByte:150]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPolygon class]]) { + [self writeByte:151]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPolyline class]]) { + [self writeByte:152]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPatternItem class]]) { + [self writeByte:153]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformTile class]]) { + [self writeByte:154]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformTileOverlay class]]) { + [self writeByte:155]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformEdgeInsets class]]) { + [self writeByte:156]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformLatLng class]]) { + [self writeByte:157]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformLatLngBounds class]]) { + [self writeByte:158]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraTargetBounds class]]) { + [self writeByte:159]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformGroundOverlay class]]) { + [self writeByte:160]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformMapViewCreationParams class]]) { + [self writeByte:161]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformMapConfiguration class]]) { + [self writeByte:162]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPoint class]]) { + [self writeByte:163]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformSize class]]) { + [self writeByte:164]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformColor class]]) { + [self writeByte:165]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformTileLayer class]]) { + [self writeByte:166]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformZoomRange class]]) { + [self writeByte:167]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmap class]]) { + [self writeByte:168]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapDefaultMarker class]]) { + [self writeByte:169]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapBytes class]]) { + [self writeByte:170]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapAsset class]]) { + [self writeByte:171]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapAssetImage class]]) { + [self writeByte:172]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapAssetMap class]]) { + [self writeByte:173]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapBytesMap class]]) { + [self writeByte:174]; + [self writeValue:[value toList]]; + } else { + [super writeValue:value]; + } +} +@end + +@interface FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter : FlutterStandardReaderWriter +@end +@implementation FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter +- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { + return [[FGMGoogleMapsFlutterPigeonMessagesPigeonCodecWriter alloc] initWithData:data]; +} +- (FlutterStandardReader *)readerWithData:(NSData *)data { + return [[FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReader alloc] initWithData:data]; +} +@end + +NSObject *FGMGetGoogleMapsFlutterPigeonMessagesCodec(void) { + static FlutterStandardMessageCodec *sSharedObject = nil; + static dispatch_once_t sPred = 0; + dispatch_once(&sPred, ^{ + FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter *readerWriter = + [[FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter alloc] init]; + sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; + }); + return sSharedObject; +} +void SetUpFGMMapsApi(id binaryMessenger, NSObject *api) { + SetUpFGMMapsApiWithSuffix(binaryMessenger, api, @""); +} + +void SetUpFGMMapsApiWithSuffix(id binaryMessenger, + NSObject *api, NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; + /// Returns once the map instance is available. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.waitForMap", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(waitForMapWithError:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(waitForMapWithError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + [api waitForMapWithError:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateMapConfiguration", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(updateWithMapConfiguration:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(updateWithMapConfiguration:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformMapConfiguration *arg_configuration = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api updateWithMapConfiguration:arg_configuration error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of circles on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateCircles", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateCirclesByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateCirclesByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateCirclesByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of heatmaps on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateHeatmaps", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateHeatmapsByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateHeatmapsByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateHeatmapsByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of custer managers for clusters on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateClusterManagers", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateClusterManagersByAdding:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateClusterManagersByAdding:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + [api updateClusterManagersByAdding:arg_toAdd removing:arg_idsToRemove error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of markers on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateMarkers", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateMarkersByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateMarkersByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateMarkersByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of polygonss on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updatePolygons", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updatePolygonsByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updatePolygonsByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updatePolygonsByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of polylines on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updatePolylines", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updatePolylinesByAdding: + changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updatePolylinesByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updatePolylinesByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of tile overlays on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateTileOverlays", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateTileOverlaysByAdding: + changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateTileOverlaysByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateTileOverlaysByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of ground overlays on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateGroundOverlays", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateGroundOverlaysByAdding: + changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateGroundOverlaysByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateGroundOverlaysByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the screen coordinate for the given map location. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.getScreenCoordinate", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(screenCoordinatesForLatLng:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(screenCoordinatesForLatLng:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformLatLng *arg_latLng = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformPoint *output = [api screenCoordinatesForLatLng:arg_latLng error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the map location for the given screen coordinate. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getLatLng", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(latLngForScreenCoordinate:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(latLngForScreenCoordinate:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformPoint *arg_screenCoordinate = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformLatLng *output = [api latLngForScreenCoordinate:arg_screenCoordinate + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the map region currently displayed on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.getVisibleRegion", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(visibleMapRegion:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(visibleMapRegion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FGMPlatformLatLngBounds *output = [api visibleMapRegion:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.moveCamera", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(moveCameraWithUpdate:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(moveCameraWithUpdate:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformCameraUpdate *arg_cameraUpdate = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api moveCameraWithUpdate:arg_cameraUpdate error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Moves the camera according to [cameraUpdate], animating the update using a + /// duration in milliseconds if provided. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.animateCamera", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(animateCameraWithUpdate:duration:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(animateCameraWithUpdate:duration:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformCameraUpdate *arg_cameraUpdate = GetNullableObjectAtIndex(args, 0); + NSNumber *arg_durationMilliseconds = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + [api animateCameraWithUpdate:arg_cameraUpdate + duration:arg_durationMilliseconds + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the current map zoom level. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getZoomLevel", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(currentZoomLevel:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(currentZoomLevel:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api currentZoomLevel:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Show the info window for the marker with the given ID. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.showInfoWindow", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(showInfoWindowForMarkerWithIdentifier:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(showInfoWindowForMarkerWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_markerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api showInfoWindowForMarkerWithIdentifier:arg_markerId error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Hide the info window for the marker with the given ID. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.hideInfoWindow", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(hideInfoWindowForMarkerWithIdentifier:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(hideInfoWindowForMarkerWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_markerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api hideInfoWindowForMarkerWithIdentifier:arg_markerId error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns true if the marker with the given ID is currently displaying its + /// info window. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.isInfoWindowShown", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(isShowingInfoWindowForMarkerWithIdentifier: + error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(isShowingInfoWindowForMarkerWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_markerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSNumber *output = [api isShowingInfoWindowForMarkerWithIdentifier:arg_markerId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Sets the style to the given map style string, where an empty string + /// indicates that the style should be cleared. + /// + /// If there was an error setting the style, such as an invalid style string, + /// returns the error message. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.setStyle", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(setStyle:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(setStyle:error:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_style = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSString *output = [api setStyle:arg_style error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns the error string from the last attempt to set the map style, if + /// any. + /// + /// This allows checking asynchronously for initial style failures, as there + /// is no way to return failures from map initialization. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.getLastStyleError", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(lastStyleError:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(lastStyleError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSString *output = [api lastStyleError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Clears the cache of tiles previously requseted from the tile provider. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.clearTileCache", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(clearTileCacheForOverlayWithIdentifier:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(clearTileCacheForOverlayWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_tileOverlayId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api clearTileCacheForOverlayWithIdentifier:arg_tileOverlayId error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Takes a snapshot of the map and returns its image data. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.takeSnapshot", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(takeSnapshotWithError:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(takeSnapshotWithError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FlutterStandardTypedData *output = [api takeSnapshotWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} +@interface FGMMapsCallbackApi () +@property(nonatomic, strong) NSObject *binaryMessenger; +@property(nonatomic, strong) NSString *messageChannelSuffix; +@end + +@implementation FGMMapsCallbackApi + +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger { + return [self initWithBinaryMessenger:binaryMessenger messageChannelSuffix:@""]; +} +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger + messageChannelSuffix:(nullable NSString *)messageChannelSuffix { + self = [self init]; + if (self) { + _binaryMessenger = binaryMessenger; + _messageChannelSuffix = [messageChannelSuffix length] == 0 + ? @"" + : [NSString stringWithFormat:@".%@", messageChannelSuffix]; + } + return self; +} +- (void)didStartCameraMoveWithCompletion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMoveStarted", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:nil + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didMoveCameraToPosition:(FGMPlatformCameraPosition *)arg_cameraPosition + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMove", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_cameraPosition ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didIdleCameraWithCompletion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraIdle", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:nil + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapAtPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didLongPressAtPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onLongPress", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapMarkerWithIdentifier:(NSString *)arg_markerId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didStartDragForMarkerWithIdentifier:(NSString *)arg_markerId + atPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null], arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didDragMarkerWithIdentifier:(NSString *)arg_markerId + atPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null], arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didEndDragForMarkerWithIdentifier:(NSString *)arg_markerId + atPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null], arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)arg_markerId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onInfoWindowTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapCircleWithIdentifier:(NSString *)arg_circleId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCircleTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_circleId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapCluster:(FGMPlatformCluster *)arg_cluster + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_cluster ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapPolygonWithIdentifier:(NSString *)arg_polygonId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolygonTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_polygonId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapPolylineWithIdentifier:(NSString *)arg_polylineId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolylineTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_polylineId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapGroundOverlayWithIdentifier:(NSString *)arg_groundOverlayId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onGroundOverlayTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_groundOverlayId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)tileWithOverlayIdentifier:(NSString *)arg_tileOverlayId + location:(FGMPlatformPoint *)arg_location + zoom:(NSInteger)arg_zoom + completion:(void (^)(FGMPlatformTile *_Nullable, + FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ + arg_tileOverlayId ?: [NSNull null], arg_location ?: [NSNull null], @(arg_zoom) + ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion(nil, [FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + FGMPlatformTile *output = reply[0] == [NSNull null] ? nil : reply[0]; + completion(output, nil); + } + } else { + completion(nil, createConnectionError(channelName)); + } + }]; +} +@end + +void SetUpFGMMapsPlatformViewApi(id binaryMessenger, + NSObject *api) { + SetUpFGMMapsPlatformViewApiWithSuffix(binaryMessenger, api, @""); +} + +void SetUpFGMMapsPlatformViewApiWithSuffix(id binaryMessenger, + NSObject *api, + NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsPlatformViewApi.createView", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(createViewType:error:)], + @"FGMMapsPlatformViewApi api (%@) doesn't respond to @selector(createViewType:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformMapViewCreationParams *arg_type = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api createViewType:arg_type error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} +void SetUpFGMMapsInspectorApi(id binaryMessenger, + NSObject *api) { + SetUpFGMMapsInspectorApiWithSuffix(binaryMessenger, api, @""); +} + +void SetUpFGMMapsInspectorApiWithSuffix(id binaryMessenger, + NSObject *api, + NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areBuildingsEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areBuildingsEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areBuildingsEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areBuildingsEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areRotateGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areRotateGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areRotateGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areRotateGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areScrollGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areScrollGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areScrollGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areScrollGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areTiltGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areTiltGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areTiltGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areTiltGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areZoomGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areZoomGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areZoomGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areZoomGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.isCompassEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(isCompassEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(isCompassEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isCompassEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.isMyLocationButtonEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(isMyLocationButtonEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(isMyLocationButtonEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isMyLocationButtonEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.isTrafficEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(isTrafficEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(isTrafficEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isTrafficEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getTileOverlayInfo", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(tileOverlayWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(tileOverlayWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_tileOverlayId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformTileLayer *output = [api tileOverlayWithIdentifier:arg_tileOverlayId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getGroundOverlayInfo", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(groundOverlayWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(groundOverlayWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_groundOverlayId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformGroundOverlay *output = [api groundOverlayWithIdentifier:arg_groundOverlayId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getHeatmapInfo", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(heatmapWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(heatmapWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_heatmapId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformHeatmap *output = [api heatmapWithIdentifier:arg_heatmapId error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getZoomRange", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(zoomRange:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(zoomRange:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FGMPlatformZoomRange *output = [api zoomRange:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getClusters", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(clustersWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(clustersWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_clusterManagerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSArray *output = [api clustersWithIdentifier:arg_clusterManagerId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getCameraPosition", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(cameraPosition:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(cameraPosition:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FGMPlatformCameraPosition *output = [api cameraPosition:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMCATransactionWrapper.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMCATransactionWrapper.h new file mode 100644 index 000000000000..41df2dedd618 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMCATransactionWrapper.h @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Foundation; + +NS_ASSUME_NONNULL_BEGIN + +/// Protocol for CATransaction to allow mocking in tests. +@protocol FGMCATransactionProtocol +- (void)begin; +- (void)commit; +- (void)setAnimationDuration:(CFTimeInterval)duration; +@end + +/// Wrapper for CATransaction to allow mocking in tests. +@interface FGMCATransactionWrapper : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMClusterManagersController.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMClusterManagersController.h new file mode 100644 index 000000000000..394f9e3d71e0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMClusterManagersController.h @@ -0,0 +1,56 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "GoogleMapsUtilsTrampoline.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// A controller that manages all of the cluster managers on a map. +@interface FGMClusterManagersController : NSObject + +/// Initializes cluster manager controller. +/// +/// @param callbackHandler A callback handler. +/// @param mapView A map view that will be used to display clustered markers. +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler; + +/// Creates cluster managers and initializes them. +/// +/// @param clusterManagersToAdd Array of cluster managers to add. +- (void)addClusterManagers:(NSArray *)clusterManagersToAdd; + +/// Removes requested cluster managers from the controller. +/// +/// @param identifiers Array of cluster manager IDs to remove. +- (void)removeClusterManagersWithIdentifiers:(NSArray *)identifiers; + +/// Returns the cluster managers for the given identifier. +/// +/// @param identifier The identifier of the cluster manager. +/// @return A cluster manager if found; otherwise, nil. +- (nullable GMUClusterManager *)clusterManagerWithIdentifier:(NSString *)identifier; + +/// Returns an array of clusters managed by the cluster manager. +/// +/// @param identifier The identifier of the cluster manager whose clusters are to be retrieved. +/// @return An array of clusters. Returns `nil` only if `error` is populated. +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error; + +/// Called when a cluster marker is tapped on the map. +/// +/// @param cluster The cluster that was tapped on. +- (void)didTapCluster:(GMUStaticCluster *)cluster; + +/// Calls the cluster method of all the cluster managers. +- (void)invokeClusteringForEachClusterManager; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMConversionUtils.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMConversionUtils.h new file mode 100644 index 000000000000..45c13797099b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMConversionUtils.h @@ -0,0 +1,97 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import Foundation; +@import GoogleMaps; + +#import "GoogleMapsUtilsTrampoline.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Returns dict[key], or nil if dict[key] is NSNull. +extern id _Nullable FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key); + +/// Creates a CGPoint from its Pigeon equivalent. +extern CGPoint FGMGetCGPointForPigeonPoint(FGMPlatformPoint *point); + +/// Converts a CGPoint to its Pigeon equivalent. +extern FGMPlatformPoint *FGMGetPigeonPointForCGPoint(CGPoint point); + +/// Creates a CLLocationCoordinate2D from its Pigeon representation. +extern CLLocationCoordinate2D FGMGetCoordinateForPigeonLatLng(FGMPlatformLatLng *latLng); + +/// Converts a CLLocationCoordinate2D to its Pigeon representation. +extern FGMPlatformLatLng *FGMGetPigeonLatLngForCoordinate(CLLocationCoordinate2D coord); + +/// Creates a GMSCoordinateBounds from its Pigeon representation. +extern GMSCoordinateBounds *FGMGetCoordinateBoundsForPigeonLatLngBounds( + FGMPlatformLatLngBounds *bounds); + +/// Converts a GMSCoordinateBounds to its Pigeon representation. +extern FGMPlatformLatLngBounds *FGMGetPigeonLatLngBoundsForCoordinateBounds( + GMSCoordinateBounds *bounds); + +/// Converts a GMSCameraPosition to its Pigeon representation. +extern FGMPlatformCameraPosition *FGMGetPigeonCameraPositionForPosition( + GMSCameraPosition *position); + +/// Creates a GMSCameraPosition from its Pigeon representation. +extern GMSCameraPosition *FGMGetCameraPositionForPigeonCameraPosition( + FGMPlatformCameraPosition *position); + +/// Creates a CLLocation array from its Pigeon equivalent. +extern NSArray *FGMGetPointsForPigeonLatLngs(NSArray *points); + +/// Creates a CLLocation arary array, representing a set of holes, from its Pigeon equivalent. +extern NSArray *> *FGMGetHolesForPigeonLatLngArrays( + NSArray *> *points); + +extern GMSMutablePath *FGMGetPathFromPoints(NSArray *points); + +/// Creates a GMSMapViewType from its Pigeon representation. +extern GMSMapViewType FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapType type); + +/// Converts a GMUStaticCluster to its Pigeon representation. +extern FGMPlatformCluster *FGMGetPigeonCluster(GMUStaticCluster *cluster, + NSString *clusterManagerIdentifier); + +/// Converts a GMSGroundOverlay to its Pigeon representation. +extern FGMPlatformGroundOverlay *FGMGetPigeonGroundOverlay(GMSGroundOverlay *groundOverlay, + NSString *overlayId, + BOOL isCreatedWithBounds, + NSNumber *_Nullable zoomLevel); + +extern GMUGradient *FGMGetGradientForPigeonHeatmapGradient(FGMPlatformHeatmapGradient *gradient); + +extern FGMPlatformHeatmapGradient *FGMGetPigeonHeatmapGradientForGradient(GMUGradient *gradient); + +/// Creates a GMUWeightedLatLng array from its Pigeon equivalent. +extern NSArray *FGMGetWeightedDataForPigeonWeightedData( + NSArray *weightedLatLngs); + +/// Converts a GMUWeightedLatLng array to its Pigeon equivalent. +extern NSArray *FGMGetPigeonWeightedDataForWeightedData( + NSArray *weightedLatLngs); + +/// Creates a GMSCameraUpdate from its Pigeon equivalent. +extern GMSCameraUpdate *_Nullable FGMGetCameraUpdateForPigeonCameraUpdate( + FGMPlatformCameraUpdate *update); + +/// Creates a UIColor from its Pigeon representation. +extern UIColor *FGMGetColorForPigeonColor(FGMPlatformColor *color); + +/// Converts a UIColor to its Pigeon representation. +extern FGMPlatformColor *FGMGetPigeonColorForColor(UIColor *color); + +/// Creates an array of GMSStrokeStyles using the given patterns and stroke color. +extern NSArray *FGMGetStrokeStylesFromPatterns( + NSArray *patterns, UIColor *strokeColor); + +/// Creates an array of span lengths using the given patterns. +extern NSArray *FGMGetSpanLengthsFromPatterns( + NSArray *patterns); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMGroundOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMGroundOverlayController.h new file mode 100644 index 000000000000..a5297f703b9e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMGroundOverlayController.h @@ -0,0 +1,64 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import CoreLocation; +@import Flutter; +@import Foundation; +@import GoogleMaps; +@import UIKit; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Controller of a single ground overlay on the map. +@interface FGMGroundOverlayController : NSObject + +/// The ground overlay this controller handles. +@property(strong, nonatomic) GMSGroundOverlay *groundOverlay; + +/// Whether ground overlay is created with bounds or position. +@property(nonatomic, assign, getter=isCreatedWithBounds) BOOL createdWithBounds; + +/// Zoom level when ground overlay is initialized with position. +@property(nonatomic, strong, nullable) NSNumber *zoomLevel; + +/// Initializes an instance of this class with a GMSGroundOverlay, a map view, and identifier. +- (instancetype)initWithGroundOverlay:(GMSGroundOverlay *)groundOverlay + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView + isCreatedWithBounds:(BOOL)isCreatedWithBounds; + +/// Removes this ground overlay from the map. +- (void)removeGroundOverlay; +@end + +/// Controller of multiple ground overlays on the map. +@interface FLTGroundOverlaysController : NSObject + +/// Initializes the controller with a GMSMapView, callback handler and registrar. +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; + +/// Adds ground overlays to the map. +- (void)addGroundOverlays:(NSArray *)groundOverlaysToAdd; + +/// Updates ground overlays on the map. +- (void)changeGroundOverlays:(NSArray *)groundOverlaysToChange; + +/// Removes ground overlays from the map. +- (void)removeGroundOverlaysWithIdentifiers:(NSArray *)identifiers; + +/// Called when a ground overlay is tapped on the map. +- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier; + +/// Returns true if a ground overlay with the given identifier exists on the map. +- (bool)hasGroundOverlaysWithIdentifier:(NSString *)identifier; + +/// Returns the ground overlay with the given identifier. +- (nullable FGMPlatformGroundOverlay *)groundOverlayWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMGroundOverlayController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMGroundOverlayController_Test.h new file mode 100644 index 000000000000..87123539947d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMGroundOverlayController_Test.h @@ -0,0 +1,29 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMGroundOverlayController.h" + +/// Internal APIs exposed for unit testing +@interface FGMGroundOverlayController (Test) + +/// Ground Overlay instance the controller is attached to +@property(strong, nonatomic) GMSGroundOverlay *groundOverlay; + +/// Function to update the gms ground overlay from platform ground overlay. +- (void)updateFromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)groundOverlay + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale; + +/// Updates the underlying GMSGroundOverlay with the properties from the given +/// FGMPlatformGroundOverlay. +/// +/// Setting the ground overlay to visible will set its map to the given mapView. ++ (void)updateGroundOverlay:(GMSGroundOverlay *)groundOverlay + fromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)groundOverlay + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingBounds:(BOOL)useBounds; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMImageUtils.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMImageUtils.h new file mode 100644 index 000000000000..37a833d79d1e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMImageUtils.h @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Creates a UIImage from Pigeon bitmap. +UIImage *_Nullable FGMIconFromBitmap(FGMPlatformBitmap *platformBitmap, + NSObject *registrar, + CGFloat screenScale); +/// Returns a BOOL indicating whether image is considered scalable with the given scale factor from +/// size. +BOOL FGMIsScalableWithScaleFactorFromSize(CGSize originalSize, CGSize targetSize); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMMarkerUserData.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMMarkerUserData.h new file mode 100644 index 000000000000..166241f3cb56 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FGMMarkerUserData.h @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import GoogleMaps; + +NS_ASSUME_NONNULL_BEGIN + +/// Defines user data object for markers. +@interface FGMMarkerUserData : NSObject + +/// The identifier of the marker. +@property(nonatomic, copy) NSString *markerIdentifier; + +/// The identifier of the cluster manager. +/// This property is set only if the marker is managed by a cluster manager. +@property(nonatomic, copy, nullable) NSString *clusterManagerIdentifier; + +@end + +/// Associates a marker identifier and optionally a cluster manager identifier with a marker's user +/// data. +extern void FGMSetIdentifiersToMarkerUserData(NSString *markerIdentifier, + NSString *_Nullable clusterManagerIdentifier, + GMSMarker *marker); + +/// Get the marker identifier from marker's user data. +/// +/// @return The marker identifier if found; otherwise, nil. +extern NSString *_Nullable FGMGetMarkerIdentifierFromMarker(GMSMarker *marker); + +/// Get the cluster manager identifier from marker's user data. +/// +/// @return The cluster manager identifier if found; otherwise, nil. +extern NSString *_Nullable FGMGetClusterManagerIdentifierFromMarker(GMSMarker *marker); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController.h new file mode 100644 index 000000000000..a9c306abe7c4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "GoogleMapsUtilsTrampoline.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Controller of a single Heatmap on the map. +@interface FLTGoogleMapHeatmapController : NSObject + +/// Initializes an instance of this class with a heatmap tile layer, a map view, and additional +/// configuration options. +/// +/// @param heatmap The heatmap data to display. +/// @param heatmapTileLayer The heatmap tile layer that will be used to display heatmap data on the +/// map. +/// @param mapView The map view where the heatmap layer will be overlaid. +/// +/// @return An initialized instance of this class, configured with the specified heatmap tile layer, +/// map view, and additional options. +- (instancetype)initWithHeatmap:(FGMPlatformHeatmap *)heatmap + tileLayer:(GMUHeatmapTileLayer *)heatmapTileLayer + mapView:(GMSMapView *)mapView; + +/// Removes this heatmap from the map. +- (void)removeHeatmap; + +/// Clears the tile cache in order to visually udpate this heatmap. +- (void)clearTileCache; +@end + +/// Controller of multiple Heatmaps on the map. +@interface FLTHeatmapsController : NSObject + +/// Initializes the controller with a GMSMapView. +- (instancetype)initWithMapView:(GMSMapView *)mapView; + +/// Adds heatmaps to the map. +- (void)addHeatmaps:(NSArray *)heatmapsToAdd; + +/// Updates heatmaps on the map. +- (void)changeHeatmaps:(NSArray *)heatmapsToChange; + +/// Removes heatmaps from the map. +- (void)removeHeatmapsWithIdentifiers:(NSArray *)identifiers; + +/// Returns true if a heatmap with the given identifier exists on the map. +- (BOOL)hasHeatmapWithIdentifier:(NSString *)identifier; + +/// Returns the heatmap with the given identifier. +- (nullable FGMPlatformHeatmap *)heatmapWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController_Test.h new file mode 100644 index 000000000000..b00a48e3477f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapHeatmapController_Test.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapHeatmapController.h" + +/// Internal APIs exposed for unit testing +@interface FLTGoogleMapHeatmapController (Test) + +/// Updates the underlying GMUHeatmapTileLayer with the properties from the given platform heatmap. +/// +/// Setting the heatmap to visible will set its map to the given mapView. ++ (void)updateHeatmap:(GMUHeatmapTileLayer *)heatmapTileLayer + fromPlatformHeatmap:(FGMPlatformHeatmap *)platformHeatmap + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapTileOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapTileOverlayController.h new file mode 100644 index 000000000000..5c1b6e5418e8 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapTileOverlayController.h @@ -0,0 +1,40 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTGoogleMapTileOverlayController : NSObject +/// The layer managed by this controller instance. +@property(readonly, nonatomic) GMSTileLayer *layer; + +- (instancetype)initWithTileOverlay:(FGMPlatformTileOverlay *)tileOverlay + tileLayer:(GMSTileLayer *)tileLayer + mapView:(GMSMapView *)mapView; +- (void)removeTileOverlay; +- (void)clearTileCache; +@end + +@interface FLTTileProviderController : GMSTileLayer +@property(copy, nonatomic, readonly) NSString *tileOverlayIdentifier; +- (instancetype)initWithTileOverlayIdentifier:(NSString *)identifier + callbackHandler:(FGMMapsCallbackApi *)callbackHandler; +@end + +@interface FLTTileOverlaysController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd; +- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange; +- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers; +- (void)clearTileCacheWithIdentifier:(NSString *)identifier; +- (nullable FLTGoogleMapTileOverlayController *)tileOverlayWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapTileOverlayController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapTileOverlayController_Test.h new file mode 100644 index 000000000000..e753698cde45 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapTileOverlayController_Test.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapTileOverlayController.h" + +/// Internal APIs exposed for unit testing +@interface FLTGoogleMapTileOverlayController (Test) + +/// Updates the underlying GMSTileLayer with the properties from the given FGMPlatformTileOverlay. +/// +/// Setting the tile overlay to visible will set its map to the given mapView. ++ (void)updateTileLayer:(GMSTileLayer *)tileLayer + fromPlatformTileOverlay:(FGMPlatformTileOverlay *)platformOverlay + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapsPlugin.h new file mode 100644 index 000000000000..a5a1d05a4cbd --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/FLTGoogleMapsPlugin.h @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMClusterManagersController.h" +#import "GoogleMapCircleController.h" +#import "GoogleMapController.h" +#import "GoogleMapMarkerController.h" +#import "GoogleMapPolygonController.h" +#import "GoogleMapPolylineController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTGoogleMapsPlugin : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapCircleController.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapCircleController.h new file mode 100644 index 000000000000..0cb21d926f6a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapCircleController.h @@ -0,0 +1,30 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +// Defines circle controllable by Flutter. +@interface FLTGoogleMapCircleController : NSObject +- (instancetype)initCircleWithPlatformCircle:(FGMPlatformCircle *)circle + mapView:(GMSMapView *)mapView; +- (void)removeCircle; +@end + +@interface FLTCirclesController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addCircles:(NSArray *)circlesToAdd; +- (void)changeCircles:(NSArray *)circlesToChange; +- (void)removeCirclesWithIdentifiers:(NSArray *)identifiers; +- (void)didTapCircleWithIdentifier:(NSString *)identifier; +- (bool)hasCircleWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapCircleController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapCircleController_Test.h new file mode 100644 index 000000000000..1c72d2060dc1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapCircleController_Test.h @@ -0,0 +1,21 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapCircleController.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Private methods exposed for testing. +@interface FLTGoogleMapCircleController (Test) + +/// Updates the underlying GMSCircle with the properties from the given FGMPlatformCircle. +/// +/// Setting the circle to visible will set its map to the given mapView. ++ (void)updateCircle:(GMSCircle *)circle + fromPlatformCircle:(FGMPlatformCircle *)platformCircle + withMapView:(GMSMapView *)mapView; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapController.h new file mode 100644 index 000000000000..e9ea39630ebf --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapController.h @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMCATransactionWrapper.h" +#import "FGMClusterManagersController.h" +#import "GoogleMapCircleController.h" +#import "GoogleMapMarkerController.h" +#import "GoogleMapPolygonController.h" +#import "GoogleMapPolylineController.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +// Defines map overlay controllable from Flutter. +@interface FLTGoogleMapController : NSObject +- (instancetype)initWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *)registrar; +- (void)showAtOrigin:(CGPoint)origin; +- (void)hide; +- (nullable GMSCameraPosition *)cameraPosition; +@end + +// Allows the engine to create new Google Map instances. +@interface FLTGoogleMapFactory : NSObject +- (instancetype)initWithRegistrar:(NSObject *)registrar; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapController_Test.h new file mode 100644 index 000000000000..219a1ac246e9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapController_Test.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMCATransactionWrapper.h" +#import "GoogleMapController.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Implementation of the Pigeon maps API. +/// +/// This is a separate object from the maps controller because the Pigeon API registration keeps a +/// strong reference to the implementor, but as the FlutterPlatformView, the lifetime of the +/// FLTGoogleMapController instance is what needs to trigger Pigeon unregistration, so can't be +/// the target of the registration. +@interface FGMMapCallHandler : NSObject + +/// The transaction wrapper to use for camera animations. +@property(nonatomic, strong) id transactionWrapper; + +@end + +/// Implementation of the Pigeon maps inspector API. +/// +/// This is a separate object from the maps controller because the Pigeon API registration keeps a +/// strong reference to the implementor, but as the FlutterPlatformView, the lifetime of the +/// FLTGoogleMapController instance is what needs to trigger Pigeon unregistration, so can't be +/// the target of the registration. +@interface FGMMapInspector : NSObject + +/// Initializes a Pigeon API for inpector with a map controller. +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix; + +@end + +@interface FLTGoogleMapController (Test) + +/// Initializes a map controller with a concrete map view. +/// +/// @param mapView A map view that will be displayed by the controller +/// @param viewId A unique identifier for the controller. +/// @param creationParameters Parameters for initialising the map view. +/// @param registrar The plugin registrar passed from Flutter. +- (instancetype)initWithMapView:(GMSMapView *)mapView + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *)registrar; + +// The main Pigeon API implementation. +@property(nonatomic, strong, readonly) FGMMapCallHandler *callHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapMarkerController.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapMarkerController.h new file mode 100644 index 000000000000..dcebcb1e2982 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapMarkerController.h @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMClusterManagersController.h" +#import "GoogleMapController.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +// Defines marker controllable by Flutter. +@interface FLTGoogleMapMarkerController : NSObject +@property(assign, nonatomic, readonly) BOOL consumeTapEvents; +- (instancetype)initWithMarker:(GMSMarker *)marker + markerIdentifier:(NSString *)markerIdentifier + mapView:(GMSMapView *)mapView; +- (void)showInfoWindow; +- (void)hideInfoWindow; +- (BOOL)isInfoWindowShown; +- (void)removeMarker; +@end + +@interface FLTMarkersController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + clusterManagersController:(nullable FGMClusterManagersController *)clusterManagersController + registrar:(NSObject *)registrar; +- (void)addMarkers:(NSArray *)markersToAdd; +- (void)changeMarkers:(NSArray *)markersToChange; +- (void)removeMarkersWithIdentifiers:(NSArray *)identifiers; +- (BOOL)didTapMarkerWithIdentifier:(NSString *)identifier; +- (void)didStartDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)coordinate; +- (void)didEndDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)coordinate; +- (void)didDragMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)coordinate; +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)identifier; +- (void)showMarkerInfoWindowWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error; +- (void)hideMarkerInfoWindowWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error; +/// Returns whether or not the info window for the marker with the given identifier is shown. +/// +/// If there is no such marker, returns nil and sets error. +- (nullable NSNumber *) + isInfoWindowShownForMarkerWithIdentifier:(NSString *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapMarkerController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapMarkerController_Test.h new file mode 100644 index 000000000000..f6ff32e791e1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapMarkerController_Test.h @@ -0,0 +1,31 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapMarkerController.h" + +/// Methods exposed for unit testing. +@interface FLTGoogleMapMarkerController (Test) + +/// The underlying controlled GMSMarker. +@property(strong, nonatomic, readonly) GMSMarker *marker; + +/// Updates the underlying GMSMarker with the properties from the given FGMPlatformMarker. +/// +/// Setting the marker to visible will set its map to the given mapView. ++ (void)updateMarker:(GMSMarker *)marker + fromPlatformMarker:(FGMPlatformMarker *)platformMarker + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingOpacityForVisibility:(BOOL)useOpacityForVisibility; + +@end + +/// Methods exposed for unit testing. +@interface FLTMarkersController (Test) + +/// A mapping from marker identifiers to corresponding marker controllers. +@property(strong, nonatomic, readonly) NSMutableDictionary *markerIdentifierToController; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolygonController.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolygonController.h new file mode 100644 index 000000000000..b26cf2416c5f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolygonController.h @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +// Defines polygon controllable by Flutter. +@interface FLTGoogleMapPolygonController : NSObject +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView; +- (void)removePolygon; +@end + +@interface FLTPolygonsController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addPolygons:(NSArray *)polygonsToAdd; +- (void)changePolygons:(NSArray *)polygonsToChange; +- (void)removePolygonWithIdentifiers:(NSArray *)identifiers; +- (void)didTapPolygonWithIdentifier:(NSString *)identifier; +- (bool)hasPolygonWithIdentifier:(NSString *)identifier; +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolygonController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolygonController_Test.h new file mode 100644 index 000000000000..ab4cf60be224 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolygonController_Test.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolygonController.h" + +/// Methods exposed for unit testing. +@interface FLTGoogleMapPolygonController (Test) + +/// Updates the underlying GMSPolygon with the properties from the given FGMPlatformPolygon. +/// +/// Setting the polygon to visible will set its map to the given mapView. ++ (void)updatePolygon:(GMSPolygon *)polygon + fromPlatformPolygon:(FGMPlatformPolygon *)polygon + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolylineController.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolylineController.h new file mode 100644 index 000000000000..5505ec54019b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolylineController.h @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +// Defines polyline controllable by Flutter. +@interface FLTGoogleMapPolylineController : NSObject +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView; +- (void)removePolyline; +@end + +@interface FLTPolylinesController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addPolylines:(NSArray *)polylinesToAdd; +- (void)changePolylines:(NSArray *)polylinesToChange; +- (void)removePolylineWithIdentifiers:(NSArray *)identifiers; +- (void)didTapPolylineWithIdentifier:(NSString *)identifier; +- (bool)hasPolylineWithIdentifier:(NSString *)identifier; +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolylineController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolylineController_Test.h new file mode 100644 index 000000000000..df9e31293951 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapPolylineController_Test.h @@ -0,0 +1,25 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolylineController.h" + +/// Internal APIs exposed for unit testing +@interface FLTGoogleMapPolylineController (Test) + +/// Polyline instance the controller is attached to +@property(strong, nonatomic) GMSPolyline *polyline; + +/// Updates the controller's polyline with the properties from the given FGMPlatformPolyline. +/// +/// Setting the polyline to visible will set its map to the controller's mapView. +- (void)updateFromPlatformPolyline:(FGMPlatformPolyline *)polyline; + +/// Updates the underlying GMSPolyline with the properties from the given FGMPlatformPolyline. +/// +/// Setting the polyline to visible will set its map to the given mapView. ++ (void)updatePolyline:(GMSPolyline *)polyline + fromPlatformPolyline:(FGMPlatformPolyline *)platformPolyline + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h new file mode 100644 index 000000000000..cf6399b5b39e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/GoogleMapsUtilsTrampoline.h @@ -0,0 +1,12 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// If Swift Package Manager is in use, Objective-C headers are available under the +// GoogleMapsUtilsObjC package. When using CocoaPods, the headers are provided by the +// GoogleMapsUtils package. +#ifdef FGM_USING_COCOAPODS +@import GoogleMapsUtils; +#else +@import GoogleMapsUtilsObjC; +#endif diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.h b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.h new file mode 100644 index 000000000000..db11f425c37c --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.h @@ -0,0 +1,940 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#import + +@protocol FlutterBinaryMessenger; +@protocol FlutterMessageCodec; +@class FlutterError; +@class FlutterStandardTypedData; + +NS_ASSUME_NONNULL_BEGIN + +/// Pigeon equivalent of MapType +typedef NS_ENUM(NSUInteger, FGMPlatformMapType) { + FGMPlatformMapTypeNone = 0, + FGMPlatformMapTypeNormal = 1, + FGMPlatformMapTypeSatellite = 2, + FGMPlatformMapTypeTerrain = 3, + FGMPlatformMapTypeHybrid = 4, +}; + +/// Wrapper for FGMPlatformMapType to allow for nullability. +@interface FGMPlatformMapTypeBox : NSObject +@property(nonatomic, assign) FGMPlatformMapType value; +- (instancetype)initWithValue:(FGMPlatformMapType)value; +@end + +/// Join types for polyline joints. +typedef NS_ENUM(NSUInteger, FGMPlatformJointType) { + FGMPlatformJointTypeMitered = 0, + FGMPlatformJointTypeBevel = 1, + FGMPlatformJointTypeRound = 2, +}; + +/// Wrapper for FGMPlatformJointType to allow for nullability. +@interface FGMPlatformJointTypeBox : NSObject +@property(nonatomic, assign) FGMPlatformJointType value; +- (instancetype)initWithValue:(FGMPlatformJointType)value; +@end + +/// Enumeration of possible types for PatternItem. +typedef NS_ENUM(NSUInteger, FGMPlatformPatternItemType) { + FGMPlatformPatternItemTypeDot = 0, + FGMPlatformPatternItemTypeDash = 1, + FGMPlatformPatternItemTypeGap = 2, +}; + +/// Wrapper for FGMPlatformPatternItemType to allow for nullability. +@interface FGMPlatformPatternItemTypeBox : NSObject +@property(nonatomic, assign) FGMPlatformPatternItemType value; +- (instancetype)initWithValue:(FGMPlatformPatternItemType)value; +@end + +/// Pigeon equivalent of [MapBitmapScaling]. +typedef NS_ENUM(NSUInteger, FGMPlatformMapBitmapScaling) { + FGMPlatformMapBitmapScalingAuto = 0, + FGMPlatformMapBitmapScalingNone = 1, +}; + +/// Wrapper for FGMPlatformMapBitmapScaling to allow for nullability. +@interface FGMPlatformMapBitmapScalingBox : NSObject +@property(nonatomic, assign) FGMPlatformMapBitmapScaling value; +- (instancetype)initWithValue:(FGMPlatformMapBitmapScaling)value; +@end + +@class FGMPlatformCameraPosition; +@class FGMPlatformCameraUpdate; +@class FGMPlatformCameraUpdateNewCameraPosition; +@class FGMPlatformCameraUpdateNewLatLng; +@class FGMPlatformCameraUpdateNewLatLngBounds; +@class FGMPlatformCameraUpdateNewLatLngZoom; +@class FGMPlatformCameraUpdateScrollBy; +@class FGMPlatformCameraUpdateZoomBy; +@class FGMPlatformCameraUpdateZoom; +@class FGMPlatformCameraUpdateZoomTo; +@class FGMPlatformCircle; +@class FGMPlatformHeatmap; +@class FGMPlatformHeatmapGradient; +@class FGMPlatformWeightedLatLng; +@class FGMPlatformInfoWindow; +@class FGMPlatformCluster; +@class FGMPlatformClusterManager; +@class FGMPlatformMarker; +@class FGMPlatformPolygon; +@class FGMPlatformPolyline; +@class FGMPlatformPatternItem; +@class FGMPlatformTile; +@class FGMPlatformTileOverlay; +@class FGMPlatformEdgeInsets; +@class FGMPlatformLatLng; +@class FGMPlatformLatLngBounds; +@class FGMPlatformCameraTargetBounds; +@class FGMPlatformGroundOverlay; +@class FGMPlatformMapViewCreationParams; +@class FGMPlatformMapConfiguration; +@class FGMPlatformPoint; +@class FGMPlatformSize; +@class FGMPlatformColor; +@class FGMPlatformTileLayer; +@class FGMPlatformZoomRange; +@class FGMPlatformBitmap; +@class FGMPlatformBitmapDefaultMarker; +@class FGMPlatformBitmapBytes; +@class FGMPlatformBitmapAsset; +@class FGMPlatformBitmapAssetImage; +@class FGMPlatformBitmapAssetMap; +@class FGMPlatformBitmapBytesMap; + +/// Pigeon representatation of a CameraPosition. +@interface FGMPlatformCameraPosition : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithBearing:(double)bearing + target:(FGMPlatformLatLng *)target + tilt:(double)tilt + zoom:(double)zoom; +@property(nonatomic, assign) double bearing; +@property(nonatomic, strong) FGMPlatformLatLng *target; +@property(nonatomic, assign) double tilt; +@property(nonatomic, assign) double zoom; +@end + +/// Pigeon representation of a CameraUpdate. +@interface FGMPlatformCameraUpdate : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithCameraUpdate:(id)cameraUpdate; +/// This Object must be one of the classes below prefixed with +/// PlatformCameraUpdate. Each such class represents a different type of +/// camera update, and each holds a different set of data, preventing the +/// use of a single unified class. +@property(nonatomic, strong) id cameraUpdate; +@end + +/// Pigeon equivalent of NewCameraPosition +@interface FGMPlatformCameraUpdateNewCameraPosition : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithCameraPosition:(FGMPlatformCameraPosition *)cameraPosition; +@property(nonatomic, strong) FGMPlatformCameraPosition *cameraPosition; +@end + +/// Pigeon equivalent of NewLatLng +@interface FGMPlatformCameraUpdateNewLatLng : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng; +@property(nonatomic, strong) FGMPlatformLatLng *latLng; +@end + +/// Pigeon equivalent of NewLatLngBounds +@interface FGMPlatformCameraUpdateNewLatLngBounds : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithBounds:(FGMPlatformLatLngBounds *)bounds padding:(double)padding; +@property(nonatomic, strong) FGMPlatformLatLngBounds *bounds; +@property(nonatomic, assign) double padding; +@end + +/// Pigeon equivalent of NewLatLngZoom +@interface FGMPlatformCameraUpdateNewLatLngZoom : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng zoom:(double)zoom; +@property(nonatomic, strong) FGMPlatformLatLng *latLng; +@property(nonatomic, assign) double zoom; +@end + +/// Pigeon equivalent of ScrollBy +@interface FGMPlatformCameraUpdateScrollBy : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithDx:(double)dx dy:(double)dy; +@property(nonatomic, assign) double dx; +@property(nonatomic, assign) double dy; +@end + +/// Pigeon equivalent of ZoomBy +@interface FGMPlatformCameraUpdateZoomBy : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAmount:(double)amount focus:(nullable FGMPlatformPoint *)focus; +@property(nonatomic, assign) double amount; +@property(nonatomic, strong, nullable) FGMPlatformPoint *focus; +@end + +/// Pigeon equivalent of ZoomIn/ZoomOut +@interface FGMPlatformCameraUpdateZoom : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithOut:(BOOL)out; +@property(nonatomic, assign) BOOL out; +@end + +/// Pigeon equivalent of ZoomTo +@interface FGMPlatformCameraUpdateZoomTo : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithZoom:(double)zoom; +@property(nonatomic, assign) double zoom; +@end + +/// Pigeon equivalent of the Circle class. +@interface FGMPlatformCircle : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithConsumeTapEvents:(BOOL)consumeTapEvents + fillColor:(FGMPlatformColor *)fillColor + strokeColor:(FGMPlatformColor *)strokeColor + visible:(BOOL)visible + strokeWidth:(NSInteger)strokeWidth + zIndex:(double)zIndex + center:(FGMPlatformLatLng *)center + radius:(double)radius + circleId:(NSString *)circleId; +@property(nonatomic, assign) BOOL consumeTapEvents; +@property(nonatomic, strong) FGMPlatformColor *fillColor; +@property(nonatomic, strong) FGMPlatformColor *strokeColor; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger strokeWidth; +@property(nonatomic, assign) double zIndex; +@property(nonatomic, strong) FGMPlatformLatLng *center; +@property(nonatomic, assign) double radius; +@property(nonatomic, copy) NSString *circleId; +@end + +/// Pigeon equivalent of the Heatmap class. +@interface FGMPlatformHeatmap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithHeatmapId:(NSString *)heatmapId + data:(NSArray *)data + gradient:(nullable FGMPlatformHeatmapGradient *)gradient + opacity:(double)opacity + radius:(NSInteger)radius + minimumZoomIntensity:(NSInteger)minimumZoomIntensity + maximumZoomIntensity:(NSInteger)maximumZoomIntensity; +@property(nonatomic, copy) NSString *heatmapId; +@property(nonatomic, copy) NSArray *data; +@property(nonatomic, strong, nullable) FGMPlatformHeatmapGradient *gradient; +@property(nonatomic, assign) double opacity; +@property(nonatomic, assign) NSInteger radius; +@property(nonatomic, assign) NSInteger minimumZoomIntensity; +@property(nonatomic, assign) NSInteger maximumZoomIntensity; +@end + +/// Pigeon equivalent of the HeatmapGradient class. +/// +/// The GMUGradient structure is slightly different from HeatmapGradient, so +/// this matches the iOS API so that conversion can be done on the Dart side +/// where the structures are easier to work with. +@interface FGMPlatformHeatmapGradient : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithColors:(NSArray *)colors + startPoints:(NSArray *)startPoints + colorMapSize:(NSInteger)colorMapSize; +@property(nonatomic, copy) NSArray *colors; +@property(nonatomic, copy) NSArray *startPoints; +@property(nonatomic, assign) NSInteger colorMapSize; +@end + +/// Pigeon equivalent of the WeightedLatLng class. +@interface FGMPlatformWeightedLatLng : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithPoint:(FGMPlatformLatLng *)point weight:(double)weight; +@property(nonatomic, strong) FGMPlatformLatLng *point; +@property(nonatomic, assign) double weight; +@end + +/// Pigeon equivalent of the InfoWindow class. +@interface FGMPlatformInfoWindow : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithTitle:(nullable NSString *)title + snippet:(nullable NSString *)snippet + anchor:(FGMPlatformPoint *)anchor; +@property(nonatomic, copy, nullable) NSString *title; +@property(nonatomic, copy, nullable) NSString *snippet; +@property(nonatomic, strong) FGMPlatformPoint *anchor; +@end + +/// Pigeon equivalent of Cluster. +@interface FGMPlatformCluster : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithClusterManagerId:(NSString *)clusterManagerId + position:(FGMPlatformLatLng *)position + bounds:(FGMPlatformLatLngBounds *)bounds + markerIds:(NSArray *)markerIds; +@property(nonatomic, copy) NSString *clusterManagerId; +@property(nonatomic, strong) FGMPlatformLatLng *position; +@property(nonatomic, strong) FGMPlatformLatLngBounds *bounds; +@property(nonatomic, copy) NSArray *markerIds; +@end + +/// Pigeon equivalent of the ClusterManager class. +@interface FGMPlatformClusterManager : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithIdentifier:(NSString *)identifier; +@property(nonatomic, copy) NSString *identifier; +@end + +/// Pigeon equivalent of the Marker class. +@interface FGMPlatformMarker : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAlpha:(double)alpha + anchor:(FGMPlatformPoint *)anchor + consumeTapEvents:(BOOL)consumeTapEvents + draggable:(BOOL)draggable + flat:(BOOL)flat + icon:(FGMPlatformBitmap *)icon + infoWindow:(FGMPlatformInfoWindow *)infoWindow + position:(FGMPlatformLatLng *)position + rotation:(double)rotation + visible:(BOOL)visible + zIndex:(NSInteger)zIndex + markerId:(NSString *)markerId + clusterManagerId:(nullable NSString *)clusterManagerId; +@property(nonatomic, assign) double alpha; +@property(nonatomic, strong) FGMPlatformPoint *anchor; +@property(nonatomic, assign) BOOL consumeTapEvents; +@property(nonatomic, assign) BOOL draggable; +@property(nonatomic, assign) BOOL flat; +@property(nonatomic, strong) FGMPlatformBitmap *icon; +@property(nonatomic, strong) FGMPlatformInfoWindow *infoWindow; +@property(nonatomic, strong) FGMPlatformLatLng *position; +@property(nonatomic, assign) double rotation; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger zIndex; +@property(nonatomic, copy) NSString *markerId; +@property(nonatomic, copy, nullable) NSString *clusterManagerId; +@end + +/// Pigeon equivalent of the Polygon class. +@interface FGMPlatformPolygon : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithPolygonId:(NSString *)polygonId + consumesTapEvents:(BOOL)consumesTapEvents + fillColor:(FGMPlatformColor *)fillColor + geodesic:(BOOL)geodesic + points:(NSArray *)points + holes:(NSArray *> *)holes + visible:(BOOL)visible + strokeColor:(FGMPlatformColor *)strokeColor + strokeWidth:(NSInteger)strokeWidth + zIndex:(NSInteger)zIndex; +@property(nonatomic, copy) NSString *polygonId; +@property(nonatomic, assign) BOOL consumesTapEvents; +@property(nonatomic, strong) FGMPlatformColor *fillColor; +@property(nonatomic, assign) BOOL geodesic; +@property(nonatomic, copy) NSArray *points; +@property(nonatomic, copy) NSArray *> *holes; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, strong) FGMPlatformColor *strokeColor; +@property(nonatomic, assign) NSInteger strokeWidth; +@property(nonatomic, assign) NSInteger zIndex; +@end + +/// Pigeon equivalent of the Polyline class. +@interface FGMPlatformPolyline : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithPolylineId:(NSString *)polylineId + consumesTapEvents:(BOOL)consumesTapEvents + color:(FGMPlatformColor *)color + geodesic:(BOOL)geodesic + jointType:(FGMPlatformJointType)jointType + patterns:(NSArray *)patterns + points:(NSArray *)points + visible:(BOOL)visible + width:(NSInteger)width + zIndex:(NSInteger)zIndex; +@property(nonatomic, copy) NSString *polylineId; +@property(nonatomic, assign) BOOL consumesTapEvents; +@property(nonatomic, strong) FGMPlatformColor *color; +@property(nonatomic, assign) BOOL geodesic; +/// The joint type. +@property(nonatomic, assign) FGMPlatformJointType jointType; +/// The pattern data, as a list of pattern items. +@property(nonatomic, copy) NSArray *patterns; +@property(nonatomic, copy) NSArray *points; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger width; +@property(nonatomic, assign) NSInteger zIndex; +@end + +/// Pigeon equivalent of the PatternItem class. +@interface FGMPlatformPatternItem : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithType:(FGMPlatformPatternItemType)type length:(nullable NSNumber *)length; +@property(nonatomic, assign) FGMPlatformPatternItemType type; +@property(nonatomic, strong, nullable) NSNumber *length; +@end + +/// Pigeon equivalent of the Tile class. +@interface FGMPlatformTile : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithWidth:(NSInteger)width + height:(NSInteger)height + data:(nullable FlutterStandardTypedData *)data; +@property(nonatomic, assign) NSInteger width; +@property(nonatomic, assign) NSInteger height; +@property(nonatomic, strong, nullable) FlutterStandardTypedData *data; +@end + +/// Pigeon equivalent of the TileOverlay class. +@interface FGMPlatformTileOverlay : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithTileOverlayId:(NSString *)tileOverlayId + fadeIn:(BOOL)fadeIn + transparency:(double)transparency + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + tileSize:(NSInteger)tileSize; +@property(nonatomic, copy) NSString *tileOverlayId; +@property(nonatomic, assign) BOOL fadeIn; +@property(nonatomic, assign) double transparency; +@property(nonatomic, assign) NSInteger zIndex; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger tileSize; +@end + +/// Pigeon equivalent of Flutter's EdgeInsets. +@interface FGMPlatformEdgeInsets : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithTop:(double)top bottom:(double)bottom left:(double)left right:(double)right; +@property(nonatomic, assign) double top; +@property(nonatomic, assign) double bottom; +@property(nonatomic, assign) double left; +@property(nonatomic, assign) double right; +@end + +/// Pigeon equivalent of LatLng. +@interface FGMPlatformLatLng : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithLatitude:(double)latitude longitude:(double)longitude; +@property(nonatomic, assign) double latitude; +@property(nonatomic, assign) double longitude; +@end + +/// Pigeon equivalent of LatLngBounds. +@interface FGMPlatformLatLngBounds : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithNortheast:(FGMPlatformLatLng *)northeast + southwest:(FGMPlatformLatLng *)southwest; +@property(nonatomic, strong) FGMPlatformLatLng *northeast; +@property(nonatomic, strong) FGMPlatformLatLng *southwest; +@end + +/// Pigeon equivalent of CameraTargetBounds. +/// +/// As with the Dart version, it exists to distinguish between not setting a +/// a target, and having an explicitly unbounded target (null [bounds]). +@interface FGMPlatformCameraTargetBounds : NSObject ++ (instancetype)makeWithBounds:(nullable FGMPlatformLatLngBounds *)bounds; +@property(nonatomic, strong, nullable) FGMPlatformLatLngBounds *bounds; +@end + +/// Pigeon equivalent of the GroundOverlay class. +@interface FGMPlatformGroundOverlay : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithGroundOverlayId:(NSString *)groundOverlayId + image:(FGMPlatformBitmap *)image + position:(nullable FGMPlatformLatLng *)position + bounds:(nullable FGMPlatformLatLngBounds *)bounds + anchor:(nullable FGMPlatformPoint *)anchor + transparency:(double)transparency + bearing:(double)bearing + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + clickable:(BOOL)clickable + zoomLevel:(nullable NSNumber *)zoomLevel; +@property(nonatomic, copy) NSString *groundOverlayId; +@property(nonatomic, strong) FGMPlatformBitmap *image; +@property(nonatomic, strong, nullable) FGMPlatformLatLng *position; +@property(nonatomic, strong, nullable) FGMPlatformLatLngBounds *bounds; +@property(nonatomic, strong, nullable) FGMPlatformPoint *anchor; +@property(nonatomic, assign) double transparency; +@property(nonatomic, assign) double bearing; +@property(nonatomic, assign) NSInteger zIndex; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) BOOL clickable; +@property(nonatomic, strong, nullable) NSNumber *zoomLevel; +@end + +/// Information passed to the platform view creation. +@interface FGMPlatformMapViewCreationParams : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype) + makeWithInitialCameraPosition:(FGMPlatformCameraPosition *)initialCameraPosition + mapConfiguration:(FGMPlatformMapConfiguration *)mapConfiguration + initialCircles:(NSArray *)initialCircles + initialMarkers:(NSArray *)initialMarkers + initialPolygons:(NSArray *)initialPolygons + initialPolylines:(NSArray *)initialPolylines + initialHeatmaps:(NSArray *)initialHeatmaps + initialTileOverlays:(NSArray *)initialTileOverlays + initialClusterManagers:(NSArray *)initialClusterManagers + initialGroundOverlays:(NSArray *)initialGroundOverlays; +@property(nonatomic, strong) FGMPlatformCameraPosition *initialCameraPosition; +@property(nonatomic, strong) FGMPlatformMapConfiguration *mapConfiguration; +@property(nonatomic, copy) NSArray *initialCircles; +@property(nonatomic, copy) NSArray *initialMarkers; +@property(nonatomic, copy) NSArray *initialPolygons; +@property(nonatomic, copy) NSArray *initialPolylines; +@property(nonatomic, copy) NSArray *initialHeatmaps; +@property(nonatomic, copy) NSArray *initialTileOverlays; +@property(nonatomic, copy) NSArray *initialClusterManagers; +@property(nonatomic, copy) NSArray *initialGroundOverlays; +@end + +/// Pigeon equivalent of MapConfiguration. +@interface FGMPlatformMapConfiguration : NSObject ++ (instancetype)makeWithCompassEnabled:(nullable NSNumber *)compassEnabled + cameraTargetBounds:(nullable FGMPlatformCameraTargetBounds *)cameraTargetBounds + mapType:(nullable FGMPlatformMapTypeBox *)mapType + minMaxZoomPreference:(nullable FGMPlatformZoomRange *)minMaxZoomPreference + rotateGesturesEnabled:(nullable NSNumber *)rotateGesturesEnabled + scrollGesturesEnabled:(nullable NSNumber *)scrollGesturesEnabled + tiltGesturesEnabled:(nullable NSNumber *)tiltGesturesEnabled + trackCameraPosition:(nullable NSNumber *)trackCameraPosition + zoomGesturesEnabled:(nullable NSNumber *)zoomGesturesEnabled + myLocationEnabled:(nullable NSNumber *)myLocationEnabled + myLocationButtonEnabled:(nullable NSNumber *)myLocationButtonEnabled + padding:(nullable FGMPlatformEdgeInsets *)padding + indoorViewEnabled:(nullable NSNumber *)indoorViewEnabled + trafficEnabled:(nullable NSNumber *)trafficEnabled + buildingsEnabled:(nullable NSNumber *)buildingsEnabled + mapId:(nullable NSString *)mapId + style:(nullable NSString *)style; +@property(nonatomic, strong, nullable) NSNumber *compassEnabled; +@property(nonatomic, strong, nullable) FGMPlatformCameraTargetBounds *cameraTargetBounds; +@property(nonatomic, strong, nullable) FGMPlatformMapTypeBox *mapType; +@property(nonatomic, strong, nullable) FGMPlatformZoomRange *minMaxZoomPreference; +@property(nonatomic, strong, nullable) NSNumber *rotateGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *scrollGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *tiltGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *trackCameraPosition; +@property(nonatomic, strong, nullable) NSNumber *zoomGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *myLocationEnabled; +@property(nonatomic, strong, nullable) NSNumber *myLocationButtonEnabled; +@property(nonatomic, strong, nullable) FGMPlatformEdgeInsets *padding; +@property(nonatomic, strong, nullable) NSNumber *indoorViewEnabled; +@property(nonatomic, strong, nullable) NSNumber *trafficEnabled; +@property(nonatomic, strong, nullable) NSNumber *buildingsEnabled; +@property(nonatomic, copy, nullable) NSString *mapId; +@property(nonatomic, copy, nullable) NSString *style; +@end + +/// Pigeon representation of an x,y coordinate. +@interface FGMPlatformPoint : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithX:(double)x y:(double)y; +@property(nonatomic, assign) double x; +@property(nonatomic, assign) double y; +@end + +/// Pigeon representation of a size. +@interface FGMPlatformSize : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithWidth:(double)width height:(double)height; +@property(nonatomic, assign) double width; +@property(nonatomic, assign) double height; +@end + +/// Pigeon representation of a color. +@interface FGMPlatformColor : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithRed:(double)red green:(double)green blue:(double)blue alpha:(double)alpha; +@property(nonatomic, assign) double red; +@property(nonatomic, assign) double green; +@property(nonatomic, assign) double blue; +@property(nonatomic, assign) double alpha; +@end + +/// Pigeon equivalent of GMSTileLayer properties. +@interface FGMPlatformTileLayer : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithVisible:(BOOL)visible + fadeIn:(BOOL)fadeIn + opacity:(double)opacity + zIndex:(NSInteger)zIndex; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) BOOL fadeIn; +@property(nonatomic, assign) double opacity; +@property(nonatomic, assign) NSInteger zIndex; +@end + +/// Pigeon equivalent of MinMaxZoomPreference. +@interface FGMPlatformZoomRange : NSObject ++ (instancetype)makeWithMin:(nullable NSNumber *)min max:(nullable NSNumber *)max; +@property(nonatomic, strong, nullable) NSNumber *min; +@property(nonatomic, strong, nullable) NSNumber *max; +@end + +/// Pigeon equivalent of [BitmapDescriptor]. As there are multiple disjoint +/// types of [BitmapDescriptor], [PlatformBitmap] contains a single field which +/// may hold the pigeon equivalent type of any of them. +@interface FGMPlatformBitmap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithBitmap:(id)bitmap; +/// One of [PlatformBitmapAssetMap], [PlatformBitmapAsset], +/// [PlatformBitmapAssetImage], [PlatformBitmapBytesMap], +/// [PlatformBitmapBytes], or [PlatformBitmapDefaultMarker]. +/// As Pigeon does not currently support data class inheritance, this +/// approach allows for the different bitmap implementations to be valid +/// argument and return types of the API methods. See +/// https://github.com/flutter/flutter/issues/117819. +@property(nonatomic, strong) id bitmap; +@end + +/// Pigeon equivalent of [DefaultMarker]. +@interface FGMPlatformBitmapDefaultMarker : NSObject ++ (instancetype)makeWithHue:(nullable NSNumber *)hue; +@property(nonatomic, strong, nullable) NSNumber *hue; +@end + +/// Pigeon equivalent of [BytesBitmap]. +@interface FGMPlatformBitmapBytes : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + size:(nullable FGMPlatformSize *)size; +@property(nonatomic, strong) FlutterStandardTypedData *byteData; +@property(nonatomic, strong, nullable) FGMPlatformSize *size; +@end + +/// Pigeon equivalent of [AssetBitmap]. +@interface FGMPlatformBitmapAsset : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithName:(NSString *)name pkg:(nullable NSString *)pkg; +@property(nonatomic, copy) NSString *name; +@property(nonatomic, copy, nullable) NSString *pkg; +@end + +/// Pigeon equivalent of [AssetImageBitmap]. +@interface FGMPlatformBitmapAssetImage : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithName:(NSString *)name + scale:(double)scale + size:(nullable FGMPlatformSize *)size; +@property(nonatomic, copy) NSString *name; +@property(nonatomic, assign) double scale; +@property(nonatomic, strong, nullable) FGMPlatformSize *size; +@end + +/// Pigeon equivalent of [AssetMapBitmap]. +@interface FGMPlatformBitmapAssetMap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAssetName:(NSString *)assetName + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height; +@property(nonatomic, copy) NSString *assetName; +@property(nonatomic, assign) FGMPlatformMapBitmapScaling bitmapScaling; +@property(nonatomic, assign) double imagePixelRatio; +@property(nonatomic, strong, nullable) NSNumber *width; +@property(nonatomic, strong, nullable) NSNumber *height; +@end + +/// Pigeon equivalent of [BytesMapBitmap]. +@interface FGMPlatformBitmapBytesMap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height; +@property(nonatomic, strong) FlutterStandardTypedData *byteData; +@property(nonatomic, assign) FGMPlatformMapBitmapScaling bitmapScaling; +@property(nonatomic, assign) double imagePixelRatio; +@property(nonatomic, strong, nullable) NSNumber *width; +@property(nonatomic, strong, nullable) NSNumber *height; +@end + +/// The codec used by all APIs. +NSObject *FGMGetGoogleMapsFlutterPigeonMessagesCodec(void); + +/// Interface for non-test interactions with the native SDK. +/// +/// For test-only state queries, see [MapsInspectorApi]. +@protocol FGMMapsApi +/// Returns once the map instance is available. +- (void)waitForMapWithError:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the map's configuration options. +/// +/// Only non-null configuration values will result in updates; options with +/// null values will remain unchanged. +- (void)updateWithMapConfiguration:(FGMPlatformMapConfiguration *)configuration + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of circles on the map. +- (void)updateCirclesByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of heatmaps on the map. +- (void)updateHeatmapsByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of custer managers for clusters on the map. +- (void)updateClusterManagersByAdding:(NSArray *)toAdd + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of markers on the map. +- (void)updateMarkersByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of polygonss on the map. +- (void)updatePolygonsByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of polylines on the map. +- (void)updatePolylinesByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of tile overlays on the map. +- (void)updateTileOverlaysByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of ground overlays on the map. +- (void)updateGroundOverlaysByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the screen coordinate for the given map location. +/// +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformPoint *)screenCoordinatesForLatLng:(FGMPlatformLatLng *)latLng + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the map location for the given screen coordinate. +/// +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformLatLng *)latLngForScreenCoordinate:(FGMPlatformPoint *)screenCoordinate + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the map region currently displayed on the map. +/// +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformLatLngBounds *)visibleMapRegion:(FlutterError *_Nullable *_Nonnull)error; +/// Moves the camera according to [cameraUpdate] immediately, with no +/// animation. +- (void)moveCameraWithUpdate:(FGMPlatformCameraUpdate *)cameraUpdate + error:(FlutterError *_Nullable *_Nonnull)error; +/// Moves the camera according to [cameraUpdate], animating the update using a +/// duration in milliseconds if provided. +- (void)animateCameraWithUpdate:(FGMPlatformCameraUpdate *)cameraUpdate + duration:(nullable NSNumber *)durationMilliseconds + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the current map zoom level. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)currentZoomLevel:(FlutterError *_Nullable *_Nonnull)error; +/// Show the info window for the marker with the given ID. +- (void)showInfoWindowForMarkerWithIdentifier:(NSString *)markerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Hide the info window for the marker with the given ID. +- (void)hideInfoWindowForMarkerWithIdentifier:(NSString *)markerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns true if the marker with the given ID is currently displaying its +/// info window. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *) + isShowingInfoWindowForMarkerWithIdentifier:(NSString *)markerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Sets the style to the given map style string, where an empty string +/// indicates that the style should be cleared. +/// +/// If there was an error setting the style, such as an invalid style string, +/// returns the error message. +- (nullable NSString *)setStyle:(NSString *)style error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the error string from the last attempt to set the map style, if +/// any. +/// +/// This allows checking asynchronously for initial style failures, as there +/// is no way to return failures from map initialization. +- (nullable NSString *)lastStyleError:(FlutterError *_Nullable *_Nonnull)error; +/// Clears the cache of tiles previously requseted from the tile provider. +- (void)clearTileCacheForOverlayWithIdentifier:(NSString *)tileOverlayId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Takes a snapshot of the map and returns its image data. +- (nullable FlutterStandardTypedData *)takeSnapshotWithError: + (FlutterError *_Nullable *_Nonnull)error; +@end + +extern void SetUpFGMMapsApi(id binaryMessenger, + NSObject *_Nullable api); + +extern void SetUpFGMMapsApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); + +/// Interface for calls from the native SDK to Dart. +@interface FGMMapsCallbackApi : NSObject +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger; +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + messageChannelSuffix:(nullable NSString *)messageChannelSuffix; +/// Called when the map camera starts moving. +- (void)didStartCameraMoveWithCompletion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map camera moves. +- (void)didMoveCameraToPosition:(FGMPlatformCameraPosition *)cameraPosition + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map camera stops moving. +- (void)didIdleCameraWithCompletion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map, not a specifc map object, is tapped. +- (void)didTapAtPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map, not a specifc map object, is long pressed. +- (void)didLongPressAtPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker is tapped. +- (void)didTapMarkerWithIdentifier:(NSString *)markerId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker drag starts. +- (void)didStartDragForMarkerWithIdentifier:(NSString *)markerId + atPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker drag updates. +- (void)didDragMarkerWithIdentifier:(NSString *)markerId + atPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker drag ends. +- (void)didEndDragForMarkerWithIdentifier:(NSString *)markerId + atPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker's info window is tapped. +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)markerId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a circle is tapped. +- (void)didTapCircleWithIdentifier:(NSString *)circleId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker cluster is tapped. +- (void)didTapCluster:(FGMPlatformCluster *)cluster + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a polygon is tapped. +- (void)didTapPolygonWithIdentifier:(NSString *)polygonId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a polyline is tapped. +- (void)didTapPolylineWithIdentifier:(NSString *)polylineId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a ground overlay is tapped. +- (void)didTapGroundOverlayWithIdentifier:(NSString *)groundOverlayId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called to get data for a map tile. +- (void)tileWithOverlayIdentifier:(NSString *)tileOverlayId + location:(FGMPlatformPoint *)location + zoom:(NSInteger)zoom + completion:(void (^)(FGMPlatformTile *_Nullable, + FlutterError *_Nullable))completion; +@end + +/// Dummy interface to force generation of the platform view creation params, +/// which are not used in any Pigeon calls, only the platform view creation +/// call made internally by Flutter. +@protocol FGMMapsPlatformViewApi +- (void)createViewType:(nullable FGMPlatformMapViewCreationParams *)type + error:(FlutterError *_Nullable *_Nonnull)error; +@end + +extern void SetUpFGMMapsPlatformViewApi(id binaryMessenger, + NSObject *_Nullable api); + +extern void SetUpFGMMapsPlatformViewApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); + +/// Inspector API only intended for use in integration tests. +@protocol FGMMapsInspectorApi +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areBuildingsEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areRotateGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areScrollGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areTiltGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areZoomGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isCompassEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isMyLocationButtonEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isTrafficEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +- (nullable FGMPlatformTileLayer *)tileOverlayWithIdentifier:(NSString *)tileOverlayId + error: + (FlutterError *_Nullable *_Nonnull)error; +- (nullable FGMPlatformGroundOverlay *) + groundOverlayWithIdentifier:(NSString *)groundOverlayId + error:(FlutterError *_Nullable *_Nonnull)error; +- (nullable FGMPlatformHeatmap *)heatmapWithIdentifier:(NSString *)heatmapId + error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformZoomRange *)zoomRange:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)clusterManagerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformCameraPosition *)cameraPosition:(FlutterError *_Nullable *_Nonnull)error; +@end + +extern void SetUpFGMMapsInspectorApi(id binaryMessenger, + NSObject *_Nullable api); + +extern void SetUpFGMMapsInspectorApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_map_inspector_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_map_inspector_ios.dart new file mode 100644 index 000000000000..a0057b9fdc54 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_map_inspector_ios.dart @@ -0,0 +1,277 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; +import 'package:flutter/foundation.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'google_maps_flutter_ios.dart'; +import 'messages.g.dart'; + +/// An Android of implementation of [GoogleMapsInspectorPlatform]. +@visibleForTesting +class GoogleMapsInspectorIOS extends GoogleMapsInspectorPlatform { + /// Creates an inspector API instance for a given map ID from + /// [inspectorProvider]. + GoogleMapsInspectorIOS( + MapsInspectorApi? Function(int mapId) inspectorProvider, + ) : _inspectorProvider = inspectorProvider; + + final MapsInspectorApi? Function(int mapId) _inspectorProvider; + + @override + Future areBuildingsEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areBuildingsEnabled(); + } + + @override + Future areRotateGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areRotateGesturesEnabled(); + } + + @override + Future areScrollGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areScrollGesturesEnabled(); + } + + @override + Future areTiltGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areTiltGesturesEnabled(); + } + + @override + Future areZoomControlsEnabled({required int mapId}) async { + // Does not exist on iOS. + return false; + } + + @override + Future areZoomGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areZoomGesturesEnabled(); + } + + @override + Future getMinMaxZoomLevels({required int mapId}) async { + final PlatformZoomRange zoomLevels = await _inspectorProvider( + mapId, + )!.getZoomRange(); + return MinMaxZoomPreference(zoomLevels.min, zoomLevels.max); + } + + @override + Future getTileOverlayInfo( + TileOverlayId tileOverlayId, { + required int mapId, + }) async { + final PlatformTileLayer? tileInfo = await _inspectorProvider( + mapId, + )!.getTileOverlayInfo(tileOverlayId.value); + if (tileInfo == null) { + return null; + } + return TileOverlay( + tileOverlayId: tileOverlayId, + fadeIn: tileInfo.fadeIn, + transparency: 1.0 - tileInfo.opacity, + visible: tileInfo.visible, + zIndex: tileInfo.zIndex, + ); + } + + @override + bool supportsGettingHeatmapInfo() => true; + + @override + Future getHeatmapInfo( + HeatmapId heatmapId, { + required int mapId, + }) async { + final PlatformHeatmap? heatmapInfo = await _inspectorProvider( + mapId, + )!.getHeatmapInfo(heatmapId.value); + if (heatmapInfo == null) { + return null; + } + + return Heatmap( + heatmapId: heatmapId, + data: heatmapInfo.data.map(_deserializeWeightedLatLng).toList(), + gradient: _deserializeHeatmapGradient(heatmapInfo.gradient), + opacity: heatmapInfo.opacity, + radius: HeatmapRadius.fromPixels(heatmapInfo.radius), + minimumZoomIntensity: heatmapInfo.minimumZoomIntensity, + maximumZoomIntensity: heatmapInfo.maximumZoomIntensity, + ); + } + + @override + bool supportsGettingGroundOverlayInfo() => true; + + @override + Future getGroundOverlayInfo( + GroundOverlayId groundOverlayId, { + required int mapId, + }) async { + final PlatformGroundOverlay? groundOverlayInfo = await _inspectorProvider( + mapId, + )!.getGroundOverlayInfo(groundOverlayId.value); + + if (groundOverlayInfo == null) { + return null; + } + + // Create dummy image to represent the image of the ground overlay. + final dummyImage = BytesMapBitmap( + Uint8List.fromList([0]), + bitmapScaling: MapBitmapScaling.none, + ); + + final PlatformLatLng? position = groundOverlayInfo.position; + final PlatformLatLngBounds? bounds = groundOverlayInfo.bounds; + + if (position != null) { + return GroundOverlay.fromPosition( + groundOverlayId: groundOverlayId, + position: LatLng(position.latitude, position.longitude), + image: dummyImage, + zIndex: groundOverlayInfo.zIndex, + bearing: groundOverlayInfo.bearing, + transparency: groundOverlayInfo.transparency, + visible: groundOverlayInfo.visible, + clickable: groundOverlayInfo.clickable, + anchor: Offset( + groundOverlayInfo.anchor!.x, + groundOverlayInfo.anchor!.y, + ), + zoomLevel: groundOverlayInfo.zoomLevel, + ); + } else if (bounds != null) { + return GroundOverlay.fromBounds( + groundOverlayId: groundOverlayId, + bounds: LatLngBounds( + southwest: LatLng( + bounds.southwest.latitude, + bounds.southwest.longitude, + ), + northeast: LatLng( + bounds.northeast.latitude, + bounds.northeast.longitude, + ), + ), + image: dummyImage, + zIndex: groundOverlayInfo.zIndex, + bearing: groundOverlayInfo.bearing, + transparency: groundOverlayInfo.transparency, + visible: groundOverlayInfo.visible, + clickable: groundOverlayInfo.clickable, + ); + } + return null; + } + + @override + Future isCompassEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.isCompassEnabled(); + } + + @override + Future isLiteModeEnabled({required int mapId}) async { + // Does not exist on iOS. + return false; + } + + @override + Future isMapToolbarEnabled({required int mapId}) async { + // Does not exist on iOS. + return false; + } + + @override + Future isMyLocationButtonEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.isMyLocationButtonEnabled(); + } + + @override + Future isTrafficEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.isTrafficEnabled(); + } + + @override + Future> getClusters({ + required int mapId, + required ClusterManagerId clusterManagerId, + }) async { + return (await _inspectorProvider( + mapId, + )!.getClusters(clusterManagerId.value)) + .map( + (PlatformCluster cluster) => + GoogleMapsFlutterIOS.clusterFromPlatformCluster(cluster), + ) + .toList(); + } + + @override + bool supportsGettingGameraPosition() => true; + + @override + Future getCameraPosition({required int mapId}) async { + final PlatformCameraPosition cameraPosition = await _inspectorProvider( + mapId, + )!.getCameraPosition(); + return CameraPosition( + target: LatLng( + cameraPosition.target.latitude, + cameraPosition.target.longitude, + ), + bearing: cameraPosition.bearing, + tilt: cameraPosition.tilt, + zoom: cameraPosition.zoom, + ); + } + + static HeatmapGradient? _deserializeHeatmapGradient( + PlatformHeatmapGradient? gradient, + ) { + if (gradient == null) { + return null; + } + return HeatmapGradient( + // Zip the colors and start points together, since they are parallel + // arrays on the platform side. + _mapEnumerated( + gradient.colors, + (PlatformColor color, int i) => HeatmapGradientColor( + Color.from( + red: color.red, + green: color.green, + blue: color.blue, + alpha: color.alpha, + ), + gradient.startPoints[i], + ), + ).toList(), + colorMapSize: gradient.colorMapSize, + ); + } + + static WeightedLatLng _deserializeWeightedLatLng( + PlatformWeightedLatLng weightedLatLng, + ) { + return WeightedLatLng( + LatLng(weightedLatLng.point.latitude, weightedLatLng.point.longitude), + weight: weightedLatLng.weight, + ); + } +} + +Iterable _mapEnumerated( + Iterable iterable, + E Function(T, int) fn, +) sync* { + var index = 0; + for (final item in iterable) { + yield fn(item, index++); + } +} 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 new file mode 100644 index 000000000000..c7e469ad1491 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/google_maps_flutter_ios.dart @@ -0,0 +1,1467 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:stream_transform/stream_transform.dart'; + +import 'google_map_inspector_ios.dart'; +import 'messages.g.dart'; + +/// The non-test implementation of `_apiProvider`. +MapsApi _productionApiProvider(int mapId) { + return MapsApi(messageChannelSuffix: mapId.toString()); +} + +/// Error thrown when an unknown map ID is provided to a method channel API. +class UnknownMapIDError extends Error { + /// Creates an assertion error with the provided [mapId] and optional + /// [message]. + UnknownMapIDError(this.mapId, [this.message]); + + /// The unknown ID. + final int mapId; + + /// Message describing the assertion error. + final Object? message; + + @override + String toString() { + if (message != null) { + return 'Unknown map ID $mapId: ${Error.safeToString(message)}'; + } + return 'Unknown map ID $mapId'; + } +} + +/// An implementation of [GoogleMapsFlutterPlatform] for iOS. +class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { + /// Creates a new Android maps implementation instance. + GoogleMapsFlutterIOS({ + @visibleForTesting MapsApi Function(int mapId)? apiProvider, + }) : _apiProvider = apiProvider ?? _productionApiProvider; + + /// Registers the iOS implementation of GoogleMapsFlutterPlatform. + static void registerWith() { + GoogleMapsFlutterPlatform.instance = GoogleMapsFlutterIOS(); + } + + final Map _hostMaps = {}; + + // A method to create MapsApi instances, which can be overridden for testing. + final MapsApi Function(int mapId) _apiProvider; + + /// The per-map handlers for callbacks from the host side. + @visibleForTesting + final Map hostMapHandlers = + {}; + + /// Accesses the MapsApi associated to the passed mapId. + MapsApi _hostApi(int mapId) { + final MapsApi? api = _hostMaps[mapId]; + if (api == null) { + throw UnknownMapIDError(mapId); + } + return api; + } + + // Keep a collection of mapId to a map of TileOverlays. + final Map> _tileOverlays = + >{}; + + /// Returns the handler for [mapId], creating it if it doesn't already exist. + @visibleForTesting + HostMapMessageHandler ensureHandlerInitialized(int mapId) { + HostMapMessageHandler? handler = hostMapHandlers[mapId]; + if (handler == null) { + handler = HostMapMessageHandler( + mapId, + _mapEventStreamController, + tileOverlayProvider: (TileOverlayId tileOverlayId) { + final Map? tileOverlaysForMap = + _tileOverlays[mapId]; + return tileOverlaysForMap?[tileOverlayId]; + }, + ); + hostMapHandlers[mapId] = handler; + } + return handler; + } + + /// Returns the API instance for [mapId], creating it if it doesn't already + /// exist. + @visibleForTesting + MapsApi ensureApiInitialized(int mapId) { + MapsApi? api = _hostMaps[mapId]; + if (api == null) { + api = _apiProvider(mapId); + _hostMaps[mapId] ??= api; + } + return api; + } + + @override + Future init(int mapId) { + ensureHandlerInitialized(mapId); + final MapsApi hostApi = ensureApiInitialized(mapId); + return hostApi.waitForMap(); + } + + @override + void dispose({required int mapId}) { + // Noop! + } + + // The controller we need to broadcast the different events coming + // from handleMethodCall. + // + // It is a `broadcast` because multiple controllers will connect to + // different stream views of this Controller. + final StreamController> _mapEventStreamController = + StreamController>.broadcast(); + + // Returns a filtered view of the events in the _controller, by mapId. + Stream> _events(int mapId) => _mapEventStreamController + .stream + .where((MapEvent event) => event.mapId == mapId); + + @override + Stream onCameraMoveStarted({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onCameraMove({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onCameraIdle({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onInfoWindowTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerDragStart({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerDrag({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerDragEnd({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onPolylineTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onPolygonTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onCircleTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onGroundOverlayTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onLongPress({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onClusterTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Future updateMapConfiguration( + MapConfiguration configuration, { + required int mapId, + }) { + return _hostApi(mapId).updateMapConfiguration( + _platformMapConfigurationFromMapConfiguration(configuration), + ); + } + + @override + Future updateMapOptions( + Map optionsUpdate, { + required int mapId, + }) { + return _hostApi(mapId).updateMapConfiguration( + _platformMapConfigurationFromOptionsJson(optionsUpdate), + ); + } + + @override + Future updateMarkers( + MarkerUpdates markerUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateMarkers( + markerUpdates.markersToAdd.map(_platformMarkerFromMarker).toList(), + markerUpdates.markersToChange.map(_platformMarkerFromMarker).toList(), + markerUpdates.markerIdsToRemove.map((MarkerId id) => id.value).toList(), + ); + } + + @override + Future updatePolygons( + PolygonUpdates polygonUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updatePolygons( + polygonUpdates.polygonsToAdd.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonsToChange.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonIdsToRemove + .map((PolygonId id) => id.value) + .toList(), + ); + } + + @override + Future updatePolylines( + PolylineUpdates polylineUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updatePolylines( + polylineUpdates.polylinesToAdd + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylinesToChange + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylineIdsToRemove + .map((PolylineId id) => id.value) + .toList(), + ); + } + + @override + Future updateCircles( + CircleUpdates circleUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateCircles( + circleUpdates.circlesToAdd.map(_platformCircleFromCircle).toList(), + circleUpdates.circlesToChange.map(_platformCircleFromCircle).toList(), + circleUpdates.circleIdsToRemove.map((CircleId id) => id.value).toList(), + ); + } + + @override + Future updateHeatmaps( + HeatmapUpdates heatmapUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateHeatmaps( + heatmapUpdates.heatmapsToAdd.map(_platformHeatmapFromHeatmap).toList(), + heatmapUpdates.heatmapsToChange.map(_platformHeatmapFromHeatmap).toList(), + heatmapUpdates.heatmapIdsToRemove + .map((HeatmapId id) => id.value) + .toList(), + ); + } + + @override + Future updateTileOverlays({ + required Set newTileOverlays, + required int mapId, + }) { + final Map? currentTileOverlays = + _tileOverlays[mapId]; + final Set previousSet = currentTileOverlays != null + ? currentTileOverlays.values.toSet() + : {}; + final updates = _TileOverlayUpdates.from(previousSet, newTileOverlays); + _tileOverlays[mapId] = keyTileOverlayId(newTileOverlays); + return _hostApi(mapId).updateTileOverlays( + updates.tileOverlaysToAdd + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlaysToChange + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlayIdsToRemove + .map((TileOverlayId id) => id.value) + .toList(), + ); + } + + @override + Future updateClusterManagers( + ClusterManagerUpdates clusterManagerUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateClusterManagers( + clusterManagerUpdates.clusterManagersToAdd + .map(_platformClusterManagerFromClusterManager) + .toList(), + clusterManagerUpdates.clusterManagerIdsToRemove + .map((ClusterManagerId id) => id.value) + .toList(), + ); + } + + @override + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) { + assert( + groundOverlayUpdates.groundOverlaysToAdd.every( + (GroundOverlay groundOverlay) => + groundOverlay.position == null || groundOverlay.zoomLevel != null, + ), + 'On iOS zoom level must be set when position is set for ground overlays.', + ); + + return _hostApi(mapId).updateGroundOverlays( + groundOverlayUpdates.groundOverlaysToAdd + .map(_platformGroundOverlayFromGroundOverlay) + .toList(), + groundOverlayUpdates.groundOverlaysToChange + .map(_platformGroundOverlayFromGroundOverlay) + .toList(), + groundOverlayUpdates.groundOverlayIdsToRemove + .map((GroundOverlayId id) => id.value) + .toList(), + ); + } + + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + required int mapId, + }) { + return _hostApi(mapId).clearTileCache(tileOverlayId.value); + } + + @override + Future animateCamera(CameraUpdate cameraUpdate, {required int mapId}) { + return animateCameraWithConfiguration( + cameraUpdate, + const CameraUpdateAnimationConfiguration(), + mapId: mapId, + ); + } + + @override + Future animateCameraWithConfiguration( + CameraUpdate cameraUpdate, + CameraUpdateAnimationConfiguration configuration, { + required int mapId, + }) { + return _hostApi(mapId).animateCamera( + _platformCameraUpdateFromCameraUpdate(cameraUpdate), + configuration.duration?.inMilliseconds, + ); + } + + @override + Future moveCamera(CameraUpdate cameraUpdate, {required int mapId}) { + return _hostApi( + mapId, + ).moveCamera(_platformCameraUpdateFromCameraUpdate(cameraUpdate)); + } + + @override + Future setMapStyle(String? mapStyle, {required int mapId}) async { + final String? errorDescription = await _hostApi( + mapId, + ).setStyle(mapStyle ?? ''); + if (errorDescription != null) { + throw MapStyleException(errorDescription); + } + } + + @override + Future getVisibleRegion({required int mapId}) async { + return _latLngBoundsFromPlatformLatLngBounds( + await _hostApi(mapId).getVisibleRegion(), + ); + } + + @override + Future getScreenCoordinate( + LatLng latLng, { + required int mapId, + }) async { + return _screenCoordinateFromPlatformPoint( + await _hostApi( + mapId, + ).getScreenCoordinate(_platformLatLngFromLatLng(latLng)), + ); + } + + @override + Future getLatLng( + ScreenCoordinate screenCoordinate, { + required int mapId, + }) async { + return _latLngFromPlatformLatLng( + await _hostApi( + mapId, + ).getLatLng(_platformPointFromScreenCoordinate(screenCoordinate)), + ); + } + + @override + Future showMarkerInfoWindow(MarkerId markerId, {required int mapId}) { + return _hostApi(mapId).showInfoWindow(markerId.value); + } + + @override + Future hideMarkerInfoWindow(MarkerId markerId, {required int mapId}) { + return _hostApi(mapId).hideInfoWindow(markerId.value); + } + + @override + Future isMarkerInfoWindowShown( + MarkerId markerId, { + required int mapId, + }) { + return _hostApi(mapId).isInfoWindowShown(markerId.value); + } + + @override + Future getZoomLevel({required int mapId}) { + return _hostApi(mapId).getZoomLevel(); + } + + @override + Future takeSnapshot({required int mapId}) { + return _hostApi(mapId).takeSnapshot(); + } + + @override + Future getStyleError({required int mapId}) { + return _hostApi(mapId).getLastStyleError(); + } + + Widget _buildView( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required PlatformMapConfiguration mapConfiguration, + required MapWidgetConfiguration widgetConfiguration, + MapObjects mapObjects = const MapObjects(), + }) { + assert( + mapObjects.groundOverlays.every( + (GroundOverlay groundOverlay) => + groundOverlay.position == null || groundOverlay.zoomLevel != null, + ), + 'On iOS zoom level must be set when position is set for ground overlays.', + ); + + final creationParams = PlatformMapViewCreationParams( + initialCameraPosition: _platformCameraPositionFromCameraPosition( + widgetConfiguration.initialCameraPosition, + ), + mapConfiguration: mapConfiguration, + initialMarkers: mapObjects.markers + .map(_platformMarkerFromMarker) + .toList(), + initialPolygons: mapObjects.polygons + .map(_platformPolygonFromPolygon) + .toList(), + initialPolylines: mapObjects.polylines + .map(_platformPolylineFromPolyline) + .toList(), + initialCircles: mapObjects.circles + .map(_platformCircleFromCircle) + .toList(), + initialHeatmaps: mapObjects.heatmaps + .map(_platformHeatmapFromHeatmap) + .toList(), + initialTileOverlays: mapObjects.tileOverlays + .map(_platformTileOverlayFromTileOverlay) + .toList(), + initialClusterManagers: mapObjects.clusterManagers + .map(_platformClusterManagerFromClusterManager) + .toList(), + initialGroundOverlays: mapObjects.groundOverlays + .map(_platformGroundOverlayFromGroundOverlay) + .toList(), + ); + + return UiKitView( + viewType: 'plugins.flutter.dev/google_maps_ios', + onPlatformViewCreated: onPlatformViewCreated, + gestureRecognizers: widgetConfiguration.gestureRecognizers, + creationParams: creationParams, + creationParamsCodec: MapsApi.pigeonChannelCodec, + ); + } + + @override + Widget buildViewWithConfiguration( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required MapWidgetConfiguration widgetConfiguration, + MapConfiguration mapConfiguration = const MapConfiguration(), + MapObjects mapObjects = const MapObjects(), + }) { + return _buildView( + creationId, + onPlatformViewCreated, + widgetConfiguration: widgetConfiguration, + mapObjects: mapObjects, + mapConfiguration: _platformMapConfigurationFromMapConfiguration( + mapConfiguration, + ), + ); + } + + @override + Widget buildViewWithTextDirection( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required CameraPosition initialCameraPosition, + required TextDirection textDirection, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set>? gestureRecognizers, + Map mapOptions = const {}, + }) { + return _buildView( + creationId, + onPlatformViewCreated, + widgetConfiguration: MapWidgetConfiguration( + initialCameraPosition: initialCameraPosition, + textDirection: textDirection, + ), + mapObjects: MapObjects( + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + tileOverlays: tileOverlays, + ), + mapConfiguration: _platformMapConfigurationFromOptionsJson(mapOptions), + ); + } + + @override + Widget buildView( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required CameraPosition initialCameraPosition, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set>? gestureRecognizers, + Map mapOptions = const {}, + }) { + return buildViewWithTextDirection( + creationId, + onPlatformViewCreated, + initialCameraPosition: initialCameraPosition, + textDirection: TextDirection.ltr, + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + tileOverlays: tileOverlays, + gestureRecognizers: gestureRecognizers, + mapOptions: mapOptions, + ); + } + + @override + @visibleForTesting + void enableDebugInspection() { + GoogleMapsInspectorPlatform.instance = GoogleMapsInspectorIOS( + (int mapId) => MapsInspectorApi(messageChannelSuffix: mapId.toString()), + ); + } + + /// Converts a Pigeon [PlatformCluster] to the corresponding [Cluster]. + static Cluster clusterFromPlatformCluster(PlatformCluster cluster) { + return Cluster( + ClusterManagerId(cluster.clusterManagerId), + cluster.markerIds.map((String markerId) => MarkerId(markerId)).toList(), + position: _latLngFromPlatformLatLng(cluster.position), + bounds: _latLngBoundsFromPlatformLatLngBounds(cluster.bounds), + ); + } + + static ScreenCoordinate _screenCoordinateFromPlatformPoint( + PlatformPoint point, + ) { + return ScreenCoordinate(x: point.x.round(), y: point.y.round()); + } + + static PlatformPoint _platformPointFromScreenCoordinate( + ScreenCoordinate coordinate, + ) { + return PlatformPoint( + x: coordinate.x.toDouble(), + y: coordinate.y.toDouble(), + ); + } + + static PlatformPoint _platformPointFromOffset(Offset offset) { + return PlatformPoint(x: offset.dx, y: offset.dy); + } + + static PlatformSize _platformSizeFromSize(Size size) { + return PlatformSize(width: size.width, height: size.height); + } + + static PlatformCircle _platformCircleFromCircle(Circle circle) { + return PlatformCircle( + consumeTapEvents: circle.consumeTapEvents, + fillColor: PlatformColor( + red: circle.fillColor.r, + green: circle.fillColor.g, + blue: circle.fillColor.b, + alpha: circle.fillColor.a, + ), + strokeColor: PlatformColor( + red: circle.strokeColor.r, + green: circle.strokeColor.g, + blue: circle.strokeColor.b, + alpha: circle.strokeColor.a, + ), + visible: circle.visible, + strokeWidth: circle.strokeWidth, + zIndex: circle.zIndex.toDouble(), + center: _platformLatLngFromLatLng(circle.center), + radius: circle.radius, + circleId: circle.circleId.value, + ); + } + + static PlatformHeatmap _platformHeatmapFromHeatmap(Heatmap heatmap) { + final HeatmapGradient? gradient = heatmap.gradient; + return PlatformHeatmap( + heatmapId: heatmap.heatmapId.value, + data: heatmap.data + .map(_platformWeightedLatLngFromWeightedLatLng) + .toList(), + gradient: _platformHeatmapGradientFromHeatmapGradient(gradient), + opacity: heatmap.opacity, + radius: heatmap.radius.radius, + minimumZoomIntensity: heatmap.minimumZoomIntensity, + maximumZoomIntensity: heatmap.maximumZoomIntensity, + ); + } + + static PlatformHeatmapGradient? _platformHeatmapGradientFromHeatmapGradient( + HeatmapGradient? gradient, + ) { + if (gradient == null) { + return null; + } + return PlatformHeatmapGradient( + colors: gradient.colors + .map( + (HeatmapGradientColor c) => PlatformColor( + red: c.color.r, + green: c.color.g, + blue: c.color.b, + alpha: c.color.a, + ), + ) + .toList(), + startPoints: gradient.colors + .map((HeatmapGradientColor c) => c.startPoint) + .toList(), + colorMapSize: gradient.colorMapSize, + ); + } + + static PlatformInfoWindow _platformInfoWindowFromInfoWindow( + InfoWindow window, + ) { + return PlatformInfoWindow( + title: window.title, + snippet: window.snippet, + anchor: _platformPointFromOffset(window.anchor), + ); + } + + static PlatformMarker _platformMarkerFromMarker(Marker marker) { + return PlatformMarker( + alpha: marker.alpha, + anchor: _platformPointFromOffset(marker.anchor), + consumeTapEvents: marker.consumeTapEvents, + draggable: marker.draggable, + flat: marker.flat, + icon: platformBitmapFromBitmapDescriptor(marker.icon), + infoWindow: _platformInfoWindowFromInfoWindow(marker.infoWindow), + position: _platformLatLngFromLatLng(marker.position), + rotation: marker.rotation, + visible: marker.visible, + zIndex: marker.zIndexInt, + markerId: marker.markerId.value, + clusterManagerId: marker.clusterManagerId?.value, + ); + } + + static PlatformGroundOverlay _platformGroundOverlayFromGroundOverlay( + GroundOverlay groundOverlay, + ) { + return PlatformGroundOverlay( + groundOverlayId: groundOverlay.groundOverlayId.value, + anchor: groundOverlay.anchor != null + ? _platformPointFromOffset(groundOverlay.anchor!) + : null, + image: platformBitmapFromBitmapDescriptor(groundOverlay.image), + position: groundOverlay.position != null + ? _platformLatLngFromLatLng(groundOverlay.position!) + : null, + bounds: _platformLatLngBoundsFromLatLngBounds(groundOverlay.bounds), + visible: groundOverlay.visible, + zIndex: groundOverlay.zIndex, + bearing: groundOverlay.bearing, + clickable: groundOverlay.clickable, + transparency: groundOverlay.transparency, + zoomLevel: groundOverlay.zoomLevel, + ); + } + + static PlatformPolygon _platformPolygonFromPolygon(Polygon polygon) { + final List points = polygon.points + .map(_platformLatLngFromLatLng) + .toList(); + final List> holes = polygon.holes.map(( + List hole, + ) { + return hole.map(_platformLatLngFromLatLng).toList(); + }).toList(); + return PlatformPolygon( + polygonId: polygon.polygonId.value, + fillColor: PlatformColor( + red: polygon.fillColor.r, + green: polygon.fillColor.g, + blue: polygon.fillColor.b, + alpha: polygon.fillColor.a, + ), + geodesic: polygon.geodesic, + consumesTapEvents: polygon.consumeTapEvents, + points: points, + holes: holes, + strokeColor: PlatformColor( + red: polygon.strokeColor.r, + green: polygon.strokeColor.g, + blue: polygon.strokeColor.b, + alpha: polygon.strokeColor.a, + ), + strokeWidth: polygon.strokeWidth, + zIndex: polygon.zIndex, + visible: polygon.visible, + ); + } + + static PlatformPolyline _platformPolylineFromPolyline(Polyline polyline) { + final List points = polyline.points + .map(_platformLatLngFromLatLng) + .toList(); + final List pattern = polyline.patterns + .map(platformPatternItemFromPatternItem) + .toList(); + return PlatformPolyline( + polylineId: polyline.polylineId.value, + consumesTapEvents: polyline.consumeTapEvents, + color: PlatformColor( + red: polyline.color.r, + green: polyline.color.g, + blue: polyline.color.b, + alpha: polyline.color.a, + ), + geodesic: polyline.geodesic, + visible: polyline.visible, + width: polyline.width, + zIndex: polyline.zIndex, + points: points, + jointType: platformJointTypeFromJointType(polyline.jointType), + patterns: pattern, + ); + } + + static PlatformTileOverlay _platformTileOverlayFromTileOverlay( + TileOverlay tileOverlay, + ) { + return PlatformTileOverlay( + tileOverlayId: tileOverlay.tileOverlayId.value, + fadeIn: tileOverlay.fadeIn, + transparency: tileOverlay.transparency, + zIndex: tileOverlay.zIndex, + visible: tileOverlay.visible, + tileSize: tileOverlay.tileSize, + ); + } + + static PlatformClusterManager _platformClusterManagerFromClusterManager( + ClusterManager clusterManager, + ) { + return PlatformClusterManager( + identifier: clusterManager.clusterManagerId.value, + ); + } + + static PlatformCameraUpdate _platformCameraUpdateFromCameraUpdate( + CameraUpdate update, + ) { + switch (update.updateType) { + case CameraUpdateType.newCameraPosition: + update as CameraUpdateNewCameraPosition; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewCameraPosition( + cameraPosition: _platformCameraPositionFromCameraPosition( + update.cameraPosition, + ), + ), + ); + case CameraUpdateType.newLatLng: + update as CameraUpdateNewLatLng; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewLatLng( + latLng: _platformLatLngFromLatLng(update.latLng), + ), + ); + case CameraUpdateType.newLatLngZoom: + update as CameraUpdateNewLatLngZoom; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewLatLngZoom( + latLng: _platformLatLngFromLatLng(update.latLng), + zoom: update.zoom, + ), + ); + case CameraUpdateType.newLatLngBounds: + update as CameraUpdateNewLatLngBounds; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewLatLngBounds( + bounds: _platformLatLngBoundsFromLatLngBounds(update.bounds)!, + padding: update.padding, + ), + ); + case CameraUpdateType.zoomTo: + update as CameraUpdateZoomTo; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoomTo(zoom: update.zoom), + ); + case CameraUpdateType.zoomBy: + update as CameraUpdateZoomBy; + final Offset? focus = update.focus; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoomBy( + amount: update.amount, + focus: focus == null ? null : _platformPointFromOffset(focus), + ), + ); + case CameraUpdateType.zoomIn: + update as CameraUpdateZoomIn; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoom(out: false), + ); + case CameraUpdateType.zoomOut: + update as CameraUpdateZoomOut; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoom(out: true), + ); + case CameraUpdateType.scrollBy: + update as CameraUpdateScrollBy; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateScrollBy( + dx: update.dx, + dy: update.dy, + ), + ); + } + } + + /// Converts [MapBitmapScaling] from platform interface to [PlatformMapBitmapScaling] Pigeon. + @visibleForTesting + static PlatformMapBitmapScaling platformMapBitmapScalingFromScaling( + MapBitmapScaling scaling, + ) { + switch (scaling) { + case MapBitmapScaling.auto: + return PlatformMapBitmapScaling.auto; + case MapBitmapScaling.none: + return PlatformMapBitmapScaling.none; + } + + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformMapBitmapScaling.auto; + } + + /// Converts [BitmapDescriptor] from platform interface to [PlatformBitmap] pigeon. + @visibleForTesting + static PlatformBitmap platformBitmapFromBitmapDescriptor( + BitmapDescriptor bitmap, + ) { + switch (bitmap) { + case final DefaultMarker marker: + return PlatformBitmap( + bitmap: PlatformBitmapDefaultMarker(hue: marker.hue?.toDouble()), + ); + // Clients may still use this deprecated format, so it must be supported. + // ignore: deprecated_member_use + case final BytesBitmap bytes: + final Size? size = bytes.size; + return PlatformBitmap( + bitmap: PlatformBitmapBytes( + byteData: bytes.byteData, + size: (size == null) ? null : _platformSizeFromSize(size), + ), + ); + case final AssetBitmap asset: + return PlatformBitmap( + bitmap: PlatformBitmapAsset(name: asset.name, pkg: asset.package), + ); + // Clients may still use this deprecated format, so it must be supported. + // ignore: deprecated_member_use + case final AssetImageBitmap asset: + final Size? size = asset.size; + return PlatformBitmap( + bitmap: PlatformBitmapAssetImage( + name: asset.name, + scale: asset.scale, + size: (size == null) ? null : _platformSizeFromSize(size), + ), + ); + case final AssetMapBitmap asset: + return PlatformBitmap( + bitmap: PlatformBitmapAssetMap( + assetName: asset.assetName, + bitmapScaling: platformMapBitmapScalingFromScaling( + asset.bitmapScaling, + ), + imagePixelRatio: asset.imagePixelRatio, + width: asset.width, + height: asset.height, + ), + ); + case final BytesMapBitmap bytes: + return PlatformBitmap( + bitmap: PlatformBitmapBytesMap( + byteData: bytes.byteData, + bitmapScaling: platformMapBitmapScalingFromScaling( + bytes.bitmapScaling, + ), + imagePixelRatio: bytes.imagePixelRatio, + width: bytes.width, + height: bytes.height, + ), + ); + default: + throw ArgumentError( + 'Unrecognized type of bitmap ${bitmap.runtimeType}', + 'bitmap', + ); + } + } +} + +/// Callback handler for map events from the platform host. +@visibleForTesting +class HostMapMessageHandler implements MapsCallbackApi { + /// Creates a new handler that listens for events from map [mapId], and + /// broadcasts them to [streamController]. + HostMapMessageHandler( + this.mapId, + this.streamController, { + required this.tileOverlayProvider, + }) { + MapsCallbackApi.setUp(this, messageChannelSuffix: mapId.toString()); + } + + /// Removes the handler for native messages. + void dispose() { + MapsCallbackApi.setUp(null, messageChannelSuffix: mapId.toString()); + } + + /// The map ID this handler listens for events from. + final int mapId; + + /// The controller used to broadcast map events coming from the + /// host platform. + final StreamController> streamController; + + /// The callback to get a tile overlay for the corresponding map. + final TileOverlay? Function(TileOverlayId tileOverlayId) tileOverlayProvider; + + @override + Future getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ) async { + final TileOverlay? tileOverlay = tileOverlayProvider( + TileOverlayId(tileOverlayId), + ); + final TileProvider? tileProvider = tileOverlay?.tileProvider; + final Tile tile = tileProvider == null + ? TileProvider.noTile + : await tileProvider.getTile( + location.x.round(), + location.y.round(), + zoom, + ); + return _platformTileFromTile(tile); + } + + @override + void onCameraIdle() { + streamController.add(CameraIdleEvent(mapId)); + } + + @override + void onCameraMove(PlatformCameraPosition cameraPosition) { + streamController.add( + CameraMoveEvent( + mapId, + CameraPosition( + target: _latLngFromPlatformLatLng(cameraPosition.target), + bearing: cameraPosition.bearing, + tilt: cameraPosition.tilt, + zoom: cameraPosition.zoom, + ), + ), + ); + } + + @override + void onCameraMoveStarted() { + streamController.add(CameraMoveStartedEvent(mapId)); + } + + @override + void onCircleTap(String circleId) { + streamController.add(CircleTapEvent(mapId, CircleId(circleId))); + } + + @override + void onClusterTap(PlatformCluster cluster) { + streamController.add( + ClusterTapEvent( + mapId, + GoogleMapsFlutterIOS.clusterFromPlatformCluster(cluster), + ), + ); + } + + @override + void onInfoWindowTap(String markerId) { + streamController.add(InfoWindowTapEvent(mapId, MarkerId(markerId))); + } + + @override + void onLongPress(PlatformLatLng position) { + streamController.add( + MapLongPressEvent(mapId, _latLngFromPlatformLatLng(position)), + ); + } + + @override + void onMarkerDrag(String markerId, PlatformLatLng position) { + streamController.add( + MarkerDragEvent( + mapId, + _latLngFromPlatformLatLng(position), + MarkerId(markerId), + ), + ); + } + + @override + void onMarkerDragStart(String markerId, PlatformLatLng position) { + streamController.add( + MarkerDragStartEvent( + mapId, + _latLngFromPlatformLatLng(position), + MarkerId(markerId), + ), + ); + } + + @override + void onMarkerDragEnd(String markerId, PlatformLatLng position) { + streamController.add( + MarkerDragEndEvent( + mapId, + _latLngFromPlatformLatLng(position), + MarkerId(markerId), + ), + ); + } + + @override + void onMarkerTap(String markerId) { + streamController.add(MarkerTapEvent(mapId, MarkerId(markerId))); + } + + @override + void onPolygonTap(String polygonId) { + streamController.add(PolygonTapEvent(mapId, PolygonId(polygonId))); + } + + @override + void onPolylineTap(String polylineId) { + streamController.add(PolylineTapEvent(mapId, PolylineId(polylineId))); + } + + @override + void onGroundOverlayTap(String groundOverlayId) { + streamController.add( + GroundOverlayTapEvent(mapId, GroundOverlayId(groundOverlayId)), + ); + } + + @override + void onTap(PlatformLatLng position) { + streamController.add( + MapTapEvent(mapId, _latLngFromPlatformLatLng(position)), + ); + } +} + +LatLng _latLngFromPlatformLatLng(PlatformLatLng latLng) { + return LatLng(latLng.latitude, latLng.longitude); +} + +LatLngBounds _latLngBoundsFromPlatformLatLngBounds( + PlatformLatLngBounds bounds, +) { + return LatLngBounds( + southwest: _latLngFromPlatformLatLng(bounds.southwest), + northeast: _latLngFromPlatformLatLng(bounds.northeast), + ); +} + +PlatformLatLng _platformLatLngFromLatLng(LatLng latLng) { + return PlatformLatLng(latitude: latLng.latitude, longitude: latLng.longitude); +} + +PlatformLatLngBounds? _platformLatLngBoundsFromLatLngBounds( + LatLngBounds? bounds, +) { + if (bounds == null) { + return null; + } + return PlatformLatLngBounds( + northeast: _platformLatLngFromLatLng(bounds.northeast), + southwest: _platformLatLngFromLatLng(bounds.southwest), + ); +} + +PlatformWeightedLatLng _platformWeightedLatLngFromWeightedLatLng( + WeightedLatLng weightedLatLng, +) { + return PlatformWeightedLatLng( + point: _platformLatLngFromLatLng(weightedLatLng.point), + weight: weightedLatLng.weight, + ); +} + +PlatformCameraTargetBounds? _platformCameraTargetBoundsFromCameraTargetBounds( + CameraTargetBounds? bounds, +) { + return bounds == null + ? null + : PlatformCameraTargetBounds( + bounds: _platformLatLngBoundsFromLatLngBounds(bounds.bounds), + ); +} + +PlatformTile _platformTileFromTile(Tile tile) { + return PlatformTile(width: tile.width, height: tile.height, data: tile.data); +} + +PlatformMapType? _platformMapTypeFromMapType(MapType? type) { + switch (type) { + case null: + return null; + case MapType.none: + return PlatformMapType.none; + case MapType.normal: + return PlatformMapType.normal; + case MapType.satellite: + return PlatformMapType.satellite; + case MapType.terrain: + return PlatformMapType.terrain; + case MapType.hybrid: + return PlatformMapType.hybrid; + } + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformMapType.normal; +} + +PlatformZoomRange? _platformZoomRangeFromMinMaxZoomPreference( + MinMaxZoomPreference? zoomPref, +) { + return zoomPref == null + ? null + : PlatformZoomRange(min: zoomPref.minZoom, max: zoomPref.maxZoom); +} + +PlatformEdgeInsets? _platformEdgeInsetsFromEdgeInsets(EdgeInsets? insets) { + return insets == null + ? null + : PlatformEdgeInsets( + top: insets.top, + bottom: insets.bottom, + left: insets.left, + right: insets.right, + ); +} + +PlatformMapConfiguration _platformMapConfigurationFromMapConfiguration( + MapConfiguration config, +) { + return PlatformMapConfiguration( + compassEnabled: config.compassEnabled, + cameraTargetBounds: _platformCameraTargetBoundsFromCameraTargetBounds( + config.cameraTargetBounds, + ), + mapType: _platformMapTypeFromMapType(config.mapType), + minMaxZoomPreference: _platformZoomRangeFromMinMaxZoomPreference( + config.minMaxZoomPreference, + ), + rotateGesturesEnabled: config.rotateGesturesEnabled, + scrollGesturesEnabled: config.scrollGesturesEnabled, + tiltGesturesEnabled: config.tiltGesturesEnabled, + trackCameraPosition: config.trackCameraPosition, + zoomGesturesEnabled: config.zoomGesturesEnabled, + myLocationEnabled: config.myLocationEnabled, + myLocationButtonEnabled: config.myLocationButtonEnabled, + padding: _platformEdgeInsetsFromEdgeInsets(config.padding), + indoorViewEnabled: config.indoorViewEnabled, + trafficEnabled: config.trafficEnabled, + buildingsEnabled: config.buildingsEnabled, + mapId: config.mapId, + style: config.style, + ); +} + +// For supporting the deprecated updateMapOptions API. +PlatformMapConfiguration _platformMapConfigurationFromOptionsJson( + Map options, +) { + // All of these hard-coded values and structures come from + // google_maps_flutter_platform_interface/lib/src/types/utils/map_configuration_serialization.dart + // to support this legacy API that relied on cross-package magic strings. + final List? padding = (options['padding'] as List?) + ?.cast(); + final mapType = options['mapType'] as int?; + return PlatformMapConfiguration( + compassEnabled: options['compassEnabled'] as bool?, + cameraTargetBounds: _platformCameraTargetBoundsFromCameraTargetBoundsJson( + options['cameraTargetBounds'], + ), + mapType: mapType == null ? null : _platformMapTypeFromMapTypeIndex(mapType), + minMaxZoomPreference: _platformZoomRangeFromMinMaxZoomPreferenceJson( + options['minMaxZoomPreference'], + ), + rotateGesturesEnabled: options['rotateGesturesEnabled'] as bool?, + scrollGesturesEnabled: options['scrollGesturesEnabled'] as bool?, + tiltGesturesEnabled: options['tiltGesturesEnabled'] as bool?, + trackCameraPosition: options['trackCameraPosition'] as bool?, + zoomGesturesEnabled: options['zoomGesturesEnabled'] as bool?, + myLocationEnabled: options['myLocationEnabled'] as bool?, + myLocationButtonEnabled: options['myLocationButtonEnabled'] as bool?, + padding: padding == null + ? null + : PlatformEdgeInsets( + top: padding[0], + left: padding[1], + bottom: padding[2], + right: padding[3], + ), + indoorViewEnabled: options['indoorEnabled'] as bool?, + trafficEnabled: options['trafficEnabled'] as bool?, + buildingsEnabled: options['buildingsEnabled'] as bool?, + mapId: options['cloudMapId'] as String?, + style: options['style'] as String?, + ); +} + +PlatformCameraPosition _platformCameraPositionFromCameraPosition( + CameraPosition position, +) { + return PlatformCameraPosition( + bearing: position.bearing, + target: _platformLatLngFromLatLng(position.target), + tilt: position.tilt, + zoom: position.zoom, + ); +} + +PlatformMapType _platformMapTypeFromMapTypeIndex(int index) { + // This is inherently fragile, but see comment in updateMapOptions. + return switch (index) { + 0 => PlatformMapType.none, + 1 => PlatformMapType.normal, + 2 => PlatformMapType.satellite, + 3 => PlatformMapType.terrain, + 4 => PlatformMapType.hybrid, + // For a new, unsupported type, just use normal. + _ => PlatformMapType.normal, + }; +} + +PlatformLatLng _platformLatLngFromLatLngJson(Object latLngJson) { + // See `LatLng.toJson`. + final List list = (latLngJson as List).cast(); + return PlatformLatLng(latitude: list[0], longitude: list[1]); +} + +PlatformLatLngBounds? _platformLatLngBoundsFromLatLngBoundsJson( + Object? boundsJson, +) { + if (boundsJson == null) { + return null; + } + // See `LatLngBounds.toJson`. + final List boundsList = (boundsJson as List).cast(); + return PlatformLatLngBounds( + southwest: _platformLatLngFromLatLngJson(boundsList[0]), + northeast: _platformLatLngFromLatLngJson(boundsList[1]), + ); +} + +PlatformCameraTargetBounds? +_platformCameraTargetBoundsFromCameraTargetBoundsJson(Object? targetJson) { + if (targetJson == null) { + return null; + } + // See `CameraTargetBounds.toJson`. + return PlatformCameraTargetBounds( + bounds: _platformLatLngBoundsFromLatLngBoundsJson( + (targetJson as List)[0], + ), + ); +} + +PlatformZoomRange? _platformZoomRangeFromMinMaxZoomPreferenceJson( + Object? zoomPrefsJson, +) { + if (zoomPrefsJson == null) { + return null; + } + // See `MinMaxZoomPreference.toJson`. + final List minMaxZoom = (zoomPrefsJson as List) + .cast(); + return PlatformZoomRange(min: minMaxZoom[0], max: minMaxZoom[1]); +} + +/// Converts platform interface's JointType to Pigeon's PlatformJointType. +@visibleForTesting +PlatformJointType platformJointTypeFromJointType(JointType jointType) { + switch (jointType) { + case JointType.mitered: + return PlatformJointType.mitered; + case JointType.bevel: + return PlatformJointType.bevel; + case JointType.round: + return PlatformJointType.round; + } + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformJointType.mitered; +} + +/// Converts a PatternItem to Pigeon's PlatformPatternItem for PlatformPolyline +/// pattern member. +@visibleForTesting +PlatformPatternItem platformPatternItemFromPatternItem(PatternItem item) { + switch (item.type) { + case PatternItemType.dot: + return PlatformPatternItem(type: PlatformPatternItemType.dot); + case PatternItemType.dash: + final double length = (item as VariableLengthPatternItem).length; + return PlatformPatternItem( + type: PlatformPatternItemType.dash, + length: length, + ); + case PatternItemType.gap: + final double length = (item as VariableLengthPatternItem).length; + return PlatformPatternItem( + type: PlatformPatternItemType.gap, + length: length, + ); + } + + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformPatternItem(type: PlatformPatternItemType.dot); +} + +/// Update specification for a set of [TileOverlay]s. +// TODO(stuartmorgan): Fix the missing export of this class in the platform +// interface, and remove this copy. +class _TileOverlayUpdates extends MapsObjectUpdates { + /// Computes [TileOverlayUpdates] given previous and current [TileOverlay]s. + _TileOverlayUpdates.from(super.previous, super.current) + : super.from(objectName: 'tileOverlay'); + + /// Set of TileOverlays to be added in this update. + Set get tileOverlaysToAdd => objectsToAdd; + + /// Set of TileOverlayIds to be removed in this update. + Set get tileOverlayIdsToRemove => + objectIdsToRemove.cast(); + + /// Set of TileOverlays to be changed in this update. + Set get tileOverlaysToChange => objectsToChange; +} 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 new file mode 100644 index 000000000000..bd54d5f62322 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/lib/src/messages.g.dart @@ -0,0 +1,4311 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, omit_obvious_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +List wrapResponse({ + Object? result, + PlatformException? error, + bool empty = false, +}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [error.code, error.message, error.details]; +} + +bool _deepEquals(Object? a, Object? b) { + if (a is List && b is List) { + return a.length == b.length && + a.indexed.every( + ((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), + ); + } + if (a is Map && b is Map) { + return a.length == b.length && + a.entries.every( + (MapEntry entry) => + (b as Map).containsKey(entry.key) && + _deepEquals(entry.value, b[entry.key]), + ); + } + return a == b; +} + +/// Pigeon equivalent of MapType +enum PlatformMapType { none, normal, satellite, terrain, hybrid } + +/// Join types for polyline joints. +enum PlatformJointType { mitered, bevel, round } + +/// Enumeration of possible types for PatternItem. +enum PlatformPatternItemType { dot, dash, gap } + +/// Pigeon equivalent of [MapBitmapScaling]. +enum PlatformMapBitmapScaling { auto, none } + +/// Pigeon representatation of a CameraPosition. +class PlatformCameraPosition { + PlatformCameraPosition({ + required this.bearing, + required this.target, + required this.tilt, + required this.zoom, + }); + + double bearing; + + PlatformLatLng target; + + double tilt; + + double zoom; + + List _toList() { + return [bearing, target, tilt, zoom]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraPosition decode(Object result) { + result as List; + return PlatformCameraPosition( + bearing: result[0]! as double, + target: result[1]! as PlatformLatLng, + tilt: result[2]! as double, + zoom: result[3]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraPosition || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate({required this.cameraUpdate}); + + /// This Object must be one of the classes below prefixed with + /// PlatformCameraUpdate. Each such class represents a different type of + /// camera update, and each holds a different set of data, preventing the + /// use of a single unified class. + Object cameraUpdate; + + List _toList() { + return [cameraUpdate]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdate decode(Object result) { + result as List; + return PlatformCameraUpdate(cameraUpdate: result[0]!); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdate || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewCameraPosition +class PlatformCameraUpdateNewCameraPosition { + PlatformCameraUpdateNewCameraPosition({required this.cameraPosition}); + + PlatformCameraPosition cameraPosition; + + List _toList() { + return [cameraPosition]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewCameraPosition decode(Object result) { + result as List; + return PlatformCameraUpdateNewCameraPosition( + cameraPosition: result[0]! as PlatformCameraPosition, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewCameraPosition || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewLatLng +class PlatformCameraUpdateNewLatLng { + PlatformCameraUpdateNewLatLng({required this.latLng}); + + PlatformLatLng latLng; + + List _toList() { + return [latLng]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewLatLng decode(Object result) { + result as List; + return PlatformCameraUpdateNewLatLng(latLng: result[0]! as PlatformLatLng); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewLatLng || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewLatLngBounds +class PlatformCameraUpdateNewLatLngBounds { + PlatformCameraUpdateNewLatLngBounds({ + required this.bounds, + required this.padding, + }); + + PlatformLatLngBounds bounds; + + double padding; + + List _toList() { + return [bounds, padding]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewLatLngBounds decode(Object result) { + result as List; + return PlatformCameraUpdateNewLatLngBounds( + bounds: result[0]! as PlatformLatLngBounds, + padding: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewLatLngBounds || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewLatLngZoom +class PlatformCameraUpdateNewLatLngZoom { + PlatformCameraUpdateNewLatLngZoom({required this.latLng, required this.zoom}); + + PlatformLatLng latLng; + + double zoom; + + List _toList() { + return [latLng, zoom]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewLatLngZoom decode(Object result) { + result as List; + return PlatformCameraUpdateNewLatLngZoom( + latLng: result[0]! as PlatformLatLng, + zoom: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewLatLngZoom || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ScrollBy +class PlatformCameraUpdateScrollBy { + PlatformCameraUpdateScrollBy({required this.dx, required this.dy}); + + double dx; + + double dy; + + List _toList() { + return [dx, dy]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateScrollBy decode(Object result) { + result as List; + return PlatformCameraUpdateScrollBy( + dx: result[0]! as double, + dy: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateScrollBy || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ZoomBy +class PlatformCameraUpdateZoomBy { + PlatformCameraUpdateZoomBy({required this.amount, this.focus}); + + double amount; + + PlatformPoint? focus; + + List _toList() { + return [amount, focus]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateZoomBy decode(Object result) { + result as List; + return PlatformCameraUpdateZoomBy( + amount: result[0]! as double, + focus: result[1] as PlatformPoint?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateZoomBy || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ZoomIn/ZoomOut +class PlatformCameraUpdateZoom { + PlatformCameraUpdateZoom({required this.out}); + + bool out; + + List _toList() { + return [out]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateZoom decode(Object result) { + result as List; + return PlatformCameraUpdateZoom(out: result[0]! as bool); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateZoom || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ZoomTo +class PlatformCameraUpdateZoomTo { + PlatformCameraUpdateZoomTo({required this.zoom}); + + double zoom; + + List _toList() { + return [zoom]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateZoomTo decode(Object result) { + result as List; + return PlatformCameraUpdateZoomTo(zoom: result[0]! as double); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateZoomTo || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle({ + this.consumeTapEvents = false, + required this.fillColor, + required this.strokeColor, + this.visible = true, + this.strokeWidth = 10, + this.zIndex = 0.0, + required this.center, + this.radius = 0, + required this.circleId, + }); + + bool consumeTapEvents; + + PlatformColor fillColor; + + PlatformColor strokeColor; + + bool visible; + + int strokeWidth; + + double zIndex; + + PlatformLatLng center; + + double radius; + + String circleId; + + List _toList() { + return [ + consumeTapEvents, + fillColor, + strokeColor, + visible, + strokeWidth, + zIndex, + center, + radius, + circleId, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformCircle decode(Object result) { + result as List; + return PlatformCircle( + consumeTapEvents: result[0]! as bool, + fillColor: result[1]! as PlatformColor, + strokeColor: result[2]! as PlatformColor, + visible: result[3]! as bool, + strokeWidth: result[4]! as int, + zIndex: result[5]! as double, + center: result[6]! as PlatformLatLng, + radius: result[7]! as double, + circleId: result[8]! as String, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCircle || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Heatmap class. +class PlatformHeatmap { + PlatformHeatmap({ + required this.heatmapId, + required this.data, + this.gradient, + required this.opacity, + required this.radius, + required this.minimumZoomIntensity, + required this.maximumZoomIntensity, + }); + + String heatmapId; + + List data; + + PlatformHeatmapGradient? gradient; + + double opacity; + + int radius; + + int minimumZoomIntensity; + + int maximumZoomIntensity; + + List _toList() { + return [ + heatmapId, + data, + gradient, + opacity, + radius, + minimumZoomIntensity, + maximumZoomIntensity, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformHeatmap decode(Object result) { + result as List; + return PlatformHeatmap( + heatmapId: result[0]! as String, + data: (result[1] as List?)!.cast(), + gradient: result[2] as PlatformHeatmapGradient?, + opacity: result[3]! as double, + radius: result[4]! as int, + minimumZoomIntensity: result[5]! as int, + maximumZoomIntensity: result[6]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformHeatmap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the HeatmapGradient class. +/// +/// The GMUGradient structure is slightly different from HeatmapGradient, so +/// this matches the iOS API so that conversion can be done on the Dart side +/// where the structures are easier to work with. +class PlatformHeatmapGradient { + PlatformHeatmapGradient({ + required this.colors, + required this.startPoints, + required this.colorMapSize, + }); + + List colors; + + List startPoints; + + int colorMapSize; + + List _toList() { + return [colors, startPoints, colorMapSize]; + } + + Object encode() { + return _toList(); + } + + static PlatformHeatmapGradient decode(Object result) { + result as List; + return PlatformHeatmapGradient( + colors: (result[0] as List?)!.cast(), + startPoints: (result[1] as List?)!.cast(), + colorMapSize: result[2]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformHeatmapGradient || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the WeightedLatLng class. +class PlatformWeightedLatLng { + PlatformWeightedLatLng({required this.point, required this.weight}); + + PlatformLatLng point; + + double weight; + + List _toList() { + return [point, weight]; + } + + Object encode() { + return _toList(); + } + + static PlatformWeightedLatLng decode(Object result) { + result as List; + return PlatformWeightedLatLng( + point: result[0]! as PlatformLatLng, + weight: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformWeightedLatLng || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the InfoWindow class. +class PlatformInfoWindow { + PlatformInfoWindow({this.title, this.snippet, required this.anchor}); + + String? title; + + String? snippet; + + PlatformPoint anchor; + + List _toList() { + return [title, snippet, anchor]; + } + + Object encode() { + return _toList(); + } + + static PlatformInfoWindow decode(Object result) { + result as List; + return PlatformInfoWindow( + title: result[0] as String?, + snippet: result[1] as String?, + anchor: result[2]! as PlatformPoint, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformInfoWindow || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of Cluster. +class PlatformCluster { + PlatformCluster({ + required this.clusterManagerId, + required this.position, + required this.bounds, + required this.markerIds, + }); + + String clusterManagerId; + + PlatformLatLng position; + + PlatformLatLngBounds bounds; + + List markerIds; + + List _toList() { + return [clusterManagerId, position, bounds, markerIds]; + } + + Object encode() { + return _toList(); + } + + static PlatformCluster decode(Object result) { + result as List; + return PlatformCluster( + clusterManagerId: result[0]! as String, + position: result[1]! as PlatformLatLng, + bounds: result[2]! as PlatformLatLngBounds, + markerIds: (result[3] as List?)!.cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCluster || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({required this.identifier}); + + String identifier; + + List _toList() { + return [identifier]; + } + + Object encode() { + return _toList(); + } + + static PlatformClusterManager decode(Object result) { + result as List; + return PlatformClusterManager(identifier: result[0]! as String); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformClusterManager || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker({ + this.alpha = 1.0, + required this.anchor, + this.consumeTapEvents = false, + this.draggable = false, + this.flat = false, + required this.icon, + required this.infoWindow, + required this.position, + this.rotation = 0.0, + this.visible = true, + this.zIndex = 0, + required this.markerId, + this.clusterManagerId, + }); + + double alpha; + + PlatformPoint anchor; + + bool consumeTapEvents; + + bool draggable; + + bool flat; + + PlatformBitmap icon; + + PlatformInfoWindow infoWindow; + + PlatformLatLng position; + + double rotation; + + bool visible; + + int zIndex; + + String markerId; + + String? clusterManagerId; + + List _toList() { + return [ + alpha, + anchor, + consumeTapEvents, + draggable, + flat, + icon, + infoWindow, + position, + rotation, + visible, + zIndex, + markerId, + clusterManagerId, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformMarker decode(Object result) { + result as List; + return PlatformMarker( + alpha: result[0]! as double, + anchor: result[1]! as PlatformPoint, + consumeTapEvents: result[2]! as bool, + draggable: result[3]! as bool, + flat: result[4]! as bool, + icon: result[5]! as PlatformBitmap, + infoWindow: result[6]! as PlatformInfoWindow, + position: result[7]! as PlatformLatLng, + rotation: result[8]! as double, + visible: result[9]! as bool, + zIndex: result[10]! as int, + markerId: result[11]! as String, + clusterManagerId: result[12] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformMarker || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon({ + required this.polygonId, + required this.consumesTapEvents, + required this.fillColor, + required this.geodesic, + required this.points, + required this.holes, + required this.visible, + required this.strokeColor, + required this.strokeWidth, + required this.zIndex, + }); + + String polygonId; + + bool consumesTapEvents; + + PlatformColor fillColor; + + bool geodesic; + + List points; + + List> holes; + + bool visible; + + PlatformColor strokeColor; + + int strokeWidth; + + int zIndex; + + List _toList() { + return [ + polygonId, + consumesTapEvents, + fillColor, + geodesic, + points, + holes, + visible, + strokeColor, + strokeWidth, + zIndex, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformPolygon decode(Object result) { + result as List; + return PlatformPolygon( + polygonId: result[0]! as String, + consumesTapEvents: result[1]! as bool, + fillColor: result[2]! as PlatformColor, + geodesic: result[3]! as bool, + points: (result[4] as List?)!.cast(), + holes: (result[5] as List?)!.cast>(), + visible: result[6]! as bool, + strokeColor: result[7]! as PlatformColor, + strokeWidth: result[8]! as int, + zIndex: result[9]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPolygon || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline({ + required this.polylineId, + required this.consumesTapEvents, + required this.color, + required this.geodesic, + required this.jointType, + required this.patterns, + required this.points, + required this.visible, + required this.width, + required this.zIndex, + }); + + String polylineId; + + bool consumesTapEvents; + + PlatformColor color; + + bool geodesic; + + /// The joint type. + PlatformJointType jointType; + + /// The pattern data, as a list of pattern items. + List patterns; + + List points; + + bool visible; + + int width; + + int zIndex; + + List _toList() { + return [ + polylineId, + consumesTapEvents, + color, + geodesic, + jointType, + patterns, + points, + visible, + width, + zIndex, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformPolyline decode(Object result) { + result as List; + return PlatformPolyline( + polylineId: result[0]! as String, + consumesTapEvents: result[1]! as bool, + color: result[2]! as PlatformColor, + geodesic: result[3]! as bool, + jointType: result[4]! as PlatformJointType, + patterns: (result[5] as List?)!.cast(), + points: (result[6] as List?)!.cast(), + visible: result[7]! as bool, + width: result[8]! as int, + zIndex: result[9]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPolyline || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the PatternItem class. +class PlatformPatternItem { + PlatformPatternItem({required this.type, this.length}); + + PlatformPatternItemType type; + + double? length; + + List _toList() { + return [type, length]; + } + + Object encode() { + return _toList(); + } + + static PlatformPatternItem decode(Object result) { + result as List; + return PlatformPatternItem( + type: result[0]! as PlatformPatternItemType, + length: result[1] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPatternItem || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Tile class. +class PlatformTile { + PlatformTile({required this.width, required this.height, this.data}); + + int width; + + int height; + + Uint8List? data; + + List _toList() { + return [width, height, data]; + } + + Object encode() { + return _toList(); + } + + static PlatformTile decode(Object result) { + result as List; + return PlatformTile( + width: result[0]! as int, + height: result[1]! as int, + data: result[2] as Uint8List?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTile || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay({ + required this.tileOverlayId, + required this.fadeIn, + required this.transparency, + required this.zIndex, + required this.visible, + required this.tileSize, + }); + + String tileOverlayId; + + bool fadeIn; + + double transparency; + + int zIndex; + + bool visible; + + int tileSize; + + List _toList() { + return [ + tileOverlayId, + fadeIn, + transparency, + zIndex, + visible, + tileSize, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformTileOverlay decode(Object result) { + result as List; + return PlatformTileOverlay( + tileOverlayId: result[0]! as String, + fadeIn: result[1]! as bool, + transparency: result[2]! as double, + zIndex: result[3]! as int, + visible: result[4]! as bool, + tileSize: result[5]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTileOverlay || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of Flutter's EdgeInsets. +class PlatformEdgeInsets { + PlatformEdgeInsets({ + required this.top, + required this.bottom, + required this.left, + required this.right, + }); + + double top; + + double bottom; + + double left; + + double right; + + List _toList() { + return [top, bottom, left, right]; + } + + Object encode() { + return _toList(); + } + + static PlatformEdgeInsets decode(Object result) { + result as List; + return PlatformEdgeInsets( + top: result[0]! as double, + bottom: result[1]! as double, + left: result[2]! as double, + right: result[3]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformEdgeInsets || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of LatLng. +class PlatformLatLng { + PlatformLatLng({required this.latitude, required this.longitude}); + + double latitude; + + double longitude; + + List _toList() { + return [latitude, longitude]; + } + + Object encode() { + return _toList(); + } + + static PlatformLatLng decode(Object result) { + result as List; + return PlatformLatLng( + latitude: result[0]! as double, + longitude: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformLatLng || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of LatLngBounds. +class PlatformLatLngBounds { + PlatformLatLngBounds({required this.northeast, required this.southwest}); + + PlatformLatLng northeast; + + PlatformLatLng southwest; + + List _toList() { + return [northeast, southwest]; + } + + Object encode() { + return _toList(); + } + + static PlatformLatLngBounds decode(Object result) { + result as List; + return PlatformLatLngBounds( + northeast: result[0]! as PlatformLatLng, + southwest: result[1]! as PlatformLatLng, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformLatLngBounds || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of CameraTargetBounds. +/// +/// As with the Dart version, it exists to distinguish between not setting a +/// a target, and having an explicitly unbounded target (null [bounds]). +class PlatformCameraTargetBounds { + PlatformCameraTargetBounds({this.bounds}); + + PlatformLatLngBounds? bounds; + + List _toList() { + return [bounds]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraTargetBounds decode(Object result) { + result as List; + return PlatformCameraTargetBounds( + bounds: result[0] as PlatformLatLngBounds?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraTargetBounds || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the GroundOverlay class. +class PlatformGroundOverlay { + PlatformGroundOverlay({ + required this.groundOverlayId, + required this.image, + this.position, + this.bounds, + this.anchor, + required this.transparency, + required this.bearing, + required this.zIndex, + required this.visible, + required this.clickable, + this.zoomLevel, + }); + + String groundOverlayId; + + PlatformBitmap image; + + PlatformLatLng? position; + + PlatformLatLngBounds? bounds; + + PlatformPoint? anchor; + + double transparency; + + double bearing; + + int zIndex; + + bool visible; + + bool clickable; + + double? zoomLevel; + + List _toList() { + return [ + groundOverlayId, + image, + position, + bounds, + anchor, + transparency, + bearing, + zIndex, + visible, + clickable, + zoomLevel, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformGroundOverlay decode(Object result) { + result as List; + return PlatformGroundOverlay( + groundOverlayId: result[0]! as String, + image: result[1]! as PlatformBitmap, + position: result[2] as PlatformLatLng?, + bounds: result[3] as PlatformLatLngBounds?, + anchor: result[4] as PlatformPoint?, + transparency: result[5]! as double, + bearing: result[6]! as double, + zIndex: result[7]! as int, + visible: result[8]! as bool, + clickable: result[9]! as bool, + zoomLevel: result[10] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformGroundOverlay || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Information passed to the platform view creation. +class PlatformMapViewCreationParams { + PlatformMapViewCreationParams({ + required this.initialCameraPosition, + required this.mapConfiguration, + required this.initialCircles, + required this.initialMarkers, + required this.initialPolygons, + required this.initialPolylines, + required this.initialHeatmaps, + required this.initialTileOverlays, + required this.initialClusterManagers, + required this.initialGroundOverlays, + }); + + PlatformCameraPosition initialCameraPosition; + + PlatformMapConfiguration mapConfiguration; + + List initialCircles; + + List initialMarkers; + + List initialPolygons; + + List initialPolylines; + + List initialHeatmaps; + + List initialTileOverlays; + + List initialClusterManagers; + + List initialGroundOverlays; + + List _toList() { + return [ + initialCameraPosition, + mapConfiguration, + initialCircles, + initialMarkers, + initialPolygons, + initialPolylines, + initialHeatmaps, + initialTileOverlays, + initialClusterManagers, + initialGroundOverlays, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformMapViewCreationParams decode(Object result) { + result as List; + return PlatformMapViewCreationParams( + initialCameraPosition: result[0]! as PlatformCameraPosition, + mapConfiguration: result[1]! as PlatformMapConfiguration, + initialCircles: (result[2] as List?)!.cast(), + initialMarkers: (result[3] as List?)!.cast(), + initialPolygons: (result[4] as List?)!.cast(), + initialPolylines: (result[5] as List?)!.cast(), + initialHeatmaps: (result[6] as List?)!.cast(), + initialTileOverlays: (result[7] as List?)! + .cast(), + initialClusterManagers: (result[8] as List?)! + .cast(), + initialGroundOverlays: (result[9] as List?)! + .cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformMapViewCreationParams || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({ + this.compassEnabled, + this.cameraTargetBounds, + this.mapType, + this.minMaxZoomPreference, + this.rotateGesturesEnabled, + this.scrollGesturesEnabled, + this.tiltGesturesEnabled, + this.trackCameraPosition, + this.zoomGesturesEnabled, + this.myLocationEnabled, + this.myLocationButtonEnabled, + this.padding, + this.indoorViewEnabled, + this.trafficEnabled, + this.buildingsEnabled, + this.mapId, + this.style, + }); + + bool? compassEnabled; + + PlatformCameraTargetBounds? cameraTargetBounds; + + PlatformMapType? mapType; + + PlatformZoomRange? minMaxZoomPreference; + + bool? rotateGesturesEnabled; + + bool? scrollGesturesEnabled; + + bool? tiltGesturesEnabled; + + bool? trackCameraPosition; + + bool? zoomGesturesEnabled; + + bool? myLocationEnabled; + + bool? myLocationButtonEnabled; + + PlatformEdgeInsets? padding; + + bool? indoorViewEnabled; + + bool? trafficEnabled; + + bool? buildingsEnabled; + + String? mapId; + + String? style; + + List _toList() { + return [ + compassEnabled, + cameraTargetBounds, + mapType, + minMaxZoomPreference, + rotateGesturesEnabled, + scrollGesturesEnabled, + tiltGesturesEnabled, + trackCameraPosition, + zoomGesturesEnabled, + myLocationEnabled, + myLocationButtonEnabled, + padding, + indoorViewEnabled, + trafficEnabled, + buildingsEnabled, + mapId, + style, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformMapConfiguration decode(Object result) { + result as List; + return PlatformMapConfiguration( + compassEnabled: result[0] as bool?, + cameraTargetBounds: result[1] as PlatformCameraTargetBounds?, + mapType: result[2] as PlatformMapType?, + minMaxZoomPreference: result[3] as PlatformZoomRange?, + rotateGesturesEnabled: result[4] as bool?, + scrollGesturesEnabled: result[5] as bool?, + tiltGesturesEnabled: result[6] as bool?, + trackCameraPosition: result[7] as bool?, + zoomGesturesEnabled: result[8] as bool?, + myLocationEnabled: result[9] as bool?, + myLocationButtonEnabled: result[10] as bool?, + padding: result[11] as PlatformEdgeInsets?, + indoorViewEnabled: result[12] as bool?, + trafficEnabled: result[13] as bool?, + buildingsEnabled: result[14] as bool?, + mapId: result[15] as String?, + style: result[16] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformMapConfiguration || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of an x,y coordinate. +class PlatformPoint { + PlatformPoint({required this.x, required this.y}); + + double x; + + double y; + + List _toList() { + return [x, y]; + } + + Object encode() { + return _toList(); + } + + static PlatformPoint decode(Object result) { + result as List; + return PlatformPoint(x: result[0]! as double, y: result[1]! as double); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPoint || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of a size. +class PlatformSize { + PlatformSize({required this.width, required this.height}); + + double width; + + double height; + + List _toList() { + return [width, height]; + } + + Object encode() { + return _toList(); + } + + static PlatformSize decode(Object result) { + result as List; + return PlatformSize( + width: result[0]! as double, + height: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformSize || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of a color. +class PlatformColor { + PlatformColor({ + required this.red, + required this.green, + required this.blue, + required this.alpha, + }); + + double red; + + double green; + + double blue; + + double alpha; + + List _toList() { + return [red, green, blue, alpha]; + } + + Object encode() { + return _toList(); + } + + static PlatformColor decode(Object result) { + result as List; + return PlatformColor( + red: result[0]! as double, + green: result[1]! as double, + blue: result[2]! as double, + alpha: result[3]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformColor || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of GMSTileLayer properties. +class PlatformTileLayer { + PlatformTileLayer({ + required this.visible, + required this.fadeIn, + required this.opacity, + required this.zIndex, + }); + + bool visible; + + bool fadeIn; + + double opacity; + + int zIndex; + + List _toList() { + return [visible, fadeIn, opacity, zIndex]; + } + + Object encode() { + return _toList(); + } + + static PlatformTileLayer decode(Object result) { + result as List; + return PlatformTileLayer( + visible: result[0]! as bool, + fadeIn: result[1]! as bool, + opacity: result[2]! as double, + zIndex: result[3]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTileLayer || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of MinMaxZoomPreference. +class PlatformZoomRange { + PlatformZoomRange({this.min, this.max}); + + double? min; + + double? max; + + List _toList() { + return [min, max]; + } + + Object encode() { + return _toList(); + } + + static PlatformZoomRange decode(Object result) { + result as List; + return PlatformZoomRange( + min: result[0] as double?, + max: result[1] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformZoomRange || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [BitmapDescriptor]. As there are multiple disjoint +/// types of [BitmapDescriptor], [PlatformBitmap] contains a single field which +/// may hold the pigeon equivalent type of any of them. +class PlatformBitmap { + PlatformBitmap({required this.bitmap}); + + /// One of [PlatformBitmapAssetMap], [PlatformBitmapAsset], + /// [PlatformBitmapAssetImage], [PlatformBitmapBytesMap], + /// [PlatformBitmapBytes], or [PlatformBitmapDefaultMarker]. + /// As Pigeon does not currently support data class inheritance, this + /// approach allows for the different bitmap implementations to be valid + /// argument and return types of the API methods. See + /// https://github.com/flutter/flutter/issues/117819. + Object bitmap; + + List _toList() { + return [bitmap]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmap decode(Object result) { + result as List; + return PlatformBitmap(bitmap: result[0]!); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [DefaultMarker]. +class PlatformBitmapDefaultMarker { + PlatformBitmapDefaultMarker({this.hue}); + + double? hue; + + List _toList() { + return [hue]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapDefaultMarker decode(Object result) { + result as List; + return PlatformBitmapDefaultMarker(hue: result[0] as double?); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapDefaultMarker || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [BytesBitmap]. +class PlatformBitmapBytes { + PlatformBitmapBytes({required this.byteData, this.size}); + + Uint8List byteData; + + PlatformSize? size; + + List _toList() { + return [byteData, size]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapBytes decode(Object result) { + result as List; + return PlatformBitmapBytes( + byteData: result[0]! as Uint8List, + size: result[1] as PlatformSize?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapBytes || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [AssetBitmap]. +class PlatformBitmapAsset { + PlatformBitmapAsset({required this.name, this.pkg}); + + String name; + + String? pkg; + + List _toList() { + return [name, pkg]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapAsset decode(Object result) { + result as List; + return PlatformBitmapAsset( + name: result[0]! as String, + pkg: result[1] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapAsset || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [AssetImageBitmap]. +class PlatformBitmapAssetImage { + PlatformBitmapAssetImage({ + required this.name, + required this.scale, + this.size, + }); + + String name; + + double scale; + + PlatformSize? size; + + List _toList() { + return [name, scale, size]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapAssetImage decode(Object result) { + result as List; + return PlatformBitmapAssetImage( + name: result[0]! as String, + scale: result[1]! as double, + size: result[2] as PlatformSize?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapAssetImage || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [AssetMapBitmap]. +class PlatformBitmapAssetMap { + PlatformBitmapAssetMap({ + required this.assetName, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + + String assetName; + + PlatformMapBitmapScaling bitmapScaling; + + double imagePixelRatio; + + double? width; + + double? height; + + List _toList() { + return [assetName, bitmapScaling, imagePixelRatio, width, height]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapAssetMap decode(Object result) { + result as List; + return PlatformBitmapAssetMap( + assetName: result[0]! as String, + bitmapScaling: result[1]! as PlatformMapBitmapScaling, + imagePixelRatio: result[2]! as double, + width: result[3] as double?, + height: result[4] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapAssetMap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [BytesMapBitmap]. +class PlatformBitmapBytesMap { + PlatformBitmapBytesMap({ + required this.byteData, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + + Uint8List byteData; + + PlatformMapBitmapScaling bitmapScaling; + + double imagePixelRatio; + + double? width; + + double? height; + + List _toList() { + return [byteData, bitmapScaling, imagePixelRatio, width, height]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapBytesMap decode(Object result) { + result as List; + return PlatformBitmapBytesMap( + byteData: result[0]! as Uint8List, + bitmapScaling: result[1]! as PlatformMapBitmapScaling, + imagePixelRatio: result[2]! as double, + width: result[3] as double?, + height: result[4] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapBytesMap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is PlatformMapType) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is PlatformJointType) { + buffer.putUint8(130); + writeValue(buffer, value.index); + } else if (value is PlatformPatternItemType) { + buffer.putUint8(131); + writeValue(buffer, value.index); + } else if (value is PlatformMapBitmapScaling) { + buffer.putUint8(132); + writeValue(buffer, value.index); + } else if (value is PlatformCameraPosition) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdate) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewCameraPosition) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewLatLng) { + buffer.putUint8(136); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewLatLngBounds) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewLatLngZoom) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateScrollBy) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateZoomBy) { + buffer.putUint8(140); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateZoom) { + buffer.putUint8(141); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateZoomTo) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); + } else if (value is PlatformCircle) { + buffer.putUint8(143); + writeValue(buffer, value.encode()); + } else if (value is PlatformHeatmap) { + buffer.putUint8(144); + writeValue(buffer, value.encode()); + } else if (value is PlatformHeatmapGradient) { + buffer.putUint8(145); + writeValue(buffer, value.encode()); + } else if (value is PlatformWeightedLatLng) { + buffer.putUint8(146); + writeValue(buffer, value.encode()); + } else if (value is PlatformInfoWindow) { + buffer.putUint8(147); + writeValue(buffer, value.encode()); + } else if (value is PlatformCluster) { + buffer.putUint8(148); + writeValue(buffer, value.encode()); + } else if (value is PlatformClusterManager) { + buffer.putUint8(149); + writeValue(buffer, value.encode()); + } else if (value is PlatformMarker) { + buffer.putUint8(150); + writeValue(buffer, value.encode()); + } else if (value is PlatformPolygon) { + buffer.putUint8(151); + writeValue(buffer, value.encode()); + } else if (value is PlatformPolyline) { + buffer.putUint8(152); + writeValue(buffer, value.encode()); + } else if (value is PlatformPatternItem) { + buffer.putUint8(153); + writeValue(buffer, value.encode()); + } else if (value is PlatformTile) { + buffer.putUint8(154); + writeValue(buffer, value.encode()); + } else if (value is PlatformTileOverlay) { + buffer.putUint8(155); + writeValue(buffer, value.encode()); + } else if (value is PlatformEdgeInsets) { + buffer.putUint8(156); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLng) { + buffer.putUint8(157); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLngBounds) { + buffer.putUint8(158); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraTargetBounds) { + buffer.putUint8(159); + writeValue(buffer, value.encode()); + } else if (value is PlatformGroundOverlay) { + buffer.putUint8(160); + writeValue(buffer, value.encode()); + } else if (value is PlatformMapViewCreationParams) { + buffer.putUint8(161); + writeValue(buffer, value.encode()); + } else if (value is PlatformMapConfiguration) { + buffer.putUint8(162); + writeValue(buffer, value.encode()); + } else if (value is PlatformPoint) { + buffer.putUint8(163); + writeValue(buffer, value.encode()); + } else if (value is PlatformSize) { + buffer.putUint8(164); + writeValue(buffer, value.encode()); + } else if (value is PlatformColor) { + buffer.putUint8(165); + writeValue(buffer, value.encode()); + } else if (value is PlatformTileLayer) { + buffer.putUint8(166); + writeValue(buffer, value.encode()); + } else if (value is PlatformZoomRange) { + buffer.putUint8(167); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmap) { + buffer.putUint8(168); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapDefaultMarker) { + buffer.putUint8(169); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapBytes) { + buffer.putUint8(170); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapAsset) { + buffer.putUint8(171); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapAssetImage) { + buffer.putUint8(172); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapAssetMap) { + buffer.putUint8(173); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapBytesMap) { + buffer.putUint8(174); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformMapType.values[value]; + case 130: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformJointType.values[value]; + case 131: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformPatternItemType.values[value]; + case 132: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformMapBitmapScaling.values[value]; + case 133: + return PlatformCameraPosition.decode(readValue(buffer)!); + case 134: + return PlatformCameraUpdate.decode(readValue(buffer)!); + case 135: + return PlatformCameraUpdateNewCameraPosition.decode(readValue(buffer)!); + case 136: + return PlatformCameraUpdateNewLatLng.decode(readValue(buffer)!); + case 137: + return PlatformCameraUpdateNewLatLngBounds.decode(readValue(buffer)!); + case 138: + return PlatformCameraUpdateNewLatLngZoom.decode(readValue(buffer)!); + case 139: + return PlatformCameraUpdateScrollBy.decode(readValue(buffer)!); + case 140: + return PlatformCameraUpdateZoomBy.decode(readValue(buffer)!); + case 141: + return PlatformCameraUpdateZoom.decode(readValue(buffer)!); + case 142: + return PlatformCameraUpdateZoomTo.decode(readValue(buffer)!); + case 143: + return PlatformCircle.decode(readValue(buffer)!); + case 144: + return PlatformHeatmap.decode(readValue(buffer)!); + case 145: + return PlatformHeatmapGradient.decode(readValue(buffer)!); + case 146: + return PlatformWeightedLatLng.decode(readValue(buffer)!); + case 147: + return PlatformInfoWindow.decode(readValue(buffer)!); + case 148: + return PlatformCluster.decode(readValue(buffer)!); + case 149: + return PlatformClusterManager.decode(readValue(buffer)!); + case 150: + return PlatformMarker.decode(readValue(buffer)!); + case 151: + return PlatformPolygon.decode(readValue(buffer)!); + case 152: + return PlatformPolyline.decode(readValue(buffer)!); + case 153: + return PlatformPatternItem.decode(readValue(buffer)!); + case 154: + return PlatformTile.decode(readValue(buffer)!); + case 155: + return PlatformTileOverlay.decode(readValue(buffer)!); + case 156: + return PlatformEdgeInsets.decode(readValue(buffer)!); + case 157: + return PlatformLatLng.decode(readValue(buffer)!); + case 158: + return PlatformLatLngBounds.decode(readValue(buffer)!); + case 159: + return PlatformCameraTargetBounds.decode(readValue(buffer)!); + case 160: + return PlatformGroundOverlay.decode(readValue(buffer)!); + case 161: + return PlatformMapViewCreationParams.decode(readValue(buffer)!); + case 162: + return PlatformMapConfiguration.decode(readValue(buffer)!); + case 163: + return PlatformPoint.decode(readValue(buffer)!); + case 164: + return PlatformSize.decode(readValue(buffer)!); + case 165: + return PlatformColor.decode(readValue(buffer)!); + case 166: + return PlatformTileLayer.decode(readValue(buffer)!); + case 167: + return PlatformZoomRange.decode(readValue(buffer)!); + case 168: + return PlatformBitmap.decode(readValue(buffer)!); + case 169: + return PlatformBitmapDefaultMarker.decode(readValue(buffer)!); + case 170: + return PlatformBitmapBytes.decode(readValue(buffer)!); + case 171: + return PlatformBitmapAsset.decode(readValue(buffer)!); + case 172: + return PlatformBitmapAssetImage.decode(readValue(buffer)!); + case 173: + return PlatformBitmapAssetMap.decode(readValue(buffer)!); + case 174: + return PlatformBitmapBytesMap.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// Interface for non-test interactions with the native SDK. +/// +/// For test-only state queries, see [MapsInspectorApi]. +class MapsApi { + /// Constructor for [MapsApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + /// Returns once the map instance is available. + Future waitForMap() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.waitForMap$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + Future updateMapConfiguration( + PlatformMapConfiguration configuration, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateMapConfiguration$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [configuration], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of circles on the map. + Future updateCircles( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateCircles$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of heatmaps on the map. + Future updateHeatmaps( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateHeatmaps$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of custer managers for clusters on the map. + Future updateClusterManagers( + List toAdd, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateClusterManagers$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of markers on the map. + Future updateMarkers( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateMarkers$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polygonss on the map. + Future updatePolygons( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updatePolygons$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polylines on the map. + Future updatePolylines( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updatePolylines$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of tile overlays on the map. + Future updateTileOverlays( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateTileOverlays$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of ground overlays on the map. + Future updateGroundOverlays( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateGroundOverlays$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Gets the screen coordinate for the given map location. + Future getScreenCoordinate(PlatformLatLng latLng) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getScreenCoordinate$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [latLng], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformPoint?)!; + } + } + + /// Gets the map location for the given screen coordinate. + Future getLatLng(PlatformPoint screenCoordinate) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getLatLng$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [screenCoordinate], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformLatLng?)!; + } + } + + /// Gets the map region currently displayed on the map. + Future getVisibleRegion() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getVisibleRegion$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformLatLngBounds?)!; + } + } + + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + Future moveCamera(PlatformCameraUpdate cameraUpdate) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.moveCamera$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [cameraUpdate], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Moves the camera according to [cameraUpdate], animating the update using a + /// duration in milliseconds if provided. + Future animateCamera( + PlatformCameraUpdate cameraUpdate, + int? durationMilliseconds, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.animateCamera$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [cameraUpdate, durationMilliseconds], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Gets the current map zoom level. + Future getZoomLevel() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getZoomLevel$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as double?)!; + } + } + + /// Show the info window for the marker with the given ID. + Future showInfoWindow(String markerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.showInfoWindow$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [markerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Hide the info window for the marker with the given ID. + Future hideInfoWindow(String markerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.hideInfoWindow$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [markerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Returns true if the marker with the given ID is currently displaying its + /// info window. + Future isInfoWindowShown(String markerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.isInfoWindowShown$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [markerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Sets the style to the given map style string, where an empty string + /// indicates that the style should be cleared. + /// + /// If there was an error setting the style, such as an invalid style string, + /// returns the error message. + Future setStyle(String style) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.setStyle$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [style], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Returns the error string from the last attempt to set the map style, if + /// any. + /// + /// This allows checking asynchronously for initial style failures, as there + /// is no way to return failures from map initialization. + Future getLastStyleError() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getLastStyleError$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Clears the cache of tiles previously requseted from the tile provider. + Future clearTileCache(String tileOverlayId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.clearTileCache$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [tileOverlayId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Takes a snapshot of the map and returns its image data. + Future takeSnapshot() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.takeSnapshot$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as Uint8List?); + } + } +} + +/// Interface for calls from the native SDK to Dart. +abstract class MapsCallbackApi { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + /// Called when the map camera starts moving. + void onCameraMoveStarted(); + + /// Called when the map camera moves. + void onCameraMove(PlatformCameraPosition cameraPosition); + + /// Called when the map camera stops moving. + void onCameraIdle(); + + /// Called when the map, not a specifc map object, is tapped. + void onTap(PlatformLatLng position); + + /// Called when the map, not a specifc map object, is long pressed. + void onLongPress(PlatformLatLng position); + + /// Called when a marker is tapped. + void onMarkerTap(String markerId); + + /// Called when a marker drag starts. + void onMarkerDragStart(String markerId, PlatformLatLng position); + + /// Called when a marker drag updates. + void onMarkerDrag(String markerId, PlatformLatLng position); + + /// Called when a marker drag ends. + void onMarkerDragEnd(String markerId, PlatformLatLng position); + + /// Called when a marker's info window is tapped. + void onInfoWindowTap(String markerId); + + /// Called when a circle is tapped. + void onCircleTap(String circleId); + + /// Called when a marker cluster is tapped. + void onClusterTap(PlatformCluster cluster); + + /// Called when a polygon is tapped. + void onPolygonTap(String polygonId); + + /// Called when a polyline is tapped. + void onPolylineTap(String polylineId); + + /// Called when a ground overlay is tapped. + void onGroundOverlayTap(String groundOverlayId); + + /// Called to get data for a map tile. + Future getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ); + + static void setUp( + MapsCallbackApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMoveStarted$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onCameraMoveStarted(); + 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.onCameraMove$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMove was null.', + ); + final List args = (message as List?)!; + final PlatformCameraPosition? arg_cameraPosition = + (args[0] as PlatformCameraPosition?); + assert( + arg_cameraPosition != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMove was null, expected non-null PlatformCameraPosition.', + ); + try { + api.onCameraMove(arg_cameraPosition!); + 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.onCameraIdle$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onCameraIdle(); + 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.onTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onTap was null.', + ); + final List args = (message as List?)!; + final PlatformLatLng? arg_position = (args[0] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onTap was null, expected non-null PlatformLatLng.', + ); + try { + api.onTap(arg_position!); + 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.onLongPress$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onLongPress was null.', + ); + final List args = (message as List?)!; + final PlatformLatLng? arg_position = (args[0] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onLongPress was null, expected non-null PlatformLatLng.', + ); + try { + api.onLongPress(arg_position!); + 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.onMarkerTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerTap was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerTap was null, expected non-null String.', + ); + try { + api.onMarkerTap(arg_markerId!); + 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.onMarkerDragStart$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart was null, expected non-null String.', + ); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart was null, expected non-null PlatformLatLng.', + ); + try { + api.onMarkerDragStart(arg_markerId!, arg_position!); + 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.onMarkerDrag$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag was null, expected non-null String.', + ); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag was null, expected non-null PlatformLatLng.', + ); + try { + api.onMarkerDrag(arg_markerId!, arg_position!); + 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.onMarkerDragEnd$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd was null, expected non-null String.', + ); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd was null, expected non-null PlatformLatLng.', + ); + try { + api.onMarkerDragEnd(arg_markerId!, arg_position!); + 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.onInfoWindowTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onInfoWindowTap was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onInfoWindowTap was null, expected non-null String.', + ); + try { + api.onInfoWindowTap(arg_markerId!); + 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.onCircleTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCircleTap was null.', + ); + final List args = (message as List?)!; + final String? arg_circleId = (args[0] as String?); + assert( + arg_circleId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCircleTap was null, expected non-null String.', + ); + try { + api.onCircleTap(arg_circleId!); + 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', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap was null.', + ); + final List args = (message as List?)!; + final PlatformCluster? arg_cluster = (args[0] as PlatformCluster?); + assert( + arg_cluster != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap was null, expected non-null PlatformCluster.', + ); + try { + api.onClusterTap(arg_cluster!); + 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.onPolygonTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolygonTap was null.', + ); + final List args = (message as List?)!; + final String? arg_polygonId = (args[0] as String?); + assert( + arg_polygonId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolygonTap was null, expected non-null String.', + ); + try { + api.onPolygonTap(arg_polygonId!); + 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.onPolylineTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolylineTap was null.', + ); + final List args = (message as List?)!; + final String? arg_polylineId = (args[0] as String?); + assert( + arg_polylineId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolylineTap was null, expected non-null String.', + ); + try { + api.onPolylineTap(arg_polylineId!); + 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.onGroundOverlayTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onGroundOverlayTap was null.', + ); + final List args = (message as List?)!; + final String? arg_groundOverlayId = (args[0] as String?); + assert( + arg_groundOverlayId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onGroundOverlayTap was null, expected non-null String.', + ); + try { + api.onGroundOverlayTap(arg_groundOverlayId!); + 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.getTileOverlayTile$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null.', + ); + final List args = (message as List?)!; + final String? arg_tileOverlayId = (args[0] as String?); + assert( + arg_tileOverlayId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null, expected non-null String.', + ); + final PlatformPoint? arg_location = (args[1] as PlatformPoint?); + assert( + arg_location != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null, expected non-null PlatformPoint.', + ); + final int? arg_zoom = (args[2] as int?); + assert( + arg_zoom != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null, expected non-null int.', + ); + try { + final PlatformTile output = await api.getTileOverlayTile( + arg_tileOverlayId!, + arg_location!, + arg_zoom!, + ); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString()), + ); + } + }); + } + } + } +} + +/// Dummy interface to force generation of the platform view creation params, +/// which are not used in any Pigeon calls, only the platform view creation +/// call made internally by Flutter. +class MapsPlatformViewApi { + /// Constructor for [MapsPlatformViewApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsPlatformViewApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future createView(PlatformMapViewCreationParams? type) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsPlatformViewApi.createView$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [type], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } +} + +/// Inspector API only intended for use in integration tests. +class MapsInspectorApi { + /// Constructor for [MapsInspectorApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsInspectorApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future areBuildingsEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areBuildingsEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areRotateGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areRotateGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areScrollGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areScrollGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areTiltGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areTiltGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areZoomGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areZoomGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future isCompassEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.isCompassEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future isMyLocationButtonEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.isMyLocationButtonEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future isTrafficEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.isTrafficEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future getTileOverlayInfo(String tileOverlayId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getTileOverlayInfo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [tileOverlayId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as PlatformTileLayer?); + } + } + + Future getGroundOverlayInfo( + String groundOverlayId, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getGroundOverlayInfo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [groundOverlayId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as PlatformGroundOverlay?); + } + } + + Future getHeatmapInfo(String heatmapId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getHeatmapInfo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [heatmapId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as PlatformHeatmap?); + } + } + + Future getZoomRange() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getZoomRange$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformZoomRange?)!; + } + } + + Future> getClusters(String clusterManagerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getClusters$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [clusterManagerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as List?)! + .cast(); + } + } + + Future getCameraPosition() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getCameraPosition$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformCameraPosition?)!; + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/copyright.txt b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/copyright.txt new file mode 100644 index 000000000000..07e5f8598a80 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/copyright.txt @@ -0,0 +1,3 @@ +Copyright 2013 The Flutter Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. 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 new file mode 100644 index 000000000000..87885a3a4390 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/pigeons/messages.dart @@ -0,0 +1,871 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + dartOut: 'lib/src/messages.g.dart', + // This uses a different output name to avoid conflicts with the pigeon + // files in other packages, without having to use full relative paths + // in #includes (which would make source sharing harder to manage). + objcHeaderOut: + 'ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/include/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.h', + objcSourceOut: + 'ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/google_maps_flutter_pigeon_messages.g.m', + objcOptions: ObjcOptions(prefix: 'FGM'), + copyrightHeader: 'pigeons/copyright.txt', + // Use the base package name so that the generated code can be shared + // across the implementation copies. + dartPackageName: 'google_maps_flutter_ios', + ), +) +/// Pigeon equivalent of MapType +enum PlatformMapType { none, normal, satellite, terrain, hybrid } + +/// Pigeon representatation of a CameraPosition. +class PlatformCameraPosition { + PlatformCameraPosition({ + required this.bearing, + required this.target, + required this.tilt, + required this.zoom, + }); + + final double bearing; + final PlatformLatLng target; + final double tilt; + final double zoom; +} + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate(this.cameraUpdate); + + /// This Object must be one of the classes below prefixed with + /// PlatformCameraUpdate. Each such class represents a different type of + /// camera update, and each holds a different set of data, preventing the + /// use of a single unified class. + // Pigeon does not support inheritance, which prevents a more strict type + // bound. See https://github.com/flutter/flutter/issues/117819. + final Object cameraUpdate; +} + +/// Pigeon equivalent of NewCameraPosition +class PlatformCameraUpdateNewCameraPosition { + PlatformCameraUpdateNewCameraPosition(this.cameraPosition); + final PlatformCameraPosition cameraPosition; +} + +/// Pigeon equivalent of NewLatLng +class PlatformCameraUpdateNewLatLng { + PlatformCameraUpdateNewLatLng(this.latLng); + final PlatformLatLng latLng; +} + +/// Pigeon equivalent of NewLatLngBounds +class PlatformCameraUpdateNewLatLngBounds { + PlatformCameraUpdateNewLatLngBounds(this.bounds, this.padding); + final PlatformLatLngBounds bounds; + final double padding; +} + +/// Pigeon equivalent of NewLatLngZoom +class PlatformCameraUpdateNewLatLngZoom { + PlatformCameraUpdateNewLatLngZoom(this.latLng, this.zoom); + final PlatformLatLng latLng; + final double zoom; +} + +/// Pigeon equivalent of ScrollBy +class PlatformCameraUpdateScrollBy { + PlatformCameraUpdateScrollBy(this.dx, this.dy); + final double dx; + final double dy; +} + +/// Pigeon equivalent of ZoomBy +class PlatformCameraUpdateZoomBy { + PlatformCameraUpdateZoomBy(this.amount, [this.focus]); + final double amount; + final PlatformPoint? focus; +} + +/// Pigeon equivalent of ZoomIn/ZoomOut +class PlatformCameraUpdateZoom { + PlatformCameraUpdateZoom(this.out); + final bool out; +} + +/// Pigeon equivalent of ZoomTo +class PlatformCameraUpdateZoomTo { + PlatformCameraUpdateZoomTo(this.zoom); + final double zoom; +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle({ + required this.circleId, + required this.center, + required this.fillColor, + required this.strokeColor, + this.consumeTapEvents = false, + this.visible = true, + this.strokeWidth = 10, + this.zIndex = 0.0, + this.radius = 0, + }); + + final bool consumeTapEvents; + final PlatformColor fillColor; + final PlatformColor strokeColor; + final bool visible; + final int strokeWidth; + final double zIndex; + final PlatformLatLng center; + final double radius; + final String circleId; +} + +/// Pigeon equivalent of the Heatmap class. +class PlatformHeatmap { + PlatformHeatmap({ + required this.heatmapId, + required this.data, + this.gradient, + required this.opacity, + required this.radius, + required this.minimumZoomIntensity, + required this.maximumZoomIntensity, + }); + + final String heatmapId; + final List data; + final PlatformHeatmapGradient? gradient; + final double opacity; + final int radius; + final int minimumZoomIntensity; + final int maximumZoomIntensity; +} + +/// Pigeon equivalent of the HeatmapGradient class. +/// +/// The GMUGradient structure is slightly different from HeatmapGradient, so +/// this matches the iOS API so that conversion can be done on the Dart side +/// where the structures are easier to work with. +class PlatformHeatmapGradient { + PlatformHeatmapGradient({ + required this.colors, + required this.startPoints, + required this.colorMapSize, + }); + + final List colors; + final List startPoints; + final int colorMapSize; +} + +/// Pigeon equivalent of the WeightedLatLng class. +class PlatformWeightedLatLng { + PlatformWeightedLatLng({required this.point, required this.weight}); + + final PlatformLatLng point; + final double weight; +} + +/// Pigeon equivalent of the InfoWindow class. +class PlatformInfoWindow { + PlatformInfoWindow({required this.anchor, this.title, this.snippet}); + + final String? title; + final String? snippet; + final PlatformPoint anchor; +} + +/// Pigeon equivalent of Cluster. +class PlatformCluster { + PlatformCluster({ + required this.clusterManagerId, + required this.position, + required this.bounds, + required this.markerIds, + }); + + final String clusterManagerId; + final PlatformLatLng position; + final PlatformLatLngBounds bounds; + final List markerIds; +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({required this.identifier}); + + final String identifier; +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker({ + required this.markerId, + required this.icon, + this.alpha = 1.0, + required this.anchor, + this.consumeTapEvents = false, + this.draggable = false, + this.flat = false, + required this.infoWindow, + required this.position, + this.rotation = 0.0, + this.visible = true, + this.zIndex = 0, + this.clusterManagerId, + }); + + final double alpha; + final PlatformPoint anchor; + final bool consumeTapEvents; + final bool draggable; + final bool flat; + + final PlatformBitmap icon; + final PlatformInfoWindow infoWindow; + final PlatformLatLng position; + final double rotation; + final bool visible; + final int zIndex; + final String markerId; + final String? clusterManagerId; +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon({ + required this.polygonId, + required this.consumesTapEvents, + required this.fillColor, + required this.geodesic, + required this.points, + required this.holes, + required this.visible, + required this.strokeColor, + required this.strokeWidth, + required this.zIndex, + }); + + final String polygonId; + final bool consumesTapEvents; + final PlatformColor fillColor; + final bool geodesic; + final List points; + final List> holes; + final bool visible; + final PlatformColor strokeColor; + final int strokeWidth; + final int zIndex; +} + +/// Join types for polyline joints. +enum PlatformJointType { mitered, bevel, round } + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline({ + required this.polylineId, + required this.consumesTapEvents, + required this.color, + required this.geodesic, + required this.jointType, + required this.patterns, + required this.points, + required this.visible, + required this.width, + required this.zIndex, + }); + + final String polylineId; + final bool consumesTapEvents; + final PlatformColor color; + final bool geodesic; + + /// The joint type. + final PlatformJointType jointType; + + /// The pattern data, as a list of pattern items. + final List patterns; + final List points; + + final bool visible; + final int width; + final int zIndex; +} + +/// Enumeration of possible types for PatternItem. +enum PlatformPatternItemType { dot, dash, gap } + +/// Pigeon equivalent of the PatternItem class. +class PlatformPatternItem { + PlatformPatternItem({required this.type, this.length}); + + final PlatformPatternItemType type; + final double? length; +} + +/// Pigeon equivalent of the Tile class. +class PlatformTile { + PlatformTile({required this.width, required this.height, required this.data}); + + final int width; + final int height; + final Uint8List? data; +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay({ + required this.tileOverlayId, + required this.fadeIn, + required this.transparency, + required this.zIndex, + required this.visible, + required this.tileSize, + }); + + final String tileOverlayId; + final bool fadeIn; + final double transparency; + final int zIndex; + final bool visible; + final int tileSize; +} + +/// Pigeon equivalent of Flutter's EdgeInsets. +class PlatformEdgeInsets { + PlatformEdgeInsets({ + required this.top, + required this.bottom, + required this.left, + required this.right, + }); + + final double top; + final double bottom; + final double left; + final double right; +} + +/// Pigeon equivalent of LatLng. +class PlatformLatLng { + PlatformLatLng({required this.latitude, required this.longitude}); + + final double latitude; + final double longitude; +} + +/// Pigeon equivalent of LatLngBounds. +class PlatformLatLngBounds { + PlatformLatLngBounds({required this.northeast, required this.southwest}); + + final PlatformLatLng northeast; + final PlatformLatLng southwest; +} + +/// Pigeon equivalent of CameraTargetBounds. +/// +/// As with the Dart version, it exists to distinguish between not setting a +/// a target, and having an explicitly unbounded target (null [bounds]). +class PlatformCameraTargetBounds { + PlatformCameraTargetBounds({required this.bounds}); + + final PlatformLatLngBounds? bounds; +} + +/// Pigeon equivalent of the GroundOverlay class. +class PlatformGroundOverlay { + PlatformGroundOverlay({ + required this.groundOverlayId, + required this.image, + required this.position, + required this.bounds, + required this.anchor, + required this.transparency, + required this.bearing, + required this.zIndex, + required this.visible, + required this.clickable, + required this.zoomLevel, + }); + + final String groundOverlayId; + final PlatformBitmap image; + final PlatformLatLng? position; + final PlatformLatLngBounds? bounds; + final PlatformPoint? anchor; + final double transparency; + final double bearing; + final int zIndex; + final bool visible; + final bool clickable; + final double? zoomLevel; +} + +/// Information passed to the platform view creation. +class PlatformMapViewCreationParams { + PlatformMapViewCreationParams({ + required this.initialCameraPosition, + required this.mapConfiguration, + required this.initialCircles, + required this.initialMarkers, + required this.initialPolygons, + required this.initialPolylines, + required this.initialHeatmaps, + required this.initialTileOverlays, + required this.initialClusterManagers, + required this.initialGroundOverlays, + }); + + final PlatformCameraPosition initialCameraPosition; + final PlatformMapConfiguration mapConfiguration; + final List initialCircles; + final List initialMarkers; + final List initialPolygons; + final List initialPolylines; + final List initialHeatmaps; + final List initialTileOverlays; + final List initialClusterManagers; + final List initialGroundOverlays; +} + +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({ + required this.compassEnabled, + required this.cameraTargetBounds, + required this.mapType, + required this.minMaxZoomPreference, + required this.rotateGesturesEnabled, + required this.scrollGesturesEnabled, + required this.tiltGesturesEnabled, + required this.trackCameraPosition, + required this.zoomGesturesEnabled, + required this.myLocationEnabled, + required this.myLocationButtonEnabled, + required this.padding, + required this.indoorViewEnabled, + required this.trafficEnabled, + required this.buildingsEnabled, + required this.mapId, + required this.style, + }); + + final bool? compassEnabled; + final PlatformCameraTargetBounds? cameraTargetBounds; + final PlatformMapType? mapType; + final PlatformZoomRange? minMaxZoomPreference; + final bool? rotateGesturesEnabled; + final bool? scrollGesturesEnabled; + final bool? tiltGesturesEnabled; + final bool? trackCameraPosition; + final bool? zoomGesturesEnabled; + final bool? myLocationEnabled; + final bool? myLocationButtonEnabled; + final PlatformEdgeInsets? padding; + final bool? indoorViewEnabled; + final bool? trafficEnabled; + final bool? buildingsEnabled; + final String? mapId; + final String? style; +} + +/// Pigeon representation of an x,y coordinate. +class PlatformPoint { + PlatformPoint({required this.x, required this.y}); + + final double x; + final double y; +} + +/// Pigeon representation of a size. +class PlatformSize { + PlatformSize({required this.width, required this.height}); + + final double width; + final double height; +} + +/// Pigeon representation of a color. +class PlatformColor { + PlatformColor({ + required this.red, + required this.green, + required this.blue, + required this.alpha, + }); + + final double red; + final double green; + final double blue; + final double alpha; +} + +/// Pigeon equivalent of GMSTileLayer properties. +class PlatformTileLayer { + PlatformTileLayer({ + required this.visible, + required this.fadeIn, + required this.opacity, + required this.zIndex, + }); + + final bool visible; + final bool fadeIn; + final double opacity; + final int zIndex; +} + +/// Pigeon equivalent of MinMaxZoomPreference. +class PlatformZoomRange { + PlatformZoomRange({required this.min, required this.max}); + + final double? min; + final double? max; +} + +/// Pigeon equivalent of [BitmapDescriptor]. As there are multiple disjoint +/// types of [BitmapDescriptor], [PlatformBitmap] contains a single field which +/// may hold the pigeon equivalent type of any of them. +class PlatformBitmap { + PlatformBitmap({required this.bitmap}); + + /// One of [PlatformBitmapAssetMap], [PlatformBitmapAsset], + /// [PlatformBitmapAssetImage], [PlatformBitmapBytesMap], + /// [PlatformBitmapBytes], or [PlatformBitmapDefaultMarker]. + /// As Pigeon does not currently support data class inheritance, this + /// approach allows for the different bitmap implementations to be valid + /// argument and return types of the API methods. See + /// https://github.com/flutter/flutter/issues/117819. + final Object bitmap; +} + +/// Pigeon equivalent of [DefaultMarker]. +class PlatformBitmapDefaultMarker { + PlatformBitmapDefaultMarker({this.hue}); + + final double? hue; +} + +/// Pigeon equivalent of [BytesBitmap]. +class PlatformBitmapBytes { + PlatformBitmapBytes({required this.byteData, this.size}); + + final Uint8List byteData; + final PlatformSize? size; +} + +/// Pigeon equivalent of [AssetBitmap]. +class PlatformBitmapAsset { + PlatformBitmapAsset({required this.name, this.pkg}); + + final String name; + final String? pkg; +} + +/// Pigeon equivalent of [AssetImageBitmap]. +class PlatformBitmapAssetImage { + PlatformBitmapAssetImage({ + required this.name, + required this.scale, + this.size, + }); + final String name; + final double scale; + final PlatformSize? size; +} + +/// Pigeon equivalent of [AssetMapBitmap]. +class PlatformBitmapAssetMap { + PlatformBitmapAssetMap({ + required this.assetName, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + final String assetName; + final PlatformMapBitmapScaling bitmapScaling; + final double imagePixelRatio; + final double? width; + final double? height; +} + +/// Pigeon equivalent of [BytesMapBitmap]. +class PlatformBitmapBytesMap { + PlatformBitmapBytesMap({ + required this.byteData, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + final Uint8List byteData; + final PlatformMapBitmapScaling bitmapScaling; + final double imagePixelRatio; + final double? width; + final double? height; +} + +/// Pigeon equivalent of [MapBitmapScaling]. +enum PlatformMapBitmapScaling { auto, none } + +/// Interface for non-test interactions with the native SDK. +/// +/// For test-only state queries, see [MapsInspectorApi]. +@HostApi() +abstract class MapsApi { + /// Returns once the map instance is available. + void waitForMap(); + + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + @ObjCSelector('updateWithMapConfiguration:') + void updateMapConfiguration(PlatformMapConfiguration configuration); + + /// Updates the set of circles on the map. + @ObjCSelector('updateCirclesByAdding:changing:removing:') + void updateCircles( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of heatmaps on the map. + @ObjCSelector('updateHeatmapsByAdding:changing:removing:') + void updateHeatmaps( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of custer managers for clusters on the map. + @ObjCSelector('updateClusterManagersByAdding:removing:') + void updateClusterManagers( + List toAdd, + List idsToRemove, + ); + + /// Updates the set of markers on the map. + @ObjCSelector('updateMarkersByAdding:changing:removing:') + void updateMarkers( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of polygonss on the map. + @ObjCSelector('updatePolygonsByAdding:changing:removing:') + void updatePolygons( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of polylines on the map. + @ObjCSelector('updatePolylinesByAdding:changing:removing:') + void updatePolylines( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of tile overlays on the map. + @ObjCSelector('updateTileOverlaysByAdding:changing:removing:') + void updateTileOverlays( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of ground overlays on the map. + @ObjCSelector('updateGroundOverlaysByAdding:changing:removing:') + void updateGroundOverlays( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Gets the screen coordinate for the given map location. + @ObjCSelector('screenCoordinatesForLatLng:') + PlatformPoint getScreenCoordinate(PlatformLatLng latLng); + + /// Gets the map location for the given screen coordinate. + @ObjCSelector('latLngForScreenCoordinate:') + PlatformLatLng getLatLng(PlatformPoint screenCoordinate); + + /// Gets the map region currently displayed on the map. + @ObjCSelector('visibleMapRegion') + PlatformLatLngBounds getVisibleRegion(); + + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + @ObjCSelector('moveCameraWithUpdate:') + void moveCamera(PlatformCameraUpdate cameraUpdate); + + /// Moves the camera according to [cameraUpdate], animating the update using a + /// duration in milliseconds if provided. + @ObjCSelector('animateCameraWithUpdate:duration:') + void animateCamera( + PlatformCameraUpdate cameraUpdate, + int? durationMilliseconds, + ); + + /// Gets the current map zoom level. + @ObjCSelector('currentZoomLevel') + double getZoomLevel(); + + /// Show the info window for the marker with the given ID. + @ObjCSelector('showInfoWindowForMarkerWithIdentifier:') + void showInfoWindow(String markerId); + + /// Hide the info window for the marker with the given ID. + @ObjCSelector('hideInfoWindowForMarkerWithIdentifier:') + void hideInfoWindow(String markerId); + + /// Returns true if the marker with the given ID is currently displaying its + /// info window. + @ObjCSelector('isShowingInfoWindowForMarkerWithIdentifier:') + bool isInfoWindowShown(String markerId); + + /// Sets the style to the given map style string, where an empty string + /// indicates that the style should be cleared. + /// + /// If there was an error setting the style, such as an invalid style string, + /// returns the error message. + @ObjCSelector('setStyle:') + String? setStyle(String style); + + /// Returns the error string from the last attempt to set the map style, if + /// any. + /// + /// This allows checking asynchronously for initial style failures, as there + /// is no way to return failures from map initialization. + @ObjCSelector('lastStyleError') + String? getLastStyleError(); + + /// Clears the cache of tiles previously requseted from the tile provider. + @ObjCSelector('clearTileCacheForOverlayWithIdentifier:') + void clearTileCache(String tileOverlayId); + + /// Takes a snapshot of the map and returns its image data. + Uint8List? takeSnapshot(); +} + +/// Interface for calls from the native SDK to Dart. +@FlutterApi() +abstract class MapsCallbackApi { + /// Called when the map camera starts moving. + @ObjCSelector('didStartCameraMoveWithCompletion') + void onCameraMoveStarted(); + + /// Called when the map camera moves. + @ObjCSelector('didMoveCameraToPosition:') + void onCameraMove(PlatformCameraPosition cameraPosition); + + /// Called when the map camera stops moving. + @ObjCSelector('didIdleCameraWithCompletion') + void onCameraIdle(); + + /// Called when the map, not a specifc map object, is tapped. + @ObjCSelector('didTapAtPosition:') + void onTap(PlatformLatLng position); + + /// Called when the map, not a specifc map object, is long pressed. + @ObjCSelector('didLongPressAtPosition:') + void onLongPress(PlatformLatLng position); + + /// Called when a marker is tapped. + @ObjCSelector('didTapMarkerWithIdentifier:') + void onMarkerTap(String markerId); + + /// Called when a marker drag starts. + @ObjCSelector('didStartDragForMarkerWithIdentifier:atPosition:') + void onMarkerDragStart(String markerId, PlatformLatLng position); + + /// Called when a marker drag updates. + @ObjCSelector('didDragMarkerWithIdentifier:atPosition:') + void onMarkerDrag(String markerId, PlatformLatLng position); + + /// Called when a marker drag ends. + @ObjCSelector('didEndDragForMarkerWithIdentifier:atPosition:') + void onMarkerDragEnd(String markerId, PlatformLatLng position); + + /// Called when a marker's info window is tapped. + @ObjCSelector('didTapInfoWindowOfMarkerWithIdentifier:') + void onInfoWindowTap(String markerId); + + /// Called when a circle is tapped. + @ObjCSelector('didTapCircleWithIdentifier:') + void onCircleTap(String circleId); + + /// Called when a marker cluster is tapped. + @ObjCSelector('didTapCluster:') + void onClusterTap(PlatformCluster cluster); + + /// Called when a polygon is tapped. + @ObjCSelector('didTapPolygonWithIdentifier:') + void onPolygonTap(String polygonId); + + /// Called when a polyline is tapped. + @ObjCSelector('didTapPolylineWithIdentifier:') + void onPolylineTap(String polylineId); + + /// Called when a ground overlay is tapped. + @ObjCSelector('didTapGroundOverlayWithIdentifier:') + void onGroundOverlayTap(String groundOverlayId); + + /// Called to get data for a map tile. + @async + @ObjCSelector('tileWithOverlayIdentifier:location:zoom:') + PlatformTile getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ); +} + +/// Dummy interface to force generation of the platform view creation params, +/// which are not used in any Pigeon calls, only the platform view creation +/// call made internally by Flutter. +@HostApi() +abstract class MapsPlatformViewApi { + // This is never actually called. + void createView(PlatformMapViewCreationParams? type); +} + +/// Inspector API only intended for use in integration tests. +@HostApi() +abstract class MapsInspectorApi { + bool areBuildingsEnabled(); + bool areRotateGesturesEnabled(); + bool areScrollGesturesEnabled(); + bool areTiltGesturesEnabled(); + bool areZoomGesturesEnabled(); + bool isCompassEnabled(); + bool isMyLocationButtonEnabled(); + bool isTrafficEnabled(); + @ObjCSelector('tileOverlayWithIdentifier:') + PlatformTileLayer? getTileOverlayInfo(String tileOverlayId); + @ObjCSelector('groundOverlayWithIdentifier:') + PlatformGroundOverlay? getGroundOverlayInfo(String groundOverlayId); + @ObjCSelector('heatmapWithIdentifier:') + PlatformHeatmap? getHeatmapInfo(String heatmapId); + @ObjCSelector('zoomRange') + PlatformZoomRange getZoomRange(); + @ObjCSelector('clustersWithIdentifier:') + List getClusters(String clusterManagerId); + @ObjCSelector('cameraPosition') + PlatformCameraPosition getCameraPosition(); +} 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 new file mode 100644 index 000000000000..4dee18297412 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.dart @@ -0,0 +1,1357 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +import 'dart:async'; + +import 'package:async/async.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'google_maps_flutter_ios_test.mocks.dart'; +import 'package_specific_test_import.dart'; + +@GenerateNiceMocks(>[MockSpec()]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + (GoogleMapsFlutterIOS, MockMapsApi) setUpMockMap({required int mapId}) { + final api = MockMapsApi(); + final maps = GoogleMapsFlutterIOS(apiProvider: (_) => api); + maps.ensureApiInitialized(mapId); + return (maps, api); + } + + test('registers instance', () async { + GoogleMapsFlutterIOS.registerWith(); + expect(GoogleMapsFlutterPlatform.instance, isA()); + }); + + test('init calls waitForMap', () async { + final api = MockMapsApi(); + final maps = GoogleMapsFlutterIOS(apiProvider: (_) => api); + + await maps.init(1); + + verify(api.waitForMap()); + }); + + test('getScreenCoordinate converts and passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Arbitrary values that are all different from each other. + const latLng = LatLng(10, 20); + const expectedCoord = ScreenCoordinate(x: 30, y: 40); + when(api.getScreenCoordinate(any)).thenAnswer( + (_) async => PlatformPoint( + x: expectedCoord.x.toDouble(), + y: expectedCoord.y.toDouble(), + ), + ); + + final ScreenCoordinate coord = await maps.getScreenCoordinate( + latLng, + mapId: mapId, + ); + expect(coord, expectedCoord); + final VerificationResult verification = verify( + api.getScreenCoordinate(captureAny), + ); + final passedLatLng = verification.captured[0] as PlatformLatLng; + expect(passedLatLng.latitude, latLng.latitude); + expect(passedLatLng.longitude, latLng.longitude); + }); + + test('getLatLng converts and passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Arbitrary values that are all different from each other. + const expectedLatLng = LatLng(10, 20); + const coord = ScreenCoordinate(x: 30, y: 40); + when(api.getLatLng(any)).thenAnswer( + (_) async => PlatformLatLng( + latitude: expectedLatLng.latitude, + longitude: expectedLatLng.longitude, + ), + ); + + final LatLng latLng = await maps.getLatLng(coord, mapId: mapId); + expect(latLng, expectedLatLng); + final VerificationResult verification = verify(api.getLatLng(captureAny)); + final passedCoord = verification.captured[0] as PlatformPoint; + expect(passedCoord.x, coord.x); + expect(passedCoord.y, coord.y); + }); + + test('getVisibleRegion converts and passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Arbitrary values that are all different from each other. + final expectedBounds = LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ); + when(api.getVisibleRegion()).thenAnswer( + (_) async => PlatformLatLngBounds( + southwest: PlatformLatLng( + latitude: expectedBounds.southwest.latitude, + longitude: expectedBounds.southwest.longitude, + ), + northeast: PlatformLatLng( + latitude: expectedBounds.northeast.latitude, + longitude: expectedBounds.northeast.longitude, + ), + ), + ); + + final LatLngBounds bounds = await maps.getVisibleRegion(mapId: mapId); + expect(bounds, expectedBounds); + }); + + test('moveCamera calls through with expected scrollBy', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final scroll = passedUpdate.cameraUpdate as PlatformCameraUpdateScrollBy; + update as CameraUpdateScrollBy; + expect(scroll.dx, update.dx); + expect(scroll.dy, update.dy); + }); + + test('animateCamera calls through with expected scrollBy', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.animateCamera(update, mapId: mapId); + + final VerificationResult verification = verify( + api.animateCamera(captureAny, captureAny), + ); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final scroll = passedUpdate.cameraUpdate as PlatformCameraUpdateScrollBy; + update as CameraUpdateScrollBy; + expect(scroll.dx, update.dx); + expect(scroll.dy, update.dy); + expect(verification.captured[1], isNull); + }); + + test('animateCameraWithConfiguration calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + const configuration = CameraUpdateAnimationConfiguration( + duration: Duration(seconds: 1), + ); + expect(configuration.duration?.inSeconds, 1); + await maps.animateCameraWithConfiguration( + update, + configuration, + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.animateCamera(captureAny, captureAny), + ); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final scroll = passedUpdate.cameraUpdate as PlatformCameraUpdateScrollBy; + update as CameraUpdateScrollBy; + expect(scroll.dx, update.dx); + expect(scroll.dy, update.dy); + + final passedDuration = verification.captured[1] as int?; + expect(passedDuration, configuration.duration?.inMilliseconds); + }); + + test('getZoomLevel passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const expectedZoom = 4.2; + when(api.getZoomLevel()).thenAnswer((_) async => expectedZoom); + + final double zoom = await maps.getZoomLevel(mapId: mapId); + expect(zoom, expectedZoom); + }); + + test('showInfoWindow calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const markedId = 'a_marker'; + await maps.showMarkerInfoWindow(const MarkerId(markedId), mapId: mapId); + + verify(api.showInfoWindow(markedId)); + }); + + test('hideInfoWindow calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const markedId = 'a_marker'; + await maps.hideMarkerInfoWindow(const MarkerId(markedId), mapId: mapId); + + verify(api.hideInfoWindow(markedId)); + }); + + test('isInfoWindowShown calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const markedId = 'a_marker'; + when(api.isInfoWindowShown(markedId)).thenAnswer((_) async => true); + + expect( + await maps.isMarkerInfoWindowShown( + const MarkerId(markedId), + mapId: mapId, + ), + true, + ); + }); + + test('takeSnapshot calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final fakeSnapshot = Uint8List(10); + when(api.takeSnapshot()).thenAnswer((_) async => fakeSnapshot); + + expect(await maps.takeSnapshot(mapId: mapId), fakeSnapshot); + }); + + test('clearTileCache calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const tileOverlayId = 'overlay'; + await maps.clearTileCache(const TileOverlayId(tileOverlayId), mapId: mapId); + + verify(api.clearTileCache(tileOverlayId)); + }); + + test('updateMapConfiguration passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Set some arbitrary options. + final cameraBounds = CameraTargetBounds( + LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + ); + final config = MapConfiguration( + compassEnabled: true, + mapType: MapType.terrain, + cameraTargetBounds: cameraBounds, + ); + await maps.updateMapConfiguration(config, mapId: mapId); + + final VerificationResult verification = verify( + api.updateMapConfiguration(captureAny), + ); + final passedConfig = verification.captured[0] as PlatformMapConfiguration; + // Each set option should be present. + expect(passedConfig.compassEnabled, true); + expect(passedConfig.mapType, PlatformMapType.terrain); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.latitude, + cameraBounds.bounds?.northeast.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.longitude, + cameraBounds.bounds?.northeast.longitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.latitude, + cameraBounds.bounds?.southwest.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.longitude, + cameraBounds.bounds?.southwest.longitude, + ); + // Spot-check that unset options are not be present. + expect(passedConfig.myLocationEnabled, isNull); + expect(passedConfig.minMaxZoomPreference, isNull); + expect(passedConfig.padding, isNull); + }); + + test('updateMapOptions passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Set some arbitrary options. + final cameraBounds = CameraTargetBounds( + LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + ); + final config = { + 'compassEnabled': true, + 'mapType': MapType.terrain.index, + 'cameraTargetBounds': cameraBounds.toJson(), + }; + await maps.updateMapOptions(config, mapId: mapId); + + final VerificationResult verification = verify( + api.updateMapConfiguration(captureAny), + ); + final passedConfig = verification.captured[0] as PlatformMapConfiguration; + // Each set option should be present. + expect(passedConfig.compassEnabled, true); + expect(passedConfig.mapType, PlatformMapType.terrain); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.latitude, + cameraBounds.bounds?.northeast.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.longitude, + cameraBounds.bounds?.northeast.longitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.latitude, + cameraBounds.bounds?.southwest.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.longitude, + cameraBounds.bounds?.southwest.longitude, + ); + // Spot-check that unset options are not be present. + expect(passedConfig.myLocationEnabled, isNull); + expect(passedConfig.minMaxZoomPreference, isNull); + expect(passedConfig.padding, isNull); + }); + + test('updateCircles passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Circle(circleId: CircleId('1')); + const object2old = Circle(circleId: CircleId('2')); + final Circle object2new = object2old.copyWith(radiusParam: 42); + const object3 = Circle(circleId: CircleId('3')); + await maps.updateCircles( + CircleUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateCircles(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.circleId.value); + // Object two should be changed. + { + expect(toChange.length, 1); + final PlatformCircle firstChanged = toChange.first; + expect(firstChanged.consumeTapEvents, object2new.consumeTapEvents); + _expectColorsEqual(firstChanged.fillColor, object2new.fillColor); + _expectColorsEqual(firstChanged.strokeColor, object2new.strokeColor); + expect(firstChanged.visible, object2new.visible); + expect(firstChanged.strokeWidth, object2new.strokeWidth); + expect(firstChanged.zIndex, object2new.zIndex.toDouble()); + expect(firstChanged.center.latitude, object2new.center.latitude); + expect(firstChanged.center.longitude, object2new.center.longitude); + expect(firstChanged.radius, object2new.radius); + expect(firstChanged.circleId, object2new.circleId.value); + } + // Object 3 should be added. + { + expect(toAdd.length, 1); + final PlatformCircle firstAdded = toAdd.first; + expect(firstAdded.consumeTapEvents, object3.consumeTapEvents); + _expectColorsEqual(firstAdded.fillColor, object3.fillColor); + _expectColorsEqual(firstAdded.strokeColor, object3.strokeColor); + expect(firstAdded.visible, object3.visible); + expect(firstAdded.strokeWidth, object3.strokeWidth); + expect(firstAdded.zIndex, object3.zIndex.toDouble()); + expect(firstAdded.center.latitude, object3.center.latitude); + expect(firstAdded.center.longitude, object3.center.longitude); + expect(firstAdded.radius, object3.radius); + expect(firstAdded.circleId, object3.circleId.value); + } + }); + + test('updateClusterManagers passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = ClusterManager(clusterManagerId: ClusterManagerId('1')); + const object3 = ClusterManager(clusterManagerId: ClusterManagerId('3')); + await maps.updateClusterManagers( + ClusterManagerUpdates.from( + {object1}, + {object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateClusterManagers(captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toRemove = verification.captured[1] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.clusterManagerId.value); + // Unlike other map object types, changes are not possible for cluster + // managers, since they have no non-ID properties. + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first.identifier, object3.clusterManagerId.value); + }); + + test('updateMarkers passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Marker(markerId: MarkerId('1')); + const object2old = Marker(markerId: MarkerId('2')); + final Marker object2new = object2old.copyWith(rotationParam: 42); + const object3 = Marker(markerId: MarkerId('3')); + await maps.updateMarkers( + MarkerUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateMarkers(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.markerId.value); + // Object two should be changed. + { + expect(toChange.length, 1); + final PlatformMarker firstChanged = toChange.first; + expect(firstChanged.alpha, object2new.alpha); + expect(firstChanged.anchor.x, object2new.anchor.dx); + expect(firstChanged.anchor.y, object2new.anchor.dy); + expect(firstChanged.consumeTapEvents, object2new.consumeTapEvents); + expect(firstChanged.draggable, object2new.draggable); + expect(firstChanged.flat, object2new.flat); + expect( + firstChanged.icon.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object2new.icon, + ).bitmap.runtimeType, + ); + expect(firstChanged.infoWindow.title, object2new.infoWindow.title); + expect(firstChanged.infoWindow.snippet, object2new.infoWindow.snippet); + expect(firstChanged.infoWindow.anchor.x, object2new.infoWindow.anchor.dx); + expect(firstChanged.infoWindow.anchor.y, object2new.infoWindow.anchor.dy); + expect(firstChanged.position.latitude, object2new.position.latitude); + expect(firstChanged.position.longitude, object2new.position.longitude); + expect(firstChanged.rotation, object2new.rotation); + expect(firstChanged.visible, object2new.visible); + expect(firstChanged.zIndex, object2new.zIndexInt); + expect(firstChanged.markerId, object2new.markerId.value); + expect(firstChanged.clusterManagerId, object2new.clusterManagerId?.value); + } + // Object 3 should be added. + { + expect(toAdd.length, 1); + final PlatformMarker firstAdded = toAdd.first; + expect(firstAdded.alpha, object3.alpha); + expect(firstAdded.anchor.x, object3.anchor.dx); + expect(firstAdded.anchor.y, object3.anchor.dy); + expect(firstAdded.consumeTapEvents, object3.consumeTapEvents); + expect(firstAdded.draggable, object3.draggable); + expect(firstAdded.flat, object3.flat); + expect( + firstAdded.icon.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object3.icon, + ).bitmap.runtimeType, + ); + expect(firstAdded.infoWindow.title, object3.infoWindow.title); + expect(firstAdded.infoWindow.snippet, object3.infoWindow.snippet); + expect(firstAdded.infoWindow.anchor.x, object3.infoWindow.anchor.dx); + expect(firstAdded.infoWindow.anchor.y, object3.infoWindow.anchor.dy); + expect(firstAdded.position.latitude, object3.position.latitude); + expect(firstAdded.position.longitude, object3.position.longitude); + expect(firstAdded.rotation, object3.rotation); + expect(firstAdded.visible, object3.visible); + expect(firstAdded.zIndex, object3.zIndexInt); + expect(firstAdded.markerId, object3.markerId.value); + expect(firstAdded.clusterManagerId, object3.clusterManagerId?.value); + } + }); + + test('updatePolygons passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Polygon(polygonId: PolygonId('1')); + const object2old = Polygon(polygonId: PolygonId('2')); + final Polygon object2new = object2old.copyWith(strokeWidthParam: 42); + const object3 = Polygon(polygonId: PolygonId('3')); + await maps.updatePolygons( + PolygonUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updatePolygons(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polygonId.value); + void expectPolygon(PlatformPolygon actual, Polygon expected) { + expect(actual.polygonId, expected.polygonId.value); + expect(actual.consumesTapEvents, expected.consumeTapEvents); + _expectColorsEqual(actual.fillColor, expected.fillColor); + expect(actual.geodesic, expected.geodesic); + expect(actual.points.length, expected.points.length); + for (final (int i, PlatformLatLng? point) in actual.points.indexed) { + expect(point?.latitude, expected.points[i].latitude); + expect(point?.longitude, expected.points[i].longitude); + } + expect(actual.holes.length, expected.holes.length); + for (final (int i, List? hole) in actual.holes.indexed) { + final List expectedHole = expected.holes[i]; + for (final (int j, PlatformLatLng? point) in hole!.indexed) { + expect(point?.latitude, expectedHole[j].latitude); + expect(point?.longitude, expectedHole[j].longitude); + } + } + expect(actual.visible, expected.visible); + _expectColorsEqual(actual.strokeColor, expected.strokeColor); + expect(actual.strokeWidth, expected.strokeWidth); + expect(actual.zIndex, expected.zIndex); + } + + // Object two should be changed. + expect(toChange.length, 1); + expectPolygon(toChange.first, object2new); + // Object 3 should be added. + expect(toAdd.length, 1); + expectPolygon(toAdd.first, object3); + }); + + test('updatePolylines passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Polyline(polylineId: PolylineId('1')); + const object2old = Polyline(polylineId: PolylineId('2')); + final Polyline object2new = object2old.copyWith( + widthParam: 42, + startCapParam: Cap.squareCap, + endCapParam: Cap.buttCap, + ); + final Cap customCap = Cap.customCapFromBitmap( + BitmapDescriptor.defaultMarker, + refWidth: 15, + ); + final object3 = Polyline( + polylineId: const PolylineId('3'), + startCap: customCap, + endCap: Cap.roundCap, + ); + await maps.updatePolylines( + PolylineUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updatePolylines(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + void expectPolyline(PlatformPolyline actual, Polyline expected) { + expect(actual.polylineId, expected.polylineId.value); + expect(actual.consumesTapEvents, expected.consumeTapEvents); + _expectColorsEqual(actual.color, expected.color); + expect(actual.geodesic, expected.geodesic); + expect( + actual.jointType, + platformJointTypeFromJointType(expected.jointType), + ); + expect(actual.visible, expected.visible); + expect(actual.width, expected.width); + expect(actual.zIndex, expected.zIndex); + expect(actual.points.length, expected.points.length); + for (final (int i, PlatformLatLng? point) in actual.points.indexed) { + expect(point?.latitude, actual.points[i].latitude); + expect(point?.longitude, actual.points[i].longitude); + } + expect(actual.patterns.length, expected.patterns.length); + for (final (int i, PlatformPatternItem? pattern) + in actual.patterns.indexed) { + expect( + pattern?.encode(), + platformPatternItemFromPatternItem(expected.patterns[i]).encode(), + ); + } + } + + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polylineId.value); + // Object two should be changed. + expect(toChange.length, 1); + expectPolyline(toChange.first, object2new); + // Object 3 should be added. + expect(toAdd.length, 1); + expectPolyline(toAdd.first, object3); + }); + + test('updateTileOverlays passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = TileOverlay(tileOverlayId: TileOverlayId('1')); + const object2old = TileOverlay(tileOverlayId: TileOverlayId('2')); + final TileOverlay object2new = object2old.copyWith(zIndexParam: 42); + const object3 = TileOverlay(tileOverlayId: TileOverlayId('3')); + // Pre-set the initial state, since this update method doesn't take the old + // state. + await maps.updateTileOverlays( + newTileOverlays: {object1, object2old}, + mapId: mapId, + ); + clearInteractions(api); + + await maps.updateTileOverlays( + newTileOverlays: {object2new, object3}, + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateTileOverlays(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + void expectTileOverlay(PlatformTileOverlay actual, TileOverlay expected) { + expect(actual.tileOverlayId, expected.tileOverlayId.value); + expect(actual.fadeIn, expected.fadeIn); + expect(actual.transparency, expected.transparency); + expect(actual.zIndex, expected.zIndex); + expect(actual.visible, expected.visible); + expect(actual.tileSize, expected.tileSize); + } + + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.tileOverlayId.value); + // Object two should be changed. + expect(toChange.length, 1); + expectTileOverlay(toChange.first, object2new); + // Object 3 should be added. + expect(toAdd.length, 1); + expectTileOverlay(toAdd.first, object3); + }); + + test('updateGroundOverlays passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final image = AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ); + + final object1 = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('1'), + bounds: LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + image: image, + ); + final object2old = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('2'), + bounds: LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + image: image, + ); + final GroundOverlay object2new = object2old.copyWith( + visibleParam: false, + bearingParam: 10, + clickableParam: false, + transparencyParam: 0.5, + zIndexParam: 100, + ); + final object3 = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('3'), + position: const LatLng(10, 20), + width: 100, + image: image, + zoomLevel: 14.0, + ); + await maps.updateGroundOverlays( + GroundOverlayUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateGroundOverlays(captureAny, captureAny, captureAny), + ); + + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.groundOverlayId.value); + // Object two should be changed. + { + expect(toChange.length, 1); + final PlatformGroundOverlay firstChanged = toChange.first; + expect(firstChanged.anchor?.x, object2new.anchor?.dx); + expect(firstChanged.anchor?.y, object2new.anchor?.dy); + expect(firstChanged.bearing, object2new.bearing); + expect( + firstChanged.bounds?.northeast.latitude, + object2new.bounds?.northeast.latitude, + ); + expect( + firstChanged.bounds?.northeast.longitude, + object2new.bounds?.northeast.longitude, + ); + expect( + firstChanged.bounds?.southwest.latitude, + object2new.bounds?.southwest.latitude, + ); + expect( + firstChanged.bounds?.southwest.longitude, + object2new.bounds?.southwest.longitude, + ); + expect(firstChanged.visible, object2new.visible); + expect(firstChanged.clickable, object2new.clickable); + expect(firstChanged.zIndex, object2new.zIndex); + expect(firstChanged.position?.latitude, object2new.position?.latitude); + expect(firstChanged.position?.longitude, object2new.position?.longitude); + expect(firstChanged.zoomLevel, object2new.zoomLevel); + expect(firstChanged.transparency, object2new.transparency); + expect( + firstChanged.image.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object2new.image, + ).bitmap.runtimeType, + ); + } + // Object three should be added. + { + expect(toAdd.length, 1); + final PlatformGroundOverlay firstAdded = toAdd.first; + expect(firstAdded.anchor?.x, object3.anchor?.dx); + expect(firstAdded.anchor?.y, object3.anchor?.dy); + expect(firstAdded.bearing, object3.bearing); + expect( + firstAdded.bounds?.northeast.latitude, + object3.bounds?.northeast.latitude, + ); + expect( + firstAdded.bounds?.northeast.longitude, + object3.bounds?.northeast.longitude, + ); + expect( + firstAdded.bounds?.southwest.latitude, + object3.bounds?.southwest.latitude, + ); + expect( + firstAdded.bounds?.southwest.longitude, + object3.bounds?.southwest.longitude, + ); + expect(firstAdded.visible, object3.visible); + expect(firstAdded.clickable, object3.clickable); + expect(firstAdded.zIndex, object3.zIndex); + expect(firstAdded.position?.latitude, object3.position?.latitude); + expect(firstAdded.position?.longitude, object3.position?.longitude); + expect(firstAdded.zoomLevel, object3.zoomLevel); + expect(firstAdded.transparency, object3.transparency); + expect( + firstAdded.image.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object3.image, + ).bitmap.runtimeType, + ); + } + }); + + test( + 'updateGroundOverlays throws assertion error on unsupported ground overlays', + () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final image = AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ); + + final object3 = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('1'), + position: const LatLng(10, 20), + // Assert should be thrown because zoomLevel is not set for position-based + // ground overlay on iOS. + // ignore: avoid_redundant_argument_values + zoomLevel: null, + image: image, + ); + + expect( + () async => maps.updateGroundOverlays( + GroundOverlayUpdates.from(const {}, { + object3, + }), + mapId: mapId, + ), + throwsAssertionError, + ); + }, + ); + + test('markers send drag event to correct streams', () async { + const mapId = 1; + const dragStartId = 'drag-start-marker'; + const dragId = 'drag-marker'; + const dragEndId = 'drag-end-marker'; + final fakePosition = PlatformLatLng(latitude: 1.0, longitude: 1.0); + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final markerDragStartStream = StreamQueue( + maps.onMarkerDragStart(mapId: mapId), + ); + final markerDragStream = StreamQueue( + maps.onMarkerDrag(mapId: mapId), + ); + final markerDragEndStream = StreamQueue( + maps.onMarkerDragEnd(mapId: mapId), + ); + + // Simulate messages from the native side. + callbackHandler.onMarkerDragStart(dragStartId, fakePosition); + callbackHandler.onMarkerDrag(dragId, fakePosition); + callbackHandler.onMarkerDragEnd(dragEndId, fakePosition); + + expect((await markerDragStartStream.next).value.value, equals(dragStartId)); + expect((await markerDragStream.next).value.value, equals(dragId)); + expect((await markerDragEndStream.next).value.value, equals(dragEndId)); + }); + + test('markers send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue(maps.onMarkerTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onMarkerTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('circles send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue(maps.onCircleTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onCircleTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('clusters send tap events to correct stream', () async { + const mapId = 1; + const managerId = 'manager-id'; + final fakePosition = PlatformLatLng(latitude: 10, longitude: 20); + final fakeBounds = PlatformLatLngBounds( + southwest: PlatformLatLng(latitude: 30, longitude: 40), + northeast: PlatformLatLng(latitude: 50, longitude: 60), + ); + const markerIds = ['marker-1', 'marker-2']; + final cluster = PlatformCluster( + clusterManagerId: managerId, + position: fakePosition, + bounds: fakeBounds, + markerIds: markerIds, + ); + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onClusterTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onClusterTap(cluster); + + final Cluster eventValue = (await stream.next).value; + expect(eventValue.clusterManagerId.value, managerId); + expect(eventValue.position.latitude, fakePosition.latitude); + expect(eventValue.position.longitude, fakePosition.longitude); + expect(eventValue.bounds.southwest.latitude, fakeBounds.southwest.latitude); + expect( + eventValue.bounds.southwest.longitude, + fakeBounds.southwest.longitude, + ); + expect(eventValue.bounds.northeast.latitude, fakeBounds.northeast.latitude); + expect( + eventValue.bounds.northeast.longitude, + fakeBounds.northeast.longitude, + ); + expect(eventValue.markerIds.length, markerIds.length); + expect(eventValue.markerIds.first.value, markerIds.first); + }); + + test('polygons send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onPolygonTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onPolygonTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('polylines send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onPolylineTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onPolylineTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('ground overlays send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onGroundOverlayTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onGroundOverlayTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('moveCamera calls through with expected newCameraPosition', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const latLng = LatLng(10.0, 20.0); + const position = CameraPosition(target: latLng); + final CameraUpdate update = CameraUpdate.newCameraPosition(position); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewCameraPosition; + update as CameraUpdateNewCameraPosition; + expect( + typedUpdate.cameraPosition.target.latitude, + update.cameraPosition.target.latitude, + ); + expect( + typedUpdate.cameraPosition.target.longitude, + update.cameraPosition.target.longitude, + ); + }); + + test('moveCamera calls through with expected newLatLng', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const latLng = LatLng(10.0, 20.0); + final CameraUpdate update = CameraUpdate.newLatLng(latLng); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewLatLng; + update as CameraUpdateNewLatLng; + expect(typedUpdate.latLng.latitude, update.latLng.latitude); + expect(typedUpdate.latLng.longitude, update.latLng.longitude); + }); + + test('moveCamera calls through with expected newLatLngBounds', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final latLng = LatLngBounds( + northeast: const LatLng(10.0, 20.0), + southwest: const LatLng(9.0, 21.0), + ); + final CameraUpdate update = CameraUpdate.newLatLngBounds(latLng, 1.0); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewLatLngBounds; + update as CameraUpdateNewLatLngBounds; + expect( + typedUpdate.bounds.northeast.latitude, + update.bounds.northeast.latitude, + ); + expect( + typedUpdate.bounds.northeast.longitude, + update.bounds.northeast.longitude, + ); + expect( + typedUpdate.bounds.southwest.latitude, + update.bounds.southwest.latitude, + ); + expect( + typedUpdate.bounds.southwest.longitude, + update.bounds.southwest.longitude, + ); + expect(typedUpdate.padding, update.padding); + }); + + test('moveCamera calls through with expected newLatLngZoom', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const latLng = LatLng(10.0, 20.0); + final CameraUpdate update = CameraUpdate.newLatLngZoom(latLng, 2.0); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewLatLngZoom; + update as CameraUpdateNewLatLngZoom; + expect(typedUpdate.latLng.latitude, update.latLng.latitude); + expect(typedUpdate.latLng.longitude, update.latLng.longitude); + expect(typedUpdate.zoom, update.zoom); + }); + + test('moveCamera calls through with expected zoomBy', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const focus = Offset(10.0, 20.0); + final CameraUpdate update = CameraUpdate.zoomBy(2.0, focus); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoomBy; + update as CameraUpdateZoomBy; + expect(typedUpdate.focus?.x, update.focus?.dx); + expect(typedUpdate.focus?.y, update.focus?.dy); + expect(typedUpdate.amount, update.amount); + }); + + test('moveCamera calls through with expected zoomTo', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.zoomTo(2.0); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoomTo; + update as CameraUpdateZoomTo; + expect(typedUpdate.zoom, update.zoom); + }); + + test('moveCamera calls through with expected zoomIn', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.zoomIn(); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoom; + expect(typedUpdate.out, false); + }); + + test('moveCamera calls through with expected zoomOut', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.zoomOut(); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoom; + expect(typedUpdate.out, true); + }); + + test('MapBitmapScaling to PlatformMapBitmapScaling', () { + expect( + GoogleMapsFlutterIOS.platformMapBitmapScalingFromScaling( + MapBitmapScaling.auto, + ), + PlatformMapBitmapScaling.auto, + ); + expect( + GoogleMapsFlutterIOS.platformMapBitmapScalingFromScaling( + MapBitmapScaling.none, + ), + PlatformMapBitmapScaling.none, + ); + }); + + test('DefaultMarker bitmap to PlatformBitmap', () { + final BitmapDescriptor bitmap = BitmapDescriptor.defaultMarkerWithHue(10.0); + final PlatformBitmap platformBitmap = + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor(bitmap); + expect(platformBitmap.bitmap, isA()); + final typedBitmap = platformBitmap.bitmap as PlatformBitmapDefaultMarker; + expect(typedBitmap.hue, 10.0); + }); + + test('BytesMapBitmap bitmap to PlatformBitmap', () { + final data = Uint8List.fromList([1, 2, 3, 4]); + final BytesMapBitmap bitmap = BitmapDescriptor.bytes( + data, + imagePixelRatio: 2.0, + width: 100.0, + height: 200.0, + ); + final PlatformBitmap platformBitmap = + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor(bitmap); + expect(platformBitmap.bitmap, isA()); + final typedBitmap = platformBitmap.bitmap as PlatformBitmapBytesMap; + expect(typedBitmap.byteData, data); + expect(typedBitmap.bitmapScaling, PlatformMapBitmapScaling.auto); + expect(typedBitmap.imagePixelRatio, 2.0); + expect(typedBitmap.width, 100.0); + expect(typedBitmap.height, 200.0); + }); + + test('AssetMapBitmap bitmap to PlatformBitmap', () { + const assetName = 'fake_asset_name'; + final bitmap = AssetMapBitmap( + assetName, + imagePixelRatio: 2.0, + width: 100.0, + height: 200.0, + ); + final PlatformBitmap platformBitmap = + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor(bitmap); + expect(platformBitmap.bitmap, isA()); + final typedBitmap = platformBitmap.bitmap as PlatformBitmapAssetMap; + expect(typedBitmap.assetName, assetName); + expect(typedBitmap.bitmapScaling, PlatformMapBitmapScaling.auto); + expect(typedBitmap.imagePixelRatio, 2.0); + expect(typedBitmap.width, 100.0); + expect(typedBitmap.height, 200.0); + }); + + testWidgets('mapId is passed', (WidgetTester tester) async { + const cloudMapId = '000000000000000'; // Dummy map ID. + final passedCloudMapIdCompleter = Completer(); + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform_views, ( + MethodCall methodCall, + ) { + if (methodCall.method == 'create') { + final args = Map.from( + methodCall.arguments as Map, + ); + if (args.containsKey('params')) { + final paramsUint8List = args['params'] as Uint8List; + final byteData = ByteData.sublistView(paramsUint8List); + final creationParams = + MapsApi.pigeonChannelCodec.decodeMessage(byteData) + as PlatformMapViewCreationParams?; + if (creationParams != null) { + final String? passedMapId = + creationParams.mapConfiguration.mapId; + if (passedMapId != null) { + passedCloudMapIdCompleter.complete(passedMapId); + } + } + } + } + return null; + }); + + final maps = GoogleMapsFlutterIOS(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: maps.buildViewWithConfiguration( + 1, + (int id) {}, + widgetConfiguration: const MapWidgetConfiguration( + initialCameraPosition: CameraPosition( + target: LatLng(0, 0), + zoom: 1, + ), + textDirection: TextDirection.ltr, + ), + mapConfiguration: const MapConfiguration(mapId: cloudMapId), + ), + ), + ); + + expect( + await passedCloudMapIdCompleter.future, + cloudMapId, + reason: 'Should pass mapId on PlatformView creation message', + ); + }); +} + +void _expectColorsEqual(PlatformColor actual, Color expected) { + expect(actual.red, expected.r); + expect(actual.green, expected.g); + expect(actual.blue, expected.b); + expect(actual.alpha, expected.a); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.mocks.dart new file mode 100644 index 000000000000..d7b768353feb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/test/google_maps_flutter_ios_test.mocks.dart @@ -0,0 +1,351 @@ +// Mocks generated by Mockito 5.4.5 from annotations +// in google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; +import 'dart:typed_data' as _i5; + +import 'package:google_maps_flutter_ios/src/messages.g.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i3; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakePlatformPoint_0 extends _i1.SmartFake implements _i2.PlatformPoint { + _FakePlatformPoint_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakePlatformLatLng_1 extends _i1.SmartFake + implements _i2.PlatformLatLng { + _FakePlatformLatLng_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakePlatformLatLngBounds_2 extends _i1.SmartFake + implements _i2.PlatformLatLngBounds { + _FakePlatformLatLngBounds_2(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [MapsApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMapsApi extends _i1.Mock implements _i2.MapsApi { + @override + String get pigeonVar_messageChannelSuffix => + (super.noSuchMethod( + Invocation.getter(#pigeonVar_messageChannelSuffix), + returnValue: _i3.dummyValue( + this, + Invocation.getter(#pigeonVar_messageChannelSuffix), + ), + returnValueForMissingStub: _i3.dummyValue( + this, + Invocation.getter(#pigeonVar_messageChannelSuffix), + ), + ) + as String); + + @override + _i4.Future waitForMap() => + (super.noSuchMethod( + Invocation.method(#waitForMap, []), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateMapConfiguration( + _i2.PlatformMapConfiguration? configuration, + ) => + (super.noSuchMethod( + Invocation.method(#updateMapConfiguration, [configuration]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateCircles( + List<_i2.PlatformCircle>? toAdd, + List<_i2.PlatformCircle>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateCircles, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateHeatmaps( + List<_i2.PlatformHeatmap>? toAdd, + List<_i2.PlatformHeatmap>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateHeatmaps, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateClusterManagers( + List<_i2.PlatformClusterManager>? toAdd, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateClusterManagers, [toAdd, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateMarkers( + List<_i2.PlatformMarker>? toAdd, + List<_i2.PlatformMarker>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateMarkers, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updatePolygons( + List<_i2.PlatformPolygon>? toAdd, + List<_i2.PlatformPolygon>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updatePolygons, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updatePolylines( + List<_i2.PlatformPolyline>? toAdd, + List<_i2.PlatformPolyline>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updatePolylines, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateTileOverlays( + List<_i2.PlatformTileOverlay>? toAdd, + List<_i2.PlatformTileOverlay>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateTileOverlays, [ + toAdd, + toChange, + idsToRemove, + ]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateGroundOverlays( + List<_i2.PlatformGroundOverlay>? toAdd, + List<_i2.PlatformGroundOverlay>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateGroundOverlays, [ + toAdd, + toChange, + idsToRemove, + ]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future<_i2.PlatformPoint> getScreenCoordinate( + _i2.PlatformLatLng? latLng, + ) => + (super.noSuchMethod( + Invocation.method(#getScreenCoordinate, [latLng]), + returnValue: _i4.Future<_i2.PlatformPoint>.value( + _FakePlatformPoint_0( + this, + Invocation.method(#getScreenCoordinate, [latLng]), + ), + ), + returnValueForMissingStub: _i4.Future<_i2.PlatformPoint>.value( + _FakePlatformPoint_0( + this, + Invocation.method(#getScreenCoordinate, [latLng]), + ), + ), + ) + as _i4.Future<_i2.PlatformPoint>); + + @override + _i4.Future<_i2.PlatformLatLng> getLatLng( + _i2.PlatformPoint? screenCoordinate, + ) => + (super.noSuchMethod( + Invocation.method(#getLatLng, [screenCoordinate]), + returnValue: _i4.Future<_i2.PlatformLatLng>.value( + _FakePlatformLatLng_1( + this, + Invocation.method(#getLatLng, [screenCoordinate]), + ), + ), + returnValueForMissingStub: _i4.Future<_i2.PlatformLatLng>.value( + _FakePlatformLatLng_1( + this, + Invocation.method(#getLatLng, [screenCoordinate]), + ), + ), + ) + as _i4.Future<_i2.PlatformLatLng>); + + @override + _i4.Future<_i2.PlatformLatLngBounds> getVisibleRegion() => + (super.noSuchMethod( + Invocation.method(#getVisibleRegion, []), + returnValue: _i4.Future<_i2.PlatformLatLngBounds>.value( + _FakePlatformLatLngBounds_2( + this, + Invocation.method(#getVisibleRegion, []), + ), + ), + returnValueForMissingStub: + _i4.Future<_i2.PlatformLatLngBounds>.value( + _FakePlatformLatLngBounds_2( + this, + Invocation.method(#getVisibleRegion, []), + ), + ), + ) + as _i4.Future<_i2.PlatformLatLngBounds>); + + @override + _i4.Future moveCamera(_i2.PlatformCameraUpdate? cameraUpdate) => + (super.noSuchMethod( + Invocation.method(#moveCamera, [cameraUpdate]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future animateCamera( + _i2.PlatformCameraUpdate? cameraUpdate, + int? durationMilliseconds, + ) => + (super.noSuchMethod( + Invocation.method(#animateCamera, [ + cameraUpdate, + durationMilliseconds, + ]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future getZoomLevel() => + (super.noSuchMethod( + Invocation.method(#getZoomLevel, []), + returnValue: _i4.Future.value(0.0), + returnValueForMissingStub: _i4.Future.value(0.0), + ) + as _i4.Future); + + @override + _i4.Future showInfoWindow(String? markerId) => + (super.noSuchMethod( + Invocation.method(#showInfoWindow, [markerId]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future hideInfoWindow(String? markerId) => + (super.noSuchMethod( + Invocation.method(#hideInfoWindow, [markerId]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future isInfoWindowShown(String? markerId) => + (super.noSuchMethod( + Invocation.method(#isInfoWindowShown, [markerId]), + returnValue: _i4.Future.value(false), + returnValueForMissingStub: _i4.Future.value(false), + ) + as _i4.Future); + + @override + _i4.Future setStyle(String? style) => + (super.noSuchMethod( + Invocation.method(#setStyle, [style]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future getLastStyleError() => + (super.noSuchMethod( + Invocation.method(#getLastStyleError, []), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearTileCache(String? tileOverlayId) => + (super.noSuchMethod( + Invocation.method(#clearTileCache, [tileOverlayId]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future<_i5.Uint8List?> takeSnapshot() => + (super.noSuchMethod( + Invocation.method(#takeSnapshot, []), + returnValue: _i4.Future<_i5.Uint8List?>.value(), + returnValueForMissingStub: _i4.Future<_i5.Uint8List?>.value(), + ) + as _i4.Future<_i5.Uint8List?>); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/run_tests.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/run_tests.dart new file mode 100644 index 000000000000..114db5c7b00f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/run_tests.dart @@ -0,0 +1,102 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: avoid_print + +// Ensures that all files that are intended to be shared between +// google_maps_flutter_ios_* packages are in sync with the shared source of +// truth. See google_maps_flutter_ios_shared_code/README.md for details. +// +// Called from the custom-tests CI action. + +import 'dart:async'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +import 'utils.dart'; + +Future main(List args) async { + // There's no reason to run this on multiple platforms in CI, so limit it to + // macOS where local development of this package will be happening. + if (!Platform.isMacOS) { + print('Skipping for non-macOS host'); + exit(0); + } + + final Directory packageRoot = Directory( + p.dirname(Platform.script.path), + ).parent; + final String packageName = p.basename(packageRoot.path); + final sharedSourceRoot = Directory( + p.join(packageRoot.parent.path, 'google_maps_flutter_ios_shared_code'), + ); + + var failed = false; + for (final FileSystemEntity entity in sharedSourceRoot.listSync( + recursive: true, + )) { + if (entity is! File) { + continue; + } + final String relativePath = p.relative( + entity.path, + from: sharedSourceRoot.path, + ); + // The shared source README.md is not part of the shared source of truth, + // just an explanation of this source-sharing system. + if (relativePath == 'README.md') { + continue; + } + + // Adjust the paths to account for the package name being part of the + // directory structure for Swift packages. + final String packagePath = p.join( + packageRoot.path, + packageRelativePathForSharedSourceRelativePath(packageName, relativePath), + ); + + print('Validating $relativePath'); + final packageFile = File(packagePath); + if (!packageFile.existsSync()) { + print(' File $relativePath does not exist in $packageName'); + failed = true; + continue; + } + final String expectedContents = normalizedFileContents(entity); + final String contents = normalizedFileContents(packageFile); + if (contents != expectedContents) { + print(' File $relativePath does not match expected contents:'); + await _printDiff(entity, packageFile); + failed = true; + } + } + + if (failed) { + print(''' + +If the changes you made should be shared with other copies of the +implementation, copy the changes to google_maps_flutter_ios_* directories: + dart run tool/sync_shared_files.dart +To validate that the changes have been shared correctly, run this tool again. + +If the changes you made should only be made to one copy of the implementation, +discuss with your reviewer or #hackers-ecosystem on Discord about the best +approach to sharing as much code as can still be shared. + +For more information on the code sharing structure used by this package, see +the google_maps_flutter_ios_shared_code/README.md file. + '''); + exit(1); + } +} + +Future _printDiff(File expected, File actual) async { + final Process process = await Process.start('diff', [ + '-u', + expected.absolute.path, + actual.absolute.path, + ], mode: ProcessStartMode.inheritStdio); + await process.exitCode; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart new file mode 100644 index 000000000000..1a423bba92e6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart @@ -0,0 +1,198 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: avoid_print + +// Synchronizes files that are intended to be shared between +// google_maps_flutter_ios_* packages with the shared source of truth and other +// copies. See google_maps_flutter_ios_shared_code/README.md for details. + +import 'dart:async'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +import 'utils.dart'; + +const String _sharedSourceRootName = 'google_maps_flutter_ios_shared_code'; + +Future main(List args) async { + final Directory packageRoot = Directory( + p.dirname(Platform.script.path), + ).parent; + final String packageName = p.basename(packageRoot.path); + final sharedSourceRoot = Directory( + p.join(packageRoot.parent.path, _sharedSourceRootName), + ); + + _syncSharedFiles(packageRoot, packageName, sharedSourceRoot); + _reportUnsharedFiles(packageRoot, packageName, sharedSourceRoot); +} + +void _syncSharedFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List otherImplementationPackages = sharedSourceRoot.parent + .listSync() + .whereType() + .map((e) => p.basename(e.path)) + .where( + (name) => + name.startsWith('google_maps_flutter_ios') && + name != _sharedSourceRootName && + name != packageName, + ) + .toList(); + + final copiedFiles = []; + final missingFiles = []; + for (final FileSystemEntity entity in sharedSourceRoot.listSync( + recursive: true, + )) { + if (entity is! File) { + continue; + } + final String relativePath = p.relative( + entity.path, + from: sharedSourceRoot.path, + ); + // The shared source README.md is not part of the shared source of truth, + // just an explanation of this source-sharing system. + if (relativePath == 'README.md') { + continue; + } + + // Adjust the paths to account for the package name being part of the + // directory structure for Swift packages. + final String packagePath = p.join( + packageRoot.path, + packageRelativePathForSharedSourceRelativePath(packageName, relativePath), + ); + + final packageFile = File(packagePath); + if (!packageFile.existsSync()) { + missingFiles.add(relativePath); + continue; + } + final String sharedContents = normalizedFileContents(entity); + final String newContents = normalizedFileContents(packageFile); + if (newContents != sharedContents) { + copiedFiles.add(relativePath); + // Copy to shared source. + _syncFile(packageFile, entity.path, 'google_maps_flutter_ios'); + // Copy to other implementation packages. + for (final otherPackageName in otherImplementationPackages) { + final String otherPackagePath = p.join( + packageRoot.parent.path, + otherPackageName, + packageRelativePathForSharedSourceRelativePath( + otherPackageName, + relativePath, + ), + ); + _syncFile(packageFile, otherPackagePath, otherPackageName); + } + } + } + + if (copiedFiles.isNotEmpty) { + print('Copied files:'); + for (final file in copiedFiles) { + print(' $file'); + } + } + if (missingFiles.isNotEmpty) { + print( + 'This package is missing the following files from the shared source:', + ); + for (final file in missingFiles) { + print(' $file'); + } + print( + 'If these files should no longer be shared, remove them from the shared source.', + ); + } +} + +/// Syncs a file from the given source to a destination package. +/// +/// If the file needs special handling of package names that appear within the +/// contents of the file, it will update the package name in the file to match +/// the destination package name. +void _syncFile( + File source, + String destinationPath, + String destinationPackageName, +) { + source.copySync(destinationPath); + if ([ + // The Pigeon definition file has output paths that must use the + // package name, to follow Swift package naming rules. + '/pigeons/', + // The mock needs to import the package. + '.mocks.dart', + ].any((pattern) => source.absolute.path.contains(pattern))) { + updatePackageNameInPathReferences( + File(destinationPath), + destinationPackageName, + ); + } +} + +void _reportUnsharedFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List codeFiles = packageRoot + .listSync(recursive: true) + .whereType() + // Only report code files. + .where( + (file) => + ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), + ) + // Flutter-generated files aren't expected to be shared. + .where((file) => !file.path.contains('GeneratedPluginRegistrant')) + // Ignore intermediate file directories. + .where((file) => !_isInIntermediateDirectory(file.path)) + .toList(); + + final unsharedFiles = []; + for (final file in codeFiles) { + final String relativePath = p.relative(file.path, from: packageRoot.path); + final String sharedPath = p.join( + sharedSourceRoot.path, + sharedSourceRelativePathForPackagePath(relativePath), + ); + final sharedFile = File(sharedPath); + if (!sharedFile.existsSync()) { + unsharedFiles.add(relativePath); + } + } + + if (unsharedFiles.isNotEmpty) { + print('\nThe following code files are not shared with other packages:'); + for (final file in unsharedFiles) { + print(' $file'); + } + print( + 'If this is not intentional, copy the relevant files to ' + '$_sharedSourceRootName, then re-run this tool.', + ); + } +} + +bool _isInIntermediateDirectory(String path) { + return [ + '.dart_tool', + '.symlinks', + '.build', + 'build', + 'ephemeral', + 'Pods', + ].any((dir) => path.contains('/$dir/')); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart new file mode 100644 index 000000000000..d311e4f64891 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +/// Adjusts a package-relative path to account for the package name being part of +/// the directory structure for Swift packages. +String sharedSourceRelativePathForPackagePath(String packageRelativePath) { + return packageRelativePath.replaceAll( + RegExp(r'/google_maps_flutter_ios[_\w\d]*/'), + '/google_maps_flutter_ios/', + ); +} + +/// Adjusts a shared-source-relative path to account for the package name being +/// part of the directory structure for Swift packages. +String packageRelativePathForSharedSourceRelativePath( + String packageName, + String sharedSourceRelativePath, +) { + return sharedSourceRelativePath.replaceAll( + '/google_maps_flutter_ios/', + '/$packageName/', + ); +} + +/// Returns the contents of the file with any differences caused only by the +/// package name removed. +String normalizedFileContents(File file) { + return file + .readAsStringSync() + // Ignore differences caused only by the package name. + .replaceAll( + RegExp(r'google_maps_flutter_ios_[\w\d]+'), + 'google_maps_flutter_ios', + ) + // Package name diffs could change line wrapping, so collapse whitespace. + .replaceAll(RegExp(r'[\s\n]+'), ' ') + .trim(); +} + +/// Updates the contents of [file] to replace any occurrences of variants of the +/// package name in things that look like paths with [packageName]. +/// +/// This should only be used on files where this is the only option, and where +/// the diffs are known to be safe, as not all instances of the package name +/// should be replaced in all files. +void updatePackageNameInPathReferences(File file, String packageName) { + final String newContents = file.readAsStringSync().replaceAllMapped( + RegExp(r'google_maps_flutter_ios[_\w\d]*([:/])'), + (match) => '$packageName${match.group(1)}', + ); + file.writeAsStringSync(newContents); +} From e92cf654caf2460b52f463bc8eea1f064dcd5f2b Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 10:59:23 -0500 Subject: [PATCH 02/19] f --- .../google_maps_flutter_android/CHANGELOG.md | 4 ++++ .../google_maps_flutter_android/android/build.gradle | 2 +- .../google_maps_flutter_android/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index 68385a54afcc..9533a9fff420 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.18.10 + +* Bump com.google.maps.android:android-maps-utils from 3.19.1 to 3.20.1. + ## 2.18.9 * Updates heatmaps passed between Dart and native to use typed data. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle b/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle index b5acf9a90ccb..34cd54da77a8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/build.gradle @@ -38,7 +38,7 @@ android { dependencies { implementation("androidx.annotation:annotation:1.9.1") implementation("com.google.android.gms:play-services-maps:19.2.0") - implementation("com.google.maps.android:android-maps-utils:3.19.1") + implementation("com.google.maps.android:android-maps-utils:3.20.1") androidTestImplementation("androidx.test:runner:1.7.0") androidTestImplementation("androidx.test:rules:1.7.0") androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0") diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index afea608e130b..4f41e83037e8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.18.9 +version: 2.18.10 environment: sdk: ^3.9.0 From 43cdd654d9cfa06638d7fc0737318966f6de65ad Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 09:25:23 -0500 Subject: [PATCH 03/19] Add CONTRIBUTING docs --- .../google_maps_flutter_ios/CONTRIBUTING.md | 9 +++++++++ .../google_maps_flutter_ios_sdk9/CONTRIBUTING.md | 9 +++++++++ .../google_maps_flutter_ios_shared_code/CONTRIBUTING.md | 9 +++++++++ 3 files changed, 27 insertions(+) create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios/CONTRIBUTING.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CONTRIBUTING.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_shared_code/CONTRIBUTING.md diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/CONTRIBUTING.md b/packages/google_maps_flutter/google_maps_flutter_ios/CONTRIBUTING.md new file mode 100644 index 000000000000..5779bf8d56c0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Code sharing + +This package shares most of its code with the other `google_maps_flutter_ios_*` +packages in this repository, so after changing any code files in this package +run: +`dart run tool/sync_shared_files.dart` + +See [the shared directory README](../google_maps_flutter_ios_shared_code/README.md) +for more details. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CONTRIBUTING.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CONTRIBUTING.md new file mode 100644 index 000000000000..5779bf8d56c0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Code sharing + +This package shares most of its code with the other `google_maps_flutter_ios_*` +packages in this repository, so after changing any code files in this package +run: +`dart run tool/sync_shared_files.dart` + +See [the shared directory README](../google_maps_flutter_ios_shared_code/README.md) +for more details. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/CONTRIBUTING.md b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/CONTRIBUTING.md new file mode 100644 index 000000000000..5779bf8d56c0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Code sharing + +This package shares most of its code with the other `google_maps_flutter_ios_*` +packages in this repository, so after changing any code files in this package +run: +`dart run tool/sync_shared_files.dart` + +See [the shared directory README](../google_maps_flutter_ios_shared_code/README.md) +for more details. From 21b23edb30086e1d9e400717783b999526f1c15e Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 09:26:43 -0500 Subject: [PATCH 04/19] Initial copy of sdk9->sdk10 --- .../google_maps_flutter_ios_sdk10/AUTHORS | 68 + .../CHANGELOG.md | 216 + .../CONTRIBUTING.md | 9 + .../google_maps_flutter_ios_sdk10/LICENSE | 25 + .../google_maps_flutter_ios_sdk10/README.md | 25 + .../example/.metadata | 8 + .../example/README.md | 13 + .../example/assets/2.0x/red_square.png | Bin 0 -> 304 bytes .../example/assets/3.0x/red_square.png | Bin 0 -> 312 bytes .../example/assets/night_mode.json | 162 + .../example/assets/red_square.png | Bin 0 -> 195 bytes .../integration_test/google_maps_test.dart | 2257 +++++++++ .../integration_test/resources/icon_image.png | Bin 0 -> 1257 bytes .../resources/icon_image_base64.dart | 49 + .../ios/Flutter/AppFrameworkInfo.plist | 28 + .../example/ios/Flutter/Debug.xcconfig | 2 + .../example/ios/Flutter/Release.xcconfig | 2 + .../example/ios/Podfile | 45 + .../ios/Runner.xcodeproj/project.pbxproj | 858 ++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/xcschemes/Runner.xcscheme | 128 + .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../example/ios/Runner/AppDelegate.swift | 21 + .../AppIcon.appiconset/Contents.json | 122 + .../Icon-App-1024x1024@1x.png | Bin 0 -> 11112 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 564 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 1588 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 1025 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 1716 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 1920 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 1283 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 2665 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 3831 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 1888 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 3294 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 3612 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 + .../ios/Runner/Base.lproj/Main.storyboard | 29 + .../example/ios/Runner/Info.plist | 53 + .../ios/Runner/Runner-Bridging-Header.h | 5 + .../RunnerTests/ExtractIconFromDataTests.m | 352 ++ .../FGMClusterManagersControllerTests.m | 145 + .../RunnerTests/FGMConversionsUtilsTests.m | 429 ++ .../FLTGoogleMapHeatmapControllerTests.m | 118 + .../FLTTileProviderControllerTests.m | 36 + .../GoogleMapsCircleControllerTests.m | 104 + .../GoogleMapsGroundOverlayControllerTests.m | 281 ++ .../GoogleMapsMarkerControllerTests.m | 361 ++ .../GoogleMapsPolygonControllerTests.m | 112 + .../GoogleMapsPolylineControllerTests.m | 181 + .../example/ios/RunnerTests/GoogleMapsTests.m | 212 + .../GoogleMapsTileOverlayControllerTests.m | 73 + .../example/ios/RunnerTests/Info.plist | 22 + .../ios/RunnerTests/PartiallyMockedMapView.h | 17 + .../ios/RunnerTests/PartiallyMockedMapView.m | 34 + .../ios/RunnerTests/assets/widegamut.png | Bin 0 -> 3025 bytes .../ios/RunnerUITests/GoogleMapsUITests.m | 288 ++ .../example/ios/RunnerUITests/Info.plist | 22 + .../example/lib/animate_camera.dart | 204 + .../example/lib/clustering.dart | 288 ++ .../example/lib/custom_marker_icon.dart | 55 + .../example/lib/example_google_map.dart | 676 +++ .../example/lib/ground_overlay.dart | 311 ++ .../example/lib/lite_mode.dart | 46 + .../example/lib/main.dart | 53 + .../example/lib/map_click.dart | 105 + .../example/lib/map_coordinates.dart | 105 + .../example/lib/map_map_id.dart | 100 + .../example/lib/map_ui.dart | 341 ++ .../example/lib/maps_demo.dart | 42 + .../example/lib/marker_icons.dart | 355 ++ .../example/lib/move_camera.dart | 161 + .../example/lib/padding.dart | 169 + .../example/lib/page.dart | 14 + .../example/lib/place_circle.dart | 227 + .../example/lib/place_marker.dart | 417 ++ .../example/lib/place_polygon.dart | 298 ++ .../example/lib/place_polyline.dart | 322 ++ .../example/lib/scrolling_map.dart | 112 + .../example/lib/snapshot.dart | 81 + .../example/lib/tile_overlay.dart | 147 + .../example/pubspec.yaml | 33 + .../example/test/example_google_map_test.dart | 176 + .../fake_google_maps_flutter_platform.dart | 350 ++ .../example/test_driver/integration_test.dart | 7 + .../ios/google_maps_flutter_ios_sdk9.podspec | 37 + .../Package.swift | 44 + .../FGMCATransactionWrapper.m | 23 + .../FGMClusterManagersController.m | 128 + .../FGMConversionUtils.m | 288 ++ .../FGMGroundOverlayController.m | 211 + .../FGMImageUtils.m | 235 + .../FGMMarkerUserData.m | 34 + .../FLTGoogleMapHeatmapController.m | 140 + .../FLTGoogleMapTileOverlayController.m | 199 + .../FLTGoogleMapsPlugin.m | 19 + .../GoogleMapCircleController.m | 130 + .../GoogleMapController.m | 838 ++++ .../GoogleMapMarkerController.m | 343 ++ .../GoogleMapPolygonController.m | 146 + .../GoogleMapPolylineController.m | 140 + .../Resources/PrivacyInfo.xcprivacy | 123 + .../google_maps_flutter_pigeon_messages.g.m | 3446 +++++++++++++ .../FGMCATransactionWrapper.h | 20 + .../FGMClusterManagersController.h | 56 + .../FGMConversionUtils.h | 97 + .../FGMGroundOverlayController.h | 64 + .../FGMGroundOverlayController_Test.h | 29 + .../FGMImageUtils.h | 20 + .../FGMMarkerUserData.h | 37 + .../FLTGoogleMapHeatmapController.h | 59 + .../FLTGoogleMapHeatmapController_Test.h | 17 + .../FLTGoogleMapTileOverlayController.h | 40 + .../FLTGoogleMapTileOverlayController_Test.h | 17 + .../FLTGoogleMapsPlugin.h | 20 + .../GoogleMapCircleController.h | 30 + .../GoogleMapCircleController_Test.h | 21 + .../GoogleMapController.h | 34 + .../GoogleMapController_Test.h | 59 + .../GoogleMapMarkerController.h | 55 + .../GoogleMapMarkerController_Test.h | 31 + .../GoogleMapPolygonController.h | 27 + .../GoogleMapPolygonController_Test.h | 17 + .../GoogleMapPolylineController.h | 27 + .../GoogleMapPolylineController_Test.h | 25 + .../GoogleMapsUtilsTrampoline.h | 12 + .../google_maps_flutter_pigeon_messages.g.h | 940 ++++ .../lib/google_maps_flutter_ios_sdk9.dart | 5 + .../lib/src/google_map_inspector_ios.dart | 277 ++ .../lib/src/google_maps_flutter_ios.dart | 1467 ++++++ .../lib/src/messages.g.dart | 4311 +++++++++++++++++ .../pigeons/copyright.txt | 3 + .../pigeons/messages.dart | 871 ++++ .../pubspec.yaml | 39 + .../test/google_maps_flutter_ios_test.dart | 1357 ++++++ .../google_maps_flutter_ios_test.mocks.dart | 351 ++ .../test/package_specific_test_import.dart | 11 + .../tool/run_tests.dart | 102 + .../tool/sync_shared_files.dart | 198 + .../tool/utils.dart | 55 + 149 files changed, 29522 insertions(+) create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/AUTHORS create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CHANGELOG.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CONTRIBUTING.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/LICENSE create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/README.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/.metadata create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/README.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/2.0x/red_square.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/3.0x/red_square.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/night_mode.json create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/red_square.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/google_maps_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/resources/icon_image.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/resources/icon_image_base64.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/Debug.xcconfig create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/Release.xcconfig create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Podfile create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/AppDelegate.swift create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Info.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Runner-Bridging-Header.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/ExtractIconFromDataTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMClusterManagersControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMConversionsUtilsTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTTileProviderControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/Info.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/PartiallyMockedMapView.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/PartiallyMockedMapView.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/assets/widegamut.png create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/Info.plist create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/animate_camera.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/clustering.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/custom_marker_icon.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/example_google_map.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/ground_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/lite_mode.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/main.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_click.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_coordinates.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_map_id.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_ui.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/maps_demo.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/marker_icons.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/move_camera.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/padding.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/page.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_circle.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_marker.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_polygon.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_polyline.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/scrolling_map.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/snapshot.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/tile_overlay.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/pubspec.yaml create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/example_google_map_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/fake_google_maps_flutter_platform.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test_driver/integration_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9.podspec create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Package.swift create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/google_maps_flutter_ios_sdk9.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_map_inspector_ios.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_maps_flutter_ios.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/messages.g.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/copyright.txt create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/messages.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pubspec.yaml create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.mocks.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/package_specific_test_import.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/run_tests.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/AUTHORS b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/AUTHORS new file mode 100644 index 000000000000..4fc3ace39f0f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/AUTHORS @@ -0,0 +1,68 @@ +# Below is a list of people and organizations that have contributed +# to the Flutter project. Names should be added to the list like so: +# +# Name/Organization + +Google Inc. +The Chromium Authors +German Saprykin +Benjamin Sauer +larsenthomasj@gmail.com +Ali Bitek +Pol Batlló +Anatoly Pulyaevskiy +Hayden Flinner +Stefano Rodriguez +Salvatore Giordano +Brian Armstrong +Paul DeMarco +Fabricio Nogueira +Simon Lightfoot +Ashton Thomas +Thomas Danner +Diego Velásquez +Hajime Nakamura +Tuyển Vũ Xuân +Miguel Ruivo +Sarthak Verma +Mike Diarmid +Invertase +Elliot Hesp +Vince Varga +Aawaz Gyawali +EUI Limited +Katarina Sheremet +Thomas Stockx +Sarbagya Dhaubanjar +Ozkan Eksi +Rishab Nayak +ko2ic +Jonathan Younger +Jose Sanchez +Debkanchan Samadder +Audrius Karosevicius +Lukasz Piliszczuk +SoundReply Solutions GmbH +Rafal Wachol +Pau Picas +Christian Weder +Alexandru Tuca +Christian Weder +Rhodes Davis Jr. +Luigi Agosti +Quentin Le Guennec +Koushik Ravikumar +Nissim Dsilva +Giancarlo Rocha +Ryo Miyake +Théo Champion +Kazuki Yamaguchi +Eitan Schwartz +Chris Rutkowski +Juan Alvarez +Aleksandr Yurkovskiy +Anton Borries +Alex Li +Rahul Raj <64.rahulraj@gmail.com> +Taha Tesser +Joonas Kerttula 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 new file mode 100644 index 000000000000..fa6e19caf286 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CHANGELOG.md @@ -0,0 +1,216 @@ +## 2.16.1 + +* Updates heatmaps passed between Dart and native to use typed data. + +## 2.16.0 + +* Adds compatibility with SDK version 10.x for apps targeting iOS 16+. + +## 2.15.8 + +* Replaces internal use of deprecated methods. + +## 2.15.7 + +* Updates to Pigeon 26. + +## 2.15.6 + +* Fixes potential flickers of default property values when adding objects to + the map. +* Updates minimum supported SDK version to Flutter 3.32/Dart 3.8. + +## 2.15.5 + +* Fixes `kCGImageAlphaPremultipliedLast` implicit conversion from enumeration type warning. + +## 2.15.4 + +* Deprecates `zIndex` parameter in Marker in favor of `zIndexInt`. + +## 2.15.3 + +* Fixes new analysis warnings. +* Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. + +## 2.15.2 + +* Fixes regression where updating a marker hides its info window. + +## 2.15.1 + +* Fixes regression in displaying info windows. + +## 2.15.0 + +* Adds support for animating the camera with a duration. + +## 2.14.0 + +* Adds support for ground overlay. +* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. + +## 2.13.2 + +* Updates most objects passed from Dart to native to use typed data. + +## 2.13.1 + +* Updates Pigeon for non-nullable collection type support. + +## 2.13.0 + +* Updates map configuration and platform view creation parameters to use Pigeon. +* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. + +## 2.12.0 + +* Adds support for marker clustering. + +## 2.11.0 + +* Adds support for heatmap layers. + +## 2.10.0 + +* Converts Obj-C->Dart calls to Pigeon. + +## 2.9.0 + +* Converts additional platform calls to Pigeon. + +## 2.8.2 + +* Converts inspector interface platform calls to Pigeon. + +## 2.8.1 + +* Improves Objective-C type handling. + +## 2.8.0 + +* Adds compatibility with SDK version 9.x for apps targetting iOS 15+. + +## 2.7.0 + +* Adds support for BitmapDescriptor classes `AssetMapBitmap` and `BytesMapBitmap`. + +## 2.6.1 + +* Adds support for patterns in polylines. + +## 2.6.0 + +* Updates the minimum allowed verison of the Google Maps SDK to 8.4, for privacy + manifest support. + * This means that applications using this package can no longer support + iOS 13 or 14, as the versions of the Google Maps SDK that support those + versions do not have privacy manifests, so cannot be used in published + applications once the new App Store enforcement of manifests takes effect. +* Includes the Google Maps SDK's [GoogleMapsPrivacy bundle](https://developers.google.com/maps/documentation/ios-sdk/config#add-apple-privacy-manifest-file) + manifest entries direct in the plugin, so that package clients do not need to + manually add that privacy bundle to the application build. + +## 2.5.2 + +* Fixes the tile overlay not correctly displaying on physical ios devices. + +## 2.5.1 + +* Makes the tile overlay callback invoke the platform channel on the platform thread. + +## 2.5.0 + +* Adds support for `MapConfiguration.style`. +* Adds support for `getStyleError`. + +## 2.4.2 + +* Fixes a bug in "takeSnapshot" function that incorrectly returns a blank image on iOS 17. + +## 2.4.1 + +* Restores the workaround to exclude arm64 simulator builds, as it is still necessary for applications targeting iOS 12. + +## 2.4.0 + +* Adds support for arm64 simulators. +* Updates minimum supported SDK version to Flutter 3.16.6. +* Removes support for iOS 11. + +## 2.3.6 + +* Adds privacy manifest. + +## 2.3.5 + +* Updates minimum required plugin_platform_interface version to 2.1.7. + +## 2.3.4 + +* Fixes new lint warnings. + +## 2.3.3 + +* Adds support for version 8 of the Google Maps SDK in apps targeting iOS 14+. +* Updates minimum supported SDK version to Flutter 3.10/Dart 3.0. + +## 2.3.2 + +* Fixes an issue where the onDragEnd callback for marker is not called. + +## 2.3.1 + +* Adds pub topics to package metadata. + +## 2.3.0 + +* Adds implementation for `cloudMapId` parameter to support cloud-based maps styling. +* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. +* Fixes unawaited_futures violations. + +## 2.2.3 + +* Removes obsolete null checks on non-nullable values. +* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. + +## 2.2.2 + +* Sets an upper bound on the `GoogleMaps` SDK version that can be used, to + avoid future breakage. + +## 2.2.1 + +* Clarifies explanation of endorsement in README. +* Aligns Dart and Flutter SDK constraints. + +## 2.2.0 + +* Updates minimum Flutter version to 3.3 and iOS 11. + +## 2.1.14 + +* Updates links for the merge of flutter/plugins into flutter/packages. + +## 2.1.13 + +* Updates code for stricter lint checks. +* Updates code for new analysis options. +* Re-enable XCUITests: testUserInterface. +* Remove unnecessary `RunnerUITests` target from Podfile of the example app. + +## 2.1.12 + +* Updates imports for `prefer_relative_imports`. +* Updates minimum Flutter version to 2.10. +* Fixes violations of new analysis option use_named_constants. +* Fixes avoid_redundant_argument_values lint warnings and minor typos. + +## 2.1.11 + +* Precaches Google Maps services initialization and syncing. + +## 2.1.10 + +* Splits iOS implementation out of `google_maps_flutter` as a federated + implementation. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CONTRIBUTING.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CONTRIBUTING.md new file mode 100644 index 000000000000..5779bf8d56c0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Code sharing + +This package shares most of its code with the other `google_maps_flutter_ios_*` +packages in this repository, so after changing any code files in this package +run: +`dart run tool/sync_shared_files.dart` + +See [the shared directory README](../google_maps_flutter_ios_shared_code/README.md) +for more details. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/LICENSE b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/LICENSE new file mode 100644 index 000000000000..29b709dac6c7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/LICENSE @@ -0,0 +1,25 @@ +Copyright 2013 The Flutter Authors + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/README.md new file mode 100644 index 000000000000..20fae87c8855 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/README.md @@ -0,0 +1,25 @@ +# google\_maps\_flutter\_ios + +The iOS implementation of [`google_maps_flutter`][1]. + +## Usage + +This package is [endorsed][2], which means you can simply use +`google_maps_flutter` normally. This package will be automatically included in +your app when you do, so you do not need to add it to your `pubspec.yaml`. + +However, if you `import` this package to use any of its APIs directly, you +should add it to your `pubspec.yaml` as usual. + +## Supported Heatmap Options + +| Field | Supported | +| ---------------------------- | :-------: | +| Heatmap.dissipating | x | +| Heatmap.maxIntensity | x | +| Heatmap.minimumZoomIntensity | ✓ | +| Heatmap.maximumZoomIntensity | ✓ | +| HeatmapGradient.colorMapSize | ✓ | + +[1]: https://pub.dev/packages/google_maps_flutter +[2]: https://flutter.dev/to/endorsed-federated-plugin diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/.metadata b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/.metadata new file mode 100644 index 000000000000..46e884ce48d1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/.metadata @@ -0,0 +1,8 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 3ea4d06340a97a1e9d7cae97567c64e0569dcaa2 + channel: beta diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/README.md new file mode 100644 index 000000000000..2d527ff468c8 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/README.md @@ -0,0 +1,13 @@ +# Platform Implementation Test App + +This is a test app for manual testing and automated integration testing +of this platform implementation. It is not intended to demonstrate actual use of +this package, since the intent is that plugin clients use the app-facing +package. + +Unless you are making changes to this implementation package, this example is +very unlikely to be relevant. + +## Versions + +This example requires iOS 14, so will select a 8.x GoogleMaps SDK version. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/2.0x/red_square.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/2.0x/red_square.png new file mode 100644 index 0000000000000000000000000000000000000000..0f82237796bf8fd2f178f9e758330b88cf715db2 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeK3?y%aJ*@^(Ea{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8Uxs6XMFi@E-`O@66Nz ziZCX5ySp&{XVSd~vL>4nJh^c}wqi2xH2cRH(iKnkC`(qX^4o2nTuqlgyLPDM{ zjv*GOlM^IZ7bl4HG(F^GV0pm6cSViEBhjN@7W>RdP`(kYX@0FtpS)Fwr$M z2r)FZGBC0-FwiwH2a=`jO&~8KH00)|WTsW3YcRAjHic*~j#{}AsDZ)L)z4*}Q$iB} Dk-bi6 literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/3.0x/red_square.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/3.0x/red_square.png new file mode 100644 index 0000000000000000000000000000000000000000..7e2739974e7bb4101cc42f520ece096cb2f5ade7 GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^6F``e8A#skDEJMeSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPMC&ZPZf#LuE|04GK z{y-7NByV>Y#{W#Z_kbME0*}aI1_m)z5N7lYQuzQBWH0gbb!C6d!o|U8+TNu22`D7x z>EamTas2H;Lq;I)(1Nf2xxD-f7#JR0XW-hvz-VXkX+BU~wZt`|BqgyV)hf9t6-Y4{ z85mmX8kp!B8iW{{S{WExnHuXFm|GbbJl~bP0 Hl+XkKwG2>~ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/night_mode.json b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/night_mode.json new file mode 100644 index 000000000000..1f16e003a920 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/night_mode.json @@ -0,0 +1,162 @@ +[ + { + "elementType": "geometry", + "stylers": [ + { + "color": "#242f3e" + } + ] + }, + { + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#746855" + } + ] + }, + { + "elementType": "labels.text.stroke", + "stylers": [ + { + "color": "#242f3e" + } + ] + }, + { + "featureType": "administrative.locality", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#d59563" + } + ] + }, + { + "featureType": "poi", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#d59563" + } + ] + }, + { + "featureType": "poi.park", + "elementType": "geometry", + "stylers": [ + { + "color": "#263c3f" + } + ] + }, + { + "featureType": "poi.park", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#6b9a76" + } + ] + }, + { + "featureType": "road", + "elementType": "geometry", + "stylers": [ + { + "color": "#38414e" + } + ] + }, + { + "featureType": "road", + "elementType": "geometry.stroke", + "stylers": [ + { + "color": "#212a37" + } + ] + }, + { + "featureType": "road", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#9ca5b3" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "geometry", + "stylers": [ + { + "color": "#746855" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "geometry.stroke", + "stylers": [ + { + "color": "#1f2835" + } + ] + }, + { + "featureType": "road.highway", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#f3d19c" + } + ] + }, + { + "featureType": "transit", + "elementType": "geometry", + "stylers": [ + { + "color": "#2f3948" + } + ] + }, + { + "featureType": "transit.station", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#d59563" + } + ] + }, + { + "featureType": "water", + "elementType": "geometry", + "stylers": [ + { + "color": "#17263c" + } + ] + }, + { + "featureType": "water", + "elementType": "labels.text.fill", + "stylers": [ + { + "color": "#515c6d" + } + ] + }, + { + "featureType": "water", + "elementType": "labels.text.stroke", + "stylers": [ + { + "color": "#17263c" + } + ] + } +] + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/red_square.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/assets/red_square.png new file mode 100644 index 0000000000000000000000000000000000000000..650a2dee711d0d404163de8d0e479d68e31d1662 GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=CqbAk63)r1AkM7~$#S7?R=q_WVZP1_OZu2ihZzoWI>~S6qbP0l+XkKvphU~ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/google_maps_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/google_maps_test.dart new file mode 100644 index 000000000000..824dea7d30c5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/google_maps_test.dart @@ -0,0 +1,2257 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_example/example_google_map.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:integration_test/integration_test.dart'; + +import 'resources/icon_image_base64.dart'; + +const LatLng _kInitialMapCenter = LatLng(0, 0); +const double _kInitialZoomLevel = 5; +const CameraPosition _kInitialCameraPosition = CameraPosition( + target: _kInitialMapCenter, + zoom: _kInitialZoomLevel, +); +const String _kCloudMapId = '000000000000000'; // Dummy map ID. + +// The tolerance value for floating-point comparisons in the tests. +// This value was selected as the minimum possible value that the test passes. +// There are multiple float conversions and calculations when data is converted +// between Dart and platform implementations. +const double _floatTolerance = 1e-6; +const double _kTestCameraZoomLevel = 10; +const double _kTestZoomByAmount = 2; +const LatLng _kTestMapCenter = LatLng(65, 25.5); +const CameraPosition _kTestCameraPosition = CameraPosition( + target: _kTestMapCenter, + zoom: _kTestCameraZoomLevel, + bearing: 1.0, + tilt: 1.0, +); +final LatLngBounds _testCameraBounds = LatLngBounds( + northeast: const LatLng(50, -65), + southwest: const LatLng(28.5, -123), +); +final ValueVariant _cameraUpdateTypeVariants = + ValueVariant(CameraUpdateType.values.toSet()); + +void main() { + IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + GoogleMapsFlutterPlatform.instance.enableDebugInspection(); + + testWidgets('testCompassToggle', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + compassEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool compassEnabled = await inspector.isCompassEnabled(mapId: mapId); + expect(compassEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + compassEnabled = await inspector.isCompassEnabled(mapId: mapId); + expect(compassEnabled, true); + }); + + testWidgets('testMapToolbar returns false', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool mapToolbarEnabled = await inspector.isMapToolbarEnabled( + mapId: mapId, + ); + // This is only supported on Android, so should always return false. + expect(mapToolbarEnabled, false); + }); + + testWidgets('updateMinMaxZoomLevels', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + const initialZoomLevel = MinMaxZoomPreference(4, 8); + const finalZoomLevel = MinMaxZoomPreference(6, 10); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + minMaxZoomPreference: initialZoomLevel, + onMapCreated: (ExampleGoogleMapController c) async { + controllerCompleter.complete(c); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + MinMaxZoomPreference zoomLevel = await inspector.getMinMaxZoomLevels( + mapId: controller.mapId, + ); + expect(zoomLevel, equals(initialZoomLevel)); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + minMaxZoomPreference: finalZoomLevel, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + zoomLevel = await inspector.getMinMaxZoomLevels(mapId: controller.mapId); + expect(zoomLevel, equals(finalZoomLevel)); + }); + + testWidgets('testZoomGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + zoomGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool zoomGesturesEnabled = await inspector.areZoomGesturesEnabled( + mapId: mapId, + ); + expect(zoomGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + zoomGesturesEnabled = await inspector.areZoomGesturesEnabled(mapId: mapId); + expect(zoomGesturesEnabled, true); + }); + + testWidgets('testZoomControlsEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool zoomControlsEnabled = await inspector.areZoomControlsEnabled( + mapId: mapId, + ); + + /// Zoom Controls functionality is not available on iOS at the moment. + expect(zoomControlsEnabled, false); + }); + + testWidgets('testRotateGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + rotateGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool rotateGesturesEnabled = await inspector.areRotateGesturesEnabled( + mapId: mapId, + ); + expect(rotateGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + rotateGesturesEnabled = await inspector.areRotateGesturesEnabled( + mapId: mapId, + ); + expect(rotateGesturesEnabled, true); + }); + + testWidgets('testTiltGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tiltGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool tiltGesturesEnabled = await inspector.areTiltGesturesEnabled( + mapId: mapId, + ); + expect(tiltGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + tiltGesturesEnabled = await inspector.areTiltGesturesEnabled(mapId: mapId); + expect(tiltGesturesEnabled, true); + }); + + testWidgets('testScrollGesturesEnabled', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + scrollGesturesEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool scrollGesturesEnabled = await inspector.areScrollGesturesEnabled( + mapId: mapId, + ); + expect(scrollGesturesEnabled, false); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + scrollGesturesEnabled = await inspector.areScrollGesturesEnabled( + mapId: mapId, + ); + expect(scrollGesturesEnabled, true); + }); + + testWidgets( + 'testInitialCenterLocationAtCenter', + (WidgetTester tester) async { + await tester.binding.setSurfaceSize(const Size(800, 600)); + + final mapControllerCompleter = Completer(); + final Key key = GlobalKey(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapControllerCompleter.complete(controller); + }, + ), + ), + ); + final ExampleGoogleMapController mapController = + await mapControllerCompleter.future; + + await tester.pumpAndSettle(); + + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + final ScreenCoordinate coordinate = await mapController + .getScreenCoordinate(_kInitialCameraPosition.target); + final Rect rect = tester.getRect(find.byKey(key)); + expect(coordinate.x, (rect.center.dx - rect.topLeft.dx).round()); + expect(coordinate.y, (rect.center.dy - rect.topLeft.dy).round()); + + await tester.binding.setSurfaceSize(null); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets( + 'testGetVisibleRegion', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final zeroLatLngBounds = LatLngBounds( + southwest: const LatLng(0, 0), + northeast: const LatLng(0, 0), + ); + + final mapControllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapControllerCompleter.complete(controller); + }, + ), + ), + ); + await tester.pumpAndSettle(); + + final ExampleGoogleMapController mapController = + await mapControllerCompleter.future; + + final LatLngBounds firstVisibleRegion = await mapController + .getVisibleRegion(); + + expect(firstVisibleRegion, isNotNull); + expect(firstVisibleRegion.southwest, isNotNull); + expect(firstVisibleRegion.northeast, isNotNull); + expect(firstVisibleRegion, isNot(zeroLatLngBounds)); + expect(firstVisibleRegion.contains(_kInitialMapCenter), isTrue); + + // Making a new `LatLngBounds` about (10, 10) distance south west to the `firstVisibleRegion`. + // The size of the `LatLngBounds` is 10 by 10. + final southWest = LatLng( + firstVisibleRegion.southwest.latitude - 20, + firstVisibleRegion.southwest.longitude - 20, + ); + final northEast = LatLng( + firstVisibleRegion.southwest.latitude - 10, + firstVisibleRegion.southwest.longitude - 10, + ); + final newCenter = LatLng( + (northEast.latitude + southWest.latitude) / 2, + (northEast.longitude + southWest.longitude) / 2, + ); + + expect(firstVisibleRegion.contains(northEast), isFalse); + expect(firstVisibleRegion.contains(southWest), isFalse); + + final latLngBounds = LatLngBounds( + southwest: southWest, + northeast: northEast, + ); + + // TODO(iskakaushik): non-zero padding is needed for some device configurations + // https://github.com/flutter/flutter/issues/30575 + const double padding = 0; + await mapController.moveCamera( + CameraUpdate.newLatLngBounds(latLngBounds, padding), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final LatLngBounds secondVisibleRegion = await mapController + .getVisibleRegion(); + + expect(secondVisibleRegion, isNotNull); + expect(secondVisibleRegion.southwest, isNotNull); + expect(secondVisibleRegion.northeast, isNotNull); + expect(secondVisibleRegion, isNot(zeroLatLngBounds)); + + expect(firstVisibleRegion, isNot(secondVisibleRegion)); + expect(secondVisibleRegion.contains(newCenter), isTrue); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets('testTraffic', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + trafficEnabled: true, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool isTrafficEnabled = await inspector.isTrafficEnabled(mapId: mapId); + expect(isTrafficEnabled, true); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + isTrafficEnabled = await inspector.isTrafficEnabled(mapId: mapId); + expect(isTrafficEnabled, false); + }); + + testWidgets('testBuildings', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool isBuildingsEnabled = await inspector.areBuildingsEnabled( + mapId: mapId, + ); + expect(isBuildingsEnabled, true); + }); + + testWidgets('testMyLocationButtonToggle', (WidgetTester tester) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + bool myLocationButtonEnabled = await inspector.isMyLocationButtonEnabled( + mapId: mapId, + ); + expect(myLocationButtonEnabled, true); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + myLocationButtonEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + myLocationButtonEnabled = await inspector.isMyLocationButtonEnabled( + mapId: mapId, + ); + expect(myLocationButtonEnabled, false); + }); + + testWidgets('testMyLocationButton initial value false', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + myLocationButtonEnabled: false, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool myLocationButtonEnabled = await inspector + .isMyLocationButtonEnabled(mapId: mapId); + expect(myLocationButtonEnabled, false); + }); + + testWidgets('testMyLocationButton initial value true', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final mapIdCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + final bool myLocationButtonEnabled = await inspector + .isMyLocationButtonEnabled(mapId: mapId); + expect(myLocationButtonEnabled, true); + }); + + testWidgets('testSetMapStyle valid Json String', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + const mapStyle = + '[{"elementType":"geometry","stylers":[{"color":"#242f3e"}]}]'; + await GoogleMapsFlutterPlatform.instance.setMapStyle( + mapStyle, + mapId: controller.mapId, + ); + }); + + testWidgets('testSetMapStyle invalid Json String', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + try { + await GoogleMapsFlutterPlatform.instance.setMapStyle( + 'invalid_value', + mapId: controller.mapId, + ); + fail('expected MapStyleException'); + } on MapStyleException catch (e) { + expect(e.cause, isNotNull); + expect(await controller.getStyleError(), isNotNull); + } + }); + + testWidgets('testSetMapStyle null string', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + await GoogleMapsFlutterPlatform.instance.setMapStyle( + null, + mapId: controller.mapId, + ); + }); + + testWidgets('testGetLatLng', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + final LatLngBounds visibleRegion = await controller.getVisibleRegion(); + final LatLng topLeft = await controller.getLatLng( + const ScreenCoordinate(x: 0, y: 0), + ); + final northWest = LatLng( + visibleRegion.northeast.latitude, + visibleRegion.southwest.longitude, + ); + + expect(topLeft, northWest); + }); + + testWidgets( + 'testGetZoomLevel', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + double zoom = await controller.getZoomLevel(); + expect(zoom, _kInitialZoomLevel); + + await controller.moveCamera(CameraUpdate.zoomTo(7)); + await tester.pumpAndSettle(); + zoom = await controller.getZoomLevel(); + expect(zoom, equals(7)); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets( + 'testScreenCoordinate', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + final LatLngBounds visibleRegion = await controller.getVisibleRegion(); + final northWest = LatLng( + visibleRegion.northeast.latitude, + visibleRegion.southwest.longitude, + ); + final ScreenCoordinate topLeft = await controller.getScreenCoordinate( + northWest, + ); + expect(topLeft, const ScreenCoordinate(x: 0, y: 0)); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets('testResizeWidget', (WidgetTester tester) async { + final controllerCompleter = Completer(); + final map = ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) async { + controllerCompleter.complete(controller); + }, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MaterialApp( + home: Scaffold(body: SizedBox(height: 100, width: 100, child: map)), + ), + ), + ); + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MaterialApp( + home: Scaffold(body: SizedBox(height: 400, width: 400, child: map)), + ), + ), + ); + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and `mapControllerCompleter.complete(controller)` above should happen + // in `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + // Simple call to make sure that the app hasn't crashed. + final LatLngBounds bounds1 = await controller.getVisibleRegion(); + final LatLngBounds bounds2 = await controller.getVisibleRegion(); + expect(bounds1, bounds2); + }); + + testWidgets('testToggleInfoWindow', (WidgetTester tester) async { + const marker = Marker( + markerId: MarkerId('marker'), + infoWindow: InfoWindow(title: 'InfoWindow'), + ); + final markers = {marker}; + + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + onMapCreated: (ExampleGoogleMapController googleMapController) { + controllerCompleter.complete(googleMapController); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + bool iwVisibleStatus = await controller.isMarkerInfoWindowShown( + marker.markerId, + ); + expect(iwVisibleStatus, false); + + await controller.showMarkerInfoWindow(marker.markerId); + iwVisibleStatus = await controller.isMarkerInfoWindowShown(marker.markerId); + expect(iwVisibleStatus, true); + + await controller.hideMarkerInfoWindow(marker.markerId); + iwVisibleStatus = await controller.isMarkerInfoWindowShown(marker.markerId); + expect(iwVisibleStatus, false); + }); + + testWidgets('updating a marker does not hide its info window', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + const marker = Marker( + markerId: MarkerId('marker'), + infoWindow: InfoWindow(title: 'InfoWindow'), + ); + var markers = {marker}; + + const clusterManager = ClusterManager( + clusterManagerId: ClusterManagerId('cluster_manager'), + ); + final clusterManagers = {clusterManager}; + + final 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 controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final Uint8List? bytes = await controller.takeSnapshot(); + expect(bytes?.isNotEmpty, true); + }, + // TODO(stuartmorgan): Re-enable; see https://github.com/flutter/flutter/issues/139825 + skip: true, + ); + + testWidgets('set tileOverlay correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final tileOverlay1 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + transparency: 0.2, + ); + + final tileOverlay2 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_2'), + tileProvider: _DebugTileProvider(), + zIndex: 1, + visible: false, + transparency: 0.3, + fadeIn: false, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1, tileOverlay2}, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + final TileOverlay tileOverlayInfo1 = (await inspector.getTileOverlayInfo( + tileOverlay1.mapsId, + mapId: mapId, + ))!; + final TileOverlay tileOverlayInfo2 = (await inspector.getTileOverlayInfo( + tileOverlay2.mapsId, + mapId: mapId, + ))!; + + expect(tileOverlayInfo1.visible, isTrue); + expect(tileOverlayInfo1.fadeIn, isTrue); + expect( + tileOverlayInfo1.transparency, + moreOrLessEquals(0.2, epsilon: 0.001), + ); + expect(tileOverlayInfo1.zIndex, 2); + + expect(tileOverlayInfo2.visible, isFalse); + expect(tileOverlayInfo2.fadeIn, isFalse); + expect( + tileOverlayInfo2.transparency, + moreOrLessEquals(0.3, epsilon: 0.001), + ); + expect(tileOverlayInfo2.zIndex, 1); + }); + + testWidgets('update tileOverlays correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + final tileOverlay1 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + transparency: 0.2, + ); + + final tileOverlay2 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_2'), + tileProvider: _DebugTileProvider(), + zIndex: 3, + transparency: 0.5, + ); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1, tileOverlay2}, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + final tileOverlay1New = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 1, + visible: false, + transparency: 0.3, + fadeIn: false, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1New}, + onMapCreated: (ExampleGoogleMapController controller) { + fail('update: OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final TileOverlay tileOverlayInfo1 = (await inspector.getTileOverlayInfo( + tileOverlay1.mapsId, + mapId: mapId, + ))!; + final TileOverlay? tileOverlayInfo2 = await inspector.getTileOverlayInfo( + tileOverlay2.mapsId, + mapId: mapId, + ); + + expect(tileOverlayInfo1.visible, isFalse); + expect(tileOverlayInfo1.fadeIn, isFalse); + expect( + tileOverlayInfo1.transparency, + moreOrLessEquals(0.3, epsilon: 0.001), + ); + expect(tileOverlayInfo1.zIndex, 1); + + expect(tileOverlayInfo2, isNull); + }); + + testWidgets('remove tileOverlays correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + final tileOverlay1 = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + zIndex: 2, + transparency: 0.2, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + tileOverlays: {tileOverlay1}, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + final TileOverlay? tileOverlayInfo1 = await inspector.getTileOverlayInfo( + tileOverlay1.mapsId, + mapId: mapId, + ); + + expect(tileOverlayInfo1, isNull); + }); + + testWidgets('marker clustering', (WidgetTester tester) async { + final Key key = GlobalKey(); + const clusterManagersAmount = 2; + const markersPerClusterManager = 5; + final markers = {}; + final clusterManagers = {}; + + for (var i = 0; i < clusterManagersAmount; i++) { + final clusterManagerId = ClusterManagerId('cluster_manager_$i'); + final clusterManager = ClusterManager(clusterManagerId: clusterManagerId); + clusterManagers.add(clusterManager); + } + + for (final cm in clusterManagers) { + for (var i = 0; i < markersPerClusterManager; i++) { + final markerId = MarkerId('${cm.clusterManagerId.value}_marker_$i'); + final marker = Marker( + markerId: markerId, + clusterManagerId: cm.clusterManagerId, + position: LatLng( + _kInitialMapCenter.latitude + i, + _kInitialMapCenter.longitude, + ), + ); + markers[markerId] = marker; + } + } + + final controllerCompleter = Completer(); + + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + clusterManagers: clusterManagers, + markers: Set.of(markers.values), + onMapCreated: (ExampleGoogleMapController googleMapController) { + controllerCompleter.complete(googleMapController); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + for (final cm in clusterManagers) { + final List clusters = await inspector.getClusters( + mapId: controller.mapId, + clusterManagerId: cm.clusterManagerId, + ); + final int markersAmountForClusterManager = clusters + .map((Cluster cluster) => cluster.count) + .reduce((int value, int element) => value + element); + 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); + } + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + clusterManagers: clusterManagers, + markers: Set.of(markers.values), + ), + ), + ); + + for (final cm in clusterManagers) { + final List clusters = await inspector.getClusters( + mapId: controller.mapId, + clusterManagerId: cm.clusterManagerId, + ); + expect(clusters.length, 0); + } + }); + + testWidgets('testSetStyleMapId', (WidgetTester tester) async { + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + mapId: _kCloudMapId, + ), + ), + ); + }); + + testWidgets('getStyleError reports last error', (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + style: '[[[this is an invalid style', + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final String? error = await controller.getStyleError(); + expect(error, isNotNull); + }); + + testWidgets('getStyleError returns null for a valid style', ( + WidgetTester tester, + ) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + // An empty array is the simplest valid style. + style: '[]', + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + final String? error = await controller.getStyleError(); + expect(error, isNull); + }); + + testWidgets('markerWithAssetMapBitmap', (WidgetTester tester) async { + final markers = { + Marker( + markerId: const MarkerId('1'), + icon: AssetMapBitmap('assets/red_square.png', imagePixelRatio: 1.0), + ), + }; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + ), + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithAssetMapBitmapCreate', (WidgetTester tester) async { + final imageConfiguration = ImageConfiguration( + devicePixelRatio: tester.view.devicePixelRatio, + ); + final markers = { + Marker( + markerId: const MarkerId('1'), + icon: await AssetMapBitmap.create( + imageConfiguration, + 'assets/red_square.png', + ), + ), + }; + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + ), + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithBytesMapBitmap', (WidgetTester tester) async { + final Uint8List bytes = const Base64Decoder().convert(iconImageBase64); + final markers = { + Marker( + markerId: const MarkerId('1'), + icon: BytesMapBitmap( + bytes, + imagePixelRatio: tester.view.devicePixelRatio, + ), + ), + }; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + ), + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithLegacyAsset', (WidgetTester tester) async { + //tester.view.devicePixelRatio = 2.0; + const imageConfiguration = ImageConfiguration( + devicePixelRatio: 2.0, + size: Size(100, 100), + ); + final markers = { + Marker( + markerId: const MarkerId('1'), + // Intentionally testing the deprecated code path. + // ignore: deprecated_member_use + icon: await BitmapDescriptor.fromAssetImage( + imageConfiguration, + 'assets/red_square.png', + ), + ), + }; + final controllerCompleter = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + onMapCreated: (ExampleGoogleMapController controller) => + controllerCompleter.complete(controller), + ), + ), + ); + + await controllerCompleter.future; + }); + + testWidgets('markerWithLegacyBytes', (WidgetTester tester) async { + tester.view.devicePixelRatio = 2.0; + final Uint8List bytes = const Base64Decoder().convert(iconImageBase64); + // Intentionally testing the deprecated code path. + // ignore: deprecated_member_use + final BitmapDescriptor icon = BitmapDescriptor.fromBytes(bytes); + + final markers = {Marker(markerId: const MarkerId('1'), icon: icon)}; + final controllerCompleter = Completer(); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(10.0, 15.0), + ), + markers: markers, + onMapCreated: (ExampleGoogleMapController controller) => + controllerCompleter.complete(controller), + ), + ), + ); + await controllerCompleter.future; + }); + + group('GroundOverlay', () { + final kGroundOverlayBounds = LatLngBounds( + southwest: const LatLng(37.77483, -122.41942), + northeast: const LatLng(37.78183, -122.39105), + ); + + final groundOverlayBounds1 = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('bounds_1'), + bounds: kGroundOverlayBounds, + image: AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ), + ); + + final groundOverlayPosition1 = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('position_1'), + position: kGroundOverlayBounds.northeast, + width: 100, + height: 100, + anchor: const Offset(0.1, 0.2), + zoomLevel: 14.0, + image: AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ), + ); + + void expectGroundOverlayEquals( + GroundOverlay source, + GroundOverlay response, + ) { + expect(response.groundOverlayId, source.groundOverlayId); + expect( + response.transparency, + moreOrLessEquals(source.transparency, epsilon: _floatTolerance), + ); + expect( + response.bearing, + moreOrLessEquals(source.bearing, epsilon: _floatTolerance), + ); + + // Only test bounds if it was given in the original object + if (source.bounds != null) { + expect(response.bounds, source.bounds); + } + + // Only test position if it was given in the original object + if (source.position != null) { + expect(response.position, source.position); + } + + expect(response.clickable, source.clickable); + expect(response.zIndex, source.zIndex); + expect(response.zoomLevel, source.zoomLevel); + expect( + response.anchor?.dx, + moreOrLessEquals(source.anchor!.dx, epsilon: _floatTolerance), + ); + expect( + response.anchor?.dy, + moreOrLessEquals(source.anchor!.dy, epsilon: _floatTolerance), + ); + } + + testWidgets('set ground overlays correctly', (WidgetTester tester) async { + final mapIdCompleter = Completer(); + final groundOverlayBounds2 = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('bounds_2'), + bounds: groundOverlayBounds1.bounds!, + image: groundOverlayBounds1.image, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1, + groundOverlayBounds2, + groundOverlayPosition1, + }, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + await tester.pumpAndSettle(const Duration(seconds: 3)); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + if (inspector.supportsGettingGroundOverlayInfo()) { + final GroundOverlay groundOverlayBoundsInfo1 = (await inspector + .getGroundOverlayInfo(groundOverlayBounds1.mapsId, mapId: mapId))!; + final GroundOverlay groundOverlayBoundsInfo2 = (await inspector + .getGroundOverlayInfo(groundOverlayBounds2.mapsId, mapId: mapId))!; + final GroundOverlay groundOverlayPositionInfo1 = (await inspector + .getGroundOverlayInfo( + groundOverlayPosition1.mapsId, + mapId: mapId, + ))!; + + expectGroundOverlayEquals( + groundOverlayBounds1, + groundOverlayBoundsInfo1, + ); + expectGroundOverlayEquals( + groundOverlayBounds2, + groundOverlayBoundsInfo2, + ); + expectGroundOverlayEquals( + groundOverlayPosition1, + groundOverlayPositionInfo1, + ); + } + }); + + testWidgets('update ground overlays correctly', ( + WidgetTester tester, + ) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1, + groundOverlayPosition1, + }, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + final GroundOverlay groundOverlayBounds1New = groundOverlayBounds1 + .copyWith( + bearingParam: 10, + clickableParam: false, + transparencyParam: 0.5, + visibleParam: false, + zIndexParam: 10, + ); + + final GroundOverlay groundOverlayPosition1New = groundOverlayPosition1 + .copyWith( + bearingParam: 10, + clickableParam: false, + transparencyParam: 0.5, + visibleParam: false, + zIndexParam: 10, + ); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1New, + groundOverlayPosition1New, + }, + onMapCreated: (ExampleGoogleMapController controller) { + fail('update: OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + if (inspector.supportsGettingGroundOverlayInfo()) { + final GroundOverlay groundOverlayBounds1Info = (await inspector + .getGroundOverlayInfo(groundOverlayBounds1.mapsId, mapId: mapId))!; + final GroundOverlay groundOverlayPosition1Info = (await inspector + .getGroundOverlayInfo( + groundOverlayPosition1.mapsId, + mapId: mapId, + ))!; + + expectGroundOverlayEquals( + groundOverlayBounds1New, + groundOverlayBounds1Info, + ); + expectGroundOverlayEquals( + groundOverlayPosition1New, + groundOverlayPosition1Info, + ); + } + }); + + testWidgets('remove ground overlays correctly', ( + WidgetTester tester, + ) async { + final mapIdCompleter = Completer(); + final Key key = GlobalKey(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + groundOverlays: { + groundOverlayBounds1, + groundOverlayPosition1, + }, + onMapCreated: (ExampleGoogleMapController controller) { + mapIdCompleter.complete(controller.mapId); + }, + ), + ), + ); + + final int mapId = await mapIdCompleter.future; + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onMapCreated: (ExampleGoogleMapController controller) { + fail('OnMapCreated should get called only once.'); + }, + ), + ), + ); + + await tester.pumpAndSettle(const Duration(seconds: 3)); + + if (inspector.supportsGettingGroundOverlayInfo()) { + final GroundOverlay? groundOverlayBounds1Info = await inspector + .getGroundOverlayInfo(groundOverlayBounds1.mapsId, mapId: mapId); + final GroundOverlay? groundOverlayPositionInfo = await inspector + .getGroundOverlayInfo(groundOverlayPosition1.mapsId, mapId: mapId); + + expect(groundOverlayBounds1Info, isNull); + expect(groundOverlayPositionInfo, isNull); + } + }); + }); + + testWidgets( + 'testAnimateCameraWithoutDuration', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + /// Completer to track when the camera has come to rest. + Completer? cameraIdleCompleter; + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onCameraIdle: () { + if (cameraIdleCompleter != null && + !cameraIdleCompleter.isCompleted) { + cameraIdleCompleter.complete(); + } + }, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and + // `mapControllerCompleter.complete(controller)` above should happen in + // `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + // Create completer for camera idle event. + cameraIdleCompleter = Completer(); + + final CameraUpdate cameraUpdate = _getCameraUpdateForType( + _cameraUpdateTypeVariants.currentValue!, + ); + await controller.animateCamera(cameraUpdate); + + // Immediately after calling animateCamera, check that the camera hasn't + // reached its final position. This relies on the assumption that the + // camera move is animated and won't complete instantly. + final CameraPosition beforeFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + beforeFinishedPosition, + null, + controller, + (Matcher matcher) => isNot(matcher), + ); + + // Wait for the animation to complete (onCameraIdle). + expect(cameraIdleCompleter.isCompleted, isFalse); + await cameraIdleCompleter.future; + + // After onCameraIdle event, the camera should be at the final position. + final CameraPosition afterFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + afterFinishedPosition, + beforeFinishedPosition, + controller, + (Matcher matcher) => matcher, + ); + + await tester.pumpAndSettle(); + }, + variant: _cameraUpdateTypeVariants, + // Hanging in CI, https://github.com/flutter/flutter/issues/166139 + skip: true, + ); + + /// Tests animating the camera with specified durations to verify timing + /// behavior. + /// + /// This test checks two scenarios: short and long animation durations. + /// It uses a midpoint duration to ensure the short animation completes in + /// less time and the long animation takes more time than that midpoint. + /// This ensures that the animation duration is respected by the platform and + /// that the default camera animation duration does not affect the test + /// results. + testWidgets( + 'testAnimateCameraWithDuration', + (WidgetTester tester) async { + final Key key = GlobalKey(); + final controllerCompleter = Completer(); + final GoogleMapsInspectorPlatform inspector = + GoogleMapsInspectorPlatform.instance!; + + /// Completer to track when the camera has come to rest. + Completer? cameraIdleCompleter; + + const shortCameraAnimationDurationMS = 200; + const longCameraAnimationDurationMS = 1000; + + /// Calculate the midpoint duration of the animation test, which will + /// serve as a reference to verify that animations complete more quickly + /// with shorter durations and more slowly with longer durations. + const int animationDurationMiddlePoint = + (shortCameraAnimationDurationMS + longCameraAnimationDurationMS) ~/ 2; + + // Stopwatch to measure the time taken for the animation to complete. + final stopwatch = Stopwatch(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + key: key, + initialCameraPosition: _kInitialCameraPosition, + onCameraIdle: () { + if (cameraIdleCompleter != null && + !cameraIdleCompleter.isCompleted) { + stopwatch.stop(); + cameraIdleCompleter.complete(); + } + }, + onMapCreated: (ExampleGoogleMapController controller) { + controllerCompleter.complete(controller); + }, + ), + ), + ); + + final ExampleGoogleMapController controller = + await controllerCompleter.future; + + await tester.pumpAndSettle(); + // TODO(cyanglaz): Remove this after we added `mapRendered` callback, and + // `mapControllerCompleter.complete(controller)` above should happen in + // `mapRendered`. + // https://github.com/flutter/flutter/issues/54758 + await Future.delayed(const Duration(seconds: 1)); + + // Create completer for camera idle event. + cameraIdleCompleter = Completer(); + + // Start stopwatch to check the time taken for the animation to complete. + // Stopwatch is stopped on camera idle callback. + stopwatch.reset(); + stopwatch.start(); + + // First phase with shorter animation duration. + final CameraUpdate cameraUpdateShort = _getCameraUpdateForType( + _cameraUpdateTypeVariants.currentValue!, + ); + await controller.animateCamera( + cameraUpdateShort, + duration: const Duration(milliseconds: shortCameraAnimationDurationMS), + ); + + // Wait for the animation to complete (onCameraIdle). + expect(cameraIdleCompleter.isCompleted, isFalse); + await cameraIdleCompleter.future; + + // For short animation duration, check that the animation is completed + // faster than the midpoint benchmark. + expect( + stopwatch.elapsedMilliseconds, + lessThan(animationDurationMiddlePoint), + ); + + // Reset camera to initial position before testing long duration. + await controller.moveCamera( + CameraUpdate.newCameraPosition(_kInitialCameraPosition), + ); + await tester.pumpAndSettle(); + + // Create completer for camera idle event. + cameraIdleCompleter = Completer(); + + // Start stopwatch to check the time taken for the animation to complete. + // Stopwatch is stopped on camera idle callback. + stopwatch.reset(); + stopwatch.start(); + + // Second phase with longer animation duration. + final CameraUpdate cameraUpdateLong = _getCameraUpdateForType( + _cameraUpdateTypeVariants.currentValue!, + ); + await controller.animateCamera( + cameraUpdateLong, + duration: const Duration(milliseconds: longCameraAnimationDurationMS), + ); + + // Immediately after calling animateCamera, check that the camera hasn't + // reached its final position. This relies on the assumption that the + // camera move is animated and won't complete instantly. + final CameraPosition beforeFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + beforeFinishedPosition, + null, + controller, + (Matcher matcher) => isNot(matcher), + ); + + // Wait for the animation to complete (onCameraIdle). + expect(cameraIdleCompleter.isCompleted, isFalse); + await cameraIdleCompleter.future; + + // For longer animation duration, check that the animation is completed + // slower than the midpoint benchmark. + expect( + stopwatch.elapsedMilliseconds, + greaterThan(animationDurationMiddlePoint), + ); + + // Camera should be at the final position. + final CameraPosition afterFinishedPosition = await inspector + .getCameraPosition(mapId: controller.mapId); + await _checkCameraUpdateByType( + _cameraUpdateTypeVariants.currentValue!, + afterFinishedPosition, + beforeFinishedPosition, + controller, + (Matcher matcher) => matcher, + ); + + await tester.pumpAndSettle(); + }, + variant: _cameraUpdateTypeVariants, + // Hanging in CI, https://github.com/flutter/flutter/issues/166139 + skip: true, + ); +} + +class _DebugTileProvider implements TileProvider { + _DebugTileProvider() { + boxPaint.isAntiAlias = true; + boxPaint.color = Colors.blue; + boxPaint.strokeWidth = 2.0; + boxPaint.style = PaintingStyle.stroke; + } + + static const int width = 100; + static const int height = 100; + static final Paint boxPaint = Paint(); + static const TextStyle textStyle = TextStyle(color: Colors.red, fontSize: 20); + + @override + Future getTile(int x, int y, int? zoom) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final textSpan = TextSpan(text: '$x,$y', style: textStyle); + final textPainter = TextPainter( + text: textSpan, + textDirection: TextDirection.ltr, + ); + textPainter.layout(maxWidth: width.toDouble()); + textPainter.paint(canvas, Offset.zero); + canvas.drawRect( + Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), + boxPaint, + ); + final ui.Picture picture = recorder.endRecording(); + final Uint8List byteData = await picture + .toImage(width, height) + .then( + (ui.Image image) => image.toByteData(format: ui.ImageByteFormat.png), + ) + .then((ByteData? byteData) => byteData!.buffer.asUint8List()); + return Tile(width, height, byteData); + } +} + +Marker _copyMarkerWithClusterManagerId( + Marker marker, + ClusterManagerId? clusterManagerId, +) { + return Marker( + markerId: marker.markerId, + alpha: marker.alpha, + anchor: marker.anchor, + consumeTapEvents: marker.consumeTapEvents, + draggable: marker.draggable, + flat: marker.flat, + icon: marker.icon, + infoWindow: marker.infoWindow, + position: marker.position, + rotation: marker.rotation, + visible: marker.visible, + zIndexInt: marker.zIndexInt, + onTap: marker.onTap, + onDragStart: marker.onDragStart, + onDrag: marker.onDrag, + onDragEnd: marker.onDragEnd, + clusterManagerId: clusterManagerId, + ); +} + +CameraUpdate _getCameraUpdateForType(CameraUpdateType type) { + return switch (type) { + CameraUpdateType.newCameraPosition => CameraUpdate.newCameraPosition( + _kTestCameraPosition, + ), + CameraUpdateType.newLatLng => CameraUpdate.newLatLng(_kTestMapCenter), + CameraUpdateType.newLatLngBounds => CameraUpdate.newLatLngBounds( + _testCameraBounds, + 0, + ), + CameraUpdateType.newLatLngZoom => CameraUpdate.newLatLngZoom( + _kTestMapCenter, + _kTestCameraZoomLevel, + ), + CameraUpdateType.scrollBy => CameraUpdate.scrollBy(10, 10), + CameraUpdateType.zoomBy => CameraUpdate.zoomBy( + _kTestZoomByAmount, + const Offset(1, 1), + ), + CameraUpdateType.zoomTo => CameraUpdate.zoomTo(_kTestCameraZoomLevel), + CameraUpdateType.zoomIn => CameraUpdate.zoomIn(), + CameraUpdateType.zoomOut => CameraUpdate.zoomOut(), + }; +} + +Future _checkCameraUpdateByType( + CameraUpdateType type, + CameraPosition currentPosition, + CameraPosition? oldPosition, + ExampleGoogleMapController controller, + Matcher Function(Matcher matcher) wrapMatcher, +) async { + // As the target might differ a bit from the expected target, a threshold is + // used. + const latLngThreshold = 0.05; + + switch (type) { + case CameraUpdateType.newCameraPosition: + expect( + currentPosition.bearing, + wrapMatcher(equals(_kTestCameraPosition.bearing)), + ); + expect( + currentPosition.zoom, + wrapMatcher(equals(_kTestCameraPosition.zoom)), + ); + expect( + currentPosition.tilt, + wrapMatcher(equals(_kTestCameraPosition.tilt)), + ); + expect( + currentPosition.target.latitude, + wrapMatcher( + closeTo(_kTestCameraPosition.target.latitude, latLngThreshold), + ), + ); + expect( + currentPosition.target.longitude, + wrapMatcher( + closeTo(_kTestCameraPosition.target.longitude, latLngThreshold), + ), + ); + case CameraUpdateType.newLatLng: + expect( + currentPosition.target.latitude, + wrapMatcher(closeTo(_kTestMapCenter.latitude, latLngThreshold)), + ); + expect( + currentPosition.target.longitude, + wrapMatcher(closeTo(_kTestMapCenter.longitude, latLngThreshold)), + ); + case CameraUpdateType.newLatLngBounds: + final LatLngBounds bounds = await controller.getVisibleRegion(); + expect( + bounds.northeast.longitude, + wrapMatcher( + closeTo(_testCameraBounds.northeast.longitude, latLngThreshold), + ), + ); + expect( + bounds.southwest.longitude, + wrapMatcher( + closeTo(_testCameraBounds.southwest.longitude, latLngThreshold), + ), + ); + case CameraUpdateType.newLatLngZoom: + expect( + currentPosition.target.latitude, + wrapMatcher(closeTo(_kTestMapCenter.latitude, latLngThreshold)), + ); + expect( + currentPosition.target.longitude, + wrapMatcher(closeTo(_kTestMapCenter.longitude, latLngThreshold)), + ); + expect(currentPosition.zoom, wrapMatcher(equals(_kTestCameraZoomLevel))); + case CameraUpdateType.scrollBy: + // For scrollBy, just check that the location has changed. + if (oldPosition != null) { + expect( + currentPosition.target.latitude, + isNot(equals(oldPosition.target.latitude)), + ); + expect( + currentPosition.target.longitude, + isNot(equals(oldPosition.target.longitude)), + ); + } + case CameraUpdateType.zoomBy: + expect( + currentPosition.zoom, + wrapMatcher(equals(_kInitialZoomLevel + _kTestZoomByAmount)), + ); + case CameraUpdateType.zoomTo: + expect(currentPosition.zoom, wrapMatcher(equals(_kTestCameraZoomLevel))); + case CameraUpdateType.zoomIn: + expect(currentPosition.zoom, wrapMatcher(equals(_kInitialZoomLevel + 1))); + case CameraUpdateType.zoomOut: + expect(currentPosition.zoom, wrapMatcher(equals(_kInitialZoomLevel - 1))); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/resources/icon_image.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/resources/icon_image.png new file mode 100644 index 0000000000000000000000000000000000000000..920b93f74d7875578cfddd9fb3a86ffc91cc66aa GIT binary patch literal 1257 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|T2doC(|mmy zw18|523AHP24;{FAY@>aVqgWc85q16rQz%#Mh&PMCI*J~Oa>OHnkXO*0v4nJa0`PlBg3pY5xV%QuQiw3qZOUY$~jP%-qzHM1_jnoV;SI3R@+x3M(KRB&@Hb09I0xZL1XF8=&Bv zUzDm~s%N5Spk&9TprBw=l#*r@P?Wt5Z@Sn2DRmzV368|&p4rRy77T3YHG z80i}s=>k>g7FXt#Bv$C=6)QswftllyTAW;zSx}OhpQivaH!&%{w8U0P31kr*K-^i9 znTD__uNdkrpa=CqGWv#k2KsQbfm&@qqE`MznW;dVLFU^T+JIG}h(YbK(Fa+MGhS)(5hysGVj@1S=_(gPCCO{ zqhwks#Vc``|8 z#o#O*d;N2|BC{jvU{z}(n^^Vap!a1%`y(*n{sOkJ|#X3oe;O!Zo?Dnhr)@GQ`z`?mdD=yHSxr< zDy_rs-x{jCabub6U?S+*S@!Va>4+T*Hmzz(*!gva0^=QR?pv-qbGCN6d|Si4{*vsJ zlH0zk1sd5rv=;3+XYfL0!@WaC`Ahb=eYxm+=guaBQ~enqLO(hNXMfPrI^{pDhK z-4_e9Y*sb;Jj~0Qs$sV`^@y=`QNlJK=FPXKOL(O1`}w`Gn*UDUbd&Ixz5e<2va`xH z41-N}zw;G7BCl8SdS-H5ozdgaGryVtGld%!O3p1V7HRwR?9co=RqwyAbPax;#ec&s zvsY)SyxMWE30Fc-y!yt-7}jeScd5ucNzCQ_c1QOYYo)m6PP)2@Gs?hW+Rx4&FMFT6 zT8Ccju)dun6cb3O7sF#-G(!!nzha!-kf?C|8-&R&#t@} QJ5YZ2boFyt=akR{0O*p@82|tP literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/resources/icon_image_base64.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/resources/icon_image_base64.dart new file mode 100644 index 000000000000..6b576e010572 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/integration_test/resources/icon_image_base64.dart @@ -0,0 +1,49 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// This constant holds the base64-encoded data of a 16x16 PNG image of the +/// Flutter logo. +/// +/// See `icon_image.png` source in the same directory. +/// +/// To create or update this image, follow these steps: +/// 1. Create or update a 16x16 PNG image. +/// 2. Convert the image to a base64 string using a script below. +/// 3. Replace the existing base64 string below with the new one. +/// +/// Example of converting an image to base64 in Dart: +/// ```dart +/// import 'dart:convert'; +/// import 'dart:io'; +/// +/// void main() async { +/// final bytes = await File('icon_image.png').readAsBytes(); +/// final base64String = base64Encode(bytes); +/// print(base64String); +/// } +/// ``` +const String iconImageBase64 = + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAIRlWElmTU' + '0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIA' + 'AIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQ' + 'AAABCgAwAEAAAAAQAAABAAAAAAx28c8QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1M' + 'OmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIH' + 'g6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8v' + 'd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcm' + 'lwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFk' + 'b2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk' + '9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6' + 'eG1wbWV0YT4KTMInWQAAAplJREFUOBF1k01ME1EQx2fe7tIPoGgTE6AJgQQSPaiH9oAtkFbsgX' + 'jygFcT0XjSkxcTDxtPJh6MR28ePMHBBA8cNLSIony0oBhEMVETP058tE132+7uG3cW24DAXN57' + '2fn9/zPz3iIcEdEl0nIxtNLr1IlVeoMadkubKmoL+u2SzAV8IjV5Ekt4GN+A8+VOUPwLarOI2G' + 'Vpqq0i4JQorwQxPtWHVZ1IKP8LNGDXGaSyqARFxDGo7MJBy4XVf3AyQ+qTHnTEXoF9cFUy3OkY' + '0oWxmWFtD5xNoc1sQ6AOn1+hCNTkkhKow8KFZV77tVs2O9dhFvBm0IA/U0RhZ7/ocEx23oUDlh' + 'h8HkNjZIN8Lb3gOU8gOp7AKJHCB2/aNZkTftHumNzzbtl2CBPZHqxw8mHhVZBeoz6w5DvhE2FZ' + 'lQYPjKdd2/qRyKZ6KsPv7TEk7EYEk0A0EUmJduHRy1i4oLKqgmC59ZggAdwrC9pFuWy1iUT2rA' + 'uv0h2UdNtNqxCBBkgqorjOMOgksN7CxQ90vEb00U3c3LIwyo9o8FXxQVNr8Coqyk+S5EPBXnjt' + 'xRmc4TegI7qWbvBkeeUbGMnTCd4nZnYeDOWIEtlC6cKK/JJepY3hZSvN33jovO6L0XFqPKqBTO' + 'FuapUoPr1lxDM7cmC2TAOz25cYSGa++feBew/cjpc0V+mNT29/HZp3KDFTNLvuTRPEHy5065lj' + 'Xn4y41XM+wP/AlcycRmdc3MUhvLm/J/ceu/3qUVT62oP2EZpjSylHybHSpDUVcjq9gEBVo0+Xt' + 'JyN2IWRO+3QUforRoKnZLVsglaMECW+YmMSj9M3SrC6Lg71CMiqWfUrJ6ywzefhnZ+G69BaKdB' + 'WhXQAn6wzDUpfUPw7MrmX/WhbfmKblw+AAAAAElFTkSuQmCC'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/AppFrameworkInfo.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 000000000000..6fe4034356ac --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + UIRequiredDeviceCapabilities + + arm64 + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/Debug.xcconfig b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 000000000000..e8efba114687 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/Release.xcconfig b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/Release.xcconfig new file mode 100644 index 000000000000..399e9340e6f6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Podfile b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Podfile new file mode 100644 index 000000000000..37d20e51d606 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Podfile @@ -0,0 +1,45 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '15.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + + pod 'OCMock', '~> 3.9.1' + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000000..27d1133df09f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,858 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 0DD7B6C32B744EEF00E857FD /* FLTTileProviderControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0DD7B6C22B744EEF00E857FD /* FLTTileProviderControllerTests.m */; }; + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 2A6906C72D263DF4001F8426 /* GoogleMapsGroundOverlayControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */; }; + 2BDE99378062AE3E60B40021 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */; }; + 330909FF2D99B7A60077A751 /* GoogleMapsMarkerControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */; }; + 339355BA2EB3E50300EBF864 /* GoogleMapsCircleControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */; }; + 339355BD2EB3E56300EBF864 /* GoogleMapsTileOverlayControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */; }; + 339355BF2EB535A600EBF864 /* FLTGoogleMapHeatmapControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */; }; + 339DF1F02F1FE49800748863 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339DF1EF2F1FE49300748863 /* AppDelegate.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 478116522BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */; }; + 528F16832C62941000148160 /* FGMClusterManagersControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 528F16822C62941000148160 /* FGMClusterManagersControllerTests.m */; }; + 528F16872C62952700148160 /* ExtractIconFromDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 528F16862C62952700148160 /* ExtractIconFromDataTests.m */; }; + 6851F3562835BC180032B7C8 /* FGMConversionsUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6851F3552835BC180032B7C8 /* FGMConversionsUtilsTests.m */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + 982F2A6C27BADE17003C81F4 /* PartiallyMockedMapView.m in Sources */ = {isa = PBXBuildFile; fileRef = 982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */; }; + B3A7FA04ABB7B84780729949 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 61A9A8623F5CA9BBC813DC6B /* Pods_Runner.framework */; }; + F269303B2BB389BF00BF17C4 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = F269303A2BB389BF00BF17C4 /* assets */; }; + F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */; }; + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + F7151F15265D7ED70028CB91 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; + F7151F23265D7EE50028CB91 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0DD7B6C22B744EEF00E857FD /* FLTTileProviderControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTTileProviderControllerTests.m; sourceTree = ""; }; + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsGroundOverlayControllerTests.m; sourceTree = ""; }; + 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsMarkerControllerTests.m; sourceTree = ""; }; + 339355B82EB3E4D500EBF864 /* GoogleMapsPolygonControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsPolygonControllerTests.m; sourceTree = ""; }; + 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsCircleControllerTests.m; sourceTree = ""; }; + 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsTileOverlayControllerTests.m; sourceTree = ""; }; + 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTGoogleMapHeatmapControllerTests.m; sourceTree = ""; }; + 339DF1EF2F1FE49300748863 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 339DF1F12F1FE4AD00748863 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsPolylineControllerTests.m; sourceTree = ""; }; + 528F16822C62941000148160 /* FGMClusterManagersControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FGMClusterManagersControllerTests.m; sourceTree = ""; }; + 528F16862C62952700148160 /* ExtractIconFromDataTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExtractIconFromDataTests.m; sourceTree = ""; }; + 61A9A8623F5CA9BBC813DC6B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6851F3552835BC180032B7C8 /* FGMConversionsUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FGMConversionsUtilsTests.m; sourceTree = ""; }; + 733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 982F2A6A27BADE17003C81F4 /* PartiallyMockedMapView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PartiallyMockedMapView.h; sourceTree = ""; }; + 982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PartiallyMockedMapView.m; sourceTree = ""; }; + B7AFC65E3DD5AC60D834D83D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + E52C6A6210A56F027C582EF9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + EA0E91726245EDC22B97E8B9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + F269303A2BB389BF00BF17C4 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = ""; }; + F7151F10265D7ED70028CB91 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsTests.m; sourceTree = ""; }; + F7151F14265D7ED70028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F7151F1E265D7EE50028CB91 /* RunnerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsUITests.m; sourceTree = ""; }; + F7151F22265D7EE50028CB91 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + B3A7FA04ABB7B84780729949 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F0D265D7ED70028CB91 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2BDE99378062AE3E60B40021 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F1B265D7EE50028CB91 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1E7CF0857EFC88FC263CF3B2 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 61A9A8623F5CA9BBC813DC6B /* Pods_Runner.framework */, + 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + F7151F11265D7ED70028CB91 /* RunnerTests */, + F7151F1F265D7EE50028CB91 /* RunnerUITests */, + 97C146EF1CF9000F007C117D /* Products */, + A189CFE5474BF8A07908B2E0 /* Pods */, + 1E7CF0857EFC88FC263CF3B2 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + F7151F10265D7ED70028CB91 /* RunnerTests.xctest */, + F7151F1E265D7EE50028CB91 /* RunnerUITests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 339DF1EF2F1FE49300748863 /* AppDelegate.swift */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 339DF1F12F1FE4AD00748863 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + A189CFE5474BF8A07908B2E0 /* Pods */ = { + isa = PBXGroup; + children = ( + B7AFC65E3DD5AC60D834D83D /* Pods-Runner.debug.xcconfig */, + EA0E91726245EDC22B97E8B9 /* Pods-Runner.release.xcconfig */, + E52C6A6210A56F027C582EF9 /* Pods-RunnerTests.debug.xcconfig */, + 733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + F7151F11265D7ED70028CB91 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + F269303A2BB389BF00BF17C4 /* assets */, + 528F16862C62952700148160 /* ExtractIconFromDataTests.m */, + 528F16822C62941000148160 /* FGMClusterManagersControllerTests.m */, + 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */, + 6851F3552835BC180032B7C8 /* FGMConversionsUtilsTests.m */, + 0DD7B6C22B744EEF00E857FD /* FLTTileProviderControllerTests.m */, + F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */, + 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */, + 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */, + 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */, + 339355B82EB3E4D500EBF864 /* GoogleMapsPolygonControllerTests.m */, + 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */, + 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */, + 982F2A6A27BADE17003C81F4 /* PartiallyMockedMapView.h */, + 982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */, + F7151F14265D7ED70028CB91 /* Info.plist */, + ); + path = RunnerTests; + sourceTree = ""; + }; + F7151F1F265D7EE50028CB91 /* RunnerUITests */ = { + isa = PBXGroup; + children = ( + F7151F20265D7EE50028CB91 /* GoogleMapsUITests.m */, + F7151F22265D7EE50028CB91 /* Info.plist */, + ); + path = RunnerUITests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 74BF216DF17B0C7F983459BD /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + BB6BD9A1101E970BEF85B6D2 /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; + F7151F0F265D7ED70028CB91 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = F7151F19265D7ED70028CB91 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + D067548A17DC238B80D2BD12 /* [CP] Check Pods Manifest.lock */, + F7151F0C265D7ED70028CB91 /* Sources */, + F7151F0D265D7ED70028CB91 /* Frameworks */, + F7151F0E265D7ED70028CB91 /* Resources */, + DF182F6A1B9E41DA05BFCB87 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + F7151F16265D7ED70028CB91 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = F7151F10265D7ED70028CB91 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + F7151F1D265D7EE50028CB91 /* RunnerUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = F7151F25265D7EE50028CB91 /* Build configuration list for PBXNativeTarget "RunnerUITests" */; + buildPhases = ( + F7151F1A265D7EE50028CB91 /* Sources */, + F7151F1B265D7EE50028CB91 /* Frameworks */, + F7151F1C265D7EE50028CB91 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + F7151F24265D7EE50028CB91 /* PBXTargetDependency */, + ); + name = RunnerUITests; + productName = RunnerUITests; + productReference = F7151F1E265D7EE50028CB91 /* RunnerUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = "The Flutter Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 2620; + }; + F7151F0F265D7ED70028CB91 = { + CreatedOnToolsVersion = 12.5; + ProvisioningStyle = Automatic; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + F7151F1D265D7EE50028CB91 = { + CreatedOnToolsVersion = 12.5; + ProvisioningStyle = Automatic; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + F7151F0F265D7ED70028CB91 /* RunnerTests */, + F7151F1D265D7EE50028CB91 /* RunnerUITests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F0E265D7ED70028CB91 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F269303B2BB389BF00BF17C4 /* assets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F1C265D7EE50028CB91 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 74BF216DF17B0C7F983459BD /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + BB6BD9A1101E970BEF85B6D2 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/GoogleMaps/GoogleMapsResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/google_maps_flutter_ios_sdk9/google_maps_flutter_ios_sdk9_privacy.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMapsResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/google_maps_flutter_ios_sdk9_privacy.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + D067548A17DC238B80D2BD12 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + DF182F6A1B9E41DA05BFCB87 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-RunnerTests/Pods-RunnerTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 339DF1F02F1FE49800748863 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F0C265D7ED70028CB91 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 528F16832C62941000148160 /* FGMClusterManagersControllerTests.m in Sources */, + 339355BA2EB3E50300EBF864 /* GoogleMapsCircleControllerTests.m in Sources */, + 339355BF2EB535A600EBF864 /* FLTGoogleMapHeatmapControllerTests.m in Sources */, + 339355BD2EB3E56300EBF864 /* GoogleMapsTileOverlayControllerTests.m in Sources */, + F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */, + 6851F3562835BC180032B7C8 /* FGMConversionsUtilsTests.m in Sources */, + 982F2A6C27BADE17003C81F4 /* PartiallyMockedMapView.m in Sources */, + 330909FF2D99B7A60077A751 /* GoogleMapsMarkerControllerTests.m in Sources */, + 478116522BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m in Sources */, + 2A6906C72D263DF4001F8426 /* GoogleMapsGroundOverlayControllerTests.m in Sources */, + 0DD7B6C32B744EEF00E857FD /* FLTTileProviderControllerTests.m in Sources */, + 528F16872C62952700148160 /* ExtractIconFromDataTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F7151F1A265D7EE50028CB91 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F7151F21265D7EE50028CB91 /* GoogleMapsUITests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + F7151F16265D7ED70028CB91 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = F7151F15265D7ED70028CB91 /* PBXContainerItemProxy */; + }; + F7151F24265D7EE50028CB91 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = F7151F23265D7EE50028CB91 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.googleMobileMapsExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.googleMobileMapsExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 6.0; + }; + name = Release; + }; + F7151F17265D7ED70028CB91 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E52C6A6210A56F027C582EF9 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + INFOPLIST_FILE = RunnerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + }; + name = Debug; + }; + F7151F18265D7ED70028CB91 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = i386; + INFOPLIST_FILE = RunnerTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/Runner"; + }; + name = Release; + }; + F7151F26265D7EE50028CB91 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = RunnerUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = Runner; + }; + name = Debug; + }; + F7151F27265D7EE50028CB91 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = RunnerUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_TARGET_NAME = Runner; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F7151F19265D7ED70028CB91 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F7151F17265D7ED70028CB91 /* Debug */, + F7151F18265D7ED70028CB91 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F7151F25265D7EE50028CB91 /* Build configuration list for PBXNativeTarget "RunnerUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F7151F26265D7EE50028CB91 /* Debug */, + F7151F27265D7EE50028CB91 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..919434a6254f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000000..3ea203b77e3b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..21a3cc14c74e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/AppDelegate.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/AppDelegate.swift new file mode 100644 index 000000000000..a382ba8b736e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,21 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import Flutter +import GoogleMaps +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + var mapsApiKey = ProcessInfo.processInfo.environment["MAPS_API_KEY"] ?? "YOUR KEY HERE" + GMSServices.provideAPIKey(mapsApiKey) + + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000000..d36b1fab2d9d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..3d43d11e66f4de3da27ed045ca4fe38ad8b48094 GIT binary patch literal 11112 zcmeHN3sh5A)((b(k1DoWZSj%R+R=^`Y(b;ElB$1^R>iT7q6h&WAVr806i~>Gqn6rM z>3}bMG&oq%DIriqR35=rtEdos5L6z)YC*Xq0U-$_+Il@RaU zXYX%+``hR28`(B*uJ6G9&iz>|)PS%!)9N`7=LcmcxH}k69HPyT-%S zH7+jBCC<%76cg_H-n41cTqnKn`u_V9p~XaTLUe3s{KRPSTeK6apP4Jg%VQ$e#72ms zxyWzmGSRwN?=fRgpx!?W&ZsrLfuhAsRxm%;_|P@3@3~BJwY4ZVBJ3f&$5x>`^fD?d zI+z!v#$!gz%FtL*%mR^Uwa*8LJFZ_;X!y$cD??W#c)31l@ervOa_Qk86R{HJiZb$f z&&&0xYmB{@D@yl~^l5IXtB_ou{xFiYP(Jr<9Ce{jCN z<3Rf2TD%}_N?y>bgWq|{`RKd}n>P4e8Z-D+(fn^4)+|pv$DcR&i+RHNhv$71F*McT zl`phYBlb;wO`b7)*10XF6UXhY9`@UR*6-#(Zp`vyU(__*te6xYtV&N0(zjMtev{tZ zapmGin===teMXjsS0>CYxUy<2izOKOPai0}!B9+6q$s3CF8W{xUwz?A0ADO5&BsiB z{SFt|KehNd-S#eiDq!y&+mW9N_!wH-i~q|oNm=mEzkx}B?Ehe%q$tK8f=QY#*6rH9 zNHHaG(9WBqzP!!TMEktSVuh$i$4A^b25LK}&1*4W?ul*5pZYjL1OZ@X9?3W7Y|T6} z1SXx0Wn-|!A;fZGGlYn9a1Jz5^8)~v#mXhmm>um{QiGG459N}L<&qyD+sy_ixD@AP zW0XV6w#3(JW>TEV}MD=O0O>k5H>p#&|O zD2mGf0Cz7+>l7`NuzGobt;(o@vb9YiOpHN8QJ9Uva|i7R?7nnq;L_iq+ZqPv*oGu! zN@GuJ9fm;yrEFga63m?1qy|5&fd32<%$yP$llh}Udrp>~fb>M>R55I@BsGYhCj8m1 zC=ziFh4@hoytpfrJlr}FsV|C(aV4PZ^8^`G29(+!Bk8APa#PemJqkF zE{IzwPaE)I&r`OxGk*vPErm6sGKaQJ&6FODW$;gAl_4b_j!oH4yE@ zP~Cl4?kp>Ccc~Nm+0kjIb`U0N7}zrQEN5!Ju|}t}LeXi!baZOyhlWha5lq{Ld2rdo zGz7hAJQt<6^cxXTe0xZjmADL85cC&H+~Lt2siIIh{$~+U#&#^{Ub22IA|ea6 z5j12XLc`~dh$$1>3o0Cgvo*ybi$c*z>n=5L&X|>Wy1~eagk;lcEnf^2^2xB=e58Z` z@Rw{1ssK)NRV+2O6c<8qFl%efHE;uy!mq(Xi1P*H2}LMi z3EqWN2U?eW{J$lSFxDJg-=&RH!=6P9!y|S~gmjg)gPKGMxq6r9cNIhW` zS})-obO}Ao_`;=>@fAwU&=|5$J;?~!s4LN2&XiMXEl>zk9M}tVEg#kkIkbKp%Ig2QJ2aCILCM1E=aN*iuz>;q#T_I7aVM=E4$m_#OWLnXQnFUnu?~(X>$@NP zBJ@Zw>@bmErSuW7SR2=6535wh-R`WZ+5dLqwTvw}Ks8~4F#hh0$Qn^l-z=;>D~St( z-1yEjCCgd*z5qXa*bJ7H2Tk54KiX&=Vd}z?%dcc z`N8oeYUKe17&|B5A-++RHh8WQ%;gN{vf%05@jZF%wn1Z_yk#M~Cn(i@MB_mpcbLj5 zR#QAtC`k=tZ*h|){Mjz`7bNL zGWOW=bjQhX@`Vw^xn#cVwn28c2D9vOb0TLLy~-?-%gOyHSeJ9a>P}5OF5$n}k-pvUa*pvLw)KvG~>QjNWS3LY1f*OkFwPZ5qC@+3^Bt=HZbf`alKY#{pn zdY}NEIgo1sd)^TPxVzO{uvU$|Z-jkK0p1x##LexgQ$zx1^bNPOG*u2RmZkIM!zFVz zz|IsP3I?qrlmjGS2w_(azCvGTnf~flqogV@Q%mH{76uLU(>UB zQZ?*ys3BO&TV{Pj_qEa-hkH7mOMe_Bnu3%CXCgu90XNKf$N)PUc3Ei-&~@tT zI^49Lm^+=TrI=h4h=W@jW{GjWd{_kVuSzAL6Pi@HKYYnnNbtcYdIRww+jY$(30=#p8*if(mzbvau z00#}4Qf+gH&ce_&8y3Z@CZV>b%&Zr7xuPSSqOmoaP@arwPrMx^jQBQQi>YvBUdpBn zI``MZ3I3HLqp)@vk^E|~)zw$0$VI_RPsL9u(kqulmS`tnb%4U)hm{)h@bG*jw@Y*#MX;Th1wu3TrO}Srn_+YWYesEgkO1 zv?P8uWB)is;#&=xBBLf+y5e4?%y>_8$1KwkAJ8UcW|0CIz89{LydfJKr^RF=JFPi}MAv|ecbuZ!YcTSxsD$(Pr#W*oytl?@+2 zXBFb32Kf_G3~EgOS7C`8w!tx}DcCT%+#qa76VSbnHo;4(oJ7)}mm?b5V65ir`7Z}s zR2)m15b#E}z_2@rf34wo!M^CnVoi# ze+S(IK({C6u=Sm{1>F~?)8t&fZpOOPcby;I3jO;7^xmLKM(<%i-nyj9mgw9F1Lq4|DZUHZ4)V9&6fQM(ZxbG{h+}(koiTu`SQw6#6q2Yg z-d+1+MRp$zYT2neIR2cKij2!R;C~ooQ3<;^8)_Gch&ZyEtiQwmF0Mb_)6)4lVEBF< zklXS7hvtu30uJR`3OzcqUNOdYsfrKSGkIQAk|4=&#ggxdU4^Y(;)$8}fQ>lTgQdJ{ zzie8+1$3@E;|a`kzuFh9Se}%RHTmBg)h$eH;gttjL_)pO^10?!bNev6{mLMaQpY<< z7M^ZXrg>tw;vU@9H=khbff?@nu)Yw4G% zGxobPTUR2p_ed7Lvx?dkrN^>Cv$Axuwk;Wj{5Z@#$sK@f4{7SHg%2bpcS{(~s;L(mz@9r$cK@m~ef&vf%1@ z@8&@LLO2lQso|bJD6}+_L1*D^}>oqg~$NipL>QlP3 zM#ATSy@ycMkKs5-0X8nFAtMhO_=$DlWR+@EaZ}`YduRD4A2@!at3NYRHmlENea9IF zN*s>mi?zy*Vv+F+&4-o`Wj}P3mLGM*&M(z|;?d82>hQkkY?e-hJ47mWOLCPL*MO04 z3lE(n2RM=IIo;Z?I=sKJ_h=iJHbQ2<}WW0b@I6Qf-{T=Qn#@N0yG5xH&ofEy^mZMPzd22nR`t!Q)VkNgf*VOxE z$XhOunG3ZN#`Ks$Hp~}`OX5vmHP={GYUJ+-g0%PS$*Qi5+-40M47zJ24vK1#? zb$s^%r?+>#lw$mpZaMa1aO%wlPm3~cno_(S%U&-R;6eK(@`CjswAW2)HfZ>ptItaZ|XqQ z&sHVVL>WCe|E4iPb2~gS5ITs6xfg(kmt&3$YcI=zTuqj37t|+9ojCr(G^ul#p{>k) zM94pI>~5VZ$!*Qurq<@RIXgP3sx-2kL$1Q~da%rnNIh?)&+c~*&e~CYPDhPYjb+Xu zKg5w^XB3(_9{Waa4E(-J-Kq_u6t_k?a8kEHqai-N-4#`SRerO!h}!cS%SMC<)tGix zOzVP^_t!HN&HIPL-ZpcgWitHM&yFRC7!k4zSI+-<_uQ}|tX)n{Ib;X>Xx>i_d*KkH zCzogKQFpP1408_2!ofU|iBq2R8hW6G zuqJs9Tyw{u%-uWczPLkM!MfKfflt+NK9Vk8E!C>AsJwNDRoe2~cL+UvqNP|5J8t)( z0$iMa!jhudJ+fqFn+um&@Oj6qXJd_3-l`S^I1#0fnt!z3?D*hAHr*u(*wR@`4O z#avrtg%s`Fh{?$FtBFM^$@@hW!8ZfF4;=n0<8In&X}-Rp=cd0TqT_ne46$j^r}FzE z26vX^!PzScuQfFfl1HEZ{zL?G88mcc76zHGizWiykBf4m83Z${So-+dZ~YGhm*RO7 zB1gdIdqnFi?qw+lPRFW5?}CQ3Me3G^muvll&4iN+*5#_mmIu;loULMwb4lu9U*dFM z-Sr**(0Ei~u=$3<6>C-G6z4_LNCx||6YtjS)<;hf)YJTPKXW+w%hhCTUAInIse9>r zl2YU6nRb$u-FJlWN*{{%sm_gi_UP5{=?5}5^D2vPzM=oPfNw~azZQ#P zl5z8RtSSiTIpEohC15i-Q1Bk{3&ElsD0uGAOxvbk29VUDmmA0w;^v`W#0`};O3DVE z&+-ca*`YcN%z*#VXWK9Qa-OEME#fykF%|7o=1Y+eF;Rtv0W4~kKRDx9YBHOWhC%^I z$Jec0cC7o37}Xt}cu)NH5R}NT+=2Nap*`^%O)vz?+{PV<2~qX%TzdJOGeKj5_QjqR&a3*K@= P-1+_A+?hGkL;m(J7kc&K literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..28c6bf03016f6c994b70f38d1b7346e5831b531f GIT binary patch literal 564 zcmV-40?Yl0P)Px$?ny*JR5%f>l)FnDQ543{x%ZCiu33$Wg!pQFfT_}?5Q|_VSlIbLC`dpoMXL}9 zHfd9&47Mo(7D231gb+kjFxZHS4-m~7WurTH&doVX2KI5sU4v(sJ1@T9eCIKPjsqSr z)C01LsCxk=72-vXmX}CQD#BD;Cthymh&~=f$Q8nn0J<}ZrusBy4PvRNE}+1ceuj8u z0mW5k8fmgeLnTbWHGwfKA3@PdZxhn|PypR&^p?weGftrtCbjF#+zk_5BJh7;0`#Wr zgDpM_;Ax{jO##IrT`Oz;MvfwGfV$zD#c2xckpcXC6oou4ML~ezCc2EtnsQTB4tWNg z?4bkf;hG7IMfhgNI(FV5Gs4|*GyMTIY0$B=_*mso9Ityq$m^S>15>-?0(zQ<8Qy<_TjHE33(?_M8oaM zyc;NxzRVK@DL6RJnX%U^xW0Gpg(lXp(!uK1v0YgHjs^ZXSQ|m#lV7ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..f091b6b0bca859a3f474b03065bef75ba58a9e4c GIT binary patch literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0ef06e7edb86cdfe0d15b4b0d98334a86163658 GIT binary patch literal 1716 zcmds$`#;kQ7{|XelZftyR5~xW7?MLxS4^|Hw3&P7^y)@A9Fj{Xm1~_CIV^XZ%SLBn zA;!r`GqGHg=7>xrB{?psZQs88ZaedDoagm^KF{a*>G|dJWRSe^I$DNW008I^+;Kjt z>9p3GNR^I;v>5_`+91i(*G;u5|L+Bu6M=(afLjtkya#yZ175|z$pU~>2#^Z_pCZ7o z1c6UNcv2B3?; zX%qdxCXQpdKRz=#b*q0P%b&o)5ZrNZt7$fiETSK_VaY=mb4GK`#~0K#~9^ zcY!`#Af+4h?UMR-gMKOmpuYeN5P*RKF!(tb`)oe0j2BH1l?=>y#S5pMqkx6i{*=V9JF%>N8`ewGhRE(|WohnD59R^$_36{4>S zDFlPC5|k?;SPsDo87!B{6*7eqmMdU|QZ84>6)Kd9wNfh90=y=TFQay-0__>=<4pk& zYDjgIhL-jQ9o>z32K)BgAH+HxamL{ZL~ozu)Qqe@a`FpH=oQRA8=L-m-1dam(Ix2V z?du;LdMO+ooBelr^_y4{|44tmgH^2hSzPFd;U^!1p>6d|o)(-01z{i&Kj@)z-yfWQ)V#3Uo!_U}q3u`(fOs`_f^ueFii1xBNUB z6MecwJN$CqV&vhc+)b(p4NzGGEgwWNs z@*lUV6LaduZH)4_g!cE<2G6#+hJrWd5(|p1Z;YJ7ifVHv+n49btR}dq?HHDjl{m$T z!jLZcGkb&XS2OG~u%&R$(X+Z`CWec%QKt>NGYvd5g20)PU(dOn^7%@6kQb}C(%=vr z{?RP(z~C9DPnL{q^@pVw@|Vx~@3v!9dCaBtbh2EdtoNHm4kGxp>i#ct)7p|$QJs+U z-a3qtcPvhihub?wnJqEt>zC@)2suY?%-96cYCm$Q8R%-8$PZYsx3~QOLMDf(piXMm zB=<63yQk1AdOz#-qsEDX>>c)EES%$owHKue;?B3)8aRd}m~_)>SL3h2(9X;|+2#7X z+#2)NpD%qJvCQ0a-uzZLmz*ms+l*N}w)3LRQ*6>|Ub-fyptY(keUxw+)jfwF5K{L9 z|Cl_w=`!l_o><384d&?)$6Nh(GAm=4p_;{qVn#hI8lqewW7~wUlyBM-4Z|)cZr?Rh z=xZ&Ol>4(CU85ea(CZ^aO@2N18K>ftl8>2MqetAR53_JA>Fal`^)1Y--Am~UDa4th zKfCYpcXky$XSFDWBMIl(q=Mxj$iMBX=|j9P)^fDmF(5(5$|?Cx}DKEJa&XZP%OyE`*GvvYQ4PV&!g2|L^Q z?YG}tx;sY@GzMmsY`7r$P+F_YLz)(e}% zyakqFB<6|x9R#TdoP{R$>o7y(-`$$p0NxJ6?2B8tH)4^yF(WhqGZlM3=9Ibs$%U1w zWzcss*_c0=v_+^bfb`kBFsI`d;ElwiU%frgRB%qBjn@!0U2zZehBn|{%uNIKBA7n= zzE`nnwTP85{g;8AkYxA68>#muXa!G>xH22D1I*SiD~7C?7Za+9y7j1SHiuSkKK*^O zsZ==KO(Ua#?YUpXl{ViynyT#Hzk=}5X$e04O@fsMQjb}EMuPWFO0e&8(2N(29$@Vd zn1h8Yd>6z(*p^E{c(L0Lg=wVdupg!z@WG;E0k|4a%s7Up5C0c)55XVK*|x9RQeZ1J@1v9MX;>n34(i>=YE@Iur`0Vah(inE3VUFZNqf~tSz{1fz3Fsn_x4F>o(Yo;kpqvBe-sbwH(*Y zu$JOl0b83zu$JMvy<#oH^Wl>aWL*?aDwnS0iEAwC?DK@aT)GHRLhnz2WCvf3Ba;o=aY7 z2{Asu5MEjGOY4O#Ggz@@J;q*0`kd2n8I3BeNuMmYZf{}pg=jTdTCrIIYuW~luKecn z+E-pHY%ohj@uS0%^ z&(OxwPFPD$+#~`H?fMvi9geVLci(`K?Kj|w{rZ9JgthFHV+=6vMbK~0)Ea<&WY-NC zy-PnZft_k2tfeQ*SuC=nUj4H%SQ&Y$gbH4#2sT0cU0SdFs=*W*4hKGpuR1{)mV;Qf5pw4? zfiQgy0w3fC*w&Bj#{&=7033qFR*<*61B4f9K%CQvxEn&bsWJ{&winp;FP!KBj=(P6 z4Z_n4L7cS;ao2)ax?Tm|I1pH|uLpDSRVghkA_UtFFuZ0b2#>!8;>-_0ELjQSD-DRd z4im;599VHDZYtnWZGAB25W-e(2VrzEh|etsv2YoP#VbIZ{aFkwPrzJ#JvCvA*mXS& z`}Q^v9(W4GiSs}#s7BaN!WA2bniM$0J(#;MR>uIJ^uvgD3GS^%*ikdW6-!VFUU?JV zZc2)4cMsX@j z5HQ^e3BUzOdm}yC-xA%SY``k$rbfk z;CHqifhU*jfGM@DkYCecD9vl*qr58l6x<8URB=&%{!Cu3RO*MrKZ4VO}V6R0a zZw3Eg^0iKWM1dcTYZ0>N899=r6?+adUiBKPciJw}L$=1f4cs^bio&cr9baLF>6#BM z(F}EXe-`F=f_@`A7+Q&|QaZ??Txp_dB#lg!NH=t3$G8&06MFhwR=Iu*Im0s_b2B@| znW>X}sy~m#EW)&6E&!*0%}8UAS)wjt+A(io#wGI@Z2S+Ms1Cxl%YVE800007ip7{`C_J2TxPmfw%h$|%acrYHt)Re^PB%O&&=~a zhS(%I#+V>J-vjIib^<+s%ludY7y^C(P8nmqn9fp!i+?vr`bziDE=bx`%2W#Xyrj|i z!XQ4v1%L`m{7KT7q+LZNB^h8Ha2e=`Wp65^0;J00)_^G=au=8Yo;1b`CV&@#=jIBo zjN^JNVfYSs)+kDdGe7`1&8!?MQYKS?DuHZf3iogk_%#9E|5S zWeHrmAo>P;ejX7mwq#*}W25m^ZI+{(Z8fI?4jM_fffY0nok=+88^|*_DwcW>mR#e+ zX$F_KMdb6sRz!~7KkyN0G(3XQ+;z3X%PZ4gh;n-%62U<*VUKNv(D&Q->Na@Xb&u5Q3`3DGf+a8O5x7c#7+R+EAYl@R5us)CIw z7sT@_y~Ao@uL#&^LIh&QceqiT^+lb0YbFZt_SHOtWA%mgPEKVNvVgCsXy{5+zl*X8 zCJe)Q@y>wH^>l4;h1l^Y*9%-23TSmE>q5nI@?mt%n;Sj4Qq`Z+ib)a*a^cJc%E9^J zB;4s+K@rARbcBLT5P=@r;IVnBMKvT*)ew*R;&8vu%?Z&S>s?8?)3*YawM0P4!q$Kv zMmKh3lgE~&w&v%wVzH3Oe=jeNT=n@Y6J6TdHWTjXfX~-=1A1Bw`EW8rn}MqeI34nh zexFeA?&C3B2(E?0{drE@DA2pu(A#ElY&6el60Rn|Qpn-FkfQ8M93AfWIr)drgDFEU zghdWK)^71EWCP(@(=c4kfH1Y(4iugD4fve6;nSUpLT%!)MUHs1!zJYy4y||C+SwQ! z)KM&$7_tyM`sljP2fz6&Z;jxRn{Wup8IOUx8D4uh&(=O zx-7$a;U><*5L^!%xRlw)vAbh;sdlR||& ze}8_8%)c2Fwy=F&H|LM+p{pZB5DKTx>Y?F1N%BlZkXf!}JeGuMZk~LPi7{cidvUGB zAJ4LVeNV%XO>LTrklB#^-;8nb;}6l;1oW&WS=Mz*Az!4cqqQzbOSFq`$Q%PfD7srM zpKgP-D_0XPTRX*hAqeq0TDkJ;5HB1%$3Np)99#16c{ zJImlNL(npL!W|Gr_kxl1GVmF5&^$^YherS7+~q$p zt}{a=*RiD2Ikv6o=IM1kgc7zqpaZ;OB)P!1zz*i3{U()Dq#jG)egvK}@uFLa`oyWZ zf~=MV)|yJn`M^$N%ul5);JuQvaU1r2wt(}J_Qgyy`qWQI`hEeRX0uC@c1(dQ2}=U$ tNIIaX+dr)NRWXcxoR{>fqI{SF_dm1Ylv~=3YHI)h002ovPDHLkV1g(pWS;;4 literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c8f9ed8f5cee1c98386d13b17e89f719e83555b2 GIT binary patch literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d6b8609df07bf62e5100a53a01510388bd2b22 GIT binary patch literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b2d164a5a98e212cca15ea7bf2ab5de5108680 GIT binary patch literal 3831 zcmVjJBgitF5mAp-i>4+KS_oR{|13AP->1TD4=w)g|)JHOx|a2Wk1Va z!k)vP$UcQ#mdj%wNQoaJ!w>jv_6&JPyutpQps?s5dmDQ>`%?Bvj>o<%kYG!YW6H-z zu`g$@mp`;qDR!51QaS}|ZToSuAGcJ7$2HF0z`ln4t!#Yg46>;vGG9N9{V@9z#}6v* zfP?}r6b{*-C*)(S>NECI_E~{QYzN5SXRmVnP<=gzP+_Sp(Aza_hKlZ{C1D&l*(7IKXxQC1Z9#6wx}YrGcn~g%;icdw>T0Rf^w0{ z$_wn1J+C0@!jCV<%Go5LA45e{5gY9PvZp8uM$=1}XDI+9m7!A95L>q>>oe0$nC->i zeexUIvq%Uk<-$>DiDb?!In)lAmtuMWxvWlk`2>4lNuhSsjAf2*2tjT`y;@d}($o)S zn(+W&hJ1p0xy@oxP%AM15->wPLp{H!k)BdBD$toBpJh+crWdsNV)qsHaqLg2_s|Ih z`8E9z{E3sA!}5aKu?T!#enD(wLw?IT?k-yWVHZ8Akz4k5(TZJN^zZgm&zM28sfTD2BYJ|Fde3Xzh;;S` z=GXTnY4Xc)8nYoz6&vF;P7{xRF-{|2Xs5>a5)@BrnQ}I(_x7Cgpx#5&Td^4Q9_FnQ zX5so*;#8-J8#c$OlA&JyPp$LKUhC~-e~Ij!L%uSMu!-VZG7Hx-L{m2DVR2i=GR(_% zCVD!4N`I)&Q5S`?P&fQZ=4#Dgt_v2-DzkT}K(9gF0L(owe-Id$Rc2qZVLqI_M_DyO z9@LC#U28_LU{;wGZ&))}0R2P4MhajKCd^K#D+JJ&JIXZ_p#@+7J9A&P<0kdRujtQ_ zOy>3=C$kgi6$0pW06KaLz!21oOryKM3ZUOWqppndxfH}QpgjEJ`j7Tzn5bk6K&@RA?vl##y z$?V~1E(!wB5rH`>3nc&@)|#<1dN2cMzzm=PGhQ|Yppne(C-Vlt450IXc`J4R0W@I7 zd1e5uW6juvO%ni(WX7BsKx3MLngO7rHO;^R5I~0^nE^9^E_eYLgiR9&KnJ)pBbfno zSVnW$0R+&6jOOsZ82}nJ126+c|%svPo;TeUku<2G7%?$oft zyaO;tVo}(W)VsTUhq^XmFi#2z%-W9a{7mXn{uzivYQ_d6b7VJG{77naW(vHt-uhnY zVN#d!JTqVh(7r-lhtXVU6o})aZbDt_;&wJVGl2FKYFBFpU-#9U)z#(A%=IVnqytR$SY-sO( z($oNE09{D^@OuYPz&w~?9>Fl5`g9u&ecFGhqX=^#fmR=we0CJw+5xna*@oHnkahk+ z9aWeE3v|An+O5%?4fA&$Fgu~H_YmqR!yIU!bFCk4!#pAj%(lI(A5n)n@Id#M)O9Yx zJU9oKy{sRAIV3=5>(s8n{8ryJ!;ho}%pn6hZKTKbqk=&m=f*UnK$zW3YQP*)pw$O* zIfLA^!-bmBl6%d_n$#tP8Zd_(XdA*z*WH|E_yILwjtI~;jK#v-6jMl^?<%Y%`gvpwv&cFb$||^v4D&V=aNy?NGo620jL3VZnA%s zH~I|qPzB~e(;p;b^gJr7Ure#7?8%F0m4vzzPy^^(q4q1OdthF}Fi*RmVZN1OwTsAP zn9CZP`FazX3^kG(KodIZ=Kty8DLTy--UKfa1$6XugS zk%6v$Kmxt6U!YMx0JQ)0qX*{CXwZZk$vEROidEc7=J-1;peNat!vS<3P-FT5po>iE z!l3R+<`#x|+_hw!HjQGV=8!q|76y8L7N8gP3$%0kfush|u0uU^?dKBaeRSBUpOZ0c z62;D&Mdn2}N}xHRFTRI?zRv=>=AjHgH}`2k4WK=#AHB)UFrR-J87GgX*x5fL^W2#d z=(%K8-oZfMO=i{aWRDg=FX}UubM4eotRDcn;OR#{3q=*?3mE3_oJ-~prjhxh%PgQT zyn)Qozaq0@o&|LEgS{Ind4Swsr;b`u185hZPOBLL<`d2%^Yp1?oL)=jnLi;Zo0ZDliTtQ^b5SmfIMe{T==zZkbvn$KTQGlbG8w}s@M3TZnde;1Am46P3juKb zl9GU&3F=q`>j!`?SyH#r@O59%@aMX^rx}Nxe<>NqpUp5=lX1ojGDIR*-D^SDuvCKF z?3$xG(gVUsBERef_YjPFl^rU9EtD{pt z0CXwpN7BN3!8>hajGaTVk-wl=9rxmfWtIhC{mheHgStLi^+Nz12a?4r(fz)?3A%at zMlvQmL<2-R)-@G1wJ0^zQK%mR=r4d{Y3fHp){nWXUL#|CqXl(+v+qDh>FkF9`eWrW zfr^D%LNfOcTNvtx0JXR35J0~Jpi2#P3Q&80w+nqNfc}&G0A~*)lGHKv=^FE+b(37|)zL;KLF>oiGfb(?&1 zV3XRu!Sw>@quKiab%g6jun#oZ%!>V#A%+lNc?q>6+VvyAn=kf_6z^(TZUa4Eelh{{ zqFX-#dY(EV@7l$NE&kv9u9BR8&Ojd#ZGJ6l8_BW}^r?DIS_rU2(XaGOK z225E@kH5Opf+CgD^{y29jD4gHbGf{1MD6ggQ&%>UG4WyPh5q_tb`{@_34B?xfSO*| zZv8!)q;^o-bz`MuxXk*G^}(6)ACb@=Lfs`Hxoh>`Y0NE8QRQ!*p|SH@{r8=%RKd4p z+#Ty^-0kb=-H-O`nAA3_6>2z(D=~Tbs(n8LHxD0`R0_ATFqp-SdY3(bZ3;VUM?J=O zKCNsxsgt@|&nKMC=*+ZqmLHhX1KHbAJs{nGVMs6~TiF%Q)P@>!koa$%oS zjXa=!5>P`vC-a}ln!uH1ooeI&v?=?v7?1n~P(wZ~0>xWxd_Aw;+}9#eULM7M8&E?Y zC-ZLhi3RoM92SXUb-5i-Lmt5_rfjE{6y^+24`y$1lywLyHO!)Boa7438K4#iLe?rh z2O~YGSgFUBH?og*6=r9rme=peP~ah`(8Zt7V)j5!V0KPFf_mebo3z95U8(up$-+EA^9dTRLq>Yl)YMBuch9%=e5B`Vnb>o zt03=kq;k2TgGe4|lGne&zJa~h(UGutjP_zr?a7~#b)@15XNA>Dj(m=gg2Q5V4-$)D|Q9}R#002ovPDHLkV1o7DH3k3x literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..c4df70d39da7941ef3f6dcb7f06a192d8dcb308d GIT binary patch literal 1888 zcmV-m2cP(fP)x~L`~4d)Rspd&<9kFh{hn*KP1LP0~$;u(LfAu zp%fx&qLBcRHx$G|3q(bv@+b;o0*D|jwD-Q9uQR(l*ST}s+uPgQ-MeFwZ#GS?b332? z&Tk$&_miXn3IGq)AmQ)3sisq{raD4(k*bHvpCe-TdWq^NRTEVM)i9xbgQ&ccnUVx* zEY%vS%gDcSg=!tuIK8$Th2_((_h^+7;R|G{n06&O2#6%LK`a}n?h_fL18btz<@lFG za}xS}u?#DBMB> zw^b($1Z)`9G?eP95EKi&$eOy@K%h;ryrR3la%;>|o*>CgB(s>dDcNOXg}CK9SPmD? zmr-s{0wRmxUnbDrYfRvnZ@d z6johZ2sMX{YkGSKWd}m|@V7`Degt-43=2M?+jR%8{(H$&MLLmS;-|JxnX2pnz;el1jsvqQz}pGSF<`mqEXRQ5sC4#BbwnB_4` zc5bFE-Gb#JV3tox9fp-vVEN{(tOCpRse`S+@)?%pz+zVJXSooTrNCUg`R6`hxwb{) zC@{O6MKY8tfZ5@!yy=p5Y|#+myRL=^{tc(6YgAnkg3I(Cd!r5l;|;l-MQ8B`;*SCE z{u)uP^C$lOPM z5d~UhKhRRmvv{LIa^|oavk1$QiEApSrP@~Jjbg`<*dW4TO?4qG%a%sTPUFz(QtW5( zM)lA+5)0TvH~aBaOAs|}?u2FO;yc-CZ1gNM1dAxJ?%m?YsGR`}-xk2*dxC}r5j$d* zE!#Vtbo69h>V4V`BL%_&$} z+oJAo@jQ^Tk`;%xw-4G>hhb&)B?##U+(6Fi7nno`C<|#PVA%$Y{}N-?(Gc$1%tr4Pc}}hm~yY#fTOe!@v9s-ik$dX~|ygArPhByaXn8 zpI^FUjNWMsTFKTP3X7m?UK)3m zp6rI^_zxRYrx6_QmhoWoDR`fp4R7gu6;gdO)!KexaoO2D88F9x#TM1(9Bn7g;|?|o z)~$n&Lh#hCP6_LOPD>a)NmhW})LADx2kq=X7}7wYRj-0?dXr&bHaRWCfSqvzFa=sn z-8^gSyn-RmH=BZ{AJZ~!8n5621GbUJV7Qvs%JNv&$%Q17s_X%s-41vAPfIR>;x0Wlqr5?09S>x#%Qkt>?(&XjFRY}*L6BeQ3 z<6XEBh^S7>AbwGm@XP{RkeEKj6@_o%oV?hDuUpUJ+r#JZO?!IUc;r0R?>mi)*ZpQ) z#((dn=A#i_&EQn|hd)N$#A*fjBFuiHcYvo?@y1 z5|fV=a^a~d!c-%ZbMNqkMKiSzM{Yq=7_c&1H!mXk60Uv32dV;vMg&-kQ)Q{+PFtwc zj|-uQ;b^gts??J*9VxxOro}W~Q9j4Em|zSRv)(WSO9$F$s=Ydu%Q+5DOid~lwk&we zY%W(Z@ofdwPHncEZzZgmqS|!gTj3wQq9rxQy+^eNYKr1mj&?tm@wkO*9@UtnRMG>c aR{jt9+;fr}hV%pg00001^@s67{VYS000c7NklQEG_j zup^)eW&WUIApqy$=APz8jE@awGp)!bsTjDbrJO`$x^ZR^dr;>)LW>{ zs70vpsD38v)19rI=GNk1b(0?Js9~rjsQsu*K;@SD40RB-3^gKU-MYC7G!Bw{fZsqp zih4iIi;Hr_xZ033Iu{sQxLS=}yBXgLMn40d++>aQ0#%8D1EbGZp7+ z5=mK?t31BkVYbGOxE9`i748x`YgCMwL$qMsChbSGSE1`p{nSmadR zcQ#R)(?!~dmtD0+D2!K zR9%!Xp1oOJzm(vbLvT^$IKp@+W2=-}qTzTgVtQ!#Y7Gxz}stUIm<1;oBQ^Sh2X{F4ibaOOx;5ZGSNK z0maF^@(UtV$=p6DXLgRURwF95C=|U8?osGhgOED*b z7woJ_PWXBD>V-NjQAm{~T%sjyJ{5tn2f{G%?J!KRSrrGvQ1(^`YLA5B!~eycY(e5_ z*%aa{at13SxC(=7JT7$IQF~R3sy`Nn%EMv!$-8ZEAryB*yB1k&stni)=)8-ODo41g zkJu~roIgAih94tb=YsL%iH5@^b~kU9M-=aqgXIrbtxMpFy5mekFm#edF9z7RQ6V}R zBIhbXs~pMzt0VWy1Fi$^fh+1xxLDoK09&5&MJl(q#THjPm(0=z2H2Yfm^a&E)V+a5 zbi>08u;bJsDRUKR9(INSc7XyuWv(JsD+BB*0hS)FO&l&7MdViuur@-<-EHw>kHRGY zqoT}3fDv2-m{NhBG8X}+rgOEZ;amh*DqN?jEfQdqxdj08`Sr=C-KmT)qU1 z+9Cl)a1mgXxhQiHVB}l`m;-RpmKy?0*|yl?FXvJkFxuu!fKlcmz$kN(a}i*saM3nr z0!;a~_%Xqy24IxA2rz<+08=B-Q|2PT)O4;EaxP^6qixOv7-cRh?*T?zZU`{nIM-at zTKYWr9rJ=tppQ9I#Z#mLgINVB!pO-^FOcvFw6NhV0gztuO?g ztoA*C-52Q-Z-P#xB4HAY3KQVd%dz1S4PA3vHp0aa=zAO?FCt zC_GaTyVBg2F!bBr3U@Zy2iJgIAt>1sf$JWA9kh{;L+P*HfUBX1Zy{4MgNbDfBV_ly z!y#+753arsZUt@366jIC0klaC@ckuk!qu=pAyf7&QmiBUT^L1&tOHzsK)4n|pmrVT zs2($4=?s~VejTFHbFdDOwG;_58LkIj1Fh@{glkO#F1>a==ymJS$z;gdedT1zPx4Kj ztjS`y_C}%af-RtpehdQDt3a<=W5C4$)9W@QAse;WUry$WYmr51ml9lkeunUrE`-3e zmq1SgSOPNEE-Mf+AGJ$g0M;3@w!$Ej;hMh=v=I+Lpz^n%Pg^MgwyqOkNyu2c^of)C z1~ALor3}}+RiF*K4+4{(1%1j3pif1>sv0r^mTZ?5Jd-It!tfPfiG_p$AY*Vfak%FG z4z#;wLtw&E&?}w+eKG^=#jF7HQzr8rV0mY<1YAJ_uGz~$E13p?F^fPSzXSn$8UcI$ z8er9{5w5iv0qf8%70zV71T1IBB1N}R5Kp%NO0=5wJalZt8;xYp;b{1K) zHY>2wW-`Sl{=NpR%iu3(u6l&)rc%%cSA#aV7WCowfbFR4wcc{LQZv~o1u_`}EJA3>ki`?9CKYTA!rhO)if*zRdd}Kn zEPfYbhoVE~!FI_2YbC5qAj1kq;xP6%J8+?2PAs?`V3}nyFVD#sV3+uP`pi}{$l9U^ zSz}_M9f7RgnnRhaoIJgT8us!1aB&4!*vYF07Hp&}L zCRlop0oK4DL@ISz{2_BPlezc;xj2|I z23RlDNpi9LgTG_#(w%cMaS)%N`e>~1&a3<{Xy}>?WbF>OOLuO+j&hc^YohQ$4F&ze z+hwnro1puQjnKm;vFG~o>`kCeUIlkA-2tI?WBKCFLMBY=J{hpSsQ=PDtU$=duS_hq zHpymHt^uuV1q@uc4bFb{MdG*|VoW@15Osrqt2@8ll0qO=j*uOXn{M0UJX#SUztui9FN4)K3{9!y8PC-AHHvpVTU;x|-7P+taAtyglk#rjlH2 z5Gq8ik}BPaGiM{#Woyg;*&N9R2{J0V+WGB69cEtH7F?U~Kbi6ksi*`CFXsi931q7Y zGO82?whBhN%w1iDetv%~wM*Y;E^)@Vl?VDj-f*RX>{;o_=$fU!&KAXbuadYZ46Zbg z&6jMF=49$uL^73y;;N5jaHYv)BTyfh&`qVLYn?`o6BCA_z-0niZz=qPG!vonK3MW_ zo$V96zM!+kJRs{P-5-rQVse0VBH*n6A58)4uc&gfHMa{gIhV2fGf{st>E8sKyP-$8zp~wJX^A*@DI&-;8>gANXZj zU)R+Y)PB?=)a|Kj>8NXEu^S_h^7R`~Q&7*Kn!xyvzVv&^>?^iu;S~R2e-2fJx-oUb cX)(b1KSk$MOV07*qoM6N<$f&6$jw%VRuvdN2+38CZWny1cRtlsl+0_KtW)EU14Ei(F!UtWuj4IK+3{sK@>rh zs1Z;=(DD&U6+tlyL?UnHVN^&g6QhFi2#HS+*qz;(>63G(`|jRtW|nz$Pv7qTovP!^ zP_jES{mr@O-02w%!^a?^1ZP!_KmQiz0L~jZ=W@Qt`8wzOoclQsAS<5YdH;a(4bGLE zk8s}1If(PSIgVi!XE!5kA?~z*sobvNyohr;=Q_@h2@$6Flyej3J)D-6YfheRGl`HEcPk|~huT_2-U?PfL=4BPV)f1o!%rQ!NMt_MYw-5bUSwQ9Z&zC>u zOrl~UJglJNa%f50Ok}?WB{on`Ci`p^Y!xBA?m@rcJXLxtrE0FhRF3d*ir>yzO|BD$ z3V}HpFcCh6bTzY}Nt_(W%QYd3NG)jJ4<`F<1Od) zfQblTdC&h2lCz`>y?>|9o2CdvC8qZeIZt%jN;B7Hdn2l*k4M4MFEtq`q_#5?}c$b$pf_3y{Y!cRDafZBEj-*OD|gz#PBDeu3QoueOesLzB+O zxjf2wvf6Wwz>@AiOo2mO4=TkAV+g~%_n&R;)l#!cBxjuoD$aS-`IIJv7cdX%2{WT7 zOm%5rs(wqyPE^k5SIpUZ!&Lq4<~%{*>_Hu$2|~Xa;iX*tz8~G6O3uFOS?+)tWtdi| zV2b#;zRN!m@H&jd=!$7YY6_}|=!IU@=SjvGDFtL;aCtw06U;-v^0%k0FOyESt z1Wv$={b_H&8FiRV?MrzoHWd>%v6KTRU;-v^Miiz+@q`(BoT!+<37CKhoKb)|8!+RG z6BQFU^@fRW;s8!mOf2QViKQGk0TVER6EG1`#;Nm39Do^PoT!+<37AD!%oJe86(=et zZ~|sLzU>V-qYiU6V8$0GmU7_K8|Fd0B?+9Un1BhKAz#V~Fk^`mJtlCX#{^8^M8!me z8Yg;8-~>!e<-iG;h*0B1kBKm}hItVGY6WnjVpgnTTAC$rqQ^v)4KvOtpY|sIj@WYg zyw##ZZ5AC2IKNC;^hwg9BPk0wLStlmBr;E|$5GoAo$&Ui_;S9WY62n3)i49|T%C#i017z3J=$RF|KyZWnci*@lW4 z=AKhNN6+m`Q!V3Ye68|8y@%=am>YD0nG99M)NWc20%)gwO!96j7muR}Fr&54SxKP2 zP30S~lt=a*qDlbu3+Av57=9v&vr<6g0&`!8E2fq>I|EJGKs}t|{h7+KT@)LfIV-3K zK)r_fr2?}FFyn*MYoLC>oV-J~eavL2ho4a4^r{E-8m2hi>~hA?_vIG4a*KT;2eyl1 zh_hUvUJpNCFwBvRq5BI*srSle>c6%n`#VNsyC|MGa{(P&08p=C9+WUw9Hl<1o9T4M zdD=_C0F7#o8A_bRR?sFNmU0R6tW`ElnF8p53IdHo#S9(JoZCz}fHwJ6F<&?qrpVqE zte|m%89JQD+XwaPU#%#lVs-@-OL);|MdfINd6!XwP2h(eyafTUsoRkA%&@fe?9m@jw-v(yTTiV2(*fthQH9}SqmsRPVnwwbV$1E(_lkmo&S zF-truCU914_$jpqjr(>Ha4HkM4YMT>m~NosUu&UZ>zirfHo%N6PPs9^_o$WqPA0#5 z%tG>qFCL+b*0s?sZ;Sht0nE7Kl>OVXy=gjWxxK;OJ3yGd7-pZf7JYNcZo2*1SF`u6 zHJyRRxGw9mDlOiXqVMsNe#WX`fC`vrtjSQ%KmLcl(lC>ZOQzG^%iql2w-f_K@r?OE zwCICifM#L-HJyc7Gm>Ern?+Sk3&|Khmu4(~3qa$(m6Ub^U0E5RHq49za|XklN#?kP zl;EstdW?(_4D>kwjWy2f!LM)y?F94kyU3`W!6+AyId-89v}sXJpuic^NLL7GJItl~ zsiuB98AI-(#Mnm|=A-R6&2fwJ0JVSY#Q>&3$zFh|@;#%0qeF=j5Ajq@4i0tIIW z&}sk$&fGwoJpe&u-JeGLi^r?dO`m=y(QO{@h zQqAC7$rvz&5+mo3IqE?h=a~6m>%r5Quapvzq;{y~p zJpyXOBgD9VrW7@#p6l7O?o3feml(DtSL>D^R) zZUY%T2b0-vBAFN7VB;M88!~HuOXi4KcI6aRQ&h|XQ0A?m%j2=l1f0cGP}h(oVfJ`N zz#PpmFC*ieab)zJK<4?^k=g%OjPnkANzbAbmGZHoVRk*mTfm75s_cWVa`l*f$B@xu z5E*?&@seIo#*Y~1rBm!7sF9~~u6Wrj5oICUOuz}CS)jdNIznfzCA(stJ(7$c^e5wN z?lt>eYgbA!kvAR7zYSD&*r1$b|(@;9dcZ^67R0 zXAXJKa|5Sdmj!g578Nwt6d$sXuc&MWezA0Whd`94$h{{?1IwXP4)Tx4obDK%xoFZ_Z zjjHJ_P@R_e5blG@yEjnaJb`l;s%Lb2&=8$&Ct-fV`E^4CUs)=jTk!I}2d&n!f@)bm z@ z_4Dc86+3l2*p|~;o-Sb~oXb_RuLmoifDU^&Te$*FevycC0*nE3Xws8gsWp|Rj2>SM zns)qcYj?^2sd8?N!_w~4v+f-HCF|a$TNZDoNl$I1Uq87euoNgKb6&r26TNrfkUa@o zfdiFA@p{K&mH3b8i!lcoz)V{n8Q@g(vR4ns4r6w;K z>1~ecQR0-<^J|Ndg5fvVUM9g;lbu-){#ghGw(fg>L zh)T5Ljb%lWE;V9L!;Cqk>AV1(rULYF07ZBJbGb9qbSoLAd;in9{)95YqX$J43-dY7YU*k~vrM25 zxh5_IqO0LYZW%oxQ5HOzmk4x{atE*vipUk}sh88$b2tn?!ujEHn`tQLe&vo}nMb&{ zio`xzZ&GG6&ZyN3jnaQy#iVqXE9VT(3tWY$n-)uWDQ|tc{`?fq2F`oQ{;d3aWPg4Hp-(iE{ry>MIPWL> iW8Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 000000000000..89c2725b70f1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 000000000000..f2e259c7c939 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Base.lproj/Main.storyboard b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 000000000000..ca2ca3396824 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Info.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Info.plist new file mode 100644 index 000000000000..6783ca935f1d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Info.plist @@ -0,0 +1,53 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + google_maps_flutter_example + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + NSLocationWhenInUseUsageDescription + This app needs your location to test the location feature of the Google Maps plugin. + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Runner-Bridging-Header.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 000000000000..ba04211afd0a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1,5 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GeneratedPluginRegistrant.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/ExtractIconFromDataTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/ExtractIconFromDataTests.m new file mode 100644 index 000000000000..4d7da98cac59 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/ExtractIconFromDataTests.m @@ -0,0 +1,352 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; + +#import +#import + +@interface ExtractIconFromDataTests : XCTestCase +- (UIImage *)createOnePixelImage; +@end + +@implementation ExtractIconFromDataTests + +- (void)testExtractIconFromDataAssetAuto { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testExtractIconFromDataAssetAutoWithScale { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:10 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 10); + XCTAssertEqual(resultImage.size.width, 0.1); + XCTAssertEqual(resultImage.size.height, 0.1); +} + +- (void)testExtractIconFromDataAssetAutoAndSizeWithSameAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + XCTAssertEqual(testImage.scale, 1.0); + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + const CGFloat width = 15.0; + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(testImage.scale, 1.0); + + // As image has same aspect ratio as the original image, + // only image scale has been changed to match the target size. + CGFloat targetScale = testImage.scale * (testImage.size.width / width); + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(resultImage.scale, targetScale, accuracy); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, width); +} + +- (void)testExtractIconFromDataAssetAutoAndSizeWithDifferentAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + const CGFloat width = 15.0; + const CGFloat height = 45.0; + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:@(height)]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, screenScale); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, height); +} + +- (void)testExtractIconFromDataAssetNoScaling { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + id mockImageClass = OCMClassMock([UIImage class]); + UIImage *testImage = [self createOnePixelImage]; + + OCMStub([mockRegistrar lookupKeyForAsset:@"fakeImageNameKey"]).andReturn(@"fakeAssetKey"); + OCMStub(ClassMethod([mockImageClass imageNamed:@"fakeAssetKey"])).andReturn(testImage); + + FGMPlatformBitmapAssetMap *bitmap = + [FGMPlatformBitmapAssetMap makeWithAssetName:@"fakeImageNameKey" + bitmapScaling:FGMPlatformMapBitmapScalingNone + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testExtractIconFromDataBytesAuto { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testExtractIconFromDataBytesAutoWithScaling { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:10 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 10); + XCTAssertEqual(resultImage.size.width, 0.1); + XCTAssertEqual(resultImage.size.height, 0.1); +} + +- (void)testExtractIconFromDataBytesAutoAndSizeWithSameAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + const CGFloat width = 15.0; + const CGFloat height = 15.0; + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:@(height)]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + + XCTAssertNotNil(resultImage); + XCTAssertEqual(testImage.scale, 1.0); + + // As image has same aspect ratio as the original image, + // only image scale has been changed to match the target size. + CGFloat targetScale = testImage.scale * (testImage.size.width / width); + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(resultImage.scale, targetScale, accuracy); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, height); +} + +- (void)testExtractIconFromDataBytesAutoAndSizeWithDifferentAspectRatio { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + const CGFloat width = 15.0; + const CGFloat height = 45.0; + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingAuto + imagePixelRatio:1 + width:@(width) + height:@(height)]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, screenScale); + XCTAssertEqual(resultImage.size.width, width); + XCTAssertEqual(resultImage.size.height, height); +} + +- (void)testExtractIconFromDataBytesNoScaling { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + UIImage *testImage = [self createOnePixelImage]; + NSData *pngData = UIImagePNGRepresentation(testImage); + XCTAssertNotNil(pngData); + + FlutterStandardTypedData *typedData = [FlutterStandardTypedData typedDataWithBytes:pngData]; + FGMPlatformBitmapBytesMap *bitmap = + [FGMPlatformBitmapBytesMap makeWithByteData:typedData + bitmapScaling:FGMPlatformMapBitmapScalingNone + imagePixelRatio:1 + width:nil + height:nil]; + + CGFloat screenScale = 3.0; + + UIImage *resultImage = + FGMIconFromBitmap([FGMPlatformBitmap makeWithBitmap:bitmap], mockRegistrar, screenScale); + XCTAssertNotNil(resultImage); + XCTAssertEqual(resultImage.scale, 1.0); + XCTAssertEqual(resultImage.size.width, 1.0); + XCTAssertEqual(resultImage.size.height, 1.0); +} + +- (void)testIsScalableWithScaleFactorFromSize100x100to10x100 { + CGSize originalSize = CGSizeMake(100.0, 100.0); + CGSize targetSize = CGSizeMake(10.0, 100.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize100x100to10x10 { + CGSize originalSize = CGSizeMake(100.0, 100.0); + CGSize targetSize = CGSizeMake(10.0, 10.0); + XCTAssertTrue(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize233x200to23x20 { + CGSize originalSize = CGSizeMake(233.0, 200.0); + CGSize targetSize = CGSizeMake(23.0, 20.0); + XCTAssertTrue(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize233x200to22x20 { + CGSize originalSize = CGSizeMake(233.0, 200.0); + CGSize targetSize = CGSizeMake(22.0, 20.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize200x233to20x23 { + CGSize originalSize = CGSizeMake(200.0, 233.0); + CGSize targetSize = CGSizeMake(20.0, 23.0); + XCTAssertTrue(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize200x233to20x22 { + CGSize originalSize = CGSizeMake(200.0, 233.0); + CGSize targetSize = CGSizeMake(20.0, 22.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (void)testIsScalableWithScaleFactorFromSize1024x768to500x250 { + CGSize originalSize = CGSizeMake(1024.0, 768.0); + CGSize targetSize = CGSizeMake(500.0, 250.0); + XCTAssertFalse(FGMIsScalableWithScaleFactorFromSize(originalSize, targetSize)); +} + +- (UIImage *)createOnePixelImage { + CGSize size = CGSizeMake(1, 1); + UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat]; + format.scale = 1.0; + format.opaque = YES; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size + format:format]; + UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { + [UIColor.whiteColor setFill]; + [context fillRect:CGRectMake(0, 0, size.width, size.height)]; + }]; + return image; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMClusterManagersControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMClusterManagersControllerTests.m new file mode 100644 index 000000000000..f9baaa10184b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMClusterManagersControllerTests.m @@ -0,0 +1,145 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import +#import "PartiallyMockedMapView.h" + +@interface FGMClusterManagersControllerTests : XCTestCase +@end + +@implementation FGMClusterManagersControllerTests + +- (void)testClustering { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + CGRect frame = CGRectMake(0, 0, 100, 100); + + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + id handler = OCMClassMock([FGMMapsCallbackApi class]); + + FGMClusterManagersController *clusterManagersController = + [[FGMClusterManagersController alloc] initWithMapView:mapView callbackHandler:handler]; + + FLTMarkersController *markersController = + [[FLTMarkersController alloc] initWithMapView:mapView + callbackHandler:handler + clusterManagersController:clusterManagersController + registrar:registrar]; + + // Add cluster managers. + NSString *clusterManagerId = @"cm"; + FGMPlatformClusterManager *clusterManagerToAdd = + [FGMPlatformClusterManager makeWithIdentifier:clusterManagerId]; + [clusterManagersController addClusterManagers:@[ clusterManagerToAdd ]]; + + // Verify that cluster managers are available + GMUClusterManager *clusterManager = + [clusterManagersController clusterManagerWithIdentifier:clusterManagerId]; + XCTAssertNotNil(clusterManager, @"Cluster Manager should not be nil"); + + // Add markers + NSString *markerId1 = @"m1"; + NSString *markerId2 = @"m2"; + + FGMPlatformPoint *zeroPoint = [FGMPlatformPoint makeWithX:0 y:0]; + FGMPlatformLatLng *zeroLatLng = [FGMPlatformLatLng makeWithLatitude:0 longitude:0]; + FGMPlatformBitmap *bitmap = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + FGMPlatformInfoWindow *infoWindow = [FGMPlatformInfoWindow makeWithTitle:@"Info" + snippet:NULL + anchor:zeroPoint]; + FGMPlatformMarker *marker1 = [FGMPlatformMarker makeWithAlpha:1 + anchor:zeroPoint + consumeTapEvents:NO + draggable:NO + flat:NO + icon:bitmap + infoWindow:infoWindow + position:zeroLatLng + rotation:0 + visible:YES + zIndex:1 + markerId:markerId1 + clusterManagerId:clusterManagerId]; + FGMPlatformMarker *marker2 = [FGMPlatformMarker makeWithAlpha:1 + anchor:zeroPoint + consumeTapEvents:NO + draggable:NO + flat:NO + icon:bitmap + infoWindow:infoWindow + position:zeroLatLng + rotation:0 + visible:YES + zIndex:1 + markerId:markerId2 + clusterManagerId:clusterManagerId]; + + [markersController addMarkers:@[ marker1, marker2 ]]; + + FlutterError *error = nil; + + // Invoke clustering + [clusterManagersController invokeClusteringForEachClusterManager]; + + // Verify that the markers were added to the cluster manager + NSArray *clusters1 = + [clusterManagersController clustersWithIdentifier:clusterManagerId error:&error]; + XCTAssertNil(error, @"Error should be nil"); + for (FGMPlatformCluster *cluster in clusters1) { + NSString *cmId = cluster.clusterManagerId; + XCTAssertNotNil(cmId, @"Cluster Manager Identifier should not be nil"); + if ([cmId isEqualToString:clusterManagerId]) { + NSArray *markerIds = cluster.markerIds; + XCTAssertEqual(markerIds.count, 2, @"Cluster should contain two marker"); + XCTAssertTrue([markerIds containsObject:markerId1], @"Cluster should contain markerId1"); + XCTAssertTrue([markerIds containsObject:markerId2], @"Cluster should contain markerId2"); + return; + } + } + + [markersController removeMarkersWithIdentifiers:@[ markerId2 ]]; + + // Verify that the marker2 is removed from the clusterManager + NSArray *clusters2 = + [clusterManagersController clustersWithIdentifier:clusterManagerId error:&error]; + XCTAssertNil(error, @"Error should be nil"); + + for (FGMPlatformCluster *cluster in clusters2) { + NSString *cmId = cluster.clusterManagerId; + XCTAssertNotNil(cmId, @"Cluster Manager ID should not be nil"); + if ([cmId isEqualToString:clusterManagerId]) { + NSArray *markerIds = cluster.markerIds; + XCTAssertEqual(markerIds.count, 1, @"Cluster should contain one marker"); + XCTAssertTrue([markerIds containsObject:markerId1], @"Cluster should contain markerId1"); + return; + } + } + + [markersController removeMarkersWithIdentifiers:@[ markerId1 ]]; + + // Verify that all markers are removed from clusterManager + NSArray *clusters3 = + [clusterManagersController clustersWithIdentifier:clusterManagerId error:&error]; + XCTAssertNil(error, @"Error should be nil"); + XCTAssertEqual(clusters3.count, 0, @"Cluster Manager should not contain any clusters"); + + // Remove cluster manager + [clusterManagersController removeClusterManagersWithIdentifiers:@[ clusterManagerId ]]; + + // Verify that the cluster manager is removed + clusterManager = [clusterManagersController clusterManagerWithIdentifier:clusterManagerId]; + XCTAssertNil(clusterManager, @"Cluster Manager should be nil"); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMConversionsUtilsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMConversionsUtilsTests.m new file mode 100644 index 000000000000..ea39943cf571 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMConversionsUtilsTests.m @@ -0,0 +1,429 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +@interface FGMConversionUtilsTests : XCTestCase +@end + +@implementation FGMConversionUtilsTests + +- (void)testGetValueOrNilWithValue { + NSString *key = @"key"; + NSString *value = @"value"; + NSDictionary *dict = @{key : value}; + + XCTAssertEqual(FGMGetValueOrNilFromDict(dict, key), value); +} + +- (void)testGetValueOrNilWithNoEntry { + NSString *key = @"key"; + NSDictionary *dict = @{}; + + XCTAssertNil(FGMGetValueOrNilFromDict(dict, key)); +} + +- (void)testGetValueOrNilWithNSNull { + NSString *key = @"key"; + NSDictionary *dict = @{key : [NSNull null]}; + + XCTAssertNil(FGMGetValueOrNilFromDict(dict, key)); +} + +- (void)testColorFromPlatformColor { + double platformRed = 1 / 255.0; + double platformGreen = 2 / 255.0; + double platformBlue = 3 / 255.0; + double platformAlpha = 4 / 255.0; + UIColor *color = FGMGetColorForPigeonColor([FGMPlatformColor makeWithRed:platformRed + green:platformGreen + blue:platformBlue + alpha:platformAlpha]); + CGFloat red, green, blue, alpha; + BOOL success = [color getRed:&red green:&green blue:&blue alpha:&alpha]; + XCTAssertTrue(success); + const CGFloat accuracy = 0.0001; + XCTAssertEqualWithAccuracy(red, platformRed, accuracy); + XCTAssertEqualWithAccuracy(green, platformGreen, accuracy); + XCTAssertEqualWithAccuracy(blue, platformBlue, accuracy); + XCTAssertEqualWithAccuracy(alpha, platformAlpha, accuracy); +} + +- (void)testPlatformColorFromColor { + double red = 1 / 255.0; + double green = 2 / 255.0; + double blue = 3 / 255.0; + double alpha = 4 / 255.0; + UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; + FGMPlatformColor *platformColor = FGMGetPigeonColorForColor(color); + const CGFloat accuracy = 0.0001; + XCTAssertEqualWithAccuracy(red, platformColor.red, accuracy); + XCTAssertEqualWithAccuracy(green, platformColor.green, accuracy); + XCTAssertEqualWithAccuracy(blue, platformColor.blue, accuracy); + XCTAssertEqualWithAccuracy(alpha, platformColor.alpha, accuracy); +} + +- (void)testPointsFromLatLongs { + NSArray *latlongs = @[ + [FGMPlatformLatLng makeWithLatitude:1 longitude:2], [FGMPlatformLatLng makeWithLatitude:3 + longitude:4] + ]; + NSArray *locations = FGMGetPointsForPigeonLatLngs(latlongs); + XCTAssertEqual(locations.count, 2); + XCTAssertEqual(locations[0].coordinate.latitude, 1); + XCTAssertEqual(locations[0].coordinate.longitude, 2); + XCTAssertEqual(locations[1].coordinate.latitude, 3); + XCTAssertEqual(locations[1].coordinate.longitude, 4); +} + +- (void)testHolesFromPointsArray { + NSArray *> *pointsArray = @[ + @[ + [FGMPlatformLatLng makeWithLatitude:1 longitude:2], [FGMPlatformLatLng makeWithLatitude:3 + longitude:4] + ], + @[ + [FGMPlatformLatLng makeWithLatitude:5 longitude:6], [FGMPlatformLatLng makeWithLatitude:7 + longitude:8] + ] + ]; + NSArray *> *holes = FGMGetHolesForPigeonLatLngArrays(pointsArray); + XCTAssertEqual(holes.count, 2); + XCTAssertEqual(holes[0][0].coordinate.latitude, 1); + XCTAssertEqual(holes[0][0].coordinate.longitude, 2); + XCTAssertEqual(holes[0][1].coordinate.latitude, 3); + XCTAssertEqual(holes[0][1].coordinate.longitude, 4); + XCTAssertEqual(holes[1][0].coordinate.latitude, 5); + XCTAssertEqual(holes[1][0].coordinate.longitude, 6); + XCTAssertEqual(holes[1][1].coordinate.latitude, 7); + XCTAssertEqual(holes[1][1].coordinate.longitude, 8); +} + +- (void)testGetPigeonCameraPositionForPosition { + GMSCameraPosition *position = + [[GMSCameraPosition alloc] initWithTarget:CLLocationCoordinate2DMake(1, 2) + zoom:2.0 + bearing:3.0 + viewingAngle:75.0]; + FGMPlatformCameraPosition *pigeonPosition = FGMGetPigeonCameraPositionForPosition(position); + XCTAssertEqualWithAccuracy(pigeonPosition.target.latitude, position.target.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.target.longitude, position.target.longitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.zoom, position.zoom, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.bearing, position.bearing, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPosition.tilt, position.viewingAngle, DBL_EPSILON); +} + +- (void)testPigeonPointForGCPoint { + CGPoint point = CGPointMake(10, 20); + FGMPlatformPoint *pigeonPoint = FGMGetPigeonPointForCGPoint(point); + XCTAssertEqualWithAccuracy(pigeonPoint.x, point.x, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPoint.y, point.y, DBL_EPSILON); +} + +- (void)testPigeonLatLngBoundsForCoordinateBounds { + GMSCoordinateBounds *bounds = + [[GMSCoordinateBounds alloc] initWithCoordinate:CLLocationCoordinate2DMake(10, 20) + coordinate:CLLocationCoordinate2DMake(30, 40)]; + FGMPlatformLatLngBounds *pigeonBounds = FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds); + XCTAssertEqualWithAccuracy(pigeonBounds.southwest.latitude, bounds.southWest.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonBounds.southwest.longitude, bounds.southWest.longitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonBounds.northeast.latitude, bounds.northEast.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonBounds.northeast.longitude, bounds.northEast.longitude, + DBL_EPSILON); +} + +- (void)testGetCameraPostionForPigeonCameraPosition { + FGMPlatformCameraPosition *pigeonCameraPosition = [FGMPlatformCameraPosition + makeWithBearing:1.0 + target:[FGMPlatformLatLng makeWithLatitude:2.0 longitude:3.0] + tilt:4.0 + zoom:5.0]; + + GMSCameraPosition *cameraPosition = + FGMGetCameraPositionForPigeonCameraPosition(pigeonCameraPosition); + + XCTAssertEqualWithAccuracy(cameraPosition.target.latitude, pigeonCameraPosition.target.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.target.longitude, pigeonCameraPosition.target.longitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.zoom, pigeonCameraPosition.zoom, DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.bearing, pigeonCameraPosition.bearing, DBL_EPSILON); + XCTAssertEqualWithAccuracy(cameraPosition.viewingAngle, pigeonCameraPosition.tilt, DBL_EPSILON); +} + +- (void)testCGPointForPigeonPoint { + FGMPlatformPoint *pigeonPoint = [FGMPlatformPoint makeWithX:1.0 y:2.0]; + + CGPoint point = FGMGetCGPointForPigeonPoint(pigeonPoint); + + XCTAssertEqualWithAccuracy(pigeonPoint.x, point.x, DBL_EPSILON); + XCTAssertEqualWithAccuracy(pigeonPoint.y, point.y, DBL_EPSILON); +} + +- (void)testCoordinateBoundsFromLatLongs { + FGMPlatformLatLngBounds *pigeonBounds = [FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng makeWithLatitude:3 longitude:4] + southwest:[FGMPlatformLatLng makeWithLatitude:1 longitude:2]]; + + GMSCoordinateBounds *bounds = FGMGetCoordinateBoundsForPigeonLatLngBounds(pigeonBounds); + + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(bounds.southWest.latitude, 1, accuracy); + XCTAssertEqualWithAccuracy(bounds.southWest.longitude, 2, accuracy); + XCTAssertEqualWithAccuracy(bounds.northEast.latitude, 3, accuracy); + XCTAssertEqualWithAccuracy(bounds.northEast.longitude, 4, accuracy); +} + +- (void)testMapViewTypeFromPigeonType { + XCTAssertEqual(kGMSTypeNormal, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeNormal)); + XCTAssertEqual(kGMSTypeSatellite, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeSatellite)); + XCTAssertEqual(kGMSTypeTerrain, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeTerrain)); + XCTAssertEqual(kGMSTypeHybrid, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeHybrid)); + XCTAssertEqual(kGMSTypeNone, FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapTypeNone)); +} + +- (void)testCameraUpdateFromNewCameraPosition { + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMPlatformCameraUpdateNewCameraPosition *newPositionUpdate = + [FGMPlatformCameraUpdateNewCameraPosition + makeWithCameraPosition:[FGMPlatformCameraPosition + makeWithBearing:4 + target:[FGMPlatformLatLng makeWithLatitude:1 + longitude:2] + tilt:5 + zoom:3]]; + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:newPositionUpdate]); + [[classMockCameraUpdate expect] + setCamera:FGMGetCameraPositionForPigeonCameraPosition(newPositionUpdate.cameraPosition)]; + [classMockCameraUpdate stopMocking]; +} + +// TODO(cyanglaz): Fix the test for cameraUpdateFromArray with the "NewLatlng" key. +// 2 approaches have been tried and neither worked for the tests. +// +// 1. Use OCMock to vefiry that [GMSCameraUpdate setTarget:] is triggered with the correct value. +// This class method conflicts with certain category method in OCMock, causing OCMock not able to +// disambigious them. +// +// 2. Directly verify the GMSCameraUpdate object returned by the method. +// The GMSCameraUpdate object returned from the method doesn't have any accessors to the "target" +// property. It can be used to update the "camera" property in GMSMapView. However, [GMSMapView +// moveCamera:] doesn't update the camera immediately. Thus the GMSCameraUpdate object cannot be +// verified. +// +// The code in below test uses the 2nd approach. +- (void)skip_testCameraUpdateFromNewLatLong { + const CGFloat lat = 1; + const CGFloat lng = 2; + FGMPlatformCameraUpdateNewLatLng *platformUpdate = [FGMPlatformCameraUpdateNewLatLng + makeWithLatLng:[FGMPlatformLatLng makeWithLatitude:lat longitude:lng]]; + + GMSCameraUpdate *update = FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init]; + options.frame = CGRectZero; + options.camera = [GMSCameraPosition cameraWithTarget:CLLocationCoordinate2DMake(5, 6) zoom:1]; + GMSMapView *mapView = [[GMSMapView alloc] initWithOptions:options]; + [mapView moveCamera:update]; + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(mapView.camera.target.latitude, lat, + accuracy); // mapView.camera.target.latitude is still 5. + XCTAssertEqualWithAccuracy(mapView.camera.target.longitude, lng, + accuracy); // mapView.camera.target.longitude is still 6. +} + +- (void)testCameraUpdateFromNewLatLngBounds { + FGMPlatformLatLngBounds *pigeonBounds = [FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng makeWithLatitude:1 longitude:2] + southwest:[FGMPlatformLatLng makeWithLatitude:3 longitude:4]]; + GMSCoordinateBounds *bounds = FGMGetCoordinateBoundsForPigeonLatLngBounds(pigeonBounds); + + const CGFloat padding = 20; + FGMPlatformCameraUpdateNewLatLngBounds *platformUpdate = [FGMPlatformCameraUpdateNewLatLngBounds + makeWithBounds:FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds) + padding:padding]; + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] fitBounds:bounds withPadding:padding]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromNewLatLngZoom { + const CGFloat lat = 1; + const CGFloat lng = 2; + const CGFloat zoom = 3; + FGMPlatformCameraUpdateNewLatLngZoom *platformUpdate = [FGMPlatformCameraUpdateNewLatLngZoom + makeWithLatLng:[FGMPlatformLatLng makeWithLatitude:lat longitude:lng] + zoom:zoom]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] setTarget:CLLocationCoordinate2DMake(lat, lng) zoom:zoom]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromScrollBy { + const CGFloat x = 1; + const CGFloat y = 2; + FGMPlatformCameraUpdateScrollBy *platformUpdate = [FGMPlatformCameraUpdateScrollBy makeWithDx:x + dy:y]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] scrollByX:x Y:y]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomBy { + const CGFloat zoom = 1; + FGMPlatformCameraUpdateZoomBy *platformUpdateNoPoint = + [FGMPlatformCameraUpdateZoomBy makeWithAmount:zoom focus:nil]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdateNoPoint]); + + [[classMockCameraUpdate expect] zoomBy:zoom]; + + const CGFloat x = 2; + const CGFloat y = 3; + FGMPlatformCameraUpdateZoomBy *platformUpdate = + [FGMPlatformCameraUpdateZoomBy makeWithAmount:zoom focus:[FGMPlatformPoint makeWithX:x y:y]]; + + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomBy:zoom atPoint:CGPointMake(x, y)]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomIn { + FGMPlatformCameraUpdateZoom *platformUpdate = [FGMPlatformCameraUpdateZoom makeWithOut:NO]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomIn]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomOut { + FGMPlatformCameraUpdateZoom *platformUpdate = [FGMPlatformCameraUpdateZoom makeWithOut:YES]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomOut]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromZoomTo { + const CGFloat zoom = 1; + FGMPlatformCameraUpdateZoomTo *platformUpdate = [FGMPlatformCameraUpdateZoomTo makeWithZoom:zoom]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + FGMGetCameraUpdateForPigeonCameraUpdate( + [FGMPlatformCameraUpdate makeWithCameraUpdate:platformUpdate]); + + [[classMockCameraUpdate expect] zoomTo:zoom]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testStrokeStylesFromPatterns { + NSArray *patterns = @[ + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeGap length:@(1)], + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeDash length:@(1)] + ]; + UIColor *strokeColor = UIColor.redColor; + + NSArray *patternStrokeStyle = + FGMGetStrokeStylesFromPatterns(patterns, strokeColor); + + XCTAssertEqual(patternStrokeStyle.count, 2); + + // None of the parameters of `patternStrokeStyle` is observable, so we limit to testing + // the length of this output array. +} + +- (void)testLengthsFromPatterns { + const CGFloat gapLength = 10; + const CGFloat dashLength = 6.4; + NSArray *patterns = @[ + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeGap length:@(gapLength)], + [FGMPlatformPatternItem makeWithType:FGMPlatformPatternItemTypeDash length:@(dashLength)] + ]; + + NSArray *spanLengths = FGMGetSpanLengthsFromPatterns(patterns); + + XCTAssertEqual(spanLengths.count, 2); + + NSNumber *firstSpanLength = spanLengths[0]; + NSNumber *secondSpanLength = spanLengths[1]; + + XCTAssertEqual(firstSpanLength.doubleValue, gapLength); + XCTAssertEqual(secondSpanLength.doubleValue, dashLength); +} + +- (void)testWeightedDataFromPlatformWeightedData { + CGFloat intensity1 = 3.0; + CGFloat intensity2 = 6.0; + NSArray *data = @[ + [FGMPlatformWeightedLatLng makeWithPoint:[FGMPlatformLatLng makeWithLatitude:10 longitude:20] + weight:intensity1], + [FGMPlatformWeightedLatLng makeWithPoint:[FGMPlatformLatLng makeWithLatitude:30 longitude:40] + weight:intensity2], + ]; + + NSArray *weightedData = FGMGetWeightedDataForPigeonWeightedData(data); + XCTAssertEqual([weightedData[0] intensity], intensity1); + XCTAssertEqual([weightedData[1] intensity], intensity2); +} + +- (void)testGradientFromPlatformGradient { + CGFloat startPoint = 0.6; + CGFloat platformRed = 0.1; + CGFloat platformGreen = 0.2; + CGFloat platformBlue = 0.3; + CGFloat platformAlpha = 0.4; + NSInteger colorMapSize = 200; + FGMPlatformHeatmapGradient *platformGradient = + [FGMPlatformHeatmapGradient makeWithColors:@[ [FGMPlatformColor makeWithRed:platformRed + green:platformGreen + blue:platformBlue + alpha:platformAlpha] ] + startPoints:@[ @(startPoint) ] + colorMapSize:colorMapSize]; + + GMUGradient *gradient = FGMGetGradientForPigeonHeatmapGradient(platformGradient); + CGFloat red, green, blue, alpha; + [[gradient colors][0] getRed:&red green:&green blue:&blue alpha:&alpha]; + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(red, platformRed, accuracy); + XCTAssertEqualWithAccuracy(green, platformGreen, accuracy); + XCTAssertEqualWithAccuracy(blue, platformBlue, accuracy); + XCTAssertEqualWithAccuracy(alpha, platformAlpha, accuracy); + XCTAssertEqualWithAccuracy([[gradient startPoints][0] doubleValue], startPoint, accuracy); + XCTAssertEqual([gradient mapSize], colorMapSize); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m new file mode 100644 index 000000000000..2b0134d3ef9b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m @@ -0,0 +1,118 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; +@import GoogleMapsUtils; + +#import "PartiallyMockedMapView.h" + +@interface PropertyOrderValidatingHeatmap : GMUHeatmapTileLayer { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsHeatmapControllerTests : XCTestCase +@end + +@implementation GoogleMapsHeatmapControllerTests + +- (void)testUpdateHeatmapSetsVisibilityLast { + PropertyOrderValidatingHeatmap *heatmap = [[PropertyOrderValidatingHeatmap alloc] init]; + FGMPlatformHeatmapGradient *gradient = [FGMPlatformHeatmapGradient makeWithColors:@[ + [FGMPlatformColor makeWithRed:0 green:0 blue:0 alpha:0], + [FGMPlatformColor makeWithRed:1.0 green:1.0 blue:1.0 alpha:1.0], + ] + startPoints:@[ @(0), @(1) ] + colorMapSize:256]; + [FLTGoogleMapHeatmapController + updateHeatmap:heatmap + fromPlatformHeatmap:[FGMPlatformHeatmap + makeWithHeatmapId:@"heatmap" + data:@[ + [FGMPlatformWeightedLatLng + makeWithPoint:[FGMPlatformLatLng + makeWithLatitude:5.0 + longitude:5.0] + weight:0.5], + [FGMPlatformWeightedLatLng + makeWithPoint:[FGMPlatformLatLng + makeWithLatitude:10.0 + longitude:10.0] + weight:0.75], + ] + gradient:gradient + opacity:0.5 + radius:1 + minimumZoomIntensity:1 + maximumZoomIntensity:2] + withMapView:[GoogleMapsHeatmapControllerTests mapView]]; + XCTAssertTrue(heatmap.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingHeatmap + +- (void)setWeightedData:(NSArray *)weightedData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.weightedData = weightedData; +} + +- (void)setRadius:(NSUInteger)radius { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.radius = radius; +} + +- (void)setGradient:(GMUGradient *)gradient { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.gradient = gradient; +} + +- (void)setMinimumZoomIntensity:(NSUInteger)minimumZoomIntensity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.minimumZoomIntensity = minimumZoomIntensity; +} + +- (void)setMaximumZoomIntensity:(NSUInteger)maximumZoomIntensity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.maximumZoomIntensity = maximumZoomIntensity; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setTileSize:(NSInteger)tileSize { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tileSize = tileSize; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setFadeIn:(BOOL)fadeIn { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fadeIn = fadeIn; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTTileProviderControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTTileProviderControllerTests.m new file mode 100644 index 000000000000..3c7f43b3c206 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTTileProviderControllerTests.m @@ -0,0 +1,36 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import XCTest; +@import GoogleMaps; +@import google_maps_flutter_ios; + +#import + +@interface FLTTileProviderControllerTests : XCTestCase +@end + +@implementation FLTTileProviderControllerTests + +- (void)testCallChannelOnPlatformThread { + id handler = OCMClassMock([FGMMapsCallbackApi class]); + FLTTileProviderController *controller = + [[FLTTileProviderController alloc] initWithTileOverlayIdentifier:@"foo" + callbackHandler:handler]; + XCTAssertNotNil(controller); + XCTestExpectation *expectation = [self expectationWithDescription:@"invokeMethod"]; + OCMStub([handler tileWithOverlayIdentifier:[OCMArg any] + location:[OCMArg any] + zoom:0 + completion:[OCMArg any]]) + .andDo(^(NSInvocation *invocation) { + XCTAssertTrue([[NSThread currentThread] isMainThread]); + [expectation fulfill]; + }); + id receiver = OCMProtocolMock(@protocol(GMSTileReceiver)); + [controller requestTileForX:0 y:0 zoom:0 receiver:receiver]; + [self waitForExpectations:@[ expectation ] timeout:10.0]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m new file mode 100644 index 000000000000..7514a70704f5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m @@ -0,0 +1,104 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import "PartiallyMockedMapView.h" + +/// A GMSCircle that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingCircle : GMSCircle { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsCircleControllerTests : XCTestCase +@end + +@implementation GoogleMapsCircleControllerTests + +- (void)testUpdateCircleSetsVisibilityLast { + PropertyOrderValidatingCircle *circle = [[PropertyOrderValidatingCircle alloc] init]; + [FLTGoogleMapCircleController + updateCircle:circle + fromPlatformCircle:[FGMPlatformCircle + makeWithConsumeTapEvents:NO + fillColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + strokeColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + visible:YES + strokeWidth:0 + zIndex:0 + center:[FGMPlatformLatLng makeWithLatitude:0 + longitude:0] + radius:10 + circleId:@"circle"] + withMapView:[GoogleMapsCircleControllerTests mapView]]; + XCTAssertTrue(circle.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingCircle +- (void)setPosition:(CLLocationCoordinate2D)position { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.position = position; +} + +- (void)setRadius:(CLLocationDistance)radius { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.radius = radius; +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeWidth = strokeWidth; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeColor = strokeColor; +} + +- (void)setFillColor:(UIColor *)fillColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fillColor = fillColor; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m new file mode 100644 index 000000000000..9169d6064956 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -0,0 +1,281 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +/// A GMSGroundOverlay that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingGroundOverlay : GMSGroundOverlay { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsGroundOverlayControllerTests : XCTestCase +@end + +@implementation GoogleMapsGroundOverlayControllerTests + +/// Returns GoogleMapGroundOverlayController object instantiated with position and a mocked map +/// instance. +/// +/// @return An object of FLTGoogleMapGroundOverlayController ++ (FGMGroundOverlayController *)groundOverlayControllerWithPositionWithMockedMap { + NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"widegamut" + ofType:@"png" + inDirectory:@"assets"]; + UIImage *wideGamutImage = [UIImage imageWithContentsOfFile:imagePath]; + GMSGroundOverlay *groundOverlay = + [GMSGroundOverlay groundOverlayWithPosition:CLLocationCoordinate2DMake(52.4816, 3.1791) + icon:wideGamutImage + zoomLevel:14.0]; + + GMSMapView *mapView = [GoogleMapsGroundOverlayControllerTests mapView]; + + return [[FGMGroundOverlayController alloc] initWithGroundOverlay:groundOverlay + identifier:@"id_1" + mapView:mapView + isCreatedWithBounds:NO]; +} + +/// Returns GoogleMapGroundOverlayController object instantiated with bounds and a mocked map +/// instance. +/// +/// @return An object of FLTGoogleMapGroundOverlayController ++ (FGMGroundOverlayController *)groundOverlayControllerWithBoundsWithMockedMap { + NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"widegamut" + ofType:@"png" + inDirectory:@"assets"]; + UIImage *wideGamutImage = [UIImage imageWithContentsOfFile:imagePath]; + GMSGroundOverlay *groundOverlay = [GMSGroundOverlay + groundOverlayWithBounds:[[GMSCoordinateBounds alloc] + initWithCoordinate:CLLocationCoordinate2DMake(10, 20) + coordinate:CLLocationCoordinate2DMake(30, 40)] + icon:wideGamutImage]; + + GMSMapView *mapView = [GoogleMapsGroundOverlayControllerTests mapView]; + + return [[FGMGroundOverlayController alloc] initWithGroundOverlay:groundOverlay + identifier:@"id_1" + mapView:mapView + isCreatedWithBounds:YES]; +} + +- (void)testUpdatingGroundOverlayWithPosition { + FGMGroundOverlayController *groundOverlayController = + [GoogleMapsGroundOverlayControllerTests groundOverlayControllerWithPositionWithMockedMap]; + + FGMPlatformLatLng *position = [FGMPlatformLatLng makeWithLatitude:52.4816 longitude:3.1791]; + + FGMPlatformBitmap *bitmap = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + + FGMPlatformGroundOverlay *platformGroundOverlay = + [FGMPlatformGroundOverlay makeWithGroundOverlayId:@"id_1" + image:bitmap + position:position + bounds:nil + anchor:[FGMPlatformPoint makeWithX:0.5 y:0.5] + transparency:0.5 + bearing:65.0 + zIndex:2.0 + visible:true + clickable:true + zoomLevel:@14.0]; + + [groundOverlayController updateFromPlatformGroundOverlay:platformGroundOverlay + registrar:mockRegistrar + screenScale:1.0]; + + XCTAssertNotNil(groundOverlayController.groundOverlay.icon); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.position.latitude, + position.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.position.longitude, + position.longitude, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.opacity, platformGroundOverlay.transparency); + XCTAssertEqual(groundOverlayController.groundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.zIndex, platformGroundOverlay.zIndex); + + FGMPlatformGroundOverlay *convertedPlatformGroundOverlay = + FGMGetPigeonGroundOverlay(groundOverlayController.groundOverlay, @"id_1", NO, @14.0); + XCTAssertEqualObjects(convertedPlatformGroundOverlay.groundOverlayId, @"id_1"); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.position.latitude, position.latitude, + DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.position.longitude, position.longitude, + DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.zoomLevel.doubleValue, 14.0); + XCTAssertEqual(convertedPlatformGroundOverlay.transparency, platformGroundOverlay.transparency); + XCTAssertEqual(convertedPlatformGroundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.zIndex, platformGroundOverlay.zIndex); +} + +- (void)testUpdatingGroundOverlayWithBounds { + FGMGroundOverlayController *groundOverlayController = + [GoogleMapsGroundOverlayControllerTests groundOverlayControllerWithBoundsWithMockedMap]; + + FGMPlatformLatLngBounds *bounds = [FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng makeWithLatitude:54.4816 longitude:5.1791] + southwest:[FGMPlatformLatLng makeWithLatitude:52.4816 longitude:3.1791]]; + + FGMPlatformBitmap *bitmap = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + + FGMPlatformGroundOverlay *platformGroundOverlay = + [FGMPlatformGroundOverlay makeWithGroundOverlayId:@"id_1" + image:bitmap + position:nil + bounds:bounds + anchor:[FGMPlatformPoint makeWithX:0.5 y:0.5] + transparency:0.5 + bearing:65.0 + zIndex:2.0 + visible:true + clickable:true + zoomLevel:nil]; + + [groundOverlayController updateFromPlatformGroundOverlay:platformGroundOverlay + registrar:mockRegistrar + screenScale:1.0]; + + XCTAssertNotNil(groundOverlayController.groundOverlay.icon); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.northEast.latitude, + bounds.northeast.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.northEast.longitude, + bounds.northeast.longitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.southWest.latitude, + bounds.southwest.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.bounds.southWest.longitude, + bounds.southwest.longitude, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.opacity, platformGroundOverlay.transparency); + XCTAssertEqual(groundOverlayController.groundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(groundOverlayController.groundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(groundOverlayController.groundOverlay.zIndex, platformGroundOverlay.zIndex); + + FGMPlatformGroundOverlay *convertedPlatformGroundOverlay = + FGMGetPigeonGroundOverlay(groundOverlayController.groundOverlay, @"id_1", YES, nil); + XCTAssertEqualObjects(convertedPlatformGroundOverlay.groundOverlayId, @"id_1"); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.northeast.latitude, + bounds.northeast.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.northeast.longitude, + bounds.northeast.longitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.southwest.latitude, + bounds.southwest.latitude, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.bounds.southwest.longitude, + bounds.southwest.longitude, DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.transparency, platformGroundOverlay.transparency); + XCTAssertEqual(convertedPlatformGroundOverlay.bearing, platformGroundOverlay.bearing); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.x, 0.5, DBL_EPSILON); + XCTAssertEqualWithAccuracy(convertedPlatformGroundOverlay.anchor.y, 0.5, DBL_EPSILON); + XCTAssertEqual(convertedPlatformGroundOverlay.zIndex, platformGroundOverlay.zIndex); +} + +- (void)testUpdateGroundOverlaySetsVisibilityLast { + PropertyOrderValidatingGroundOverlay *groundOverlay = + [[PropertyOrderValidatingGroundOverlay alloc] init]; + [FGMGroundOverlayController + updateGroundOverlay:groundOverlay + fromPlatformGroundOverlay: + [FGMPlatformGroundOverlay + makeWithGroundOverlayId:@"groundOverlay" + image:[FGMPlatformBitmap + makeWithBitmap:[FGMPlatformBitmapDefaultMarker + makeWithHue:@0]] + position:[FGMPlatformLatLng makeWithLatitude:0 longitude:0] + bounds:[FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng + makeWithLatitude:54.4816 + longitude:5.1791] + southwest:[FGMPlatformLatLng + makeWithLatitude:52.4816 + longitude:3.1791]] + anchor:[FGMPlatformPoint makeWithX:0.5 y:0.5] + transparency:0.5 + bearing:65.0 + zIndex:2.0 + visible:YES + clickable:YES + zoomLevel:nil] + withMapView:[GoogleMapsGroundOverlayControllerTests mapView] + registrar:nil + screenScale:1.0 + usingBounds:YES]; + XCTAssertTrue(groundOverlay.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingGroundOverlay + +- (void)setPosition:(CLLocationCoordinate2D)position { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.position = position; +} + +- (void)setAnchor:(CGPoint)anchor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.anchor = anchor; +} + +- (void)setIcon:(UIImage *)icon { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.icon = icon; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setBearing:(CLLocationDirection)bearing { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.bearing = bearing; +} + +- (void)setBounds:(GMSCoordinateBounds *)bounds { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.bounds = bounds; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m new file mode 100644 index 000000000000..bac3fb2cc84e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -0,0 +1,361 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import + +#import "PartiallyMockedMapView.h" + +/// A GMSMarker that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingMarker : GMSMarker { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsMarkerControllerTests : XCTestCase +@end + +@implementation GoogleMapsMarkerControllerTests + +/// Returns a simple map view for use with marker controllers. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +/// Returns a FLTMarkersController instance instantiated with the given map view. +/// +/// The mapView should outlive the controller, as the controller keeps a weak reference to it. +- (FLTMarkersController *)markersControllerWithMapView:(GMSMapView *)mapView { + NSObject *mockRegistrar = + OCMStrictProtocolMock(@protocol(FlutterPluginRegistrar)); + return [[FLTMarkersController alloc] initWithMapView:mapView + callbackHandler:[[FGMMapsCallbackApi alloc] init] + clusterManagersController:nil + registrar:mockRegistrar]; +} + +- (FGMPlatformBitmap *)placeholderBitmap { + return [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:@0]]; +} + +- (void)testSetsMarkerNumericProperties { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + double anchorX = 3.14; + double anchorY = 2.718; + double alpha = 0.4; + double rotation = 90.0; + double zIndex = 3.0; + double latitutde = 10.0; + double longitude = 20.0; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:alpha + anchor:[FGMPlatformPoint makeWithX:anchorX y:anchorY] + consumeTapEvents:YES + draggable:YES + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:latitutde + longitude:longitude] + rotation:rotation + visible:YES + zIndex:zIndex + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + const double delta = 0.0001; + XCTAssertEqualWithAccuracy(marker.opacity, alpha, delta); + XCTAssertEqualWithAccuracy(marker.rotation, rotation, delta); + XCTAssertEqualWithAccuracy(marker.zIndex, zIndex, delta); + XCTAssertEqualWithAccuracy(marker.groundAnchor.x, anchorX, delta); + XCTAssertEqualWithAccuracy(marker.groundAnchor.y, anchorY, delta); + XCTAssertEqualWithAccuracy(marker.position.latitude, latitutde, delta); + XCTAssertEqualWithAccuracy(marker.position.longitude, longitude, delta); +} + +// Boolean properties are tested individually to ensure they aren't accidentally cross-assigned from +// another property. +- (void)testSetsDraggable { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:NO + draggable:YES + flat:NO + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0.0 longitude:0.0] + rotation:0 + visible:NO + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + XCTAssertTrue(marker.draggable); +} + +// Boolean properties are tested individually to ensure they aren't accidentally cross-assigned from +// another property. +- (void)testSetsFlat { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:NO + draggable:NO + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0.0 longitude:0.0] + rotation:0 + visible:NO + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + XCTAssertTrue(marker.flat); +} + +// Boolean properties are tested individually to ensure they aren't accidentally cross-assigned from +// another property. +- (void)testSetsVisible { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + [controller addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:NO + draggable:NO + flat:NO + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint makeWithX:0 y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0.0 longitude:0.0] + rotation:0 + visible:YES + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + // Visibility is controlled by being set to a map. + XCTAssertNotNil(marker.map); +} + +- (void)testSetsMarkerInfoWindowProperties { + GMSMapView *mapView = [GoogleMapsMarkerControllerTests mapView]; + FLTMarkersController *controller = [self markersControllerWithMapView:mapView]; + + NSString *markerIdentifier = @"marker"; + NSString *title = @"info title"; + NSString *snippet = @"info snippet"; + double anchorX = 3.14; + double anchorY = 2.718; + [controller + addMarkers:@[ [FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:YES + draggable:YES + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:title + snippet:snippet + anchor:[FGMPlatformPoint makeWithX:anchorX + y:anchorY]] + position:[FGMPlatformLatLng makeWithLatitude:0 longitude:0] + rotation:0 + visible:YES + zIndex:0 + markerId:markerIdentifier + clusterManagerId:nil] ]]; + + FLTGoogleMapMarkerController *markerController = + controller.markerIdentifierToController[markerIdentifier]; + GMSMarker *marker = markerController.marker; + + const double delta = 0.0001; + XCTAssertEqualWithAccuracy(marker.infoWindowAnchor.x, anchorX, delta); + XCTAssertEqualWithAccuracy(marker.infoWindowAnchor.y, anchorY, delta); + XCTAssertEqual(marker.title, title); + XCTAssertEqual(marker.snippet, snippet); +} + +- (void)testUpdateMarkerSetsVisibilityLast { + PropertyOrderValidatingMarker *marker = [[PropertyOrderValidatingMarker alloc] init]; + [FLTGoogleMapMarkerController + updateMarker:marker + fromPlatformMarker:[FGMPlatformMarker + makeWithAlpha:1.0 + anchor:[FGMPlatformPoint makeWithX:0 y:0] + consumeTapEvents:YES + draggable:YES + flat:YES + icon:[self placeholderBitmap] + infoWindow:[FGMPlatformInfoWindow + makeWithTitle:@"info title" + snippet:@"info snippet" + anchor:[FGMPlatformPoint + makeWithX:0 + y:0]] + position:[FGMPlatformLatLng makeWithLatitude:0 + longitude:0] + rotation:0 + visible:YES + zIndex:0 + markerId:@"marker" + clusterManagerId:nil] + withMapView:[GoogleMapsMarkerControllerTests mapView] + registrar:nil + screenScale:1 + usingOpacityForVisibility:NO]; + XCTAssertTrue(marker.hasSetMap); +} + +@end + +@implementation PropertyOrderValidatingMarker + +- (void)setPosition:(CLLocationCoordinate2D)position { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.position = position; +} + +- (void)setSnippet:(NSString *)snippet { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.snippet = snippet; +} + +- (void)setIcon:(UIImage *)icon { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.icon = icon; +} + +- (void)setIconView:(UIView *)iconView { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.iconView = iconView; +} + +- (void)setTracksViewChanges:(BOOL)tracksViewChanges { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tracksViewChanges = tracksViewChanges; +} + +- (void)setTracksInfoWindowChanges:(BOOL)tracksInfoWindowChanges { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tracksInfoWindowChanges = tracksInfoWindowChanges; +} + +- (void)setGroundAnchor:(CGPoint)groundAnchor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.groundAnchor = groundAnchor; +} + +- (void)setInfoWindowAnchor:(CGPoint)infoWindowAnchor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.infoWindowAnchor = infoWindowAnchor; +} + +- (void)setAppearAnimation:(GMSMarkerAnimation)appearAnimation { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.appearAnimation = appearAnimation; +} + +- (void)setDraggable:(BOOL)draggable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.draggable = draggable; +} + +- (void)setFlat:(BOOL)flat { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.flat = flat; +} + +- (void)setRotation:(CLLocationDegrees)rotation { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.rotation = rotation; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setPanoramaView:(GMSPanoramaView *)panoramaView { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.panoramaView = panoramaView; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setUserData:(id)userData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.userData = userData; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m new file mode 100644 index 000000000000..2cb386e0fc55 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m @@ -0,0 +1,112 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +/// A GMSPolygon that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingPolygon : GMSPolygon { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsPolygonControllerTests : XCTestCase +@end + +@implementation GoogleMapsPolygonControllerTests + +- (void)testUpdatePolygonSetsVisibilityLast { + PropertyOrderValidatingPolygon *polygon = [[PropertyOrderValidatingPolygon alloc] init]; + [FLTGoogleMapPolygonController + updatePolygon:polygon + fromPlatformPolygon:[FGMPlatformPolygon + makeWithConsumeTapEvents:NO + fillColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + geodesic:NO + holes:@[] + strokeColor:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + strokeWidth:0 + visible:YES + zIndex:0 + points:@[] + polygonId:@"polygon"] + withMapView:[GoogleMapsPolygonControllerTests mapView]]; + XCTAssertTrue(polygon.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingPolygon +- (void)setPath:(GMSPath *)path { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.path = path; +} + +- (void)setHoles:(NSArray *)holes { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.holes = holes; +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeWidth = strokeWidth; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeColor = strokeColor; +} + +- (void)setFillColor:(UIColor *)fillColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fillColor = fillColor; +} + +- (void)setGeodesic:(BOOL)geodesic { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.geodesic = geodesic; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setUserData:(id)userData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.userData = userData; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m new file mode 100644 index 000000000000..19ca6e84a266 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m @@ -0,0 +1,181 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +/// A GMSPolyline that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingPolyline : GMSPolyline { +} +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsPolylineControllerTests : XCTestCase +@end + +@implementation GoogleMapsPolylineControllerTests + +/// Returns GoogleMapPolylineController object instantiated with a mocked map instance +/// +/// @return An object of FLTGoogleMapPolylineController +- (FLTGoogleMapPolylineController *)polylineControllerWithMockedMap { + FGMPlatformPolyline *polyline = [FGMPlatformPolyline + makeWithPolylineId:@"polyline_id_0" + consumesTapEvents:NO + color:[FGMPlatformColor makeWithRed:0 green:0 blue:0 alpha:0] + geodesic:NO + jointType:FGMPlatformJointTypeRound + patterns:@[] + points:[GoogleMapsPolylineControllerTests polylinePoints] + visible:NO + width:1 + zIndex:0]; + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSCameraPosition *camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + mapViewOptions.camera = camera; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + GMSMutablePath *path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(polyline.points)); + + FLTGoogleMapPolylineController *polylineControllerWithMockedMap = + [[FLTGoogleMapPolylineController alloc] initWithPath:path + identifier:polyline.polylineId + mapView:mapView]; + + return polylineControllerWithMockedMap; +} + +- (void)testPatternsSetSpans { + FLTGoogleMapPolylineController *polylineController = [self polylineControllerWithMockedMap]; + + XCTAssertNil(polylineController.polyline.spans); + + [polylineController + updateFromPlatformPolyline:[FGMPlatformPolyline + makeWithPolylineId:@"polyline_id_0" + consumesTapEvents:NO + color:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + geodesic:NO + jointType:FGMPlatformJointTypeRound + patterns:@[ + [FGMPlatformPatternItem + makeWithType:FGMPlatformPatternItemTypeDot + length:@(10)], + [FGMPlatformPatternItem + makeWithType:FGMPlatformPatternItemTypeDash + length:@(10)] + ] + points:[GoogleMapsPolylineControllerTests + polylinePoints] + visible:YES + width:1 + zIndex:0]]; + + // `GMSStyleSpan` doesn't implement `isEqual` so cannot be compared by value at present. + XCTAssertNotNil(polylineController.polyline.spans); +} + +- (void)testUpdatePolylineSetsVisibilityLast { + PropertyOrderValidatingPolyline *polyline = [[PropertyOrderValidatingPolyline alloc] init]; + [FLTGoogleMapPolylineController + updatePolyline:polyline + fromPlatformPolyline:[FGMPlatformPolyline + makeWithPolylineId:@"polyline" + consumesTapEvents:NO + color:[FGMPlatformColor makeWithRed:0 + green:0 + blue:0 + alpha:0] + geodesic:NO + jointType:FGMPlatformJointTypeRound + patterns:@[] + points:[GoogleMapsPolylineControllerTests polylinePoints] + visible:YES + width:1 + zIndex:0] + withMapView:[GoogleMapsPolylineControllerTests mapView]]; + XCTAssertTrue(polyline.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +/// Returns a set of points to use for tests that need a valid but arbitrary line. ++ (NSArray *)polylinePoints { + return @[ + [FGMPlatformLatLng makeWithLatitude:52.4816 longitude:-3.1791], + [FGMPlatformLatLng makeWithLatitude:54.043 longitude:-2.9925], + [FGMPlatformLatLng makeWithLatitude:54.1396 longitude:-4.2739], + [FGMPlatformLatLng makeWithLatitude:53.4153 longitude:-4.0829], + ]; +} + +@end + +@implementation PropertyOrderValidatingPolyline + +- (void)setPath:(GMSPath *)path { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.path = path; +} + +- (void)setStrokeWidth:(CGFloat)strokeWidth { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeWidth = strokeWidth; +} + +- (void)setStrokeColor:(UIColor *)strokeColor { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.strokeColor = strokeColor; +} + +- (void)setGeodesic:(BOOL)geodesic { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.geodesic = geodesic; +} + +- (void)setTitle:(NSString *)title { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.title = title; +} + +- (void)setTappable:(BOOL)tappable { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tappable = tappable; +} + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setUserData:(id)userData { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.userData = userData; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.m new file mode 100644 index 000000000000..ecbef7b3924e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.m @@ -0,0 +1,212 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import +#import "FGMCATransactionWrapper.h" +#import "PartiallyMockedMapView.h" + +@interface FLTGoogleMapFactory (Test) +@property(strong, nonatomic, readonly) id sharedMapServices; +@end + +@interface GoogleMapsTests : XCTestCase +@end + +@interface FLTTileProviderController (Testing) +- (UIImage *)handleResultTile:(nullable UIImage *)tileImage; +@end + +@implementation GoogleMapsTests + +- (void)testPlugin { + FLTGoogleMapsPlugin *plugin = [[FLTGoogleMapsPlugin alloc] init]; + XCTAssertNotNil(plugin); +} + +- (void)testFrameObserver { + id registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init]; + options.frame = frame; + options.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:options]; + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + for (NSInteger i = 0; i < 10; ++i) { + [controller view]; + } + XCTAssertEqual(mapView.frameObserverCount, 1); + + mapView.frame = frame; + XCTAssertEqual(mapView.frameObserverCount, 0); +} + +- (void)testMapsServiceSync { + id registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + FLTGoogleMapFactory *factory1 = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + XCTAssertNotNil(factory1.sharedMapServices); + FLTGoogleMapFactory *factory2 = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + // Test pointer equality, should be same retained singleton +[GMSServices sharedServices] object. + // Retaining the opaque object should be enough to avoid multiple internal initializations, + // but don't test the internals of the GoogleMaps API. Assume that it does what is documented. + // https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_services#a436e03c32b1c0be74e072310a7158831 + XCTAssertEqual(factory1.sharedMapServices, factory2.sharedMapServices); +} + +- (void)testHandleResultTileDownsamplesWideGamutImages { + FLTTileProviderController *controller = [[FLTTileProviderController alloc] init]; + + NSString *imagePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"widegamut" + ofType:@"png" + inDirectory:@"assets"]; + UIImage *wideGamutImage = [UIImage imageWithContentsOfFile:imagePath]; + + XCTAssertNotNil(wideGamutImage, @"The image should be loaded."); + + UIImage *downsampledImage = [controller handleResultTile:wideGamutImage]; + + CGImageRef imageRef = downsampledImage.CGImage; + size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); + + // non wide gamut images use 8 bit format + XCTAssertEqual(bitsPerComponent, 8); + XCTAssertEqual(CGImageGetAlphaInfo(imageRef), kCGImageAlphaPremultipliedLast); +} + +- (void)testAnimateCameraWithUpdate { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + + // Init camera with zero zoom. + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + id mapViewMock = OCMPartialMock(mapView); + id mockTransactionWrapper = OCMProtocolMock(@protocol(FGMCATransactionProtocol)); + controller.callHandler.transactionWrapper = mockTransactionWrapper; + + FGMPlatformCameraUpdateZoomTo *zoomTo = [FGMPlatformCameraUpdateZoomTo makeWithZoom:10.0]; + FGMPlatformCameraUpdate *cameraUpdate = [FGMPlatformCameraUpdate makeWithCameraUpdate:zoomTo]; + FlutterError *error = nil; + + OCMReject([mockTransactionWrapper begin]); + OCMReject([mockTransactionWrapper commit]); + OCMExpect([mapViewMock animateWithCameraUpdate:[OCMArg any]]); + [controller.callHandler animateCameraWithUpdate:cameraUpdate duration:nil error:&error]; + OCMVerifyAll(mapViewMock); + OCMVerifyAll(mockTransactionWrapper); +} + +- (void)testAnimateCameraWithUpdateAndDuration { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + + // Init camera with zero zoom. + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + id mapViewMock = OCMPartialMock(mapView); + id mockTransactionWrapper = OCMProtocolMock(@protocol(FGMCATransactionProtocol)); + controller.callHandler.transactionWrapper = mockTransactionWrapper; + + FGMPlatformCameraUpdateZoomTo *zoomTo = [FGMPlatformCameraUpdateZoomTo makeWithZoom:10.0]; + FGMPlatformCameraUpdate *cameraUpdate = [FGMPlatformCameraUpdate makeWithCameraUpdate:zoomTo]; + FlutterError *error = nil; + + NSNumber *durationMilliseconds = @100; + OCMExpect([mockTransactionWrapper begin]); + OCMExpect( + [mockTransactionWrapper setAnimationDuration:[durationMilliseconds doubleValue] / 1000]); + OCMExpect([mockTransactionWrapper commit]); + OCMExpect([mapViewMock animateWithCameraUpdate:[OCMArg any]]); + [controller.callHandler animateCameraWithUpdate:cameraUpdate + duration:durationMilliseconds + error:&error]; + OCMVerifyAll(mapViewMock); + OCMVerifyAll(mockTransactionWrapper); +} + +- (void)testInspectorAPICameraPosition { + NSObject *registrar = OCMProtocolMock(@protocol(FlutterPluginRegistrar)); + + CGRect frame = CGRectMake(0, 0, 100, 100); + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = frame; + + // Init camera with specific position. + GMSCameraPosition *initialCameraPosition = [[GMSCameraPosition alloc] initWithLatitude:37.7749 + longitude:-122.4194 + zoom:10]; + mapViewOptions.camera = initialCameraPosition; + + PartiallyMockedMapView *mapView = [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; + + FLTGoogleMapController *controller = + [[FLTGoogleMapController alloc] initWithMapView:mapView + viewIdentifier:0 + creationParameters:[self emptyCreationParameters] + registrar:registrar]; + + FGMMapInspector *inspector = [[FGMMapInspector alloc] initWithMapController:controller + messenger:registrar.messenger + pigeonSuffix:@"0"]; + + FlutterError *error = nil; + FGMPlatformCameraPosition *cameraPosition = [inspector cameraPosition:&error]; + + XCTAssertEqual(cameraPosition.target.latitude, initialCameraPosition.target.latitude); + XCTAssertEqual(cameraPosition.target.longitude, initialCameraPosition.target.longitude); + XCTAssertEqual(cameraPosition.zoom, initialCameraPosition.zoom); +} + +/// Creates an empty creation paramaters object for tests where the values don't matter, just that +/// there's a valid object to pass in. +- (FGMPlatformMapViewCreationParams *)emptyCreationParameters { + return [FGMPlatformMapViewCreationParams + makeWithInitialCameraPosition:[FGMPlatformCameraPosition + makeWithBearing:0.0 + target:[FGMPlatformLatLng makeWithLatitude:0.0 + longitude:0.0] + tilt:0.0 + zoom:0.0] + mapConfiguration:[[FGMPlatformMapConfiguration alloc] init] + initialCircles:@[] + initialMarkers:@[] + initialPolygons:@[] + initialPolylines:@[] + initialHeatmaps:@[] + initialTileOverlays:@[] + initialClusterManagers:@[] + initialGroundOverlays:@[]]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m new file mode 100644 index 000000000000..e7b1118a8d56 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m @@ -0,0 +1,73 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import google_maps_flutter_ios; +@import XCTest; +@import GoogleMaps; + +#import "PartiallyMockedMapView.h" + +/// A GMSTileOverlay that ensures that property updates are made before the map is set. +@interface PropertyOrderValidatingTileLayer : GMSTileLayer +@property(nonatomic) BOOL hasSetMap; +@end + +@interface GoogleMapsTileOverlayControllerTests : XCTestCase +@end + +@implementation GoogleMapsTileOverlayControllerTests + +- (void)testUpdateTileOverlaySetsVisibilityLast { + PropertyOrderValidatingTileLayer *tileLayer = [[PropertyOrderValidatingTileLayer alloc] init]; + [FLTGoogleMapTileOverlayController + updateTileLayer:tileLayer + fromPlatformTileOverlay:[FGMPlatformTileOverlay makeWithTileOverlayId:@"overlay" + fadeIn:NO + transparency:0.5 + zIndex:0 + visible:YES + tileSize:1] + withMapView:[GoogleMapsTileOverlayControllerTests mapView]]; + XCTAssertTrue(tileLayer.hasSetMap); +} + +/// Returns a simple map view to add map objects to. ++ (GMSMapView *)mapView { + GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; + mapViewOptions.frame = CGRectMake(0, 0, 100, 100); + mapViewOptions.camera = [[GMSCameraPosition alloc] initWithLatitude:0 longitude:0 zoom:0]; + return [[PartiallyMockedMapView alloc] initWithOptions:mapViewOptions]; +} + +@end + +@implementation PropertyOrderValidatingTileLayer + +- (void)setZIndex:(int)zIndex { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.zIndex = zIndex; +} + +- (void)setTileSize:(NSInteger)tileSize { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.tileSize = tileSize; +} + +- (void)setOpacity:(float)opacity { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.opacity = opacity; +} + +- (void)setFadeIn:(BOOL)fadeIn { + XCTAssertFalse(self.hasSetMap, @"Property set after map was set."); + super.fadeIn = fadeIn; +} + +- (void)setMap:(GMSMapView *)map { + // Don't actually set the map, since that requires more test setup. + if (map) { + self.hasSetMap = YES; + } +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/Info.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/Info.plist new file mode 100644 index 000000000000..64d65ca49577 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/PartiallyMockedMapView.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/PartiallyMockedMapView.h new file mode 100644 index 000000000000..9a04ae84ab24 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/PartiallyMockedMapView.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import GoogleMaps; + +/** + * Defines a map view used for testing key-value observing. + */ +@interface PartiallyMockedMapView : GMSMapView + +/** + * The number of times that the `frame` KVO has been added. + */ +@property(nonatomic, assign, readonly) NSInteger frameObserverCount; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/PartiallyMockedMapView.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/PartiallyMockedMapView.m new file mode 100644 index 000000000000..47d48d2e07fc --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/PartiallyMockedMapView.m @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "PartiallyMockedMapView.h" + +@interface PartiallyMockedMapView () + +@property(nonatomic, assign) NSInteger frameObserverCount; + +@end + +@implementation PartiallyMockedMapView + +- (void)addObserver:(NSObject *)observer + forKeyPath:(NSString *)keyPath + options:(NSKeyValueObservingOptions)options + context:(void *)context { + [super addObserver:observer forKeyPath:keyPath options:options context:context]; + + if ([keyPath isEqualToString:@"frame"]) { + ++self.frameObserverCount; + } +} + +- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath { + [super removeObserver:observer forKeyPath:keyPath]; + + if ([keyPath isEqualToString:@"frame"]) { + --self.frameObserverCount; + } +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/assets/widegamut.png b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/assets/widegamut.png new file mode 100644 index 0000000000000000000000000000000000000000..32f032bae3de42c8c7ba9529d2d18ad41e81bede GIT binary patch literal 3025 zcma)84Lp-;8-MnNW=cq#befNPEo?LS*qV>od`25nQR-ORux1~&Vd3PXb2NR9e4SF1 zUI|5tljKb&Ig&Sr)O%1AIh9T)r5vZyInPk^R&VdK-@W_VbzlGgb^WjVe(v8gSgXDD zkS0g~0Q7u)7(w97(+nLg@LM{N6AS>5SOJ~R64Jftl4yyHE#+|e41ru4&DqMb2LP+g zSarjy%PgZS%<`b0DXO`PO-UK_u1;iJOq8{eCovdN&OWehjws0z7ZhW-4mZ9e;Cns6?V*M&7MVqvVupjMA^GyR*6)pVV|pSXR; zVRl(Wb?H$X%;0sqC&fyh|=Z175x1^u*wK=}>MUr;jPX5W7?Z5OD z-dvY=#dJ8ZjbpeBy^|G~3P;>aesg25+g@AQx^NbLAJnFm;XB{3x@q+1BOC)#j1FyB zeNO&(+q{#nuZl!Z7vzhi*9kp69x&%aNA}t9D$#;dR))U$baa%61wP@GCeK^1m@r?)w z0G5Nc4uF6d05H&kfFA&20w5-B0Puq>dT$3o>;Nd}Hv`A|9RdJ89g_skn#TtmAbM)1 z@g$r1SXPuoA(2N(q*&4lydBmmfWsAtH69!o2Q7lW=in8=W^8Z`IDI0{5uD~oeM02` zplhfZ5a2)o8UWyNg5VHENPs_uD-q#2nnZY|NUA{rR3!y8MSKMZs}x0xxhL^Kh602}A zH`gS3|4h}X5Jb#m63eG$fdUDd6@nd}Nca>C6dMrmzQPZ1N{)0ACK7!TDOUvXKa=qt zQXafj$|nTz<&sz#mk)+pe5Qo|UBLUEfRd>iHIz^dXLPKlFRo4`>ZHUEoHGrY0)%`D zFx&ax0H#d92lr$$gWYt3*}hrvlP#n$_%cBppXVi$h$gp6%8|+W8vQQj?;0>$hepa| z2Pp!vT)`1@`MwNSkO?mk@F;W!ZH2v)lan*e%gN5plR;pE}rNMw*4h-8u@gG%@a zI#bUKGf%>e6@e6Px=vbR??|8-_Lf5 z{3Y61&<|-TbQzzckjR21l4#d2-8YlsKR`^AQ3;wibJm+Wbq!2l*#NAlULt5%a@>`%;{;9ls6{t}6ES%b=Ajj-# zN|LW}yIQJT@a%`^cG#BV;)I$tck&QvEY*wS(QelwCbp^0r@pC+?r*J4F`7SCk^ZbW z?AS!Z<95@9yPpn4SfiU_>d1_N{g~qLyW88U(gVvb7^}NEVMrf1DrtT1()0=|bgq0y z_XL z)bcSxRkr0LTZ$WjR=J=eer=ik?cnRL#KR?Cxx3i&LWgmOiT6j>nw>nw)P-}<7aKUr zcFYDfE|t;fo*#v7QqKh$np(m&l#P+gR>3ThUg?~&-}P~z!~NT6q6%jUMwk?Kcz}?` z$Ov7S0m5RCxF%k$57rl@h(k9$oNEd78si}KN$aqI#E2GDJXSZ|@@XC(Qyu=otSfQ{ zEF*;mi!>>@tx58r&C!N_G`#HqW|%=wu|a43G1h4cDm&nk7@>3MQC6)E`uPd18oyJR zx@PtD@SA4>QuRY}+Zz!(mDF2kW2a>ih%pB=6YYF^QAsVaWv;Mzbrbi}@qel!FavtU z|EP*D8QWaA^3}@$GN*v2cZMw(;%;FV99+;@IYDsw+xmVg~tx zG-QLSJdPU}J$uAG%7?(NB_`~7U>YlcF8OoC8aI{_#eQfh-_W^?hTBS=*yz~TTl#G1 zVtq*>g8sVRslb_b$h%*sp!DsCt=L`VZGh zK1vkBztVLn>ic`-)I{)rr2c!;MTzylA}^-j`!n*@QBG0lc~nMP3{$)Mg41IC1l<0& zEp0^|3FnJpylMqK_rZd-{3FNU&(jD0swcGj zXFe?@IjB|s5XSwH91~Rn4(if6;(!1>mm(P@{t!zN`+jeE0n&$20{m#tE`c81lrTi* z`(aJ`aV|?TTu7kF^D{EyKPr{2#|E-SR+88yS_TNu?u=yN!LM}Ee2T2waCv~a)$+*0 z4+$_hI{!Zwc3%gWJcF!nWum^$X&Bs5#2U8Wx3VlTUMN&0#dlnV<-vo55Tk@MLwRR} zcN{w{Pk-m~Q9wV3+Ncj8Y*agViu7hdfdl#%%dN b>|umk_w!q81@)IS|E7FBS2Ip|gs1%tSx05K literal 0 HcmV?d00001 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.m new file mode 100644 index 000000000000..cb7fbc196b40 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/GoogleMapsUITests.m @@ -0,0 +1,288 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import CoreLocation; +@import XCTest; +@import os.log; + +static const NSTimeInterval kWaitTime = 60; + +// TODO(bparrishMines): Remove once https://github.com/flutter/flutter/issues/154641 is fixed. +static const BOOL skipFor154641 = YES; + +@interface GoogleMapsUITests : XCTestCase +@property(nonatomic, strong) XCUIApplication *app; +@end + +@implementation GoogleMapsUITests + +- (void)setUp { + self.continueAfterFailure = NO; + + self.app = [[XCUIApplication alloc] init]; + [self.app launch]; + + [self + addUIInterruptionMonitorWithDescription:@"Permission popups" + handler:^BOOL(XCUIElement *_Nonnull interruptingElement) { + if (@available(iOS 14, *)) { + XCUIElement *locationPermission = + interruptingElement.buttons[@"Allow While Using App"]; + if (![locationPermission + waitForExistenceWithTimeout:kWaitTime]) { + XCTFail(@"Failed due to not able to find " + @"locationPermission button"); + } + [locationPermission tap]; + + } else { + XCUIElement *allow = + interruptingElement.buttons[@"Allow"]; + if (![allow waitForExistenceWithTimeout:kWaitTime]) { + XCTFail(@"Failed due to not able to find Allow button"); + } + [allow tap]; + } + return YES; + }]; +} + +- (void)testUserInterface { + XCTSkipIf(skipFor154641); + + XCUIApplication *app = self.app; + XCUIElement *userInteface = app.staticTexts[@"User interface"]; + if (![userInteface waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find User interface"); + } + [userInteface tap]; + + XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; + if (![platformView waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find platform view"); + } + + // There is a known bug where the permission popups interruption won't get fired until a tap + // happened in the app. We expect a permission popup so we do a tap here. + // iOS 16 has a bug where if the app itself is directly tapped: [app tap], the first button + // (disable compass) in the app is also tapped, so instead we tap a arbitrary location in the app + // instead. + XCUICoordinate *coordinate = [app coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; + [coordinate tap]; + XCUIElement *compass = app.buttons[@"disable compass"]; + if (![compass waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find disable compass button"); + } + + [self forceTap:compass]; +} + +- (void)testMapCoordinatesPage { + XCTSkipIf(skipFor154641); + + XCUIApplication *app = self.app; + XCUIElement *mapCoordinates = app.staticTexts[@"Map coordinates"]; + if (![mapCoordinates waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'Map coordinates''"); + } + [mapCoordinates tap]; + + XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; + if (![platformView waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find platform view"); + } + + XCUIElement *titleBar = app.otherElements[@"Map coordinates"]; + if (![titleBar waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find title bar"); + } + + NSPredicate *visibleRegionPredicate = + [NSPredicate predicateWithFormat:@"label BEGINSWITH 'VisibleRegion'"]; + XCUIElement *visibleRegionText = + [app.staticTexts elementMatchingPredicate:visibleRegionPredicate]; + if (![visibleRegionText waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find Visible Region label'"); + } + + // Validate visible region does not change when scrolled under safe areas. + // https://github.com/flutter/flutter/issues/107913 + + // Example -33.79495661816674, 151.313996873796 + CLLocationCoordinate2D originalNortheast; + // Example -33.90900557679571, 151.10800322145224 + CLLocationCoordinate2D originalSouthwest; + [self validateVisibleRegion:visibleRegionText.label + northeast:&originalNortheast + southwest:&originalSouthwest]; + XCTAssertGreaterThan(originalNortheast.latitude, originalSouthwest.latitude); + XCTAssertGreaterThan(originalNortheast.longitude, originalSouthwest.longitude); + + XCTAssertLessThan(originalNortheast.latitude, 0); + XCTAssertLessThan(originalSouthwest.latitude, 0); + XCTAssertGreaterThan(originalNortheast.longitude, 0); + XCTAssertGreaterThan(originalSouthwest.longitude, 0); + + // Drag the map upward to under the title bar. + [platformView pressForDuration:0 thenDragToElement:titleBar]; + + CLLocationCoordinate2D draggedNortheast; + CLLocationCoordinate2D draggedSouthwest; + [self validateVisibleRegion:visibleRegionText.label + northeast:&draggedNortheast + southwest:&draggedSouthwest]; + XCTAssertEqual(originalNortheast.latitude, draggedNortheast.latitude); + XCTAssertEqual(originalNortheast.longitude, draggedNortheast.longitude); + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); + XCTAssertEqual(originalSouthwest.latitude, draggedSouthwest.latitude); +} + +- (void)validateVisibleRegion:(NSString *)label + northeast:(CLLocationCoordinate2D *)northeast + southwest:(CLLocationCoordinate2D *)southwest { + // String will be "VisibleRegion:\nnortheast: LatLng(-33.79495661816674, + // 151.313996873796),\nsouthwest: LatLng(-33.90900557679571, 151.10800322145224)" + NSScanner *scan = [NSScanner scannerWithString:label]; + + // northeast + [scan scanString:@"VisibleRegion:\nnortheast: LatLng(" intoString:NULL]; + double northeastLatitude; + [scan scanDouble:&northeastLatitude]; + [scan scanString:@", " intoString:NULL]; + XCTAssertNotEqual(northeastLatitude, 0); + double northeastLongitude; + [scan scanDouble:&northeastLongitude]; + XCTAssertNotEqual(northeastLongitude, 0); + + [scan scanString:@"),\nsouthwest: LatLng(" intoString:NULL]; + double southwestLatitude; + [scan scanDouble:&southwestLatitude]; + XCTAssertNotEqual(southwestLatitude, 0); + [scan scanString:@", " intoString:NULL]; + double southwestLongitude; + [scan scanDouble:&southwestLongitude]; + XCTAssertNotEqual(southwestLongitude, 0); + *northeast = CLLocationCoordinate2DMake(northeastLatitude, northeastLongitude); + *southwest = CLLocationCoordinate2DMake(southwestLatitude, southwestLongitude); +} + +- (void)testMapClickPage { + XCTSkipIf(skipFor154641); + + XCUIApplication *app = self.app; + XCUIElement *mapClick = app.staticTexts[@"Map click"]; + if (![mapClick waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'Map click''"); + } + [mapClick tap]; + + XCUIElement *platformView = app.otherElements[@"platform_view[0]"]; + if (![platformView waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find platform view"); + } + + [platformView tap]; + + XCUIElement *tapped = app.staticTexts[@"Tapped"]; + if (![tapped waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'tapped''"); + } + + [platformView pressForDuration:5.0]; + + XCUIElement *longPressed = app.staticTexts[@"Long pressed"]; + if (![longPressed waitForExistenceWithTimeout:kWaitTime]) { + os_log_error(OS_LOG_DEFAULT, "%@", app.debugDescription); + XCTFail(@"Failed due to not able to find 'longPressed''"); + } +} + +- (void)forceTap:(XCUIElement *)button { + // iOS 16 introduced a bug where hittable is NO for buttons. We force hit the location of the + // button if that is the case. It is likely similar to + // https://github.com/flutter/flutter/issues/113377. + if (button.isHittable) { + [button tap]; + return; + } + XCUICoordinate *coordinate = [button coordinateWithNormalizedOffset:CGVectorMake(0, 0)]; + [coordinate tap]; +} + +- (void)testMarkerDraggingCallbacks { + XCTSkipIf(skipFor154641); + + XCUIApplication *application = [[XCUIApplication alloc] init]; + [application launch]; + XCUIElement *placeMarkerButton = application.staticTexts[@"Place marker"]; + if (![placeMarkerButton waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the Place marker button."); + } + [placeMarkerButton tap]; + + XCUIElement *Add = application.buttons[@"Add"]; + if (![Add waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the Add button."); + } + [Add tap]; + + XCUIElement *marker = application.buttons[@"marker_id_1"]; + if (![marker waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the marker."); + } + [marker tap]; + + XCUIElement *toggleDraggable = application.buttons[@"toggle draggable"]; + if (![toggleDraggable waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the toggle draggable."); + } + [toggleDraggable tap]; + + // Drag marker to center + [marker pressForDuration:5 thenDragToElement:application]; + + NSPredicate *predicateDragStart = + [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragStart"]; + NSPredicate *predicateDrag = + [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDrag called"]; + NSPredicate *predicateDragEnd = + [NSPredicate predicateWithFormat:@"label CONTAINS[c] %@", @"_onMarkerDragEnd"]; + + XCUIElement *dragStart = [application.staticTexts matchingPredicate:predicateDragStart].element; + if (![dragStart waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the _onMarkerDragStart."); + } + XCTAssertTrue(dragStart.exists); + + XCUIElement *drag = [application.staticTexts matchingPredicate:predicateDrag].element; + if (![drag waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the _onMarkerDrag."); + } + XCTAssertTrue(drag.exists); + + XCUIElement *dragEnd = [application.staticTexts matchingPredicate:predicateDragEnd].element; + if (![dragEnd waitForExistenceWithTimeout:kWaitTime]) { + NSLog(@"application.debugDescription: %@", application.debugDescription); + XCTFail(@"Failed to find the _onMarkerDragEnd."); + } + XCTAssertTrue(dragEnd.exists); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/Info.plist b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/Info.plist new file mode 100644 index 000000000000..64d65ca49577 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerUITests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/animate_camera.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/animate_camera.dart new file mode 100644 index 000000000000..a7c515c36928 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/animate_camera.dart @@ -0,0 +1,204 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class AnimateCameraPage extends GoogleMapExampleAppPage { + const AnimateCameraPage({Key? key}) + : super(const Icon(Icons.map), 'Camera control, animated', key: key); + + @override + Widget build(BuildContext context) { + return const AnimateCamera(); + } +} + +class AnimateCamera extends StatefulWidget { + const AnimateCamera({super.key}); + @override + State createState() => AnimateCameraState(); +} + +// Animation duration for a animation configuration. +const int _durationSeconds = 10; + +class AnimateCameraState extends State { + ExampleGoogleMapController? mapController; + Duration? _cameraUpdateAnimationDuration; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + mapController = controller; + } + + void _toggleAnimationDuration() { + setState(() { + _cameraUpdateAnimationDuration = _cameraUpdateAnimationDuration != null + ? null + : const Duration(seconds: _durationSeconds); + }); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(0.0, 0.0), + ), + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newCameraPosition( + const CameraPosition( + bearing: 270.0, + target: LatLng(51.5160895, -0.1294527), + tilt: 30.0, + zoom: 17.0, + ), + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newCameraPosition'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newLatLng( + const LatLng(56.1725505, 10.1850512), + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newLatLng'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newLatLngBounds( + LatLngBounds( + southwest: const LatLng(-38.483935, 113.248673), + northeast: const LatLng(-8.982446, 153.823821), + ), + 10.0, + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newLatLngBounds'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.newLatLngZoom( + const LatLng(37.4231613, -122.087159), + 11.0, + ), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('newLatLngZoom'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.scrollBy(150.0, -225.0), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('scrollBy'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomBy(-0.5, const Offset(30.0, 20.0)), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomBy with focus'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomBy(-0.5), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomBy'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomIn(), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomIn'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomOut(), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomOut'), + ), + TextButton( + onPressed: () { + mapController?.animateCamera( + CameraUpdate.zoomTo(16.0), + duration: _cameraUpdateAnimationDuration, + ); + }, + child: const Text('zoomTo'), + ), + ], + ), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('With 10 second duration', textAlign: TextAlign.right), + const SizedBox(width: 5), + Switch( + value: _cameraUpdateAnimationDuration != null, + onChanged: (bool value) { + _toggleAnimationDuration(); + }, + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/clustering.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/clustering.dart new file mode 100644 index 000000000000..5757717c215b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/clustering.dart @@ -0,0 +1,288 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +/// Page for demonstrating marker clustering support. +class ClusteringPage extends GoogleMapExampleAppPage { + /// Default Constructor. + const ClusteringPage({Key? key}) + : super(const Icon(Icons.place), 'Manage clustering', key: key); + + @override + Widget build(BuildContext context) { + return const ClusteringBody(); + } +} + +/// Body of the clustering page. +class ClusteringBody extends StatefulWidget { + /// Default Constructor. + const ClusteringBody({super.key}); + + @override + State createState() => ClusteringBodyState(); +} + +/// State of the clustering page. +class ClusteringBodyState extends State { + /// Default Constructor. + ClusteringBodyState(); + + /// Starting point from where markers are added. + static const LatLng center = LatLng(-33.86, 151.1547171); + + /// Marker offset factor for randomizing marker placing. + static const double _markerOffsetFactor = 0.05; + + /// Offset for longitude when placing markers to different cluster managers. + static const double _clusterManagerLongitudeOffset = 0.1; + + /// Maximum amount of cluster managers. + static const int _clusterManagerMaxCount = 3; + + /// Amount of markers to be added to the cluster manager at once. + static const int _markersToAddToClusterManagerCount = 10; + + /// Fully visible alpha value. + static const double _fullyVisibleAlpha = 1.0; + + /// Half visible alpha value. + static const double _halfVisibleAlpha = 0.5; + + /// Google map controller. + ExampleGoogleMapController? controller; + + /// Map of clusterManagers with identifier as the key. + Map clusterManagers = + {}; + + /// Map of markers with identifier as the key. + Map markers = {}; + + /// Id of the currently selected marker. + MarkerId? selectedMarker; + + /// Counter for added cluster manager ids. + int _clusterManagerIdCounter = 1; + + /// Counter for added markers ids. + int _markerIdCounter = 1; + + /// Cluster that was tapped most recently. + Cluster? lastCluster; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onMarkerTapped(MarkerId markerId) { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + final MarkerId? previousMarkerId = selectedMarker; + if (previousMarkerId != null && markers.containsKey(previousMarkerId)) { + final Marker resetOld = markers[previousMarkerId]!.copyWith( + iconParam: BitmapDescriptor.defaultMarker, + ); + markers[previousMarkerId] = resetOld; + } + selectedMarker = markerId; + final Marker newMarker = tappedMarker.copyWith( + iconParam: BitmapDescriptor.defaultMarkerWithHue( + BitmapDescriptor.hueGreen, + ), + ); + markers[markerId] = newMarker; + }); + } + } + + void _addClusterManager() { + if (clusterManagers.length == _clusterManagerMaxCount) { + return; + } + + final clusterManagerIdVal = 'cluster_manager_id_$_clusterManagerIdCounter'; + _clusterManagerIdCounter++; + final clusterManagerId = ClusterManagerId(clusterManagerIdVal); + + final clusterManager = ClusterManager( + clusterManagerId: clusterManagerId, + onClusterTap: (Cluster cluster) => setState(() { + lastCluster = cluster; + }), + ); + + setState(() { + clusterManagers[clusterManagerId] = clusterManager; + }); + _addMarkersToCluster(clusterManager); + } + + void _removeClusterManager(ClusterManager clusterManager) { + setState(() { + // Remove markers managed by cluster manager to be removed. + markers.removeWhere( + (MarkerId key, Marker marker) => + marker.clusterManagerId == clusterManager.clusterManagerId, + ); + // Remove cluster manager. + clusterManagers.remove(clusterManager.clusterManagerId); + }); + } + + void _addMarkersToCluster(ClusterManager clusterManager) { + for (var i = 0; i < _markersToAddToClusterManagerCount; i++) { + final markerIdVal = + '${clusterManager.clusterManagerId.value}_marker_id_$_markerIdCounter'; + _markerIdCounter++; + final markerId = MarkerId(markerIdVal); + + final int clusterManagerIndex = clusterManagers.values.toList().indexOf( + clusterManager, + ); + + // Add additional offset to longitude for each cluster manager to space + // out markers in different cluster managers. + final double clusterManagerLongitudeOffset = + clusterManagerIndex * _clusterManagerLongitudeOffset; + + final marker = Marker( + clusterManagerId: clusterManager.clusterManagerId, + markerId: markerId, + position: LatLng( + center.latitude + _getRandomOffset(), + center.longitude + _getRandomOffset() + clusterManagerLongitudeOffset, + ), + infoWindow: InfoWindow(title: markerIdVal, snippet: '*'), + onTap: () => _onMarkerTapped(markerId), + ); + markers[markerId] = marker; + } + setState(() {}); + } + + double _getRandomOffset() { + return (Random().nextDouble() - 0.5) * _markerOffsetFactor; + } + + void _remove(MarkerId markerId) { + setState(() { + if (markers.containsKey(markerId)) { + markers.remove(markerId); + } + }); + } + + void _changeMarkersAlpha() { + for (final MarkerId markerId in markers.keys) { + final Marker marker = markers[markerId]!; + final double current = marker.alpha; + markers[markerId] = marker.copyWith( + alphaParam: current == _fullyVisibleAlpha + ? _halfVisibleAlpha + : _fullyVisibleAlpha, + ); + } + setState(() {}); + } + + @override + Widget build(BuildContext context) { + final MarkerId? selectedId = selectedMarker; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + SizedBox( + height: 300.0, + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(-33.852, 151.25), + zoom: 11.0, + ), + markers: Set.of(markers.values), + clusterManagers: Set.of(clusterManagers.values), + ), + ), + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: clusterManagers.length >= _clusterManagerMaxCount + ? null + : () => _addClusterManager(), + child: const Text('Add cluster manager'), + ), + TextButton( + onPressed: clusterManagers.isEmpty + ? null + : () => + _removeClusterManager(clusterManagers.values.last), + child: const Text('Remove cluster manager'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + for (final MapEntry + clusterEntry + in clusterManagers.entries) + TextButton( + onPressed: () => _addMarkersToCluster(clusterEntry.value), + child: Text('Add markers to ${clusterEntry.key.value}'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: selectedId == null + ? null + : () { + _remove(selectedId); + setState(() { + selectedMarker = null; + }); + }, + child: const Text('Remove selected marker'), + ), + TextButton( + onPressed: markers.isEmpty + ? null + : () => _changeMarkersAlpha(), + child: const Text('Change all markers alpha'), + ), + ], + ), + if (lastCluster != null) + Padding( + padding: const EdgeInsets.all(10), + child: Text( + 'Cluster with ${lastCluster!.count} markers clicked at ${lastCluster!.position}', + ), + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/custom_marker_icon.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/custom_marker_icon.dart new file mode 100644 index 000000000000..548146c6206c --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/custom_marker_icon.dart @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +/// Returns a generated png image in [ByteData] format with the requested size. +Future createCustomMarkerIconImage({required Size size}) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final painter = _MarkerPainter(); + + painter.paint(canvas, size); + + final ui.Image image = await recorder.endRecording().toImage( + size.width.floor(), + size.height.floor(), + ); + + final ByteData? bytes = await image.toByteData( + format: ui.ImageByteFormat.png, + ); + return bytes!; +} + +class _MarkerPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Rect rect = Offset.zero & size; + const gradient = RadialGradient( + colors: [Colors.yellow, Colors.red], + stops: [0.4, 1.0], + ); + + // Draw radial gradient + canvas.drawRect(rect, Paint()..shader = gradient.createShader(rect)); + + // Draw diagonal black line + canvas.drawLine( + Offset.zero, + Offset(size.width, size.height), + Paint() + ..color = Colors.black + ..strokeWidth = 1, + ); + } + + @override + bool shouldRepaint(_MarkerPainter oldDelegate) => false; + @override + bool shouldRebuildSemantics(_MarkerPainter oldDelegate) => false; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/example_google_map.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/example_google_map.dart new file mode 100644 index 000000000000..152f83c16f38 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/example_google_map.dart @@ -0,0 +1,676 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +// This is a pared down version of the Dart code from the app-facing package, +// to allow running the same examples for package-local testing. +// TODO(stuartmorgan): Consider extracting this to a shared package. See also +// https://github.com/flutter/flutter/issues/46716. + +/// Controller for a single ExampleGoogleMap instance running on the host platform. +class ExampleGoogleMapController { + ExampleGoogleMapController._(this._googleMapState, {required this.mapId}) { + _connectStreams(mapId); + } + + /// The mapId for this controller + final int mapId; + + /// Initialize control of a [ExampleGoogleMap] with [id]. + /// + /// Mainly for internal use when instantiating a [ExampleGoogleMapController] passed + /// in [ExampleGoogleMap.onMapCreated] callback. + static Future _init( + int id, + CameraPosition initialCameraPosition, + _ExampleGoogleMapState googleMapState, + ) async { + await GoogleMapsFlutterPlatform.instance.init(id); + return ExampleGoogleMapController._(googleMapState, mapId: id); + } + + final _ExampleGoogleMapState _googleMapState; + + void _connectStreams(int mapId) { + if (_googleMapState.widget.onCameraMoveStarted != null) { + GoogleMapsFlutterPlatform.instance + .onCameraMoveStarted(mapId: mapId) + .listen((_) => _googleMapState.widget.onCameraMoveStarted!()); + } + if (_googleMapState.widget.onCameraMove != null) { + GoogleMapsFlutterPlatform.instance + .onCameraMove(mapId: mapId) + .listen( + (CameraMoveEvent e) => + _googleMapState.widget.onCameraMove!(e.value), + ); + } + if (_googleMapState.widget.onCameraIdle != null) { + GoogleMapsFlutterPlatform.instance + .onCameraIdle(mapId: mapId) + .listen((_) => _googleMapState.widget.onCameraIdle!()); + } + GoogleMapsFlutterPlatform.instance + .onMarkerTap(mapId: mapId) + .listen((MarkerTapEvent e) => _googleMapState.onMarkerTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onMarkerDragStart(mapId: mapId) + .listen( + (MarkerDragStartEvent e) => + _googleMapState.onMarkerDragStart(e.value, e.position), + ); + GoogleMapsFlutterPlatform.instance + .onMarkerDrag(mapId: mapId) + .listen( + (MarkerDragEvent e) => + _googleMapState.onMarkerDrag(e.value, e.position), + ); + GoogleMapsFlutterPlatform.instance + .onMarkerDragEnd(mapId: mapId) + .listen( + (MarkerDragEndEvent e) => + _googleMapState.onMarkerDragEnd(e.value, e.position), + ); + GoogleMapsFlutterPlatform.instance + .onInfoWindowTap(mapId: mapId) + .listen( + (InfoWindowTapEvent e) => _googleMapState.onInfoWindowTap(e.value), + ); + GoogleMapsFlutterPlatform.instance + .onPolylineTap(mapId: mapId) + .listen((PolylineTapEvent e) => _googleMapState.onPolylineTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onPolygonTap(mapId: mapId) + .listen((PolygonTapEvent e) => _googleMapState.onPolygonTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onCircleTap(mapId: mapId) + .listen((CircleTapEvent e) => _googleMapState.onCircleTap(e.value)); + GoogleMapsFlutterPlatform.instance + .onGroundOverlayTap(mapId: mapId) + .listen( + (GroundOverlayTapEvent e) => + _googleMapState.onGroundOverlayTap(e.value), + ); + GoogleMapsFlutterPlatform.instance + .onTap(mapId: mapId) + .listen((MapTapEvent e) => _googleMapState.onTap(e.position)); + GoogleMapsFlutterPlatform.instance + .onLongPress(mapId: mapId) + .listen( + (MapLongPressEvent e) => _googleMapState.onLongPress(e.position), + ); + GoogleMapsFlutterPlatform.instance + .onClusterTap(mapId: mapId) + .listen((ClusterTapEvent e) => _googleMapState.onClusterTap(e.value)); + } + + /// Updates configuration options of the map user interface. + Future _updateMapConfiguration(MapConfiguration update) { + return GoogleMapsFlutterPlatform.instance.updateMapConfiguration( + update, + mapId: mapId, + ); + } + + /// Updates marker configuration. + Future _updateMarkers(MarkerUpdates markerUpdates) { + return GoogleMapsFlutterPlatform.instance.updateMarkers( + markerUpdates, + mapId: mapId, + ); + } + + /// Updates cluster manager configuration. + Future _updateClusterManagers( + ClusterManagerUpdates clusterManagerUpdates, + ) { + return GoogleMapsFlutterPlatform.instance.updateClusterManagers( + clusterManagerUpdates, + mapId: mapId, + ); + } + + /// Updates ground overlay configuration. + Future _updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, + ) { + return GoogleMapsFlutterPlatform.instance.updateGroundOverlays( + groundOverlayUpdates, + mapId: mapId, + ); + } + + /// Updates polygon configuration. + Future _updatePolygons(PolygonUpdates polygonUpdates) { + return GoogleMapsFlutterPlatform.instance.updatePolygons( + polygonUpdates, + mapId: mapId, + ); + } + + /// Updates polyline configuration. + Future _updatePolylines(PolylineUpdates polylineUpdates) { + return GoogleMapsFlutterPlatform.instance.updatePolylines( + polylineUpdates, + mapId: mapId, + ); + } + + /// Updates circle configuration. + Future _updateCircles(CircleUpdates circleUpdates) { + return GoogleMapsFlutterPlatform.instance.updateCircles( + circleUpdates, + mapId: mapId, + ); + } + + /// Updates tile overlays configuration. + Future _updateTileOverlays(Set newTileOverlays) { + return GoogleMapsFlutterPlatform.instance.updateTileOverlays( + newTileOverlays: newTileOverlays, + mapId: mapId, + ); + } + + /// Clears the tile cache so that all tiles will be requested again from the + /// [TileProvider]. + Future clearTileCache(TileOverlayId tileOverlayId) async { + return GoogleMapsFlutterPlatform.instance.clearTileCache( + tileOverlayId, + mapId: mapId, + ); + } + + /// Starts an animated change of the map camera position. + Future animateCamera(CameraUpdate cameraUpdate, {Duration? duration}) { + return GoogleMapsFlutterPlatform.instance.animateCameraWithConfiguration( + cameraUpdate, + CameraUpdateAnimationConfiguration(duration: duration), + mapId: mapId, + ); + } + + /// Changes the map camera position. + Future moveCamera(CameraUpdate cameraUpdate) { + return GoogleMapsFlutterPlatform.instance.moveCamera( + cameraUpdate, + mapId: mapId, + ); + } + + /// Return [LatLngBounds] defining the region that is visible in a map. + Future getVisibleRegion() { + return GoogleMapsFlutterPlatform.instance.getVisibleRegion(mapId: mapId); + } + + /// Return [ScreenCoordinate] of the [LatLng] in the current map view. + Future getScreenCoordinate(LatLng latLng) { + return GoogleMapsFlutterPlatform.instance.getScreenCoordinate( + latLng, + mapId: mapId, + ); + } + + /// Returns [LatLng] corresponding to the [ScreenCoordinate] in the current map view. + Future getLatLng(ScreenCoordinate screenCoordinate) { + return GoogleMapsFlutterPlatform.instance.getLatLng( + screenCoordinate, + mapId: mapId, + ); + } + + /// Programmatically show the Info Window for a [Marker]. + Future showMarkerInfoWindow(MarkerId markerId) { + return GoogleMapsFlutterPlatform.instance.showMarkerInfoWindow( + markerId, + mapId: mapId, + ); + } + + /// Programmatically hide the Info Window for a [Marker]. + Future hideMarkerInfoWindow(MarkerId markerId) { + return GoogleMapsFlutterPlatform.instance.hideMarkerInfoWindow( + markerId, + mapId: mapId, + ); + } + + /// Returns `true` when the [InfoWindow] is showing, `false` otherwise. + Future isMarkerInfoWindowShown(MarkerId markerId) { + return GoogleMapsFlutterPlatform.instance.isMarkerInfoWindowShown( + markerId, + mapId: mapId, + ); + } + + /// Returns the current zoom level of the map + Future getZoomLevel() { + return GoogleMapsFlutterPlatform.instance.getZoomLevel(mapId: mapId); + } + + /// Returns the image bytes of the map + Future takeSnapshot() { + return GoogleMapsFlutterPlatform.instance.takeSnapshot(mapId: mapId); + } + + /// Returns the last style error, if any. + Future getStyleError() { + return GoogleMapsFlutterPlatform.instance.getStyleError(mapId: mapId); + } + + /// Disposes of the platform resources + void dispose() { + GoogleMapsFlutterPlatform.instance.dispose(mapId: mapId); + } +} + +// The next map ID to create. +int _nextMapCreationId = 0; + +/// A widget which displays a map with data obtained from the Google Maps service. +class ExampleGoogleMap extends StatefulWidget { + /// Creates a widget displaying data from Google Maps services. + /// + /// [AssertionError] will be thrown if [initialCameraPosition] is null; + const ExampleGoogleMap({ + super.key, + required this.initialCameraPosition, + this.onMapCreated, + this.gestureRecognizers = const >{}, + this.compassEnabled = true, + this.cameraTargetBounds = CameraTargetBounds.unbounded, + this.mapType = MapType.normal, + this.minMaxZoomPreference = MinMaxZoomPreference.unbounded, + this.rotateGesturesEnabled = true, + this.scrollGesturesEnabled = true, + this.zoomControlsEnabled = true, + this.zoomGesturesEnabled = true, + this.tiltGesturesEnabled = true, + this.myLocationEnabled = false, + this.myLocationButtonEnabled = true, + this.layoutDirection, + + /// If no padding is specified default padding will be 0. + this.padding = EdgeInsets.zero, + this.indoorViewEnabled = false, + this.trafficEnabled = false, + this.buildingsEnabled = true, + this.markers = const {}, + this.polygons = const {}, + this.polylines = const {}, + this.circles = const {}, + this.clusterManagers = const {}, + this.onCameraMoveStarted, + this.tileOverlays = const {}, + this.groundOverlays = const {}, + this.onCameraMove, + this.onCameraIdle, + this.onTap, + this.onLongPress, + this.mapId, + this.style, + }); + + /// Callback method for when the map is ready to be used. + /// + /// Used to receive a [ExampleGoogleMapController] for this [ExampleGoogleMap]. + final void Function(ExampleGoogleMapController controller)? onMapCreated; + + /// The initial position of the map's camera. + final CameraPosition initialCameraPosition; + + /// True if the map should show a compass when rotated. + final bool compassEnabled; + + /// Geographical bounding box for the camera target. + final CameraTargetBounds cameraTargetBounds; + + /// Type of map tiles to be rendered. + final MapType mapType; + + /// The layout direction to use for the embedded view. + final TextDirection? layoutDirection; + + /// Preferred bounds for the camera zoom level. + /// + /// Actual bounds depend on map data and device. + final MinMaxZoomPreference minMaxZoomPreference; + + /// True if the map view should respond to rotate gestures. + final bool rotateGesturesEnabled; + + /// True if the map view should respond to scroll gestures. + final bool scrollGesturesEnabled; + + /// True if the map view should show zoom controls. This includes two buttons + /// to zoom in and zoom out. The default value is to show zoom controls. + final bool zoomControlsEnabled; + + /// True if the map view should respond to zoom gestures. + final bool zoomGesturesEnabled; + + /// True if the map view should respond to tilt gestures. + final bool tiltGesturesEnabled; + + /// Padding to be set on map. + final EdgeInsets padding; + + /// Markers to be placed on the map. + final Set markers; + + /// Polygons to be placed on the map. + final Set polygons; + + /// Polylines to be placed on the map. + final Set polylines; + + /// Circles to be placed on the map. + final Set circles; + + /// Tile overlays to be placed on the map. + final Set tileOverlays; + + /// Cluster Managers to be placed for the map. + final Set clusterManagers; + + /// Ground overlays to be initialized for the map. + final Set groundOverlays; + + /// Called when the camera starts moving. + final VoidCallback? onCameraMoveStarted; + + /// Called repeatedly as the camera continues to move after an + /// onCameraMoveStarted call. + final CameraPositionCallback? onCameraMove; + + /// Called when camera movement has ended, there are no pending + /// animations and the user has stopped interacting with the map. + final VoidCallback? onCameraIdle; + + /// Called every time a [ExampleGoogleMap] is tapped. + final ArgumentCallback? onTap; + + /// Called every time a [ExampleGoogleMap] is long pressed. + final ArgumentCallback? onLongPress; + + /// True if a "My Location" layer should be shown on the map. + final bool myLocationEnabled; + + /// Enables or disables the my-location button. + final bool myLocationButtonEnabled; + + /// Enables or disables the indoor view from the map + final bool indoorViewEnabled; + + /// Enables or disables the traffic layer of the map + final bool trafficEnabled; + + /// Enables or disables showing 3D buildings where available + final bool buildingsEnabled; + + /// Which gestures should be consumed by the map. + final Set> gestureRecognizers; + + /// Identifier that's associated with a specific cloud-based map style. + /// + /// See https://developers.google.com/maps/documentation/get-map-id + /// for more details. + final String? mapId; + + /// The locally configured style for the map. + final String? style; + + /// Creates a [State] for this [ExampleGoogleMap]. + @override + State createState() => _ExampleGoogleMapState(); +} + +class _ExampleGoogleMapState extends State { + final int _mapId = _nextMapCreationId++; + + final Completer _controller = + Completer(); + + Map _markers = {}; + Map _polygons = {}; + Map _polylines = {}; + Map _circles = {}; + Map _clusterManagers = + {}; + Map _groundOverlays = + {}; + late MapConfiguration _mapConfiguration; + + @override + Widget build(BuildContext context) { + return GoogleMapsFlutterPlatform.instance.buildViewWithConfiguration( + _mapId, + onPlatformViewCreated, + widgetConfiguration: MapWidgetConfiguration( + textDirection: + widget.layoutDirection ?? + Directionality.maybeOf(context) ?? + TextDirection.ltr, + initialCameraPosition: widget.initialCameraPosition, + gestureRecognizers: widget.gestureRecognizers, + ), + mapObjects: MapObjects( + markers: widget.markers, + polygons: widget.polygons, + polylines: widget.polylines, + circles: widget.circles, + clusterManagers: widget.clusterManagers, + groundOverlays: widget.groundOverlays, + ), + mapConfiguration: _mapConfiguration, + ); + } + + @override + void initState() { + super.initState(); + _mapConfiguration = _configurationFromMapWidget(widget); + _clusterManagers = keyByClusterManagerId(widget.clusterManagers); + _markers = keyByMarkerId(widget.markers); + _polygons = keyByPolygonId(widget.polygons); + _polylines = keyByPolylineId(widget.polylines); + _circles = keyByCircleId(widget.circles); + _groundOverlays = keyByGroundOverlayId(widget.groundOverlays); + } + + @override + void dispose() { + _controller.future.then( + (ExampleGoogleMapController controller) => controller.dispose(), + ); + super.dispose(); + } + + @override + void didUpdateWidget(ExampleGoogleMap oldWidget) { + super.didUpdateWidget(oldWidget); + _updateOptions(); + _updateClusterManagers(); + _updateMarkers(); + _updatePolygons(); + _updatePolylines(); + _updateCircles(); + _updateTileOverlays(); + _updateGroundOverlays(); + } + + Future _updateOptions() async { + final MapConfiguration newConfig = _configurationFromMapWidget(widget); + final MapConfiguration updates = newConfig.diffFrom(_mapConfiguration); + if (updates.isEmpty) { + return; + } + final ExampleGoogleMapController controller = await _controller.future; + unawaited(controller._updateMapConfiguration(updates)); + _mapConfiguration = newConfig; + } + + Future _updateMarkers() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateMarkers( + MarkerUpdates.from(_markers.values.toSet(), widget.markers), + ), + ); + _markers = keyByMarkerId(widget.markers); + } + + Future _updateClusterManagers() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateClusterManagers( + ClusterManagerUpdates.from( + _clusterManagers.values.toSet(), + widget.clusterManagers, + ), + ), + ); + _clusterManagers = keyByClusterManagerId(widget.clusterManagers); + } + + Future _updateGroundOverlays() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateGroundOverlays( + GroundOverlayUpdates.from( + _groundOverlays.values.toSet(), + widget.groundOverlays, + ), + ), + ); + _groundOverlays = keyByGroundOverlayId(widget.groundOverlays); + } + + Future _updatePolygons() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updatePolygons( + PolygonUpdates.from(_polygons.values.toSet(), widget.polygons), + ), + ); + _polygons = keyByPolygonId(widget.polygons); + } + + Future _updatePolylines() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updatePolylines( + PolylineUpdates.from(_polylines.values.toSet(), widget.polylines), + ), + ); + _polylines = keyByPolylineId(widget.polylines); + } + + Future _updateCircles() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited( + controller._updateCircles( + CircleUpdates.from(_circles.values.toSet(), widget.circles), + ), + ); + _circles = keyByCircleId(widget.circles); + } + + Future _updateTileOverlays() async { + final ExampleGoogleMapController controller = await _controller.future; + unawaited(controller._updateTileOverlays(widget.tileOverlays)); + } + + Future onPlatformViewCreated(int id) async { + final ExampleGoogleMapController controller = + await ExampleGoogleMapController._init( + id, + widget.initialCameraPosition, + this, + ); + _controller.complete(controller); + unawaited(_updateTileOverlays()); + widget.onMapCreated?.call(controller); + } + + void onMarkerTap(MarkerId markerId) { + _markers[markerId]!.onTap?.call(); + } + + void onMarkerDragStart(MarkerId markerId, LatLng position) { + _markers[markerId]!.onDragStart?.call(position); + } + + void onMarkerDrag(MarkerId markerId, LatLng position) { + _markers[markerId]!.onDrag?.call(position); + } + + void onMarkerDragEnd(MarkerId markerId, LatLng position) { + _markers[markerId]!.onDragEnd?.call(position); + } + + void onPolygonTap(PolygonId polygonId) { + _polygons[polygonId]!.onTap?.call(); + } + + void onPolylineTap(PolylineId polylineId) { + _polylines[polylineId]!.onTap?.call(); + } + + void onCircleTap(CircleId circleId) { + _circles[circleId]!.onTap?.call(); + } + + void onGroundOverlayTap(GroundOverlayId groundOverlayId) { + _groundOverlays[groundOverlayId]!.onTap?.call(); + } + + void onInfoWindowTap(MarkerId markerId) { + _markers[markerId]!.infoWindow.onTap?.call(); + } + + void onTap(LatLng position) { + widget.onTap?.call(position); + } + + void onLongPress(LatLng position) { + widget.onLongPress?.call(position); + } + + void onClusterTap(Cluster cluster) { + final ClusterManager? clusterManager = + _clusterManagers[cluster.clusterManagerId]; + clusterManager?.onClusterTap?.call(cluster); + } +} + +/// Builds a [MapConfiguration] from the given [map]. +MapConfiguration _configurationFromMapWidget(ExampleGoogleMap map) { + return MapConfiguration( + compassEnabled: map.compassEnabled, + cameraTargetBounds: map.cameraTargetBounds, + mapType: map.mapType, + minMaxZoomPreference: map.minMaxZoomPreference, + rotateGesturesEnabled: map.rotateGesturesEnabled, + scrollGesturesEnabled: map.scrollGesturesEnabled, + tiltGesturesEnabled: map.tiltGesturesEnabled, + trackCameraPosition: map.onCameraMove != null, + zoomControlsEnabled: map.zoomControlsEnabled, + zoomGesturesEnabled: map.zoomGesturesEnabled, + myLocationEnabled: map.myLocationEnabled, + myLocationButtonEnabled: map.myLocationButtonEnabled, + padding: map.padding, + indoorViewEnabled: map.indoorViewEnabled, + trafficEnabled: map.trafficEnabled, + buildingsEnabled: map.buildingsEnabled, + mapId: map.mapId, + style: map.style, + ); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/ground_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/ground_overlay.dart new file mode 100644 index 000000000000..d8f474eb7d5e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/ground_overlay.dart @@ -0,0 +1,311 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +enum _GroundOverlayPlacing { position, bounds } + +class GroundOverlayPage extends GoogleMapExampleAppPage { + const GroundOverlayPage({Key? key}) + : super(const Icon(Icons.map), 'Ground overlay', key: key); + + @override + Widget build(BuildContext context) { + return const GroundOverlayBody(); + } +} + +class GroundOverlayBody extends StatefulWidget { + const GroundOverlayBody({super.key}); + + @override + State createState() => GroundOverlayBodyState(); +} + +class GroundOverlayBodyState extends State { + GroundOverlayBodyState(); + + ExampleGoogleMapController? controller; + GroundOverlay? _groundOverlay; + + final LatLng _mapCenter = const LatLng(37.422026, -122.085329); + + _GroundOverlayPlacing _placingType = _GroundOverlayPlacing.bounds; + + // Positions for demonstranting placing ground overlays with position, and + // changing positions. + final LatLng _groundOverlayPos1 = const LatLng(37.422026, -122.085329); + final LatLng _groundOverlayPos2 = const LatLng(37.42, -122.08); + late LatLng _currentGroundOverlayPos; + + // Bounds for demonstranting placing ground overlays with bounds, and + // changing bounds. + final LatLngBounds _groundOverlayBounds1 = LatLngBounds( + southwest: const LatLng(37.42, -122.09), + northeast: const LatLng(37.423, -122.084), + ); + final LatLngBounds _groundOverlayBounds2 = LatLngBounds( + southwest: const LatLng(37.421, -122.091), + northeast: const LatLng(37.424, -122.08), + ); + late LatLngBounds _currentGroundOverlayBounds; + + Offset _anchor = const Offset(0.5, 0.5); + + // Index to be used as identifier for the ground overlay. + // If position is changed to bounds and vice versa, the ground overlay will + // be removed and added again with the new type. Also anchor can be given only + // when the ground overlay is created with position and cannot be changed + // after the ground overlay is created. + int _groundOverlayIndex = 0; + + @override + void initState() { + _currentGroundOverlayPos = _groundOverlayPos1; + _currentGroundOverlayBounds = _groundOverlayBounds1; + super.initState(); + } + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + void _removeGroundOverlay() { + setState(() { + _groundOverlay = null; + }); + } + + Future _addGroundOverlay() async { + final AssetMapBitmap assetMapBitmap = await AssetMapBitmap.create( + createLocalImageConfiguration(context), + 'assets/red_square.png', + bitmapScaling: MapBitmapScaling.none, + ); + + _groundOverlayIndex += 1; + + final id = GroundOverlayId('ground_overlay_$_groundOverlayIndex'); + + final GroundOverlay groundOverlay = switch (_placingType) { + _GroundOverlayPlacing.position => GroundOverlay.fromPosition( + groundOverlayId: id, + image: assetMapBitmap, + position: _currentGroundOverlayPos, + anchor: _anchor, + onTap: () { + _onGroundOverlayTapped(); + }, + zoomLevel: 14.0, + ), + _GroundOverlayPlacing.bounds => GroundOverlay.fromBounds( + groundOverlayId: id, + image: assetMapBitmap, + bounds: _currentGroundOverlayBounds, + anchor: _anchor, + onTap: () { + _onGroundOverlayTapped(); + }, + ), + }; + + setState(() { + _groundOverlay = groundOverlay; + }); + } + + void _onGroundOverlayTapped() { + _changePosition(); + } + + void _setBearing() { + assert(_groundOverlay != null); + setState(() { + // Adjusts the bearing by 10 degrees, wrapping around at 360 degrees. + // 10 is the increment, 350 degrees of the full circle -10. + _groundOverlay = _groundOverlay!.copyWith( + bearingParam: _groundOverlay!.bearing >= 350 + ? 0 + : _groundOverlay!.bearing + 10, + ); + }); + } + + void _changeTransparency() { + assert(_groundOverlay != null); + setState(() { + final transparency = _groundOverlay!.transparency == 0.0 ? 0.5 : 0.0; + _groundOverlay = _groundOverlay!.copyWith( + transparencyParam: transparency, + ); + }); + } + + Future _changePosition() async { + assert(_groundOverlay != null); + assert(_placingType == _GroundOverlayPlacing.position); + setState(() { + _currentGroundOverlayPos = _currentGroundOverlayPos == _groundOverlayPos1 + ? _groundOverlayPos2 + : _groundOverlayPos1; + }); + + // Re-add the ground overlay to apply the new position, as the position + // cannot be changed after the ground overlay is created on all platforms. + await _addGroundOverlay(); + } + + Future _changeBounds() async { + assert(_groundOverlay != null); + assert(_placingType == _GroundOverlayPlacing.bounds); + setState(() { + _currentGroundOverlayBounds = + _currentGroundOverlayBounds == _groundOverlayBounds1 + ? _groundOverlayBounds2 + : _groundOverlayBounds1; + }); + + // Re-add the ground overlay to apply the new position, as the position + // cannot be changed after the ground overlay is created on all platforms. + await _addGroundOverlay(); + } + + void _toggleVisible() { + assert(_groundOverlay != null); + setState(() { + _groundOverlay = _groundOverlay!.copyWith( + visibleParam: !_groundOverlay!.visible, + ); + }); + } + + void _changeZIndex() { + assert(_groundOverlay != null); + final int current = _groundOverlay!.zIndex; + final int zIndex = current == 12 ? 0 : current + 1; + setState(() { + _groundOverlay = _groundOverlay!.copyWith(zIndexParam: zIndex); + }); + } + + Future _changeType() async { + setState(() { + _placingType = _placingType == _GroundOverlayPlacing.position + ? _GroundOverlayPlacing.bounds + : _GroundOverlayPlacing.position; + }); + + // Re-add the ground overlay to apply the new position, as the position + // cannot be changed after the ground overlay is created on all platforms. + await _addGroundOverlay(); + } + + Future _changeAnchor() async { + assert(_groundOverlay != null); + setState(() { + _anchor = _groundOverlay!.anchor == const Offset(0.5, 0.5) + ? const Offset(1.0, 1.0) + : const Offset(0.5, 0.5); + }); + + // Re-add the ground overlay to apply the new anchor, as anchor cannot be + // changed after the ground overlay is created. + await _addGroundOverlay(); + } + + @override + Widget build(BuildContext context) { + final overlays = { + if (_groundOverlay != null) _groundOverlay!, + }; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: ExampleGoogleMap( + initialCameraPosition: CameraPosition( + target: _mapCenter, + zoom: 14.0, + ), + groundOverlays: overlays, + onMapCreated: _onMapCreated, + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: _groundOverlay == null ? _addGroundOverlay : null, + child: const Text('Add'), + ), + TextButton( + onPressed: _groundOverlay != null ? _removeGroundOverlay : null, + child: const Text('Remove'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: _groundOverlay == null + ? null + : () => _changeTransparency(), + child: const Text('change transparency'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _setBearing(), + child: const Text('change bearing'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _toggleVisible(), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _changeZIndex(), + child: const Text('change zIndex'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _changeAnchor(), + child: const Text('change anchor'), + ), + TextButton( + onPressed: _groundOverlay == null ? null : () => _changeType(), + child: Text( + _placingType == _GroundOverlayPlacing.position + ? 'use bounds' + : 'use position', + ), + ), + TextButton( + onPressed: + _placingType != _GroundOverlayPlacing.position || + _groundOverlay == null + ? null + : () => _changePosition(), + child: const Text('change position'), + ), + TextButton( + onPressed: + _placingType != _GroundOverlayPlacing.bounds || + _groundOverlay == null + ? null + : () => _changeBounds(), + child: const Text('change bounds'), + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/lite_mode.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/lite_mode.dart new file mode 100644 index 000000000000..e6359e19acc2 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/lite_mode.dart @@ -0,0 +1,46 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class LiteModePage extends GoogleMapExampleAppPage { + const LiteModePage({Key? key}) + : super(const Icon(Icons.map), 'Lite mode', key: key); + + @override + Widget build(BuildContext context) { + return const _LiteModeBody(); + } +} + +class _LiteModeBody extends StatelessWidget { + const _LiteModeBody(); + + @override + Widget build(BuildContext context) { + return const Card( + child: Padding( + padding: EdgeInsets.symmetric(vertical: 30.0), + child: Center( + child: SizedBox( + width: 300.0, + height: 300.0, + child: ExampleGoogleMap(initialCameraPosition: _kInitialPosition), + ), + ), + ), + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/main.dart new file mode 100644 index 000000000000..605e4e3a57ec --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/main.dart @@ -0,0 +1,53 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'animate_camera.dart'; +import 'clustering.dart'; +import 'ground_overlay.dart'; +import 'lite_mode.dart'; +import 'map_click.dart'; +import 'map_coordinates.dart'; +import 'map_map_id.dart'; +import 'map_ui.dart'; +import 'maps_demo.dart'; +import 'marker_icons.dart'; +import 'move_camera.dart'; +import 'padding.dart'; +import 'page.dart'; +import 'place_circle.dart'; +import 'place_marker.dart'; +import 'place_polygon.dart'; +import 'place_polyline.dart'; +import 'scrolling_map.dart'; +import 'snapshot.dart'; +import 'tile_overlay.dart'; + +void main() { + runApp( + const MaterialApp( + home: MapsDemo([ + MapUiPage(), + MapCoordinatesPage(), + MapClickPage(), + AnimateCameraPage(), + MoveCameraPage(), + PlaceMarkerPage(), + MarkerIconsPage(), + ScrollingMapPage(), + PlacePolylinePage(), + PlacePolygonPage(), + PlaceCirclePage(), + PaddingPage(), + SnapshotPage(), + LiteModePage(), + TileOverlayPage(), + GroundOverlayPage(), + ClusteringPage(), + MapIdPage(), + ]), + ), + ); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_click.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_click.dart new file mode 100644 index 000000000000..4d45e961d63e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_click.dart @@ -0,0 +1,105 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class MapClickPage extends GoogleMapExampleAppPage { + const MapClickPage({Key? key}) + : super(const Icon(Icons.mouse), 'Map click', key: key); + + @override + Widget build(BuildContext context) { + return const _MapClickBody(); + } +} + +class _MapClickBody extends StatefulWidget { + const _MapClickBody(); + + @override + State createState() => _MapClickBodyState(); +} + +class _MapClickBodyState extends State<_MapClickBody> { + _MapClickBodyState(); + + ExampleGoogleMapController? mapController; + LatLng? _lastTap; + LatLng? _lastLongPress; + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + onTap: (LatLng pos) { + setState(() { + _lastTap = pos; + }); + }, + onLongPress: (LatLng pos) { + setState(() { + _lastLongPress = pos; + }); + }, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + ]; + + if (mapController != null) { + final lastTap = 'Tap:\n${_lastTap ?? ""}\n'; + final lastLongPress = 'Long press:\n${_lastLongPress ?? ""}'; + columnChildren.add( + Center(child: Text(lastTap, textAlign: TextAlign.center)), + ); + columnChildren.add( + Center( + child: Text( + _lastTap != null ? 'Tapped' : '', + textAlign: TextAlign.center, + ), + ), + ); + columnChildren.add( + Center(child: Text(lastLongPress, textAlign: TextAlign.center)), + ); + columnChildren.add( + Center( + child: Text( + _lastLongPress != null ? 'Long pressed' : '', + textAlign: TextAlign.center, + ), + ), + ); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + Future onMapCreated(ExampleGoogleMapController controller) async { + setState(() { + mapController = controller; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_coordinates.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_coordinates.dart new file mode 100644 index 000000000000..3a93b0db93b7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_coordinates.dart @@ -0,0 +1,105 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class MapCoordinatesPage extends GoogleMapExampleAppPage { + const MapCoordinatesPage({Key? key}) + : super(const Icon(Icons.map), 'Map coordinates', key: key); + + @override + Widget build(BuildContext context) { + return const _MapCoordinatesBody(); + } +} + +class _MapCoordinatesBody extends StatefulWidget { + const _MapCoordinatesBody(); + + @override + State createState() => _MapCoordinatesBodyState(); +} + +class _MapCoordinatesBodyState extends State<_MapCoordinatesBody> { + _MapCoordinatesBodyState(); + + ExampleGoogleMapController? mapController; + LatLngBounds _visibleRegion = LatLngBounds( + southwest: const LatLng(0, 0), + northeast: const LatLng(0, 0), + ); + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + onCameraIdle: + _updateVisibleRegion, // https://github.com/flutter/flutter/issues/54758 + ); + + return NotificationListener( + onNotification: (ScrollNotification scrollState) { + _updateVisibleRegion(); + return true; + }, + child: Stack( + children: [ + ListView( + children: [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: googleMap, + ), + ), + ), + // Add a block at the bottom of this list to allow validation that the visible region of the map + // does not change when scrolled under the safe view on iOS. + // https://github.com/flutter/flutter/issues/107913 + const SizedBox(width: 300, height: 1000), + ], + ), + if (mapController != null) + Center( + child: Text( + 'VisibleRegion:' + '\nnortheast: ${_visibleRegion.northeast},' + '\nsouthwest: ${_visibleRegion.southwest}', + ), + ), + ], + ), + ); + } + + Future onMapCreated(ExampleGoogleMapController controller) async { + final LatLngBounds visibleRegion = await controller.getVisibleRegion(); + setState(() { + mapController = controller; + _visibleRegion = visibleRegion; + }); + } + + Future _updateVisibleRegion() async { + final LatLngBounds visibleRegion = await mapController!.getVisibleRegion(); + setState(() { + _visibleRegion = visibleRegion; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_map_id.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_map_id.dart new file mode 100644 index 000000000000..c62152f149d0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_map_id.dart @@ -0,0 +1,100 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class MapIdPage extends GoogleMapExampleAppPage { + const MapIdPage({Key? key}) + : super(const Icon(Icons.map), 'Cloud-based maps styling', key: key); + + @override + Widget build(BuildContext context) { + return const MapIdBody(); + } +} + +class MapIdBody extends StatefulWidget { + const MapIdBody({super.key}); + + @override + State createState() => MapIdBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +class MapIdBodyState extends State { + ExampleGoogleMapController? controller; + + Key _key = const Key('mapId#'); + String? _mapId; + final TextEditingController _mapIdController = TextEditingController(); + + void _setMapId() { + setState(() { + _mapId = _mapIdController.text; + + // Change key to initialize new map instance for new mapId. + _key = Key(_mapId ?? 'mapId#'); + }); + } + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + key: _key, + mapId: _mapId, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: TextField( + controller: _mapIdController, + decoration: const InputDecoration(hintText: 'Map Id'), + ), + ), + Padding( + padding: const EdgeInsets.all(10.0), + child: ElevatedButton( + onPressed: () => _setMapId(), + child: const Text('Press to use specified map Id'), + ), + ), + ]; + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + @override + void dispose() { + _mapIdController.dispose(); + super.dispose(); + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_ui.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_ui.dart new file mode 100644 index 000000000000..46fa320ad3a0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/map_ui.dart @@ -0,0 +1,341 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart' show rootBundle; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +final LatLngBounds sydneyBounds = LatLngBounds( + southwest: const LatLng(-34.022631, 150.620685), + northeast: const LatLng(-33.571835, 151.325952), +); + +class MapUiPage extends GoogleMapExampleAppPage { + const MapUiPage({Key? key}) + : super(const Icon(Icons.map), 'User interface', key: key); + + @override + Widget build(BuildContext context) { + return const MapUiBody(); + } +} + +class MapUiBody extends StatefulWidget { + const MapUiBody({super.key}); + + @override + State createState() => MapUiBodyState(); +} + +class MapUiBodyState extends State { + MapUiBodyState(); + + static const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, + ); + + CameraPosition _position = _kInitialPosition; + bool _isMapCreated = false; + final bool _isMoving = false; + bool _compassEnabled = true; + CameraTargetBounds _cameraTargetBounds = CameraTargetBounds.unbounded; + MinMaxZoomPreference _minMaxZoomPreference = MinMaxZoomPreference.unbounded; + MapType _mapType = MapType.normal; + bool _rotateGesturesEnabled = true; + bool _scrollGesturesEnabled = true; + bool _tiltGesturesEnabled = true; + bool _zoomControlsEnabled = false; + bool _zoomGesturesEnabled = true; + bool _indoorViewEnabled = true; + bool _myLocationEnabled = true; + bool _myTrafficEnabled = false; + bool _myLocationButtonEnabled = true; + late ExampleGoogleMapController _controller; + bool _nightMode = false; + String _mapStyle = ''; + + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + Widget _compassToggler() { + return TextButton( + child: Text('${_compassEnabled ? 'disable' : 'enable'} compass'), + onPressed: () { + setState(() { + _compassEnabled = !_compassEnabled; + }); + }, + ); + } + + Widget _latLngBoundsToggler() { + return TextButton( + child: Text( + _cameraTargetBounds.bounds == null + ? 'bound camera target' + : 'release camera target', + ), + onPressed: () { + setState(() { + _cameraTargetBounds = _cameraTargetBounds.bounds == null + ? CameraTargetBounds(sydneyBounds) + : CameraTargetBounds.unbounded; + }); + }, + ); + } + + Widget _zoomBoundsToggler() { + return TextButton( + child: Text( + _minMaxZoomPreference.minZoom == null ? 'bound zoom' : 'release zoom', + ), + onPressed: () { + setState(() { + _minMaxZoomPreference = _minMaxZoomPreference.minZoom == null + ? const MinMaxZoomPreference(12.0, 16.0) + : MinMaxZoomPreference.unbounded; + }); + }, + ); + } + + Widget _mapTypeCycler() { + final MapType nextType = + MapType.values[(_mapType.index + 1) % MapType.values.length]; + return TextButton( + child: Text('change map type to $nextType'), + onPressed: () { + setState(() { + _mapType = nextType; + }); + }, + ); + } + + Widget _rotateToggler() { + return TextButton( + child: Text('${_rotateGesturesEnabled ? 'disable' : 'enable'} rotate'), + onPressed: () { + setState(() { + _rotateGesturesEnabled = !_rotateGesturesEnabled; + }); + }, + ); + } + + Widget _scrollToggler() { + return TextButton( + child: Text('${_scrollGesturesEnabled ? 'disable' : 'enable'} scroll'), + onPressed: () { + setState(() { + _scrollGesturesEnabled = !_scrollGesturesEnabled; + }); + }, + ); + } + + Widget _tiltToggler() { + return TextButton( + child: Text('${_tiltGesturesEnabled ? 'disable' : 'enable'} tilt'), + onPressed: () { + setState(() { + _tiltGesturesEnabled = !_tiltGesturesEnabled; + }); + }, + ); + } + + Widget _zoomToggler() { + return TextButton( + child: Text('${_zoomGesturesEnabled ? 'disable' : 'enable'} zoom'), + onPressed: () { + setState(() { + _zoomGesturesEnabled = !_zoomGesturesEnabled; + }); + }, + ); + } + + Widget _zoomControlsToggler() { + return TextButton( + child: Text( + '${_zoomControlsEnabled ? 'disable' : 'enable'} zoom controls', + ), + onPressed: () { + setState(() { + _zoomControlsEnabled = !_zoomControlsEnabled; + }); + }, + ); + } + + Widget _indoorViewToggler() { + return TextButton( + child: Text('${_indoorViewEnabled ? 'disable' : 'enable'} indoor'), + onPressed: () { + setState(() { + _indoorViewEnabled = !_indoorViewEnabled; + }); + }, + ); + } + + Widget _myLocationToggler() { + return TextButton( + child: Text( + '${_myLocationEnabled ? 'disable' : 'enable'} my location marker', + ), + onPressed: () { + setState(() { + _myLocationEnabled = !_myLocationEnabled; + }); + }, + ); + } + + Widget _myLocationButtonToggler() { + return TextButton( + child: Text( + '${_myLocationButtonEnabled ? 'disable' : 'enable'} my location button', + ), + onPressed: () { + setState(() { + _myLocationButtonEnabled = !_myLocationButtonEnabled; + }); + }, + ); + } + + Widget _myTrafficToggler() { + return TextButton( + child: Text('${_myTrafficEnabled ? 'disable' : 'enable'} my traffic'), + onPressed: () { + setState(() { + _myTrafficEnabled = !_myTrafficEnabled; + }); + }, + ); + } + + Future _getFileData(String path) async { + return rootBundle.loadString(path); + } + + Widget _nightModeToggler() { + return TextButton( + child: Text('${_nightMode ? 'disable' : 'enable'} night mode'), + onPressed: () async { + _nightMode = !_nightMode; + final String style = _nightMode + ? await _getFileData('assets/night_mode.json') + : ''; + setState(() { + _mapStyle = style; + }); + }, + ); + } + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + compassEnabled: _compassEnabled, + cameraTargetBounds: _cameraTargetBounds, + minMaxZoomPreference: _minMaxZoomPreference, + mapType: _mapType, + style: _mapStyle, + rotateGesturesEnabled: _rotateGesturesEnabled, + scrollGesturesEnabled: _scrollGesturesEnabled, + tiltGesturesEnabled: _tiltGesturesEnabled, + zoomGesturesEnabled: _zoomGesturesEnabled, + zoomControlsEnabled: _zoomControlsEnabled, + indoorViewEnabled: _indoorViewEnabled, + myLocationEnabled: _myLocationEnabled, + myLocationButtonEnabled: _myLocationButtonEnabled, + trafficEnabled: _myTrafficEnabled, + onCameraMove: _updateCameraPosition, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + ]; + + if (_isMapCreated) { + columnChildren.add( + Expanded( + child: ListView( + children: [ + Text('camera bearing: ${_position.bearing}'), + Text( + 'camera target: ${_position.target.latitude.toStringAsFixed(4)},' + '${_position.target.longitude.toStringAsFixed(4)}', + ), + Text('camera zoom: ${_position.zoom}'), + Text('camera tilt: ${_position.tilt}'), + Text(_isMoving ? '(Camera moving)' : '(Camera idle)'), + _compassToggler(), + _latLngBoundsToggler(), + _mapTypeCycler(), + _zoomBoundsToggler(), + _rotateToggler(), + _scrollToggler(), + _tiltToggler(), + _zoomToggler(), + _zoomControlsToggler(), + _indoorViewToggler(), + _myLocationToggler(), + _myLocationButtonToggler(), + _myTrafficToggler(), + _nightModeToggler(), + ], + ), + ), + ); + } + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + void _updateCameraPosition(CameraPosition position) { + setState(() { + _position = position; + }); + } + + void onMapCreated(ExampleGoogleMapController controller) { + setState(() { + _controller = controller; + _isMapCreated = true; + }); + // Log any style errors to the console for debugging. + _controller.getStyleError().then((String? error) { + if (error != null) { + debugPrint(error); + } + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/maps_demo.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/maps_demo.dart new file mode 100644 index 000000000000..6d21ab3b91e9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/maps_demo.dart @@ -0,0 +1,42 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +import 'page.dart'; + +/// MapsDemo is the Main Application. +class MapsDemo extends StatelessWidget { + /// Default Constructor + const MapsDemo(this.pages, {super.key}); + + /// The list of demo pages. + final List pages; + + void _pushPage(BuildContext context, GoogleMapExampleAppPage page) { + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => Scaffold( + appBar: AppBar(title: Text(page.title)), + body: page, + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('GoogleMaps examples')), + body: ListView.builder( + itemCount: pages.length, + itemBuilder: (_, int index) => ListTile( + leading: pages[index].leading, + title: Text(pages[index].title), + onTap: () => _pushPage(context, pages[index]), + ), + ), + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/marker_icons.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/marker_icons.dart new file mode 100644 index 000000000000..2959c7c0dcf0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/marker_icons.dart @@ -0,0 +1,355 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs +// ignore_for_file: unawaited_futures + +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'custom_marker_icon.dart'; +import 'example_google_map.dart'; +import 'page.dart'; + +class MarkerIconsPage extends GoogleMapExampleAppPage { + const MarkerIconsPage({Key? key}) + : super(const Icon(Icons.image), 'Marker icons', key: key); + + @override + Widget build(BuildContext context) { + return const MarkerIconsBody(); + } +} + +class MarkerIconsBody extends StatefulWidget { + const MarkerIconsBody({super.key}); + + @override + State createState() => MarkerIconsBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +enum _MarkerSizeOption { original, width30, height40, size30x60, size120x60 } + +class MarkerIconsBodyState extends State { + final Size _markerAssetImageSize = const Size(48, 48); + _MarkerSizeOption _currentSizeOption = _MarkerSizeOption.original; + Set _markers = {}; + bool _scalingEnabled = true; + bool _mipMapsEnabled = true; + ExampleGoogleMapController? controller; + AssetMapBitmap? _markerIconAsset; + BytesMapBitmap? _markerIconBytes; + final int _markersAmountPerType = 15; + bool get _customSizeEnabled => + _currentSizeOption != _MarkerSizeOption.original; + + @override + Widget build(BuildContext context) { + _createCustomMarkerIconImages(context); + final Size referenceSize = _getMarkerReferenceSize(); + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Column( + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + markers: _markers, + onMapCreated: _onMapCreated, + ), + ), + ), + TextButton( + onPressed: () => _toggleScaling(context), + child: Text( + _scalingEnabled + ? 'Disable auto scaling' + : 'Enable auto scaling', + ), + ), + if (_scalingEnabled) ...[ + Container( + width: referenceSize.width, + height: referenceSize.height, + decoration: BoxDecoration(border: Border.all()), + ), + Text( + 'Reference box with size of ${referenceSize.width} x ${referenceSize.height} in logical pixels.', + ), + const SizedBox(height: 10), + Image.asset( + 'assets/red_square.png', + scale: _mipMapsEnabled ? null : 1.0, + ), + const Text('Asset image rendered with flutter'), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Marker size:'), + const SizedBox(width: 10), + DropdownButton<_MarkerSizeOption>( + value: _currentSizeOption, + onChanged: (_MarkerSizeOption? newValue) { + if (newValue != null) { + setState(() { + _currentSizeOption = newValue; + _updateMarkerImages(context); + }); + } + }, + items: _MarkerSizeOption.values.map(( + _MarkerSizeOption option, + ) { + return DropdownMenuItem<_MarkerSizeOption>( + value: option, + child: Text(_getMarkerSizeOptionName(option)), + ); + }).toList(), + ), + ], + ), + ], + TextButton( + onPressed: () => _toggleMipMaps(context), + child: Text( + _mipMapsEnabled ? 'Disable mipmaps' : 'Enable mipmaps', + ), + ), + ], + ), + ], + ); + } + + String _getMarkerSizeOptionName(_MarkerSizeOption option) { + switch (option) { + case _MarkerSizeOption.original: + return 'Original'; + case _MarkerSizeOption.width30: + return 'Width 30'; + case _MarkerSizeOption.height40: + return 'Height 40'; + case _MarkerSizeOption.size30x60: + return '30x60'; + case _MarkerSizeOption.size120x60: + return '120x60'; + } + } + + (double? width, double? height) _getCurrentMarkerSize() { + if (_scalingEnabled) { + switch (_currentSizeOption) { + case _MarkerSizeOption.width30: + return (30, null); + case _MarkerSizeOption.height40: + return (null, 40); + case _MarkerSizeOption.size30x60: + return (30, 60); + case _MarkerSizeOption.size120x60: + return (120, 60); + case _MarkerSizeOption.original: + return (_markerAssetImageSize.width, _markerAssetImageSize.height); + } + } else { + return (_markerAssetImageSize.width, _markerAssetImageSize.height); + } + } + + // Helper method to calculate reference size for custom marker size. + Size _getMarkerReferenceSize() { + final (double? width, double? height) = _getCurrentMarkerSize(); + + // Calculates reference size using _markerAssetImageSize aspect ration: + + if (width != null && height != null) { + return Size(width, height); + } else if (width != null) { + return Size( + width, + width * _markerAssetImageSize.height / _markerAssetImageSize.width, + ); + } else if (height != null) { + return Size( + height * _markerAssetImageSize.width / _markerAssetImageSize.height, + height, + ); + } else { + return _markerAssetImageSize; + } + } + + void _toggleMipMaps(BuildContext context) { + _mipMapsEnabled = !_mipMapsEnabled; + _updateMarkerImages(context); + } + + void _toggleScaling(BuildContext context) { + _scalingEnabled = !_scalingEnabled; + _updateMarkerImages(context); + } + + void _updateMarkerImages(BuildContext context) { + _updateMarkerAssetImage(context); + _updateMarkerBytesImage(context); + _updateMarkers(); + } + + Marker _createAssetMarker(int index) { + final position = LatLng( + _kMapCenter.latitude - (index * 0.5), + _kMapCenter.longitude - 1, + ); + + return Marker( + markerId: MarkerId('marker_asset_$index'), + position: position, + icon: _markerIconAsset!, + ); + } + + Marker _createBytesMarker(int index) { + final position = LatLng( + _kMapCenter.latitude - (index * 0.5), + _kMapCenter.longitude + 1, + ); + + return Marker( + markerId: MarkerId('marker_bytes_$index'), + position: position, + icon: _markerIconBytes!, + ); + } + + void _updateMarkers() { + final markers = {}; + for (var i = 0; i < _markersAmountPerType; i++) { + if (_markerIconAsset != null) { + markers.add(_createAssetMarker(i)); + } + if (_markerIconBytes != null) { + markers.add(_createBytesMarker(i)); + } + } + setState(() { + _markers = markers; + }); + } + + Future _updateMarkerAssetImage(BuildContext context) async { + // Width and height are used only for custom size. + final ( + double? width, + double? height, + ) = _scalingEnabled && _customSizeEnabled + ? _getCurrentMarkerSize() + : (null, null); + + AssetMapBitmap assetMapBitmap; + if (_mipMapsEnabled) { + final ImageConfiguration imageConfiguration = + createLocalImageConfiguration(context); + + assetMapBitmap = await AssetMapBitmap.create( + imageConfiguration, + 'assets/red_square.png', + width: width, + height: height, + bitmapScaling: _scalingEnabled + ? MapBitmapScaling.auto + : MapBitmapScaling.none, + ); + } else { + // Uses hardcoded asset path + // This bypasses the asset resolving logic and allows to load the asset + // with precise path. + assetMapBitmap = AssetMapBitmap( + 'assets/red_square.png', + width: width, + height: height, + bitmapScaling: _scalingEnabled + ? MapBitmapScaling.auto + : MapBitmapScaling.none, + ); + } + + _updateAssetBitmap(assetMapBitmap); + } + + Future _updateMarkerBytesImage(BuildContext context) async { + final double? devicePixelRatio = MediaQuery.maybeDevicePixelRatioOf( + context, + ); + + final Size bitmapLogicalSize = _getMarkerReferenceSize(); + final double? imagePixelRatio = _scalingEnabled ? devicePixelRatio : null; + + // Create canvasSize with physical marker size + final canvasSize = Size( + bitmapLogicalSize.width * (imagePixelRatio ?? 1.0), + bitmapLogicalSize.height * (imagePixelRatio ?? 1.0), + ); + + final ByteData bytes = await createCustomMarkerIconImage(size: canvasSize); + + // Width and height are used only for custom size. + final ( + double? width, + double? height, + ) = _scalingEnabled && _customSizeEnabled + ? _getCurrentMarkerSize() + : (null, null); + + final bitmap = BytesMapBitmap( + bytes.buffer.asUint8List(), + imagePixelRatio: imagePixelRatio, + width: width, + height: height, + bitmapScaling: _scalingEnabled + ? MapBitmapScaling.auto + : MapBitmapScaling.none, + ); + + _updateBytesBitmap(bitmap); + } + + void _updateAssetBitmap(AssetMapBitmap bitmap) { + _markerIconAsset = bitmap; + _updateMarkers(); + } + + void _updateBytesBitmap(BytesMapBitmap bitmap) { + _markerIconBytes = bitmap; + _updateMarkers(); + } + + void _createCustomMarkerIconImages(BuildContext context) { + if (_markerIconAsset == null) { + _updateMarkerAssetImage(context); + } + + if (_markerIconBytes == null) { + _updateMarkerBytesImage(context); + } + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/move_camera.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/move_camera.dart new file mode 100644 index 000000000000..bc6fcdea2651 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/move_camera.dart @@ -0,0 +1,161 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class MoveCameraPage extends GoogleMapExampleAppPage { + const MoveCameraPage({Key? key}) + : super(const Icon(Icons.map), 'Camera control', key: key); + + @override + Widget build(BuildContext context) { + return const MoveCamera(); + } +} + +class MoveCamera extends StatefulWidget { + const MoveCamera({super.key}); + @override + State createState() => MoveCameraState(); +} + +class MoveCameraState extends State { + ExampleGoogleMapController? mapController; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + mapController = controller; + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 300.0, + height: 200.0, + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(0.0, 0.0), + ), + ), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newCameraPosition( + const CameraPosition( + bearing: 270.0, + target: LatLng(51.5160895, -0.1294527), + tilt: 30.0, + zoom: 17.0, + ), + ), + ); + }, + child: const Text('newCameraPosition'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newLatLng( + const LatLng(56.1725505, 10.1850512), + ), + ); + }, + child: const Text('newLatLng'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newLatLngBounds( + LatLngBounds( + southwest: const LatLng(-38.483935, 113.248673), + northeast: const LatLng(-8.982446, 153.823821), + ), + 10.0, + ), + ); + }, + child: const Text('newLatLngBounds'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.newLatLngZoom( + const LatLng(37.4231613, -122.087159), + 11.0, + ), + ); + }, + child: const Text('newLatLngZoom'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.scrollBy(150.0, -225.0), + ); + }, + child: const Text('scrollBy'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: () { + mapController?.moveCamera( + CameraUpdate.zoomBy(-0.5, const Offset(30.0, 20.0)), + ); + }, + child: const Text('zoomBy with focus'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomBy(-0.5)); + }, + child: const Text('zoomBy'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomIn()); + }, + child: const Text('zoomIn'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomOut()); + }, + child: const Text('zoomOut'), + ), + TextButton( + onPressed: () { + mapController?.moveCamera(CameraUpdate.zoomTo(16.0)); + }, + child: const Text('zoomTo'), + ), + ], + ), + ], + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/padding.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/padding.dart new file mode 100644 index 000000000000..beb39b305f58 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/padding.dart @@ -0,0 +1,169 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PaddingPage extends GoogleMapExampleAppPage { + const PaddingPage({Key? key}) + : super(const Icon(Icons.map), 'Add padding to the map', key: key); + + @override + Widget build(BuildContext context) { + return const MarkerIconsBody(); + } +} + +class MarkerIconsBody extends StatefulWidget { + const MarkerIconsBody({super.key}); + + @override + State createState() => MarkerIconsBodyState(); +} + +const LatLng _kMapCenter = LatLng(52.4478, -3.5402); + +class MarkerIconsBodyState extends State { + ExampleGoogleMapController? controller; + + EdgeInsets _padding = EdgeInsets.zero; + + @override + Widget build(BuildContext context) { + final googleMap = ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + padding: _padding, + ); + + final columnChildren = [ + Padding( + padding: const EdgeInsets.all(10.0), + child: Center( + child: SizedBox(width: 300.0, height: 200.0, child: googleMap), + ), + ), + const Padding( + padding: EdgeInsets.only(top: 20), + child: Center( + child: Text( + 'Enter Padding Below', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), + ), + ), + ), + ]; + + columnChildren.addAll([_paddingInput(), _buttons()]); + + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: columnChildren, + ); + } + + void _onMapCreated(ExampleGoogleMapController controllerParam) { + setState(() { + controller = controllerParam; + }); + } + + final TextEditingController _topController = TextEditingController(); + final TextEditingController _bottomController = TextEditingController(); + final TextEditingController _leftController = TextEditingController(); + final TextEditingController _rightController = TextEditingController(); + + Widget _paddingInput() { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Row( + children: [ + Flexible( + flex: 2, + child: TextField( + controller: _topController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Top'), + ), + ), + const Spacer(), + Flexible( + flex: 2, + child: TextField( + controller: _bottomController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Bottom'), + ), + ), + const Spacer(), + Flexible( + flex: 2, + child: TextField( + controller: _leftController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Left'), + ), + ), + const Spacer(), + Flexible( + flex: 2, + child: TextField( + controller: _rightController, + keyboardType: TextInputType.number, + textAlign: TextAlign.center, + decoration: const InputDecoration(hintText: 'Right'), + ), + ), + ], + ), + ); + } + + Widget _buttons() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton( + child: const Text('Set Padding'), + onPressed: () { + setState(() { + _padding = EdgeInsets.fromLTRB( + double.tryParse(_leftController.value.text) ?? 0, + double.tryParse(_topController.value.text) ?? 0, + double.tryParse(_rightController.value.text) ?? 0, + double.tryParse(_bottomController.value.text) ?? 0, + ); + }); + }, + ), + TextButton( + child: const Text('Reset Padding'), + onPressed: () { + setState(() { + _topController.clear(); + _bottomController.clear(); + _leftController.clear(); + _rightController.clear(); + _padding = EdgeInsets.zero; + }); + }, + ), + ], + ), + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/page.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/page.dart new file mode 100644 index 000000000000..2793b9d10edb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/page.dart @@ -0,0 +1,14 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; + +abstract class GoogleMapExampleAppPage extends StatelessWidget { + const GoogleMapExampleAppPage(this.leading, this.title, {super.key}); + + final Widget leading; + final String title; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_circle.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_circle.dart new file mode 100644 index 000000000000..88c84c79e124 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_circle.dart @@ -0,0 +1,227 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PlaceCirclePage extends GoogleMapExampleAppPage { + const PlaceCirclePage({Key? key}) + : super(const Icon(Icons.linear_scale), 'Place circle', key: key); + + @override + Widget build(BuildContext context) { + return const PlaceCircleBody(); + } +} + +class PlaceCircleBody extends StatefulWidget { + const PlaceCircleBody({super.key}); + + @override + State createState() => PlaceCircleBodyState(); +} + +class PlaceCircleBodyState extends State { + PlaceCircleBodyState(); + + ExampleGoogleMapController? controller; + Map circles = {}; + int _circleIdCounter = 1; + CircleId? selectedCircle; + + // Values when toggling circle color + int fillColorsIndex = 0; + int strokeColorsIndex = 0; + List colors = [ + Colors.purple, + Colors.red, + Colors.green, + Colors.pink, + ]; + + // Values when toggling circle stroke width + int widthsIndex = 0; + List widths = [10, 20, 5]; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onCircleTapped(CircleId circleId) { + setState(() { + selectedCircle = circleId; + }); + } + + void _remove(CircleId circleId) { + setState(() { + if (circles.containsKey(circleId)) { + circles.remove(circleId); + } + if (circleId == selectedCircle) { + selectedCircle = null; + } + }); + } + + void _add() { + final int circleCount = circles.length; + + if (circleCount == 12) { + return; + } + + final circleIdVal = 'circle_id_$_circleIdCounter'; + _circleIdCounter++; + final circleId = CircleId(circleIdVal); + + final circle = Circle( + circleId: circleId, + consumeTapEvents: true, + strokeColor: Colors.orange, + fillColor: Colors.green, + strokeWidth: 5, + center: _createCenter(), + radius: 50000, + onTap: () { + _onCircleTapped(circleId); + }, + ); + + setState(() { + circles[circleId] = circle; + }); + } + + void _toggleVisible(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith(visibleParam: !circle.visible); + }); + } + + void _changeFillColor(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith( + fillColorParam: colors[++fillColorsIndex % colors.length], + ); + }); + } + + void _changeStrokeColor(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith( + strokeColorParam: colors[++strokeColorsIndex % colors.length], + ); + }); + } + + void _changeStrokeWidth(CircleId circleId) { + final Circle circle = circles[circleId]!; + setState(() { + circles[circleId] = circle.copyWith( + strokeWidthParam: widths[++widthsIndex % widths.length], + ); + }); + } + + @override + Widget build(BuildContext context) { + final CircleId? selectedId = selectedCircle; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(52.4478, -3.5402), + zoom: 7.0, + ), + circles: Set.of(circles.values), + onMapCreated: _onMapCreated, + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + TextButton(onPressed: _add, child: const Text('add')), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), + child: const Text('remove'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeStrokeWidth(selectedId), + child: const Text('change stroke width'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeStrokeColor(selectedId), + child: const Text('change stroke color'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeFillColor(selectedId), + child: const Text('change fill color'), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ); + } + + LatLng _createCenter() { + final double offset = _circleIdCounter.ceilToDouble(); + return _createLatLng(51.4816 + offset * 0.2, -3.1791); + } + + LatLng _createLatLng(double lat, double lng) { + return LatLng(lat, lng); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_marker.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_marker.dart new file mode 100644 index 000000000000..926c2db2e426 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_marker.dart @@ -0,0 +1,417 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:async'; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'custom_marker_icon.dart'; +import 'example_google_map.dart'; +import 'page.dart'; + +class PlaceMarkerPage extends GoogleMapExampleAppPage { + const PlaceMarkerPage({Key? key}) + : super(const Icon(Icons.place), 'Place marker', key: key); + + @override + Widget build(BuildContext context) { + return const PlaceMarkerBody(); + } +} + +class PlaceMarkerBody extends StatefulWidget { + const PlaceMarkerBody({super.key}); + + @override + State createState() => PlaceMarkerBodyState(); +} + +typedef MarkerUpdateAction = Marker Function(Marker marker); + +class PlaceMarkerBodyState extends State { + PlaceMarkerBodyState(); + static const LatLng center = LatLng(-33.86711, 151.1947171); + + ExampleGoogleMapController? controller; + Map markers = {}; + MarkerId? selectedMarker; + int _markerIdCounter = 1; + LatLng? markerPosition; + // A helper text for Xcode UITests. + String _onDragXcodeUITestHelperText = ''; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onMarkerTapped(MarkerId markerId) { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + final MarkerId? previousMarkerId = selectedMarker; + if (previousMarkerId != null && markers.containsKey(previousMarkerId)) { + final Marker resetOld = markers[previousMarkerId]!.copyWith( + iconParam: BitmapDescriptor.defaultMarker, + ); + markers[previousMarkerId] = resetOld; + } + selectedMarker = markerId; + final Marker newMarker = tappedMarker.copyWith( + iconParam: BitmapDescriptor.defaultMarkerWithHue( + BitmapDescriptor.hueGreen, + ), + ); + markers[markerId] = newMarker; + + markerPosition = null; + }); + } + } + + Future _onMarkerDrag(MarkerId markerId, LatLng newPosition) async { + setState(() { + markerPosition = newPosition; + if (!_onDragXcodeUITestHelperText.contains('\n_onMarkerDrag called')) { + // _onMarkerDrag can be called multiple times during a single drag. + // Only log _onMarkerDrag once per dragging action to reduce noises in UI. + _onDragXcodeUITestHelperText += '\n_onMarkerDrag called'; + } + }); + } + + Future _onMarkerDragStart(MarkerId markerId, LatLng newPosition) async { + setState(() { + _onDragXcodeUITestHelperText += '\n_onMarkerDragStart'; + }); + } + + Future _onMarkerDragEnd(MarkerId markerId, LatLng newPosition) async { + final Marker? tappedMarker = markers[markerId]; + if (tappedMarker != null) { + setState(() { + _onDragXcodeUITestHelperText += '\n_onMarkerDragEnd'; + markerPosition = null; + }); + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + actions: [ + TextButton( + child: const Text('OK'), + onPressed: () { + _onDragXcodeUITestHelperText = ''; + Navigator.of(context).pop(); + }, + ), + ], + content: Padding( + padding: const EdgeInsets.symmetric(vertical: 66), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text('iOS delegate called: \n $_onDragXcodeUITestHelperText'), + Text('Old position: ${tappedMarker.position}'), + Text('New position: $newPosition'), + ], + ), + ), + ); + }, + ); + } + } + + void _add() { + final int markerCount = markers.length; + + if (markerCount == 12) { + return; + } + + final markerIdVal = 'marker_id_$_markerIdCounter'; + _markerIdCounter++; + final markerId = MarkerId(markerIdVal); + + final marker = Marker( + markerId: markerId, + position: LatLng( + center.latitude + sin(_markerIdCounter * pi / 6.0) / 20.0, + center.longitude + cos(_markerIdCounter * pi / 6.0) / 20.0, + ), + infoWindow: InfoWindow(title: markerIdVal, snippet: '*'), + onTap: () => _onMarkerTapped(markerId), + onDragStart: (LatLng position) => _onMarkerDragStart(markerId, position), + onDragEnd: (LatLng position) => _onMarkerDragEnd(markerId, position), + onDrag: (LatLng position) => _onMarkerDrag(markerId, position), + ); + + setState(() { + markers[markerId] = marker; + }); + } + + void _remove(MarkerId markerId) { + setState(() { + if (markers.containsKey(markerId)) { + markers.remove(markerId); + } + }); + } + + void _changePosition(MarkerId markerId) { + final Marker marker = markers[markerId]!; + final LatLng current = marker.position; + final offset = Offset( + center.latitude - current.latitude, + center.longitude - current.longitude, + ); + setState(() { + markers[markerId] = marker.copyWith( + positionParam: LatLng( + center.latitude + offset.dy, + center.longitude + offset.dx, + ), + ); + }); + } + + void _changeAnchor(MarkerId markerId) { + final Marker marker = markers[markerId]!; + final Offset currentAnchor = marker.anchor; + final newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); + setState(() { + markers[markerId] = marker.copyWith(anchorParam: newAnchor); + }); + } + + Future _changeInfoAnchor(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final Offset currentAnchor = marker.infoWindow.anchor; + final newAnchor = Offset(1.0 - currentAnchor.dy, currentAnchor.dx); + setState(() { + markers[markerId] = marker.copyWith( + infoWindowParam: marker.infoWindow.copyWith(anchorParam: newAnchor), + ); + }); + } + + Future _toggleDraggable(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(draggableParam: !marker.draggable); + }); + } + + Future _toggleFlat(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(flatParam: !marker.flat); + }); + } + + Future _changeInfo(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final newSnippet = '${marker.infoWindow.snippet!}*'; + setState(() { + markers[markerId] = marker.copyWith( + infoWindowParam: marker.infoWindow.copyWith(snippetParam: newSnippet), + ); + }); + } + + Future _changeAlpha(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final double current = marker.alpha; + setState(() { + markers[markerId] = marker.copyWith( + alphaParam: current < 0.1 ? 1.0 : current * 0.75, + ); + }); + } + + Future _changeRotation(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final double current = marker.rotation; + setState(() { + markers[markerId] = marker.copyWith( + rotationParam: current == 330.0 ? 0.0 : current + 30.0, + ); + }); + } + + Future _toggleVisible(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(visibleParam: !marker.visible); + }); + } + + Future _changeZIndex(MarkerId markerId) async { + final Marker marker = markers[markerId]!; + final int current = marker.zIndexInt; + setState(() { + markers[markerId] = marker.copyWith( + zIndexIntParam: current == 12 ? 0 : current + 1, + ); + }); + } + + void _setMarkerIcon(MarkerId markerId, BitmapDescriptor assetIcon) { + final Marker marker = markers[markerId]!; + setState(() { + markers[markerId] = marker.copyWith(iconParam: assetIcon); + }); + } + + Future _getMarkerIcon(BuildContext context) async { + const canvasSize = Size(48, 48); + final ByteData bytes = await createCustomMarkerIconImage(size: canvasSize); + return BytesMapBitmap(bytes.buffer.asUint8List()); + } + + @override + Widget build(BuildContext context) { + final MarkerId? selectedId = selectedMarker; + return Stack( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: ExampleGoogleMap( + onMapCreated: _onMapCreated, + initialCameraPosition: const CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, + ), + markers: Set.of(markers.values), + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TextButton(onPressed: _add, child: const Text('Add')), + TextButton( + onPressed: selectedId == null + ? null + : () => _remove(selectedId), + child: const Text('Remove'), + ), + ], + ), + Wrap( + alignment: WrapAlignment.spaceEvenly, + children: [ + TextButton( + onPressed: selectedId == null + ? null + : () => _changeInfo(selectedId), + child: const Text('change info'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeInfoAnchor(selectedId), + child: const Text('change info anchor'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeAlpha(selectedId), + child: const Text('change alpha'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeAnchor(selectedId), + child: const Text('change anchor'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _toggleDraggable(selectedId), + child: const Text('toggle draggable'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _toggleFlat(selectedId), + child: const Text('toggle flat'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changePosition(selectedId), + child: const Text('change position'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeRotation(selectedId), + child: const Text('change rotation'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () => _changeZIndex(selectedId), + child: const Text('change zIndex'), + ), + TextButton( + onPressed: selectedId == null + ? null + : () { + _getMarkerIcon(context).then((BitmapDescriptor icon) { + _setMarkerIcon(selectedId, icon); + }); + }, + child: const Text('set marker icon'), + ), + ], + ), + ], + ), + Visibility( + visible: markerPosition != null, + child: Container( + color: Colors.white70, + height: 30, + padding: const EdgeInsets.only(left: 12, right: 12), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + if (markerPosition == null) + Container() + else + Expanded(child: Text('lat: ${markerPosition!.latitude}')), + if (markerPosition == null) + Container() + else + Expanded(child: Text('lng: ${markerPosition!.longitude}')), + ], + ), + ), + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_polygon.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_polygon.dart new file mode 100644 index 000000000000..ff9eac82210c --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_polygon.dart @@ -0,0 +1,298 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PlacePolygonPage extends GoogleMapExampleAppPage { + const PlacePolygonPage({Key? key}) + : super(const Icon(Icons.linear_scale), 'Place polygon', key: key); + + @override + Widget build(BuildContext context) { + return const PlacePolygonBody(); + } +} + +class PlacePolygonBody extends StatefulWidget { + const PlacePolygonBody({super.key}); + + @override + State createState() => PlacePolygonBodyState(); +} + +class PlacePolygonBodyState extends State { + PlacePolygonBodyState(); + + ExampleGoogleMapController? controller; + Map polygons = {}; + Map polygonOffsets = {}; + int _polygonIdCounter = 0; + PolygonId? selectedPolygon; + + // Values when toggling polygon color + int strokeColorsIndex = 0; + int fillColorsIndex = 0; + List colors = [ + Colors.purple, + Colors.red, + Colors.green, + Colors.pink, + ]; + + // Values when toggling polygon width + int widthsIndex = 0; + List widths = [10, 20, 5]; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onPolygonTapped(PolygonId polygonId) { + setState(() { + selectedPolygon = polygonId; + }); + } + + void _remove(PolygonId polygonId) { + setState(() { + if (polygons.containsKey(polygonId)) { + polygons.remove(polygonId); + } + selectedPolygon = null; + }); + } + + void _add() { + final int polygonCount = polygons.length; + + if (polygonCount == 12) { + return; + } + + final polygonIdVal = 'polygon_id_$_polygonIdCounter'; + final polygonId = PolygonId(polygonIdVal); + + final polygon = Polygon( + polygonId: polygonId, + consumeTapEvents: true, + strokeColor: Colors.orange, + strokeWidth: 5, + fillColor: Colors.green, + points: _createPoints(), + onTap: () { + _onPolygonTapped(polygonId); + }, + ); + + setState(() { + polygons[polygonId] = polygon; + polygonOffsets[polygonId] = _polygonIdCounter.ceilToDouble(); + // increment _polygonIdCounter to have unique polygon id each time + _polygonIdCounter++; + }); + } + + void _toggleGeodesic(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith(geodesicParam: !polygon.geodesic); + }); + } + + void _toggleVisible(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith(visibleParam: !polygon.visible); + }); + } + + void _changeStrokeColor(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + strokeColorParam: colors[++strokeColorsIndex % colors.length], + ); + }); + } + + void _changeFillColor(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + fillColorParam: colors[++fillColorsIndex % colors.length], + ); + }); + } + + void _changeWidth(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + strokeWidthParam: widths[++widthsIndex % widths.length], + ); + }); + } + + void _addHoles(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith( + holesParam: _createHoles(polygonId), + ); + }); + } + + void _removeHoles(PolygonId polygonId) { + final Polygon polygon = polygons[polygonId]!; + setState(() { + polygons[polygonId] = polygon.copyWith(holesParam: >[]); + }); + } + + @override + Widget build(BuildContext context) { + final PolygonId? selectedId = selectedPolygon; + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(52.4478, -3.5402), + zoom: 7.0, + ), + polygons: Set.of(polygons.values), + onMapCreated: _onMapCreated, + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + TextButton(onPressed: _add, child: const Text('add')), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), + child: const Text('remove'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleGeodesic(selectedId), + child: const Text('toggle geodesic'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: (selectedId == null) + ? null + : (polygons[selectedId]!.holes.isNotEmpty + ? null + : () => _addHoles(selectedId)), + child: const Text('add holes'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : (polygons[selectedId]!.holes.isEmpty + ? null + : () => _removeHoles(selectedId)), + child: const Text('remove holes'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeWidth(selectedId), + child: const Text('change stroke width'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeStrokeColor(selectedId), + child: const Text('change stroke color'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeFillColor(selectedId), + child: const Text('change fill color'), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ); + } + + List _createPoints() { + final points = []; + final double offset = _polygonIdCounter.ceilToDouble(); + points.add(_createLatLng(51.2395 + offset, -3.4314)); + points.add(_createLatLng(53.5234 + offset, -3.5314)); + points.add(_createLatLng(52.4351 + offset, -4.5235)); + points.add(_createLatLng(52.1231 + offset, -5.0829)); + return points; + } + + List> _createHoles(PolygonId polygonId) { + final holes = >[]; + final double offset = polygonOffsets[polygonId]!; + + final hole1 = []; + hole1.add(_createLatLng(51.8395 + offset, -3.8814)); + hole1.add(_createLatLng(52.0234 + offset, -3.9914)); + hole1.add(_createLatLng(52.1351 + offset, -4.4435)); + hole1.add(_createLatLng(52.0231 + offset, -4.5829)); + holes.add(hole1); + + final hole2 = []; + hole2.add(_createLatLng(52.2395 + offset, -3.6814)); + hole2.add(_createLatLng(52.4234 + offset, -3.7914)); + hole2.add(_createLatLng(52.5351 + offset, -4.2435)); + hole2.add(_createLatLng(52.4231 + offset, -4.3829)); + holes.add(hole2); + + return holes; + } + + LatLng _createLatLng(double lat, double lng) { + return LatLng(lat, lng); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_polyline.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_polyline.dart new file mode 100644 index 000000000000..f749cac5f268 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/place_polyline.dart @@ -0,0 +1,322 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class PlacePolylinePage extends GoogleMapExampleAppPage { + const PlacePolylinePage({Key? key}) + : super(const Icon(Icons.linear_scale), 'Place polyline', key: key); + + @override + Widget build(BuildContext context) { + return const PlacePolylineBody(); + } +} + +class PlacePolylineBody extends StatefulWidget { + const PlacePolylineBody({super.key}); + + @override + State createState() => PlacePolylineBodyState(); +} + +class PlacePolylineBodyState extends State { + PlacePolylineBodyState(); + + ExampleGoogleMapController? controller; + Map polylines = {}; + int _polylineIdCounter = 0; + PolylineId? selectedPolyline; + + // Values when toggling polyline color + int colorsIndex = 0; + List colors = [ + Colors.purple, + Colors.red, + Colors.green, + Colors.pink, + ]; + + // Values when toggling polyline width + int widthsIndex = 0; + List widths = [10, 20, 5]; + + int jointTypesIndex = 0; + List jointTypes = [ + JointType.mitered, + JointType.bevel, + JointType.round, + ]; + + // Values when toggling polyline end cap type + int endCapsIndex = 0; + List endCaps = [Cap.buttCap, Cap.squareCap, Cap.roundCap]; + + // Values when toggling polyline start cap type + int startCapsIndex = 0; + List startCaps = [Cap.buttCap, Cap.squareCap, Cap.roundCap]; + + // Values when toggling polyline pattern + int patternsIndex = 0; + List> patterns = >[ + [], + [ + PatternItem.dash(30.0), + PatternItem.gap(20.0), + PatternItem.dot, + PatternItem.gap(20.0), + ], + [PatternItem.dash(30.0), PatternItem.gap(20.0)], + [PatternItem.dot, PatternItem.gap(10.0)], + ]; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _onPolylineTapped(PolylineId polylineId) { + setState(() { + selectedPolyline = polylineId; + }); + } + + void _remove(PolylineId polylineId) { + setState(() { + if (polylines.containsKey(polylineId)) { + polylines.remove(polylineId); + } + selectedPolyline = null; + }); + } + + void _add() { + final int polylineCount = polylines.length; + + if (polylineCount == 12) { + return; + } + + final polylineIdVal = 'polyline_id_$_polylineIdCounter'; + _polylineIdCounter++; + final polylineId = PolylineId(polylineIdVal); + + final polyline = Polyline( + polylineId: polylineId, + consumeTapEvents: true, + color: Colors.orange, + width: 5, + points: _createPoints(), + onTap: () { + _onPolylineTapped(polylineId); + }, + ); + + setState(() { + polylines[polylineId] = polyline; + }); + } + + void _toggleGeodesic(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + geodesicParam: !polyline.geodesic, + ); + }); + } + + void _toggleVisible(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + visibleParam: !polyline.visible, + ); + }); + } + + void _changeColor(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + colorParam: colors[++colorsIndex % colors.length], + ); + }); + } + + void _changeWidth(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + widthParam: widths[++widthsIndex % widths.length], + ); + }); + } + + void _changeJointType(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + jointTypeParam: jointTypes[++jointTypesIndex % jointTypes.length], + ); + }); + } + + void _changeEndCap(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + endCapParam: endCaps[++endCapsIndex % endCaps.length], + ); + }); + } + + void _changeStartCap(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + startCapParam: startCaps[++startCapsIndex % startCaps.length], + ); + }); + } + + void _changePattern(PolylineId polylineId) { + final Polyline polyline = polylines[polylineId]!; + setState(() { + polylines[polylineId] = polyline.copyWith( + patternsParam: patterns[++patternsIndex % patterns.length], + ); + }); + } + + @override + Widget build(BuildContext context) { + final bool isIOS = !kIsWeb && defaultTargetPlatform == TargetPlatform.iOS; + + final PolylineId? selectedId = selectedPolyline; + + return Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(53.1721, -3.5402), + zoom: 7.0, + ), + polylines: Set.of(polylines.values), + onMapCreated: _onMapCreated, + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + children: [ + Column( + children: [ + TextButton(onPressed: _add, child: const Text('add')), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _remove(selectedId), + child: const Text('remove'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleVisible(selectedId), + child: const Text('toggle visible'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _toggleGeodesic(selectedId), + child: const Text('toggle geodesic'), + ), + ], + ), + Column( + children: [ + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeWidth(selectedId), + child: const Text('change width'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changeColor(selectedId), + child: const Text('change color'), + ), + TextButton( + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeStartCap(selectedId), + child: const Text('change start cap [Android only]'), + ), + TextButton( + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeEndCap(selectedId), + child: const Text('change end cap [Android only]'), + ), + TextButton( + onPressed: isIOS || (selectedId == null) + ? null + : () => _changeJointType(selectedId), + child: const Text('change joint type [Android only]'), + ), + TextButton( + onPressed: (selectedId == null) + ? null + : () => _changePattern(selectedId), + child: const Text('change pattern'), + ), + ], + ), + ], + ), + ], + ), + ), + ), + ], + ); + } + + List _createPoints() { + final points = []; + final double offset = _polylineIdCounter.ceilToDouble(); + points.add(_createLatLng(51.4816 + offset, -3.1791)); + points.add(_createLatLng(53.0430 + offset, -2.9925)); + points.add(_createLatLng(53.1396 + offset, -4.2739)); + points.add(_createLatLng(52.4153 + offset, -4.0829)); + return points; + } + + LatLng _createLatLng(double lat, double lng) { + return LatLng(lat, lng); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/scrolling_map.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/scrolling_map.dart new file mode 100644 index 000000000000..57d8cd6d9ff4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/scrolling_map.dart @@ -0,0 +1,112 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const LatLng _center = LatLng(32.080664, 34.9563837); + +class ScrollingMapPage extends GoogleMapExampleAppPage { + const ScrollingMapPage({Key? key}) + : super(const Icon(Icons.map), 'Scrolling map', key: key); + + @override + Widget build(BuildContext context) { + return const ScrollingMapBody(); + } +} + +class ScrollingMapBody extends StatelessWidget { + const ScrollingMapBody({super.key}); + + @override + Widget build(BuildContext context) { + return ListView( + children: [ + Card( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 30.0), + child: Column( + children: [ + const Padding( + padding: EdgeInsets.only(bottom: 12.0), + child: Text('This map consumes all touch events.'), + ), + Center( + child: SizedBox( + width: 300.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: _center, + zoom: 11.0, + ), + gestureRecognizers: // + >{ + Factory( + () => EagerGestureRecognizer(), + ), + }, + ), + ), + ), + ], + ), + ), + ), + Card( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 30.0), + child: Column( + children: [ + const Text("This map doesn't consume the vertical drags."), + const Padding( + padding: EdgeInsets.only(bottom: 12.0), + child: Text( + 'It still gets other gestures (e.g scale or tap).', + ), + ), + Center( + child: SizedBox( + width: 300.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: _center, + zoom: 11.0, + ), + markers: { + Marker( + markerId: const MarkerId('test_marker_id'), + position: LatLng(_center.latitude, _center.longitude), + infoWindow: const InfoWindow( + title: 'An interesting location', + snippet: '*', + ), + ), + }, + gestureRecognizers: + >{ + Factory( + () => ScaleGestureRecognizer(), + ), + }, + ), + ), + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/snapshot.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/snapshot.dart new file mode 100644 index 000000000000..8fa4d67b6422 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/snapshot.dart @@ -0,0 +1,81 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:typed_data'; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +const CameraPosition _kInitialPosition = CameraPosition( + target: LatLng(-33.852, 151.211), + zoom: 11.0, +); + +class SnapshotPage extends GoogleMapExampleAppPage { + const SnapshotPage({Key? key}) + : super( + const Icon(Icons.camera_alt), + 'Take a snapshot of the map', + key: key, + ); + + @override + Widget build(BuildContext context) { + return _SnapshotBody(); + } +} + +class _SnapshotBody extends StatefulWidget { + @override + _SnapshotBodyState createState() => _SnapshotBodyState(); +} + +class _SnapshotBodyState extends State<_SnapshotBody> { + ExampleGoogleMapController? _mapController; + Uint8List? _imageBytes; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox( + height: 180, + child: ExampleGoogleMap( + onMapCreated: onMapCreated, + initialCameraPosition: _kInitialPosition, + ), + ), + TextButton( + child: const Text('Take a snapshot'), + onPressed: () async { + final Uint8List? imageBytes = await _mapController + ?.takeSnapshot(); + setState(() { + _imageBytes = imageBytes; + }); + }, + ), + Container( + decoration: BoxDecoration(color: Colors.blueGrey[50]), + height: 180, + child: _imageBytes != null ? Image.memory(_imageBytes!) : null, + ), + ], + ), + ); + } + + // ignore: use_setters_to_change_properties + void onMapCreated(ExampleGoogleMapController controller) { + _mapController = controller; + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/tile_overlay.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/tile_overlay.dart new file mode 100644 index 000000000000..bcce3b5f387b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/lib/tile_overlay.dart @@ -0,0 +1,147 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: public_member_api_docs + +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'example_google_map.dart'; +import 'page.dart'; + +class TileOverlayPage extends GoogleMapExampleAppPage { + const TileOverlayPage({Key? key}) + : super(const Icon(Icons.map), 'Tile overlay', key: key); + + @override + Widget build(BuildContext context) { + return const TileOverlayBody(); + } +} + +class TileOverlayBody extends StatefulWidget { + const TileOverlayBody({super.key}); + + @override + State createState() => TileOverlayBodyState(); +} + +class TileOverlayBodyState extends State { + TileOverlayBodyState(); + + ExampleGoogleMapController? controller; + TileOverlay? _tileOverlay; + + // ignore: use_setters_to_change_properties + void _onMapCreated(ExampleGoogleMapController controller) { + this.controller = controller; + } + + @override + void dispose() { + super.dispose(); + } + + void _removeTileOverlay() { + setState(() { + _tileOverlay = null; + }); + } + + void _addTileOverlay() { + final tileOverlay = TileOverlay( + tileOverlayId: const TileOverlayId('tile_overlay_1'), + tileProvider: _DebugTileProvider(), + ); + setState(() { + _tileOverlay = tileOverlay; + }); + } + + void _clearTileCache() { + if (_tileOverlay != null && controller != null) { + controller!.clearTileCache(_tileOverlay!.tileOverlayId); + } + } + + @override + Widget build(BuildContext context) { + final overlays = {if (_tileOverlay != null) _tileOverlay!}; + return Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition( + target: LatLng(59.935460, 30.325177), + zoom: 7.0, + ), + tileOverlays: overlays, + onMapCreated: _onMapCreated, + ), + ), + ), + TextButton( + onPressed: _addTileOverlay, + child: const Text('Add tile overlay'), + ), + TextButton( + onPressed: _removeTileOverlay, + child: const Text('Remove tile overlay'), + ), + TextButton( + onPressed: _clearTileCache, + child: const Text('Clear tile cache'), + ), + ], + ); + } +} + +class _DebugTileProvider implements TileProvider { + _DebugTileProvider() { + boxPaint.isAntiAlias = true; + boxPaint.color = Colors.blue; + boxPaint.strokeWidth = 2.0; + boxPaint.style = PaintingStyle.stroke; + } + + static const int width = 100; + static const int height = 100; + static final Paint boxPaint = Paint(); + static const TextStyle textStyle = TextStyle(color: Colors.red, fontSize: 20); + + @override + Future getTile(int x, int y, int? zoom) async { + final recorder = ui.PictureRecorder(); + final canvas = Canvas(recorder); + final textSpan = TextSpan(text: '$x,$y', style: textStyle); + final textPainter = TextPainter( + text: textSpan, + textDirection: TextDirection.ltr, + ); + textPainter.layout(maxWidth: width.toDouble()); + textPainter.paint(canvas, Offset.zero); + canvas.drawRect( + Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), + boxPaint, + ); + final ui.Picture picture = recorder.endRecording(); + final Uint8List byteData = await picture + .toImage(width, height) + .then( + (ui.Image image) => image.toByteData(format: ui.ImageByteFormat.png), + ) + .then((ByteData? byteData) => byteData!.buffer.asUint8List()); + return Tile(width, height, byteData); + } +} 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 new file mode 100644 index 000000000000..d439bbf8cd46 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/pubspec.yaml @@ -0,0 +1,33 @@ +name: google_maps_flutter_example +description: Demonstrates how to use the google_maps_flutter plugin. +publish_to: none + +environment: + sdk: ^3.9.0 + flutter: ">=3.35.0" + +dependencies: + cupertino_icons: ^1.0.5 + flutter: + sdk: flutter + flutter_plugin_android_lifecycle: ^2.0.1 + google_maps_flutter_ios_sdk9: + # When depending on this package from a real application you should use: + # google_maps_flutter_ios_sdk9: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # 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.13.0 + +dev_dependencies: + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + stream_transform: ^2.0.0 + +flutter: + uses-material-design: true + assets: + - assets/ diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/example_google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/example_google_map_test.dart new file mode 100644 index 000000000000..261fc473e8bb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/example_google_map_test.dart @@ -0,0 +1,176 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_example/example_google_map.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'fake_google_maps_flutter_platform.dart'; + +Widget _mapWithObjects({ + Set circles = const {}, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set tileOverlays = const {}, +}) { + return Directionality( + textDirection: TextDirection.ltr, + child: ExampleGoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + circles: circles, + markers: markers, + polygons: polygons, + polylines: polylines, + tileOverlays: tileOverlays, + ), + ); +} + +void main() { + late FakeGoogleMapsFlutterPlatform platform; + + setUp(() { + platform = FakeGoogleMapsFlutterPlatform(); + GoogleMapsFlutterPlatform.instance = platform; + }); + + testWidgets('circle updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const c1 = Circle(circleId: CircleId('circle_1')); + const c2 = Circle(circleId: CircleId('circle_2')); + const c3 = Circle(circleId: CircleId('circle_3'), radius: 1); + const c3updated = Circle(circleId: CircleId('circle_3'), radius: 10); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(circles: {c1, c2})); + await tester.pumpWidget(_mapWithObjects(circles: {c1, c3})); + await tester.pumpWidget(_mapWithObjects(circles: {c1, c3updated})); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.circleUpdates.length, 3); + + expect(map.circleUpdates[0].circlesToChange.isEmpty, true); + expect(map.circleUpdates[0].circlesToAdd, {c1, c2}); + expect(map.circleUpdates[0].circleIdsToRemove.isEmpty, true); + + expect(map.circleUpdates[1].circlesToChange.isEmpty, true); + expect(map.circleUpdates[1].circlesToAdd, {c3}); + expect(map.circleUpdates[1].circleIdsToRemove, {c2.circleId}); + + expect(map.circleUpdates[2].circlesToChange, {c3updated}); + expect(map.circleUpdates[2].circlesToAdd.isEmpty, true); + expect(map.circleUpdates[2].circleIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); + + testWidgets('marker updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const m1 = Marker(markerId: MarkerId('marker_1')); + const m2 = Marker(markerId: MarkerId('marker_2')); + const m3 = Marker(markerId: MarkerId('marker_3')); + const m3updated = Marker(markerId: MarkerId('marker_3'), draggable: true); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(markers: {m1, m2})); + await tester.pumpWidget(_mapWithObjects(markers: {m1, m3})); + await tester.pumpWidget(_mapWithObjects(markers: {m1, m3updated})); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.markerUpdates.length, 3); + + expect(map.markerUpdates[0].markersToChange.isEmpty, true); + expect(map.markerUpdates[0].markersToAdd, {m1, m2}); + expect(map.markerUpdates[0].markerIdsToRemove.isEmpty, true); + + expect(map.markerUpdates[1].markersToChange.isEmpty, true); + expect(map.markerUpdates[1].markersToAdd, {m3}); + expect(map.markerUpdates[1].markerIdsToRemove, {m2.markerId}); + + expect(map.markerUpdates[2].markersToChange, {m3updated}); + expect(map.markerUpdates[2].markersToAdd.isEmpty, true); + expect(map.markerUpdates[2].markerIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); + + testWidgets('polygon updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const p1 = Polygon(polygonId: PolygonId('polygon_1')); + const p2 = Polygon(polygonId: PolygonId('polygon_2')); + const p3 = Polygon(polygonId: PolygonId('polygon_3'), strokeWidth: 1); + const p3updated = Polygon( + polygonId: PolygonId('polygon_3'), + strokeWidth: 2, + ); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(polygons: {p1, p2})); + await tester.pumpWidget(_mapWithObjects(polygons: {p1, p3})); + await tester.pumpWidget( + _mapWithObjects(polygons: {p1, p3updated}), + ); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.polygonUpdates.length, 3); + + expect(map.polygonUpdates[0].polygonsToChange.isEmpty, true); + expect(map.polygonUpdates[0].polygonsToAdd, {p1, p2}); + expect(map.polygonUpdates[0].polygonIdsToRemove.isEmpty, true); + + expect(map.polygonUpdates[1].polygonsToChange.isEmpty, true); + expect(map.polygonUpdates[1].polygonsToAdd, {p3}); + expect(map.polygonUpdates[1].polygonIdsToRemove, {p2.polygonId}); + + expect(map.polygonUpdates[2].polygonsToChange, {p3updated}); + expect(map.polygonUpdates[2].polygonsToAdd.isEmpty, true); + expect(map.polygonUpdates[2].polygonIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); + + testWidgets('polyline updates with delays', (WidgetTester tester) async { + platform.simulatePlatformDelay = true; + + const p1 = Polyline(polylineId: PolylineId('polyline_1')); + const p2 = Polyline(polylineId: PolylineId('polyline_2')); + const p3 = Polyline(polylineId: PolylineId('polyline_3'), width: 1); + const p3updated = Polyline(polylineId: PolylineId('polyline_3'), width: 2); + + // First remove one and add another, then update the new one. + await tester.pumpWidget(_mapWithObjects(polylines: {p1, p2})); + await tester.pumpWidget(_mapWithObjects(polylines: {p1, p3})); + await tester.pumpWidget( + _mapWithObjects(polylines: {p1, p3updated}), + ); + + final PlatformMapStateRecorder map = platform.lastCreatedMap; + + expect(map.polylineUpdates.length, 3); + + expect(map.polylineUpdates[0].polylinesToChange.isEmpty, true); + expect(map.polylineUpdates[0].polylinesToAdd, {p1, p2}); + expect(map.polylineUpdates[0].polylineIdsToRemove.isEmpty, true); + + expect(map.polylineUpdates[1].polylinesToChange.isEmpty, true); + expect(map.polylineUpdates[1].polylinesToAdd, {p3}); + expect(map.polylineUpdates[1].polylineIdsToRemove, { + p2.polylineId, + }); + + expect(map.polylineUpdates[2].polylinesToChange, {p3updated}); + expect(map.polylineUpdates[2].polylinesToAdd.isEmpty, true); + expect(map.polylineUpdates[2].polylineIdsToRemove.isEmpty, true); + + await tester.pumpAndSettle(); + }); +} 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 new file mode 100644 index 000000000000..899a7709c548 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test/fake_google_maps_flutter_platform.dart @@ -0,0 +1,350 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:stream_transform/stream_transform.dart'; + +// A dummy implementation of the platform interface for tests. +class FakeGoogleMapsFlutterPlatform extends GoogleMapsFlutterPlatform { + FakeGoogleMapsFlutterPlatform(); + + /// The IDs passed to each call to buildView, in call order. + List createdIds = []; + + /// A map of creation IDs to fake map instances. + Map mapInstances = + {}; + + PlatformMapStateRecorder get lastCreatedMap => mapInstances[createdIds.last]!; + + /// Whether to add a small delay to async calls to simulate more realistic + /// async behavior (simulating the platform channel calls most + /// implementations will do). + /// + /// When true, requires tests to `pumpAndSettle` at the end of the test + /// to avoid exceptions. + bool simulatePlatformDelay = false; + + /// Whether `dispose` has been called. + bool disposed = false; + + /// Stream controller to inject events for testing. + final StreamController> mapEventStreamController = + StreamController>.broadcast(); + + @override + Future init(int mapId) async {} + + @override + Future updateMapConfiguration( + MapConfiguration update, { + required int mapId, + }) async { + mapInstances[mapId]?.mapConfiguration = update; + await _fakeDelay(); + } + + @override + Future updateMarkers( + MarkerUpdates markerUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.markerUpdates.add(markerUpdates); + await _fakeDelay(); + } + + @override + Future updatePolygons( + PolygonUpdates polygonUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.polygonUpdates.add(polygonUpdates); + await _fakeDelay(); + } + + @override + Future updatePolylines( + PolylineUpdates polylineUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.polylineUpdates.add(polylineUpdates); + await _fakeDelay(); + } + + @override + Future updateCircles( + CircleUpdates circleUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.circleUpdates.add(circleUpdates); + await _fakeDelay(); + } + + @override + Future updateTileOverlays({ + required Set newTileOverlays, + required int mapId, + }) async { + mapInstances[mapId]?.tileOverlaySets.add(newTileOverlays); + await _fakeDelay(); + } + + @override + Future updateClusterManagers( + ClusterManagerUpdates clusterManagerUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.clusterManagerUpdates.add(clusterManagerUpdates); + await _fakeDelay(); + } + + @override + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) async { + mapInstances[mapId]?.groundOverlayUpdates.add(groundOverlayUpdates); + await _fakeDelay(); + } + + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + required int mapId, + }) async {} + + @override + Future animateCamera( + CameraUpdate cameraUpdate, { + required int mapId, + }) async {} + + @override + Future animateCameraWithConfiguration( + CameraUpdate cameraUpdate, + CameraUpdateAnimationConfiguration configuration, { + required int mapId, + }) async {} + + @override + Future moveCamera( + CameraUpdate cameraUpdate, { + required int mapId, + }) async {} + + @override + Future setMapStyle(String? mapStyle, {required int mapId}) async {} + + @override + Future getVisibleRegion({required int mapId}) async { + return LatLngBounds( + southwest: const LatLng(0, 0), + northeast: const LatLng(0, 0), + ); + } + + @override + Future getScreenCoordinate( + LatLng latLng, { + required int mapId, + }) async { + return const ScreenCoordinate(x: 0, y: 0); + } + + @override + Future getLatLng( + ScreenCoordinate screenCoordinate, { + required int mapId, + }) async { + return const LatLng(0, 0); + } + + @override + Future showMarkerInfoWindow( + MarkerId markerId, { + required int mapId, + }) async {} + + @override + Future hideMarkerInfoWindow( + MarkerId markerId, { + required int mapId, + }) async {} + + @override + Future isMarkerInfoWindowShown( + MarkerId markerId, { + required int mapId, + }) async { + return false; + } + + @override + Future getZoomLevel({required int mapId}) async { + return 0.0; + } + + @override + Future takeSnapshot({required int mapId}) async { + return null; + } + + @override + Stream onCameraMoveStarted({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCameraMove({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCameraIdle({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onInfoWindowTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDragStart({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDrag({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onMarkerDragEnd({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onPolylineTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onPolygonTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onCircleTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onLongPress({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onClusterTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + Stream onGroundOverlayTap({required int mapId}) { + return mapEventStreamController.stream.whereType(); + } + + @override + void dispose({required int mapId}) { + disposed = true; + } + + @override + Widget buildViewWithConfiguration( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required MapWidgetConfiguration widgetConfiguration, + MapObjects mapObjects = const MapObjects(), + MapConfiguration mapConfiguration = const MapConfiguration(), + }) { + final PlatformMapStateRecorder? instance = mapInstances[creationId]; + if (instance == null) { + createdIds.add(creationId); + mapInstances[creationId] = PlatformMapStateRecorder( + widgetConfiguration: widgetConfiguration, + mapConfiguration: mapConfiguration, + mapObjects: mapObjects, + ); + onPlatformViewCreated(creationId); + } + return Container(); + } + + Future _fakeDelay() async { + if (!simulatePlatformDelay) { + return; + } + return Future.delayed(const Duration(microseconds: 1)); + } +} + +/// A fake implementation of a native map, which stores all the updates it is +/// sent for inspection in tests. +class PlatformMapStateRecorder { + PlatformMapStateRecorder({ + required this.widgetConfiguration, + this.mapObjects = const MapObjects(), + this.mapConfiguration = const MapConfiguration(), + }) { + clusterManagerUpdates.add( + ClusterManagerUpdates.from( + const {}, + mapObjects.clusterManagers, + ), + ); + groundOverlayUpdates.add( + GroundOverlayUpdates.from( + const {}, + mapObjects.groundOverlays, + ), + ); + markerUpdates.add(MarkerUpdates.from(const {}, mapObjects.markers)); + polygonUpdates.add( + PolygonUpdates.from(const {}, mapObjects.polygons), + ); + polylineUpdates.add( + PolylineUpdates.from(const {}, mapObjects.polylines), + ); + circleUpdates.add(CircleUpdates.from(const {}, mapObjects.circles)); + tileOverlaySets.add(mapObjects.tileOverlays); + } + + MapWidgetConfiguration widgetConfiguration; + MapObjects mapObjects; + MapConfiguration mapConfiguration; + + final List markerUpdates = []; + final List polygonUpdates = []; + final List polylineUpdates = []; + final List circleUpdates = []; + final List> tileOverlaySets = >[]; + final List clusterManagerUpdates = + []; + final List groundOverlayUpdates = + []; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test_driver/integration_test.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test_driver/integration_test.dart new file mode 100644 index 000000000000..fb3dec00bee9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/test_driver/integration_test.dart @@ -0,0 +1,7 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9.podspec b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9.podspec new file mode 100644 index 000000000000..7f45f35b59e8 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9.podspec @@ -0,0 +1,37 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# +Pod::Spec.new do |s| + s.name = 'google_maps_flutter_ios_sdk9' + s.version = '0.0.1' + s.summary = 'Google Maps for Flutter' + s.description = <<-DESC +A Flutter plugin that provides a Google Maps widget. +Downloaded by pub (not CocoaPods). + DESC + s.homepage = 'https://github.com/flutter/packages' + s.license = { :type => 'BSD', :file => '../LICENSE' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :http => 'https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios_sdk9' } + s.documentation_url = 'https://pub.dev/packages/google_maps_flutter_ios_sdk9' + s.source_files = 'google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/**/*.{h,m}' + s.public_header_files = 'google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/**/*.h' + s.dependency 'Flutter' + s.dependency 'GoogleMaps', '~> 9.0' + # Google-Maps-iOS-Utils 6.0 and 6.1.0 support GoogleMaps 9.x. The next release + # was 6.1.3, which switched to GoogleMaps 10.x without a major version change. + s.dependency 'Google-Maps-iOS-Utils', '>= 6.0', '<= 6.1.0' + s.static_framework = true + s.platform = :ios, '15.0' + # "Google-Maps-iOS-Utils" is static and contains Swift classes. + # Find the Swift runtime when these plugins are built as libraries without `use_frameworks!` + s.swift_version = '5.9' + s.xcconfig = { + 'LIBRARY_SEARCH_PATHS' => '$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', + 'LD_RUNPATH_SEARCH_PATHS' => '$(inherited) /usr/lib/swift', + # To handle the difference in framework names between CocoaPods and Swift Package Manager. + 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) FGM_USING_COCOAPODS=1', + } + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.resource_bundles = {'google_maps_flutter_ios_sdk9_privacy' => ['google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy']} +end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Package.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Package.swift new file mode 100644 index 000000000000..6df0b1cc1ba5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Package.swift @@ -0,0 +1,44 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import PackageDescription + +let package = Package( + name: "google_maps_flutter_ios_sdk9", + platforms: [ + .iOS(.v15) + ], + products: [ + .library(name: "google-maps-flutter-ios-sdk9", type: .static, targets: ["google_maps_flutter_ios_sdk9"]) + ], + dependencies: [ + .package(url: "https://github.com/googlemaps/ios-maps-sdk", "9.0.0"..<"10.0.0"), + // 6.1.3+ requires SDK 10. + .package(url: "https://github.com/googlemaps/google-maps-ios-utils", "6.0.0"..<"6.1.3"), + ], + targets: [ + .target( + name: "google_maps_flutter_ios_sdk9", + dependencies: [ + .product( + name: "GoogleMapsUtils", + package: "google-maps-ios-utils" + ), + .product( + name: "GoogleMaps", + package: "ios-maps-sdk" + ), + ], + resources: [ + .process("Resources") + ], + cSettings: [ + .headerSearchPath("include/google_maps_flutter_ios_sdk9") + ] + ) + ] +) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m new file mode 100644 index 000000000000..5fb79de8b17a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m @@ -0,0 +1,23 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMCATransactionWrapper.h" + +@import QuartzCore; + +@implementation FGMCATransactionWrapper + +- (void)begin { + [CATransaction begin]; +} + +- (void)commit { + [CATransaction commit]; +} + +- (void)setAnimationDuration:(CFTimeInterval)duration { + [CATransaction setAnimationDuration:duration]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m new file mode 100644 index 000000000000..04c3f04c9285 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m @@ -0,0 +1,128 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMClusterManagersController.h" + +#import "FGMConversionUtils.h" +#import "FGMMarkerUserData.h" + +@interface FGMClusterManagersController () + +/// A dictionary mapping unique cluster manager identifiers to their corresponding cluster managers. +@property(strong, nonatomic) + NSMutableDictionary *clusterManagerIdentifierToManagers; + +/// The callback handler interface for calls to Flutter. +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; + +/// The current map instance on which the cluster managers are operating. +@property(strong, nonatomic) GMSMapView *mapView; + +@end + +@implementation FGMClusterManagersController +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _clusterManagerIdentifierToManagers = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)addClusterManagers:(NSArray *)clusterManagersToAdd { + for (FGMPlatformClusterManager *clusterManager in clusterManagersToAdd) { + NSString *identifier = clusterManager.identifier; + [self addClusterManager:identifier]; + } +} + +- (void)addClusterManager:(NSString *)identifier { + id algorithm = [[GMUNonHierarchicalDistanceBasedAlgorithm alloc] init]; + id iconGenerator = [[GMUDefaultClusterIconGenerator alloc] init]; + id renderer = + [[GMUDefaultClusterRenderer alloc] initWithMapView:self.mapView + clusterIconGenerator:iconGenerator]; + self.clusterManagerIdentifierToManagers[identifier] = + [[GMUClusterManager alloc] initWithMap:self.mapView algorithm:algorithm renderer:renderer]; + ; +} + +- (void)removeClusterManagersWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + GMUClusterManager *clusterManager = + [self.clusterManagerIdentifierToManagers objectForKey:identifier]; + if (!clusterManager) { + continue; + } + [clusterManager clearItems]; + [self.clusterManagerIdentifierToManagers removeObjectForKey:identifier]; + } +} + +- (nullable GMUClusterManager *)clusterManagerWithIdentifier:(NSString *)identifier { + return [self.clusterManagerIdentifierToManagers objectForKey:identifier]; +} + +- (void)invokeClusteringForEachClusterManager { + for (GMUClusterManager *clusterManager in [self.clusterManagerIdentifierToManagers allValues]) { + [clusterManager cluster]; + } +} + +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMUClusterManager *clusterManager = + [self.clusterManagerIdentifierToManagers objectForKey:identifier]; + + if (!clusterManager) { + *error = [FlutterError + errorWithCode:@"Invalid clusterManagerId" + message:@"getClusters called with invalid clusterManagerId" + details:[NSString stringWithFormat:@"clusterManagerId was: '%@'", identifier]]; + return nil; + } + + // Ref: + // https://github.com/googlemaps/google-maps-ios-utils/blob/0e7ed81f1bbd9d29e4529c40ae39b0791b0a0eb8/src/Clustering/GMUClusterManager.m#L94. + NSUInteger integralZoom = (NSUInteger)floorf(_mapView.camera.zoom + 0.5f); + NSArray> *clusters = [clusterManager.algorithm clustersAtZoom:integralZoom]; + NSMutableArray *response = + [[NSMutableArray alloc] initWithCapacity:clusters.count]; + for (id cluster in clusters) { + FGMPlatformCluster *platFormCluster = FGMGetPigeonCluster(cluster, identifier); + [response addObject:platFormCluster]; + } + return response; +} + +- (void)didTapCluster:(GMUStaticCluster *)cluster { + NSString *clusterManagerId = [self clusterManagerIdentifierForCluster:cluster]; + if (!clusterManagerId) { + return; + } + FGMPlatformCluster *platFormCluster = FGMGetPigeonCluster(cluster, clusterManagerId); + [self.callbackHandler didTapCluster:platFormCluster + completion:^(FlutterError *_Nullable _){ + }]; +} + +#pragma mark - Private methods + +/// Returns the cluster manager identifier for given cluster. +/// +/// @return The cluster manager identifier if found; otherwise, nil. +- (nullable NSString *)clusterManagerIdentifierForCluster:(GMUStaticCluster *)cluster { + if ([cluster.items.firstObject isKindOfClass:[GMSMarker class]]) { + GMSMarker *firstMarker = (GMSMarker *)cluster.items.firstObject; + return FGMGetClusterManagerIdentifierFromMarker(firstMarker); + } + + return nil; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m new file mode 100644 index 000000000000..876ec0d1e4aa --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m @@ -0,0 +1,288 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMConversionUtils.h" + +#import "FGMMarkerUserData.h" + +/// Returns dict[key], or nil if dict[key] is NSNull. +id FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key) { + id value = dict[key]; + return value == [NSNull null] ? nil : value; +} + +CGPoint FGMGetCGPointForPigeonPoint(FGMPlatformPoint *point) { + return CGPointMake(point.x, point.y); +} + +FGMPlatformPoint *FGMGetPigeonPointForCGPoint(CGPoint point) { + return [FGMPlatformPoint makeWithX:point.x y:point.y]; +} + +CLLocationCoordinate2D FGMGetCoordinateForPigeonLatLng(FGMPlatformLatLng *latLng) { + return CLLocationCoordinate2DMake(latLng.latitude, latLng.longitude); +} + +FGMPlatformLatLng *FGMGetPigeonLatLngForCoordinate(CLLocationCoordinate2D coord) { + return [FGMPlatformLatLng makeWithLatitude:coord.latitude longitude:coord.longitude]; +} + +GMSCoordinateBounds *FGMGetCoordinateBoundsForPigeonLatLngBounds(FGMPlatformLatLngBounds *bounds) { + return [[GMSCoordinateBounds alloc] + initWithCoordinate:FGMGetCoordinateForPigeonLatLng(bounds.northeast) + coordinate:FGMGetCoordinateForPigeonLatLng(bounds.southwest)]; +} + +FGMPlatformLatLngBounds *FGMGetPigeonLatLngBoundsForCoordinateBounds(GMSCoordinateBounds *bounds) { + return + [FGMPlatformLatLngBounds makeWithNortheast:FGMGetPigeonLatLngForCoordinate(bounds.northEast) + southwest:FGMGetPigeonLatLngForCoordinate(bounds.southWest)]; +} + +FGMPlatformCameraPosition *FGMGetPigeonCameraPositionForPosition(GMSCameraPosition *position) { + return [FGMPlatformCameraPosition makeWithBearing:position.bearing + target:FGMGetPigeonLatLngForCoordinate(position.target) + tilt:position.viewingAngle + zoom:position.zoom]; +} + +GMSCameraPosition *FGMGetCameraPositionForPigeonCameraPosition( + FGMPlatformCameraPosition *position) { + return [GMSCameraPosition cameraWithTarget:FGMGetCoordinateForPigeonLatLng(position.target) + zoom:position.zoom + bearing:position.bearing + viewingAngle:position.tilt]; +} + +NSArray *FGMGetPointsForPigeonLatLngs(NSArray *pigeonPoints) { + NSMutableArray *points = [[NSMutableArray alloc] initWithCapacity:pigeonPoints.count]; + for (FGMPlatformLatLng *point in pigeonPoints) { + [points addObject:[[CLLocation alloc] initWithLatitude:point.latitude + longitude:point.longitude]]; + } + return points; +} + +NSArray *> *FGMGetHolesForPigeonLatLngArrays( + NSArray *> *pigeonHolePoints) { + NSMutableArray *> *holes = + [[NSMutableArray alloc] initWithCapacity:pigeonHolePoints.count]; + for (NSArray *holePoints in pigeonHolePoints) { + [holes addObject:FGMGetPointsForPigeonLatLngs(holePoints)]; + } + return holes; +} + +GMSMutablePath *FGMGetPathFromPoints(NSArray *points) { + GMSMutablePath *path = [GMSMutablePath path]; + for (CLLocation *location in points) { + [path addCoordinate:location.coordinate]; + } + return path; +} + +GMSMapViewType FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapType type) { + switch (type) { + case FGMPlatformMapTypeNone: + return kGMSTypeNone; + case FGMPlatformMapTypeNormal: + return kGMSTypeNormal; + case FGMPlatformMapTypeSatellite: + return kGMSTypeSatellite; + case FGMPlatformMapTypeTerrain: + return kGMSTypeTerrain; + case FGMPlatformMapTypeHybrid: + return kGMSTypeHybrid; + } +} + +FGMPlatformCluster *FGMGetPigeonCluster(GMUStaticCluster *cluster, + NSString *clusterManagerIdentifier) { + NSMutableArray *markerIDs = [[NSMutableArray alloc] initWithCapacity:cluster.items.count]; + GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] init]; + + for (GMSMarker *marker in cluster.items) { + [markerIDs addObject:FGMGetMarkerIdentifierFromMarker(marker)]; + bounds = [bounds includingCoordinate:marker.position]; + } + + return [FGMPlatformCluster + makeWithClusterManagerId:clusterManagerIdentifier + position:FGMGetPigeonLatLngForCoordinate(cluster.position) + bounds:FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds) + markerIds:markerIDs]; +} + +FGMPlatformGroundOverlay *FGMGetPigeonGroundOverlay(GMSGroundOverlay *groundOverlay, + NSString *overlayId, BOOL isCreatedWithBounds, + NSNumber *zoomLevel) { + // Image is mandatory field on FGMPlatformGroundOverlay (and it should be kept + // non-nullable), therefore image must be set for the object. The image is + // description either contains set of bytes, or path to asset. This info is + // converted to format google maps uses (BitmapDescription), and the original + // data is not stored on native code. Therefore placeholder image is used for + // the image field. + FGMPlatformBitmap *placeholderImage = + [FGMPlatformBitmap makeWithBitmap:[FGMPlatformBitmapDefaultMarker makeWithHue:0]]; + if (isCreatedWithBounds) { + return [FGMPlatformGroundOverlay + makeWithGroundOverlayId:overlayId + image:placeholderImage + position:nil + bounds:[FGMPlatformLatLngBounds + makeWithNortheast:[FGMPlatformLatLng + makeWithLatitude:groundOverlay.bounds + .northEast.latitude + longitude:groundOverlay.bounds + .northEast.longitude] + southwest:[FGMPlatformLatLng + makeWithLatitude:groundOverlay.bounds + .southWest.latitude + longitude:groundOverlay.bounds + .southWest + .longitude]] + anchor:[FGMPlatformPoint makeWithX:groundOverlay.anchor.x + y:groundOverlay.anchor.y] + transparency:1.0f - groundOverlay.opacity + bearing:groundOverlay.bearing + zIndex:groundOverlay.zIndex + visible:groundOverlay.map != nil + clickable:groundOverlay.isTappable + zoomLevel:zoomLevel]; + } else { + return [FGMPlatformGroundOverlay + makeWithGroundOverlayId:overlayId + image:placeholderImage + position:[FGMPlatformLatLng + makeWithLatitude:groundOverlay.position.latitude + longitude:groundOverlay.position.longitude] + bounds:nil + anchor:[FGMPlatformPoint makeWithX:groundOverlay.anchor.x + y:groundOverlay.anchor.y] + transparency:1.0f - groundOverlay.opacity + bearing:groundOverlay.bearing + zIndex:groundOverlay.zIndex + visible:groundOverlay.map != nil + clickable:groundOverlay.isTappable + zoomLevel:zoomLevel]; + } +} + +GMUGradient *FGMGetGradientForPigeonHeatmapGradient(FGMPlatformHeatmapGradient *gradient) { + NSMutableArray *colors = [[NSMutableArray alloc] initWithCapacity:gradient.colors.count]; + for (FGMPlatformColor *color in gradient.colors) { + [colors addObject:FGMGetColorForPigeonColor(color)]; + } + return [[GMUGradient alloc] initWithColors:colors + startPoints:gradient.startPoints + colorMapSize:gradient.colorMapSize]; +} + +FGMPlatformHeatmapGradient *FGMGetPigeonHeatmapGradientForGradient(GMUGradient *gradient) { + NSMutableArray *colors = [[NSMutableArray alloc] initWithCapacity:gradient.colors.count]; + for (UIColor *color in gradient.colors) { + [colors addObject:FGMGetPigeonColorForColor(color)]; + } + return [FGMPlatformHeatmapGradient makeWithColors:colors + startPoints:gradient.startPoints + colorMapSize:gradient.mapSize]; +} + +NSArray *FGMGetWeightedDataForPigeonWeightedData( + NSArray *weightedLatLngs) { + NSMutableArray *weightedData = [[NSMutableArray alloc] initWithCapacity:weightedLatLngs.count]; + for (FGMPlatformWeightedLatLng *weightedLatLng in weightedLatLngs) { + [weightedData + addObject:[[GMUWeightedLatLng alloc] + initWithCoordinate:FGMGetCoordinateForPigeonLatLng(weightedLatLng.point) + intensity:weightedLatLng.weight]]; + } + return weightedData; +} + +NSArray *FGMGetPigeonWeightedDataForWeightedData( + NSArray *weightedLatLngs) { + NSMutableArray *weightedData = [[NSMutableArray alloc] initWithCapacity:weightedLatLngs.count]; + for (GMUWeightedLatLng *weightedLatLng in weightedLatLngs) { + GMSMapPoint point = {weightedLatLng.point.x, weightedLatLng.point.y}; + [weightedData addObject:[FGMPlatformWeightedLatLng + makeWithPoint:FGMGetPigeonLatLngForCoordinate(GMSUnproject(point)) + weight:weightedLatLng.intensity]]; + } + return weightedData; +} + +GMSCameraUpdate *FGMGetCameraUpdateForPigeonCameraUpdate(FGMPlatformCameraUpdate *cameraUpdate) { + // See note in messages.dart for why this is so loosely typed. + id update = cameraUpdate.cameraUpdate; + if ([update isKindOfClass:[FGMPlatformCameraUpdateNewCameraPosition class]]) { + return [GMSCameraUpdate + setCamera:FGMGetCameraPositionForPigeonCameraPosition( + ((FGMPlatformCameraUpdateNewCameraPosition *)update).cameraPosition)]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateNewLatLng class]]) { + return [GMSCameraUpdate setTarget:FGMGetCoordinateForPigeonLatLng( + ((FGMPlatformCameraUpdateNewLatLng *)update).latLng)]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateNewLatLngBounds class]]) { + FGMPlatformCameraUpdateNewLatLngBounds *typedUpdate = + (FGMPlatformCameraUpdateNewLatLngBounds *)update; + return + [GMSCameraUpdate fitBounds:FGMGetCoordinateBoundsForPigeonLatLngBounds(typedUpdate.bounds) + withPadding:typedUpdate.padding]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateNewLatLngZoom class]]) { + FGMPlatformCameraUpdateNewLatLngZoom *typedUpdate = + (FGMPlatformCameraUpdateNewLatLngZoom *)update; + return [GMSCameraUpdate setTarget:FGMGetCoordinateForPigeonLatLng(typedUpdate.latLng) + zoom:typedUpdate.zoom]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateScrollBy class]]) { + FGMPlatformCameraUpdateScrollBy *typedUpdate = (FGMPlatformCameraUpdateScrollBy *)update; + return [GMSCameraUpdate scrollByX:typedUpdate.dx Y:typedUpdate.dy]; + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateZoomBy class]]) { + FGMPlatformCameraUpdateZoomBy *typedUpdate = (FGMPlatformCameraUpdateZoomBy *)update; + if (typedUpdate.focus) { + return [GMSCameraUpdate zoomBy:typedUpdate.amount + atPoint:FGMGetCGPointForPigeonPoint(typedUpdate.focus)]; + } else { + return [GMSCameraUpdate zoomBy:typedUpdate.amount]; + } + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateZoom class]]) { + if (((FGMPlatformCameraUpdateZoom *)update).out) { + return [GMSCameraUpdate zoomOut]; + } else { + return [GMSCameraUpdate zoomIn]; + } + } else if ([update isKindOfClass:[FGMPlatformCameraUpdateZoomTo class]]) { + return [GMSCameraUpdate zoomTo:((FGMPlatformCameraUpdateZoomTo *)update).zoom]; + } + return nil; +} + +UIColor *FGMGetColorForPigeonColor(FGMPlatformColor *color) { + return [UIColor colorWithRed:color.red green:color.green blue:color.blue alpha:color.alpha]; +} + +FGMPlatformColor *FGMGetPigeonColorForColor(UIColor *color) { + double red, green, blue, alpha; + [color getRed:&red green:&green blue:&blue alpha:&alpha]; + return [FGMPlatformColor makeWithRed:red green:green blue:blue alpha:alpha]; +} + +NSArray *FGMGetStrokeStylesFromPatterns( + NSArray *patterns, UIColor *strokeColor) { + NSMutableArray *strokeStyles = [[NSMutableArray alloc] initWithCapacity:[patterns count]]; + for (FGMPlatformPatternItem *pattern in patterns) { + UIColor *color = + pattern.type == FGMPlatformPatternItemTypeGap ? UIColor.clearColor : strokeColor; + [strokeStyles addObject:[GMSStrokeStyle solidColor:color]]; + } + return strokeStyles; +} + +NSArray *FGMGetSpanLengthsFromPatterns(NSArray *patterns) { + NSMutableArray *lengths = [[NSMutableArray alloc] initWithCapacity:[patterns count]]; + for (FGMPlatformPatternItem *pattern in patterns) { + NSNumber *length = pattern.length ?: @0; + [lengths addObject:length]; + } + return lengths; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m new file mode 100644 index 000000000000..624f43032c53 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m @@ -0,0 +1,211 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMGroundOverlayController.h" +#import "FGMGroundOverlayController_Test.h" + +#import "FGMConversionUtils.h" +#import "FGMImageUtils.h" + +@interface FGMGroundOverlayController () + +/// The GMSMapView to which the ground overlays are added. +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FGMGroundOverlayController + +- (instancetype)initWithGroundOverlay:(GMSGroundOverlay *)groundOverlay + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView + isCreatedWithBounds:(BOOL)isCreatedWithBounds { + self = [super init]; + if (self) { + _groundOverlay = groundOverlay; + _mapView = mapView; + _groundOverlay.userData = @[ identifier ]; + _createdWithBounds = isCreatedWithBounds; + } + return self; +} + +- (void)removeGroundOverlay { + self.groundOverlay.map = nil; +} + +- (void)updateFromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)groundOverlay + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale { + [FGMGroundOverlayController updateGroundOverlay:self.groundOverlay + fromPlatformGroundOverlay:groundOverlay + withMapView:self.mapView + registrar:registrar + screenScale:screenScale + usingBounds:self.createdWithBounds]; +} + ++ (void)updateGroundOverlay:(GMSGroundOverlay *)groundOverlay + fromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)platformGroundOverlay + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingBounds:(BOOL)useBounds { + groundOverlay.tappable = platformGroundOverlay.clickable; + groundOverlay.zIndex = (int)platformGroundOverlay.zIndex; + groundOverlay.anchor = + CGPointMake(platformGroundOverlay.anchor.x, platformGroundOverlay.anchor.y); + UIImage *image = FGMIconFromBitmap(platformGroundOverlay.image, registrar, screenScale); + groundOverlay.icon = image; + groundOverlay.bearing = platformGroundOverlay.bearing; + groundOverlay.opacity = 1.0 - platformGroundOverlay.transparency; + if (useBounds) { + groundOverlay.bounds = [[GMSCoordinateBounds alloc] + initWithCoordinate:CLLocationCoordinate2DMake( + platformGroundOverlay.bounds.northeast.latitude, + platformGroundOverlay.bounds.northeast.longitude) + coordinate:CLLocationCoordinate2DMake( + platformGroundOverlay.bounds.southwest.latitude, + platformGroundOverlay.bounds.southwest.longitude)]; + } else { + groundOverlay.position = CLLocationCoordinate2DMake(platformGroundOverlay.position.latitude, + platformGroundOverlay.position.longitude); + } + + // This must be done last, to avoid visual flickers of default property values. + groundOverlay.map = platformGroundOverlay.visible ? mapView : nil; +} + +@end + +@interface FLTGroundOverlaysController () + +/// A map from ground overlay id to the controller that manages it. +@property(strong, nonatomic) NSMutableDictionary + *groundOverlayControllerByIdentifier; + +/// A callback api for the map interactions. +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; + +/// Flutter Plugin Registrar used to load images. +@property(weak, nonatomic) NSObject *registrar; + +/// The map view used to generate the controllers. +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGroundOverlaysController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _groundOverlayControllerByIdentifier = [[NSMutableDictionary alloc] init]; + _registrar = registrar; + } + return self; +} + +- (void)addGroundOverlays:(NSArray *)groundOverlaysToAdd { + for (FGMPlatformGroundOverlay *groundOverlay in groundOverlaysToAdd) { + NSString *identifier = groundOverlay.groundOverlayId; + GMSGroundOverlay *gmsOverlay; + BOOL isCreatedWithBounds = NO; + if (groundOverlay.position == nil) { + isCreatedWithBounds = YES; + NSAssert(groundOverlay.bounds != nil, + @"If ground overlay is initialized without position, bounds are required"); + gmsOverlay = [GMSGroundOverlay + groundOverlayWithBounds: + [[GMSCoordinateBounds alloc] + initWithCoordinate:CLLocationCoordinate2DMake( + groundOverlay.bounds.northeast.latitude, + groundOverlay.bounds.northeast.longitude) + coordinate:CLLocationCoordinate2DMake( + groundOverlay.bounds.southwest.latitude, + groundOverlay.bounds.southwest.longitude)] + icon:FGMIconFromBitmap(groundOverlay.image, self.registrar, + [self getScreenScale])]; + } else { + NSAssert(groundOverlay.zoomLevel != nil, + @"If ground overlay is initialized with position, zoomLevel is required"); + gmsOverlay = [GMSGroundOverlay + groundOverlayWithPosition:CLLocationCoordinate2DMake(groundOverlay.position.latitude, + groundOverlay.position.longitude) + icon:FGMIconFromBitmap(groundOverlay.image, self.registrar, + [self getScreenScale]) + zoomLevel:[groundOverlay.zoomLevel doubleValue]]; + } + FGMGroundOverlayController *controller = + [[FGMGroundOverlayController alloc] initWithGroundOverlay:gmsOverlay + identifier:identifier + mapView:self.mapView + isCreatedWithBounds:isCreatedWithBounds]; + controller.zoomLevel = groundOverlay.zoomLevel; + [controller updateFromPlatformGroundOverlay:groundOverlay + registrar:self.registrar + screenScale:[self getScreenScale]]; + self.groundOverlayControllerByIdentifier[identifier] = controller; + } +} + +- (void)changeGroundOverlays:(NSArray *)groundOverlaysToChange { + for (FGMPlatformGroundOverlay *groundOverlay in groundOverlaysToChange) { + NSString *identifier = groundOverlay.groundOverlayId; + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + [controller updateFromPlatformGroundOverlay:groundOverlay + registrar:self.registrar + screenScale:[self getScreenScale]]; + } +} + +- (void)removeGroundOverlaysWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + if (!controller) { + continue; + } + [controller removeGroundOverlay]; + [self.groundOverlayControllerByIdentifier removeObjectForKey:identifier]; + } +} + +- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier { + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapGroundOverlayWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (bool)hasGroundOverlaysWithIdentifier:(NSString *)identifier { + return self.groundOverlayControllerByIdentifier[identifier] != nil; +} + +- (CGFloat)getScreenScale { + // TODO(jokerttu): This method is called on marker creation, which, for initial markers, is done + // before the view is added to the view hierarchy. This means that the traitCollection values may + // not be matching the right display where the map is finally shown. The solution should be + // revisited after the proper way to fetch the display scale is resolved for platform views. This + // should be done under the context of the following issue: + // https://github.com/flutter/flutter/issues/125496. + return self.mapView.traitCollection.displayScale; +} + +- (nullable FGMPlatformGroundOverlay *)groundOverlayWithIdentifier:(NSString *)identifier { + FGMGroundOverlayController *controller = self.groundOverlayControllerByIdentifier[identifier]; + if (!controller) { + return nil; + } + return FGMGetPigeonGroundOverlay(controller.groundOverlay, identifier, + controller.isCreatedWithBounds, controller.zoomLevel); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m new file mode 100644 index 000000000000..7bd5192c2377 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m @@ -0,0 +1,235 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMImageUtils.h" + +@import Foundation; + +/// This method is deprecated within the context of `BitmapDescriptor.fromBytes` handling in the +/// flutter google_maps_flutter_platform_interface package which has been replaced by 'bytes' +/// message handling. It will be removed when the deprecated image bitmap description type +/// 'fromBytes' is removed from the platform interface. +static UIImage *scaledImage(UIImage *image, double scale); + +/// Creates a scaled version of the provided UIImage based on a specified scale factor. If the +/// scale factor differs from the image's current scale by more than a small epsilon-delta (to +/// account for minor floating-point inaccuracies), a new UIImage object is created with the +/// specified scale. Otherwise, the original image is returned. +/// +/// @param image The UIImage to scale. +/// @param scale The factor by which to scale the image. +/// @return UIImage Returns the scaled UIImage. +static UIImage *scaledImageWithScale(UIImage *image, CGFloat scale); + +/// Scales an input UIImage to a specified size. If the aspect ratio of the input image +/// closely matches the target size, indicated by a small epsilon-delta, the image's scale +/// property is updated instead of resizing the image. If the aspect ratios differ beyond this +/// threshold, the method redraws the image at the target size. +/// +/// @param image The UIImage to scale. +/// @param size The target CGSize to scale the image to. +/// @return UIImage Returns the scaled UIImage. +static UIImage *scaledImageWithSize(UIImage *image, CGSize size); + +/// Scales an input UIImage to a specified width and height preserving aspect ratio if both +/// widht and height are not given.. +/// +/// @param image The UIImage to scale. +/// @param width The target width to scale the image to. +/// @param height The target height to scale the image to. +/// @param screenScale The current screen scale. +/// @return UIImage Returns the scaled UIImage. +static UIImage *scaledImageWithWidthHeight(UIImage *image, NSNumber *width, NSNumber *height, + CGFloat screenScale); + +UIImage *FGMIconFromBitmap(FGMPlatformBitmap *platformBitmap, + NSObject *registrar, CGFloat screenScale) { + assert(screenScale > 0 && "Screen scale must be greater than 0"); + // See comment in messages.dart for why this is so loosely typed. See also + // https://github.com/flutter/flutter/issues/117819. + id bitmap = platformBitmap.bitmap; + UIImage *image; + if ([bitmap isKindOfClass:[FGMPlatformBitmapDefaultMarker class]]) { + FGMPlatformBitmapDefaultMarker *bitmapDefaultMarker = bitmap; + CGFloat hue = bitmapDefaultMarker.hue.doubleValue; + image = [GMSMarker markerImageWithColor:[UIColor colorWithHue:hue / 360.0 + saturation:1.0 + brightness:0.7 + alpha:1.0]]; + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapAsset class]]) { + // Deprecated: This message handling for 'fromAsset' has been replaced by 'asset'. + // Refer to the flutter google_maps_flutter_platform_interface package for details. + FGMPlatformBitmapAsset *bitmapAsset = bitmap; + if (bitmapAsset.pkg) { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAsset.name + fromPackage:bitmapAsset.pkg]]; + } else { + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAsset.name]]; + } + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapAssetImage class]]) { + // Deprecated: This message handling for 'fromAssetImage' has been replaced by 'asset'. + // Refer to the flutter google_maps_flutter_platform_interface package for details. + FGMPlatformBitmapAssetImage *bitmapAssetImage = bitmap; + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAssetImage.name]]; + image = scaledImage(image, bitmapAssetImage.scale); + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapBytes class]]) { + // Deprecated: This message handling for 'fromBytes' has been replaced by 'bytes'. + // Refer to the flutter google_maps_flutter_platform_interface package for details. + FGMPlatformBitmapBytes *bitmapBytes = bitmap; + @try { + CGFloat mainScreenScale = [[UIScreen mainScreen] scale]; + image = [UIImage imageWithData:bitmapBytes.byteData.data scale:mainScreenScale]; + } @catch (NSException *exception) { + @throw [NSException exceptionWithName:@"InvalidByteDescriptor" + reason:@"Unable to interpret bytes as a valid image." + userInfo:nil]; + } + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapAssetMap class]]) { + FGMPlatformBitmapAssetMap *bitmapAssetMap = bitmap; + + image = [UIImage imageNamed:[registrar lookupKeyForAsset:bitmapAssetMap.assetName]]; + + if (bitmapAssetMap.bitmapScaling == FGMPlatformMapBitmapScalingAuto) { + NSNumber *width = bitmapAssetMap.width; + NSNumber *height = bitmapAssetMap.height; + if (width || height) { + image = scaledImageWithScale(image, screenScale); + image = scaledImageWithWidthHeight(image, width, height, screenScale); + } else { + image = scaledImageWithScale(image, bitmapAssetMap.imagePixelRatio); + } + } + } else if ([bitmap isKindOfClass:[FGMPlatformBitmapBytesMap class]]) { + FGMPlatformBitmapBytesMap *bitmapBytesMap = bitmap; + FlutterStandardTypedData *bytes = bitmapBytesMap.byteData; + + @try { + image = [UIImage imageWithData:bytes.data scale:screenScale]; + if (bitmapBytesMap.bitmapScaling == FGMPlatformMapBitmapScalingAuto) { + NSNumber *width = bitmapBytesMap.width; + NSNumber *height = bitmapBytesMap.height; + + if (width || height) { + // Before scaling the image, image must be in screenScale. + image = scaledImageWithScale(image, screenScale); + image = scaledImageWithWidthHeight(image, width, height, screenScale); + } else { + image = scaledImageWithScale(image, bitmapBytesMap.imagePixelRatio); + } + } else { + // No scaling, load image from bytes without scale parameter. + image = [UIImage imageWithData:bytes.data]; + } + } @catch (NSException *exception) { + @throw [NSException exceptionWithName:@"InvalidByteDescriptor" + reason:@"Unable to interpret bytes as a valid image." + userInfo:nil]; + } + } + + return image; +} + +UIImage *scaledImage(UIImage *image, double scale) { + if (fabs(scale - 1) > 1e-3) { + return [UIImage imageWithCGImage:[image CGImage] + scale:(image.scale * scale) + orientation:(image.imageOrientation)]; + } + return image; +} + +UIImage *scaledImageWithScale(UIImage *image, CGFloat scale) { + if (fabs(scale - image.scale) > DBL_EPSILON) { + return [UIImage imageWithCGImage:[image CGImage] + scale:scale + orientation:(image.imageOrientation)]; + } + return image; +} + +UIImage *scaledImageWithSize(UIImage *image, CGSize size) { + CGFloat originalPixelWidth = image.size.width * image.scale; + CGFloat originalPixelHeight = image.size.height * image.scale; + + // Return original image if either original image size or target size is so small that + // image cannot be resized or displayed. + if (originalPixelWidth <= 0 || originalPixelHeight <= 0 || size.width <= 0 || size.height <= 0) { + return image; + } + + // Check if the image's size, accounting for scale, matches the target size. + if (fabs(originalPixelWidth - size.width) <= DBL_EPSILON && + fabs(originalPixelHeight - size.height) <= DBL_EPSILON) { + // No need for resizing, return the original image + return image; + } + + // Check if the aspect ratios are approximately equal. + CGSize originalPixelSize = CGSizeMake(originalPixelWidth, originalPixelHeight); + if (FGMIsScalableWithScaleFactorFromSize(originalPixelSize, size)) { + // Scaled image has close to same aspect ratio, + // updating image scale instead of resizing image. + CGFloat factor = originalPixelWidth / size.width; + return scaledImageWithScale(image, image.scale * factor); + } else { + // Aspect ratios differ significantly, resize the image. + UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat]; + format.scale = 1.0; + format.opaque = NO; + UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:size + format:format]; + UIImage *newImage = + [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull context) { + [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; + }]; + + // Return image with proper scaling. + return scaledImageWithScale(newImage, image.scale); + } +} + +UIImage *scaledImageWithWidthHeight(UIImage *image, NSNumber *width, NSNumber *height, + CGFloat screenScale) { + if ((width == nil) && (height == nil)) { + return image; + } + + CGFloat targetWidth = width == nil ? image.size.width : width.doubleValue; + CGFloat targetHeight = height == nil ? image.size.height : height.doubleValue; + + if ((width != nil) && (height == nil)) { + // Calculate height based on aspect ratio if only width is provided. + double aspectRatio = image.size.height / image.size.width; + targetHeight = round(targetWidth * aspectRatio); + } else if ((width == nil) && (height != nil)) { + // Calculate width based on aspect ratio if only height is provided. + double aspectRatio = image.size.width / image.size.height; + targetWidth = round(targetHeight * aspectRatio); + } + + CGSize targetSize = + CGSizeMake(round(targetWidth * screenScale), round(targetHeight * screenScale)); + return scaledImageWithSize(image, targetSize); +} + +BOOL FGMIsScalableWithScaleFactorFromSize(CGSize originalSize, CGSize targetSize) { + // Select the scaling factor based on the longer side to have good precision. + CGFloat scaleFactor = (originalSize.width > originalSize.height) + ? (targetSize.width / originalSize.width) + : (targetSize.height / originalSize.height); + + // Calculate the scaled dimensions. + CGFloat scaledWidth = originalSize.width * scaleFactor; + CGFloat scaledHeight = originalSize.height * scaleFactor; + + // Check if the scaled dimensions are within a one-pixel + // threshold of the target dimensions. + BOOL widthWithinThreshold = fabs(scaledWidth - targetSize.width) <= 1.0; + BOOL heightWithinThreshold = fabs(scaledHeight - targetSize.height) <= 1.0; + + // The image is considered scalable with scale factor + // if both dimensions are within the threshold. + return widthWithinThreshold && heightWithinThreshold; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m new file mode 100644 index 000000000000..22b100e34102 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMMarkerUserData.h" + +@implementation FGMMarkerUserData + +@end + +void FGMSetIdentifiersToMarkerUserData(NSString *markerIdentifier, + NSString *_Nullable clusterManagerIdentifier, + GMSMarker *marker) { + FGMMarkerUserData *userData = [[FGMMarkerUserData alloc] init]; + userData.markerIdentifier = markerIdentifier; + userData.clusterManagerIdentifier = clusterManagerIdentifier; + marker.userData = userData; +}; + +NSString *_Nullable FGMGetMarkerIdentifierFromMarker(GMSMarker *marker) { + if ([marker.userData isKindOfClass:[FGMMarkerUserData class]]) { + FGMMarkerUserData *userData = (FGMMarkerUserData *)marker.userData; + return userData.markerIdentifier; + } + return nil; +}; + +NSString *_Nullable FGMGetClusterManagerIdentifierFromMarker(GMSMarker *marker) { + if ([marker.userData isKindOfClass:[FGMMarkerUserData class]]) { + FGMMarkerUserData *userData = (FGMMarkerUserData *)marker.userData; + return userData.clusterManagerIdentifier; + } + return nil; +}; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m new file mode 100644 index 000000000000..91c93933308d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m @@ -0,0 +1,140 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapHeatmapController.h" +#import "FLTGoogleMapHeatmapController_Test.h" + +@import GoogleMapsUtils; + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapHeatmapController () + +/// The heatmap tile layer this controller handles. +@property(nonatomic, strong) GMUHeatmapTileLayer *heatmapTileLayer; + +/// The GMSMapView to which the heatmaps are added. +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapHeatmapController +- (instancetype)initWithHeatmap:(FGMPlatformHeatmap *)heatmap + tileLayer:(GMUHeatmapTileLayer *)heatmapTileLayer + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _heatmapTileLayer = heatmapTileLayer; + _mapView = mapView; + + [FLTGoogleMapHeatmapController updateHeatmap:_heatmapTileLayer + fromPlatformHeatmap:heatmap + withMapView:_mapView]; + } + return self; +} + +- (void)removeHeatmap { + _heatmapTileLayer.map = nil; +} + +- (void)clearTileCache { + [_heatmapTileLayer clearTileCache]; +} + +- (void)updateFromPlatformHeatmap:(FGMPlatformHeatmap *)platformHeatmap { + [FLTGoogleMapHeatmapController updateHeatmap:_heatmapTileLayer + fromPlatformHeatmap:platformHeatmap + withMapView:_mapView]; +} + ++ (void)updateHeatmap:(GMUHeatmapTileLayer *)heatmapTileLayer + fromPlatformHeatmap:(FGMPlatformHeatmap *)platformHeatmap + withMapView:(GMSMapView *)mapView { + heatmapTileLayer.weightedData = FGMGetWeightedDataForPigeonWeightedData(platformHeatmap.data); + if (platformHeatmap.gradient) { + heatmapTileLayer.gradient = FGMGetGradientForPigeonHeatmapGradient(platformHeatmap.gradient); + } + heatmapTileLayer.opacity = platformHeatmap.opacity; + heatmapTileLayer.radius = platformHeatmap.radius; + heatmapTileLayer.minimumZoomIntensity = platformHeatmap.minimumZoomIntensity; + heatmapTileLayer.maximumZoomIntensity = platformHeatmap.maximumZoomIntensity; + + // The map must be set each time for options to update. + // This must be done last, to avoid visual flickers of default property values. + heatmapTileLayer.map = mapView; +} +@end + +@interface FLTHeatmapsController () + +/// A map from heatmapId to the controller that manages it. +@property(nonatomic, strong) + NSMutableDictionary *heatmapIdToController; + +/// The map view owned by GoogmeMapController. +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTHeatmapsController +- (instancetype)initWithMapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _mapView = mapView; + _heatmapIdToController = [NSMutableDictionary dictionary]; + } + return self; +} + +- (void)addHeatmaps:(NSArray *)heatmapsToAdd { + for (FGMPlatformHeatmap *heatmap in heatmapsToAdd) { + GMUHeatmapTileLayer *heatmapTileLayer = [[GMUHeatmapTileLayer alloc] init]; + FLTGoogleMapHeatmapController *controller = + [[FLTGoogleMapHeatmapController alloc] initWithHeatmap:heatmap + tileLayer:heatmapTileLayer + mapView:_mapView]; + _heatmapIdToController[heatmap.heatmapId] = controller; + } +} + +- (void)changeHeatmaps:(NSArray *)heatmapsToChange { + for (FGMPlatformHeatmap *heatmap in heatmapsToChange) { + FLTGoogleMapHeatmapController *controller = _heatmapIdToController[heatmap.heatmapId]; + + [controller updateFromPlatformHeatmap:heatmap]; + [controller clearTileCache]; + } +} + +- (void)removeHeatmapsWithIdentifiers:(NSArray *)identifiers { + for (NSString *heatmapId in identifiers) { + FLTGoogleMapHeatmapController *controller = _heatmapIdToController[heatmapId]; + if (!controller) { + continue; + } + [controller removeHeatmap]; + [_heatmapIdToController removeObjectForKey:heatmapId]; + } +} + +- (BOOL)hasHeatmapWithIdentifier:(NSString *)identifier { + return _heatmapIdToController[identifier] != nil; +} + +- (FGMPlatformHeatmap *)heatmapWithIdentifier:(NSString *)identifier { + GMUHeatmapTileLayer *heatmap = self.heatmapIdToController[identifier].heatmapTileLayer; + if (!heatmap) { + return nil; + } + return [FGMPlatformHeatmap + makeWithHeatmapId:identifier + data:FGMGetPigeonWeightedDataForWeightedData(heatmap.weightedData) + gradient:FGMGetPigeonHeatmapGradientForGradient(heatmap.gradient) + opacity:heatmap.opacity + radius:heatmap.radius + minimumZoomIntensity:heatmap.minimumZoomIntensity + maximumZoomIntensity:heatmap.maximumZoomIntensity]; +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m new file mode 100644 index 000000000000..c4cce14ed247 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m @@ -0,0 +1,199 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapTileOverlayController.h" +#import "FLTGoogleMapTileOverlayController_Test.h" + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapTileOverlayController () + +@property(strong, nonatomic) GMSTileLayer *layer; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapTileOverlayController + +- (instancetype)initWithTileOverlay:(FGMPlatformTileOverlay *)tileOverlay + tileLayer:(GMSTileLayer *)tileLayer + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _layer = tileLayer; + _mapView = mapView; + [FLTGoogleMapTileOverlayController updateTileLayer:tileLayer + fromPlatformTileOverlay:tileOverlay + withMapView:mapView]; + } + return self; +} + +- (void)removeTileOverlay { + self.layer.map = nil; +} + +- (void)clearTileCache { + [self.layer clearTileCache]; +} + +- (void)updateFromPlatformTileOverlay:(FGMPlatformTileOverlay *)overlay { + [FLTGoogleMapTileOverlayController updateTileLayer:self.layer + fromPlatformTileOverlay:overlay + withMapView:self.mapView]; +} + ++ (void)updateTileLayer:(GMSTileLayer *)tileLayer + fromPlatformTileOverlay:(FGMPlatformTileOverlay *)platformOverlay + withMapView:(GMSMapView *)mapView { + tileLayer.opacity = 1.0 - platformOverlay.transparency; + tileLayer.zIndex = (int)platformOverlay.zIndex; + tileLayer.fadeIn = platformOverlay.fadeIn; + tileLayer.tileSize = platformOverlay.tileSize; + + // This must be done last, to avoid visual flickers of default property values. + tileLayer.map = platformOverlay.visible ? mapView : nil; +} + +@end + +@interface FLTTileProviderController () + +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; + +@end + +@implementation FLTTileProviderController + +- (instancetype)initWithTileOverlayIdentifier:(NSString *)identifier + callbackHandler:(FGMMapsCallbackApi *)callbackHandler { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _tileOverlayIdentifier = identifier; + } + return self; +} + +#pragma mark - GMSTileLayer method + +- (UIImage *)handleResultTile:(nullable UIImage *)tile { + CGImageRef imageRef = tile.CGImage; + CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); + BOOL isFloat = bitmapInfo && kCGBitmapFloatComponents; + size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); + + // Engine use f16 pixel format for wide gamut images + // If it is wide gamut, we want to downsample it + if (isFloat & (bitsPerComponent == 16)) { + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = + CGBitmapContextCreate(nil, tile.size.width, tile.size.height, 8, 0, colorSpace, + (kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast)); + CGContextDrawImage(context, CGRectMake(0, 0, tile.size.width, tile.size.height), tile.CGImage); + CGImageRef image = CGBitmapContextCreateImage(context); + tile = [UIImage imageWithCGImage:image]; + + CGImageRelease(image); + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + } + return tile; +} + +- (void)requestTileForX:(NSUInteger)x + y:(NSUInteger)y + zoom:(NSUInteger)zoom + receiver:(id)receiver { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.callbackHandler + tileWithOverlayIdentifier:self.tileOverlayIdentifier + location:[FGMPlatformPoint makeWithX:x y:y] + zoom:zoom + completion:^(FGMPlatformTile *_Nullable tile, + FlutterError *_Nullable error) { + FlutterStandardTypedData *typedData = tile.data; + UIImage *tileImage = + typedData + ? [self handleResultTile:[UIImage imageWithData:typedData.data]] + : kGMSTileLayerNoTile; + if (error) { + NSLog(@"Can't get tile: errorCode = %@, errorMessage = %@, details = %@", + [error code], [error message], [error details]); + } + [receiver receiveTileWithX:x y:y zoom:zoom image:tileImage]; + }]; + }); +} + +@end + +@interface FLTTileOverlaysController () + +@property(strong, nonatomic) NSMutableDictionary + *tileOverlayIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTTileOverlaysController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _tileOverlayIdentifierToController = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd { + for (FGMPlatformTileOverlay *tileOverlay in tileOverlaysToAdd) { + NSString *identifier = tileOverlay.tileOverlayId; + FLTTileProviderController *tileProvider = + [[FLTTileProviderController alloc] initWithTileOverlayIdentifier:identifier + callbackHandler:self.callbackHandler]; + FLTGoogleMapTileOverlayController *controller = + [[FLTGoogleMapTileOverlayController alloc] initWithTileOverlay:tileOverlay + tileLayer:tileProvider + mapView:self.mapView]; + self.tileOverlayIdentifierToController[identifier] = controller; + } +} + +- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange { + for (FGMPlatformTileOverlay *tileOverlay in tileOverlaysToChange) { + NSString *identifier = tileOverlay.tileOverlayId; + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; + [controller updateFromPlatformTileOverlay:tileOverlay]; + } +} +- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; + if (!controller) { + continue; + } + [controller removeTileOverlay]; + [self.tileOverlayIdentifierToController removeObjectForKey:identifier]; + } +} + +- (void)clearTileCacheWithIdentifier:(NSString *)identifier { + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; + [controller clearTileCache]; +} + +- (nullable FLTGoogleMapTileOverlayController *)tileOverlayWithIdentifier:(NSString *)identifier { + return self.tileOverlayIdentifierToController[identifier]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m new file mode 100644 index 000000000000..86391b40892e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m @@ -0,0 +1,19 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapsPlugin.h" + +#pragma mark - GoogleMaps plugin implementation + +@implementation FLTGoogleMapsPlugin + ++ (void)registerWithRegistrar:(NSObject *)registrar { + FLTGoogleMapFactory *googleMapFactory = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; + [registrar registerViewFactory:googleMapFactory + withId:@"plugins.flutter.dev/google_maps_ios" + gestureRecognizersBlockingPolicy: + FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m new file mode 100644 index 000000000000..d2d0130dc64a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m @@ -0,0 +1,130 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapCircleController.h" +#import "GoogleMapCircleController_Test.h" + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapCircleController () + +@property(nonatomic, strong) GMSCircle *circle; +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapCircleController + +- (instancetype)initCircleWithPlatformCircle:(FGMPlatformCircle *)circle + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _circle = [GMSCircle circleWithPosition:FGMGetCoordinateForPigeonLatLng(circle.center) + radius:circle.radius]; + _mapView = mapView; + _circle.userData = @[ circle.circleId ]; + [FLTGoogleMapCircleController updateCircle:_circle + fromPlatformCircle:circle + withMapView:mapView]; + } + return self; +} + +- (void)removeCircle { + self.circle.map = nil; +} + +- (void)updateFromPlatformCircle:(FGMPlatformCircle *)platformCircle { + [FLTGoogleMapCircleController updateCircle:self.circle + fromPlatformCircle:platformCircle + withMapView:self.mapView]; +} + ++ (void)updateCircle:(GMSCircle *)circle + fromPlatformCircle:(FGMPlatformCircle *)platformCircle + withMapView:(GMSMapView *)mapView { + circle.tappable = platformCircle.consumeTapEvents; + circle.zIndex = platformCircle.zIndex; + circle.position = FGMGetCoordinateForPigeonLatLng(platformCircle.center); + circle.radius = platformCircle.radius; + circle.strokeColor = FGMGetColorForPigeonColor(platformCircle.strokeColor); + circle.strokeWidth = platformCircle.strokeWidth; + circle.fillColor = FGMGetColorForPigeonColor(platformCircle.fillColor); + + // This must be done last, to avoid visual flickers of default property values. + circle.map = platformCircle.visible ? mapView : nil; +} + +@end + +@interface FLTCirclesController () + +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) GMSMapView *mapView; +@property(strong, nonatomic) NSMutableDictionary *circleIdToController; + +@end + +@implementation FLTCirclesController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _circleIdToController = [NSMutableDictionary dictionaryWithCapacity:1]; + } + return self; +} + +- (void)addCircles:(NSArray *)circlesToAdd { + for (FGMPlatformCircle *circle in circlesToAdd) { + FLTGoogleMapCircleController *controller = + [[FLTGoogleMapCircleController alloc] initCircleWithPlatformCircle:circle + mapView:self.mapView]; + self.circleIdToController[circle.circleId] = controller; + } +} + +- (void)changeCircles:(NSArray *)circlesToChange { + for (FGMPlatformCircle *circle in circlesToChange) { + FLTGoogleMapCircleController *controller = self.circleIdToController[circle.circleId]; + [controller updateFromPlatformCircle:circle]; + } +} + +- (void)removeCirclesWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapCircleController *controller = self.circleIdToController[identifier]; + if (!controller) { + continue; + } + [controller removeCircle]; + [self.circleIdToController removeObjectForKey:identifier]; + } +} + +- (bool)hasCircleWithIdentifier:(NSString *)identifier { + if (!identifier) { + return false; + } + return self.circleIdToController[identifier] != nil; +} + +- (void)didTapCircleWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapCircleController *controller = self.circleIdToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapCircleWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.m new file mode 100644 index 000000000000..0537d48ba9ce --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.m @@ -0,0 +1,838 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import GoogleMapsUtils; + +#import "GoogleMapController.h" +#import "GoogleMapController_Test.h" + +#import "FGMConversionUtils.h" +#import "FGMGroundOverlayController.h" +#import "FGMMarkerUserData.h" +#import "FLTGoogleMapHeatmapController.h" +#import "FLTGoogleMapTileOverlayController.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +#pragma mark - Conversion of JSON-like values sent via platform channels. Forward declarations. + +@interface FLTGoogleMapFactory () + +@property(weak, nonatomic) NSObject *registrar; +@property(strong, nonatomic, readonly) id sharedMapServices; + +@end + +@implementation FLTGoogleMapFactory + +@synthesize sharedMapServices = _sharedMapServices; + +- (instancetype)initWithRegistrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _registrar = registrar; + } + return self; +} + +- (NSObject *)createArgsCodec { + return FGMGetGoogleMapsFlutterPigeonMessagesCodec(); +} + +- (NSObject *)createWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + arguments:(id _Nullable)args { + // Precache shared map services, if needed. + // Retain the shared map services singleton, don't use the result for anything. + (void)[self sharedMapServices]; + + return [[FLTGoogleMapController alloc] initWithFrame:frame + viewIdentifier:viewId + creationParameters:args + registrar:self.registrar]; +} + +- (id)sharedMapServices { + if (_sharedMapServices == nil) { + // Calling this prepares GMSServices on a background thread controlled + // by the GoogleMaps framework. + // Retain the singleton to cache the initialization work across all map views. + _sharedMapServices = [GMSServices sharedServices]; + } + return _sharedMapServices; +} + +@end + +#pragma mark - + +/// Private declarations of the FGMMapCallHandler. +@interface FGMMapCallHandler () +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix; + +/// The map controller this inspector corresponds to. +@property(nonatomic, weak) FLTGoogleMapController *controller; +/// The messenger this instance was registered with by Pigeon. +@property(nonatomic, copy) NSObject *messenger; +/// The suffix this instance was registered under with Pigeon. +@property(nonatomic, copy) NSString *pigeonSuffix; +@end + +#pragma mark - + +/// Private declarations of the FGMMapInspector. +@interface FGMMapInspector () + +/// The map controller this inspector corresponds to. +@property(nonatomic, weak) FLTGoogleMapController *controller; +/// The messenger this instance was registered with by Pigeon. +@property(nonatomic, copy) NSObject *messenger; +/// The suffix this instance was registered under with Pigeon. +@property(nonatomic, copy) NSString *pigeonSuffix; +@end + +#pragma mark - + +@interface FLTGoogleMapController () + +@property(nonatomic, strong) GMSMapView *mapView; +@property(nonatomic, strong) FGMMapsCallbackApi *dartCallbackHandler; +@property(nonatomic, assign) BOOL trackCameraPosition; +@property(nonatomic, weak) NSObject *registrar; +@property(nonatomic, strong) FGMClusterManagersController *clusterManagersController; +@property(nonatomic, strong) FLTMarkersController *markersController; +@property(nonatomic, strong) FLTPolygonsController *polygonsController; +@property(nonatomic, strong) FLTPolylinesController *polylinesController; +@property(nonatomic, strong) FLTCirclesController *circlesController; + +// The controller that handles heatmaps +@property(nonatomic, strong) FLTHeatmapsController *heatmapsController; +@property(nonatomic, strong) FLTTileOverlaysController *tileOverlaysController; +@property(nonatomic, strong) FLTGroundOverlaysController *groundOverlaysController; +// The resulting error message, if any, from the last attempt to set the map style. +// This is used to provide access to errors after the fact, since the map style is generally set at +// creation time and there's no mechanism to return non-fatal error details during platform view +// initialization. +@property(nonatomic, copy) NSString *styleError; +// The main Pigeon API implementation, separate to avoid lifetime extension. +@property(nonatomic, strong) FGMMapCallHandler *callHandler; +// The inspector API implementation, separate to avoid lifetime extension. +@property(nonatomic, strong) FGMMapInspector *inspector; + +@end + +@implementation FLTGoogleMapController + +- (instancetype)initWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *)registrar { + GMSCameraPosition *camera = + FGMGetCameraPositionForPigeonCameraPosition(creationParameters.initialCameraPosition); + + GMSMapViewOptions *options = [[GMSMapViewOptions alloc] init]; + options.frame = frame; + options.camera = camera; + NSString *cloudMapId = creationParameters.mapConfiguration.mapId; + if (cloudMapId) { + options.mapID = [GMSMapID mapIDWithIdentifier:cloudMapId]; + } + + GMSMapView *mapView = [[GMSMapView alloc] initWithOptions:options]; + + return [self initWithMapView:mapView + viewIdentifier:viewId + creationParameters:creationParameters + registrar:registrar]; +} + +- (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *_Nonnull)registrar { + if (self = [super init]) { + _mapView = mapView; + + _mapView.accessibilityElementsHidden = NO; + // TODO(cyanglaz): avoid sending message to self in the middle of the init method. + // https://github.com/flutter/flutter/issues/104121 + [self interpretMapConfiguration:creationParameters.mapConfiguration]; + NSString *pigeonSuffix = [NSString stringWithFormat:@"%lld", viewId]; + _dartCallbackHandler = [[FGMMapsCallbackApi alloc] initWithBinaryMessenger:registrar.messenger + messageChannelSuffix:pigeonSuffix]; + _mapView.delegate = self; + _mapView.paddingAdjustmentBehavior = kGMSMapViewPaddingAdjustmentBehaviorNever; + _registrar = registrar; + _clusterManagersController = + [[FGMClusterManagersController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler]; + _markersController = [[FLTMarkersController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + clusterManagersController:_clusterManagersController + registrar:registrar]; + _polygonsController = [[FLTPolygonsController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _polylinesController = [[FLTPolylinesController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _circlesController = [[FLTCirclesController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _heatmapsController = [[FLTHeatmapsController alloc] initWithMapView:_mapView]; + _tileOverlaysController = + [[FLTTileOverlaysController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + _groundOverlaysController = + [[FLTGroundOverlaysController alloc] initWithMapView:_mapView + callbackHandler:_dartCallbackHandler + registrar:registrar]; + [_clusterManagersController addClusterManagers:creationParameters.initialClusterManagers]; + [_markersController addMarkers:creationParameters.initialMarkers]; + [_polygonsController addPolygons:creationParameters.initialPolygons]; + [_polylinesController addPolylines:creationParameters.initialPolylines]; + [_circlesController addCircles:creationParameters.initialCircles]; + [_heatmapsController addHeatmaps:creationParameters.initialHeatmaps]; + [_tileOverlaysController addTileOverlays:creationParameters.initialTileOverlays]; + [_groundOverlaysController addGroundOverlays:creationParameters.initialGroundOverlays]; + + // Invoke clustering after markers are added. + [_clusterManagersController invokeClusteringForEachClusterManager]; + + [_mapView addObserver:self forKeyPath:@"frame" options:0 context:nil]; + + _callHandler = [[FGMMapCallHandler alloc] initWithMapController:self + messenger:registrar.messenger + pigeonSuffix:pigeonSuffix]; + SetUpFGMMapsApiWithSuffix(registrar.messenger, _callHandler, pigeonSuffix); + _inspector = [[FGMMapInspector alloc] initWithMapController:self + messenger:registrar.messenger + pigeonSuffix:pigeonSuffix]; + SetUpFGMMapsInspectorApiWithSuffix(registrar.messenger, _inspector, pigeonSuffix); + } + return self; +} + +- (void)dealloc { + // Unregister the API implementations so that they can be released; the registration created an + // owning reference. + SetUpFGMMapsApiWithSuffix(_callHandler.messenger, nil, _callHandler.pigeonSuffix); + SetUpFGMMapsInspectorApiWithSuffix(_inspector.messenger, nil, _inspector.pigeonSuffix); +} + +- (UIView *)view { + return self.mapView; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if (object == self.mapView && [keyPath isEqualToString:@"frame"]) { + CGRect bounds = self.mapView.bounds; + if (CGRectEqualToRect(bounds, CGRectZero)) { + // The workaround is to fix an issue that the camera location is not current when + // the size of the map is zero at initialization. + // So We only care about the size of the `self.mapView`, ignore the frame changes when the + // size is zero. + return; + } + // We only observe the frame for initial setup. + [self.mapView removeObserver:self forKeyPath:@"frame"]; + [self.mapView moveCamera:[GMSCameraUpdate setCamera:self.mapView.camera]]; + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +- (void)showAtOrigin:(CGPoint)origin { + CGRect frame = {origin, self.mapView.frame.size}; + self.mapView.frame = frame; + self.mapView.hidden = NO; +} + +- (void)hide { + self.mapView.hidden = YES; +} + +- (GMSCameraPosition *)cameraPosition { + if (self.trackCameraPosition) { + return self.mapView.camera; + } else { + return nil; + } +} + +- (void)setCamera:(GMSCameraPosition *)camera { + self.mapView.camera = camera; +} + +- (void)setCameraTargetBounds:(GMSCoordinateBounds *)bounds { + self.mapView.cameraTargetBounds = bounds; +} + +- (void)setCompassEnabled:(BOOL)enabled { + self.mapView.settings.compassButton = enabled; +} + +- (void)setIndoorEnabled:(BOOL)enabled { + self.mapView.indoorEnabled = enabled; +} + +- (void)setTrafficEnabled:(BOOL)enabled { + self.mapView.trafficEnabled = enabled; +} + +- (void)setBuildingsEnabled:(BOOL)enabled { + self.mapView.buildingsEnabled = enabled; +} + +- (void)setMapType:(GMSMapViewType)mapType { + self.mapView.mapType = mapType; +} + +- (void)setMinZoom:(float)minZoom maxZoom:(float)maxZoom { + [self.mapView setMinZoom:minZoom maxZoom:maxZoom]; +} + +- (void)setPaddingTop:(float)top left:(float)left bottom:(float)bottom right:(float)right { + self.mapView.padding = UIEdgeInsetsMake(top, left, bottom, right); +} + +- (void)setRotateGesturesEnabled:(BOOL)enabled { + self.mapView.settings.rotateGestures = enabled; +} + +- (void)setScrollGesturesEnabled:(BOOL)enabled { + self.mapView.settings.scrollGestures = enabled; +} + +- (void)setTiltGesturesEnabled:(BOOL)enabled { + self.mapView.settings.tiltGestures = enabled; +} + +- (void)setTrackCameraPosition:(BOOL)enabled { + _trackCameraPosition = enabled; +} + +- (void)setZoomGesturesEnabled:(BOOL)enabled { + self.mapView.settings.zoomGestures = enabled; +} + +- (void)setMyLocationEnabled:(BOOL)enabled { + self.mapView.myLocationEnabled = enabled; +} + +- (void)setMyLocationButtonEnabled:(BOOL)enabled { + self.mapView.settings.myLocationButton = enabled; +} + +/// Sets the map style, returing any error string as well as storing that error in `mapStyle` for +/// later access. +- (NSString *)setMapStyle:(NSString *)mapStyle { + NSString *errorString = nil; + if (mapStyle.length == 0) { + self.mapView.mapStyle = nil; + } else { + NSError *error; + GMSMapStyle *style = [GMSMapStyle styleWithJSONString:mapStyle error:&error]; + if (style) { + self.mapView.mapStyle = style; + } else { + errorString = [error localizedDescription]; + } + } + self.styleError = errorString; + return errorString; +} + +#pragma mark - GMSMapViewDelegate methods + +- (void)mapView:(GMSMapView *)mapView willMove:(BOOL)gesture { + [self.dartCallbackHandler didStartCameraMoveWithCompletion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position { + if (self.trackCameraPosition) { + [self.dartCallbackHandler + didMoveCameraToPosition:FGMGetPigeonCameraPositionForPosition(position) + completion:^(FlutterError *_Nullable _){ + }]; + } +} + +- (void)mapView:(GMSMapView *)mapView idleAtCameraPosition:(GMSCameraPosition *)position { + [self.dartCallbackHandler didIdleCameraWithCompletion:^(FlutterError *_Nullable _){ + }]; +} + +- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker { + if ([marker.userData isKindOfClass:[GMUStaticCluster class]]) { + GMUStaticCluster *cluster = marker.userData; + [self.clusterManagersController didTapCluster:cluster]; + // When NO is returned, the map will focus on the cluster. + return NO; + } + return + [self.markersController didTapMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker)]; +} + +- (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker { + [self.markersController + didEndDraggingMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker) + location:marker.position]; +} + +- (void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker { + [self.markersController + didStartDraggingMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker) + location:marker.position]; +} + +- (void)mapView:(GMSMapView *)mapView didDragMarker:(GMSMarker *)marker { + [self.markersController didDragMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker) + location:marker.position]; +} + +- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker { + [self.markersController + didTapInfoWindowOfMarkerWithIdentifier:FGMGetMarkerIdentifierFromMarker(marker)]; +} +- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay { + NSString *overlayId = overlay.userData[0]; + if ([self.polylinesController hasPolylineWithIdentifier:overlayId]) { + [self.polylinesController didTapPolylineWithIdentifier:overlayId]; + } else if ([self.polygonsController hasPolygonWithIdentifier:overlayId]) { + [self.polygonsController didTapPolygonWithIdentifier:overlayId]; + } else if ([self.circlesController hasCircleWithIdentifier:overlayId]) { + [self.circlesController didTapCircleWithIdentifier:overlayId]; + } else if ([self.groundOverlaysController hasGroundOverlaysWithIdentifier:overlayId]) { + [self.groundOverlaysController didTapGroundOverlayWithIdentifier:overlayId]; + } +} + +- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { + [self.dartCallbackHandler didTapAtPosition:FGMGetPigeonLatLngForCoordinate(coordinate) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate { + [self.dartCallbackHandler didLongPressAtPosition:FGMGetPigeonLatLngForCoordinate(coordinate) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)interpretMapConfiguration:(FGMPlatformMapConfiguration *)config { + FGMPlatformCameraTargetBounds *cameraTargetBounds = config.cameraTargetBounds; + if (cameraTargetBounds) { + [self setCameraTargetBounds:cameraTargetBounds.bounds + ? FGMGetCoordinateBoundsForPigeonLatLngBounds( + cameraTargetBounds.bounds) + : nil]; + } + NSNumber *compassEnabled = config.compassEnabled; + if (compassEnabled != nil) { + [self setCompassEnabled:compassEnabled.boolValue]; + } + NSNumber *indoorEnabled = config.indoorViewEnabled; + if (indoorEnabled != nil) { + [self setIndoorEnabled:indoorEnabled.boolValue]; + } + NSNumber *trafficEnabled = config.trafficEnabled; + if (trafficEnabled != nil) { + [self setTrafficEnabled:trafficEnabled.boolValue]; + } + NSNumber *buildingsEnabled = config.buildingsEnabled; + if (buildingsEnabled != nil) { + [self setBuildingsEnabled:buildingsEnabled.boolValue]; + } + FGMPlatformMapTypeBox *mapType = config.mapType; + if (mapType) { + [self setMapType:FGMGetMapViewTypeForPigeonMapType(mapType.value)]; + } + FGMPlatformZoomRange *zoomData = config.minMaxZoomPreference; + if (zoomData) { + float minZoom = zoomData.min != nil ? zoomData.min.floatValue : kGMSMinZoomLevel; + float maxZoom = zoomData.max != nil ? zoomData.max.floatValue : kGMSMaxZoomLevel; + [self setMinZoom:minZoom maxZoom:maxZoom]; + } + FGMPlatformEdgeInsets *padding = config.padding; + if (padding) { + [self setPaddingTop:padding.top left:padding.left bottom:padding.bottom right:padding.right]; + } + + NSNumber *rotateGesturesEnabled = config.rotateGesturesEnabled; + if (rotateGesturesEnabled != nil) { + [self setRotateGesturesEnabled:rotateGesturesEnabled.boolValue]; + } + NSNumber *scrollGesturesEnabled = config.scrollGesturesEnabled; + if (scrollGesturesEnabled != nil) { + [self setScrollGesturesEnabled:scrollGesturesEnabled.boolValue]; + } + NSNumber *tiltGesturesEnabled = config.tiltGesturesEnabled; + if (tiltGesturesEnabled != nil) { + [self setTiltGesturesEnabled:tiltGesturesEnabled.boolValue]; + } + NSNumber *trackCameraPosition = config.trackCameraPosition; + if (trackCameraPosition != nil) { + [self setTrackCameraPosition:trackCameraPosition.boolValue]; + } + NSNumber *zoomGesturesEnabled = config.zoomGesturesEnabled; + if (zoomGesturesEnabled != nil) { + [self setZoomGesturesEnabled:zoomGesturesEnabled.boolValue]; + } + NSNumber *myLocationEnabled = config.myLocationEnabled; + if (myLocationEnabled != nil) { + [self setMyLocationEnabled:myLocationEnabled.boolValue]; + } + NSNumber *myLocationButtonEnabled = config.myLocationButtonEnabled; + if (myLocationButtonEnabled != nil) { + [self setMyLocationButtonEnabled:myLocationButtonEnabled.boolValue]; + } + NSString *style = config.style; + if (style) { + [self setMapStyle:style]; + } +} + +@end + +#pragma mark - + +/// Private declarations of the FGMMapCallHandler. +@implementation FGMMapCallHandler + +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix { + self = [super init]; + if (self) { + _controller = controller; + _messenger = messenger; + _pigeonSuffix = suffix; + _transactionWrapper = [[FGMCATransactionWrapper alloc] init]; + } + return self; +} + +- (void)waitForMapWithError:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + // No-op; this call just ensures synchronization with the platform thread. +} + +- (void)updateCirclesByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.circlesController addCircles:toAdd]; + [self.controller.circlesController changeCircles:toChange]; + [self.controller.circlesController removeCirclesWithIdentifiers:idsToRemove]; +} + +- (void)updateHeatmapsByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.heatmapsController addHeatmaps:toAdd]; + [self.controller.heatmapsController changeHeatmaps:toChange]; + [self.controller.heatmapsController removeHeatmapsWithIdentifiers:idsToRemove]; +} + +- (void)updateWithMapConfiguration:(nonnull FGMPlatformMapConfiguration *)configuration + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller interpretMapConfiguration:configuration]; +} + +- (void)updateMarkersByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.markersController addMarkers:toAdd]; + [self.controller.markersController changeMarkers:toChange]; + [self.controller.markersController removeMarkersWithIdentifiers:idsToRemove]; + + // Invoke clustering after markers are added. + [self.controller.clusterManagersController invokeClusteringForEachClusterManager]; +} + +- (void)updateClusterManagersByAdding:(nonnull NSArray *)toAdd + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.clusterManagersController addClusterManagers:toAdd]; + [self.controller.clusterManagersController removeClusterManagersWithIdentifiers:idsToRemove]; +} + +- (void)updatePolygonsByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.polygonsController addPolygons:toAdd]; + [self.controller.polygonsController changePolygons:toChange]; + [self.controller.polygonsController removePolygonWithIdentifiers:idsToRemove]; +} + +- (void)updatePolylinesByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.polylinesController addPolylines:toAdd]; + [self.controller.polylinesController changePolylines:toChange]; + [self.controller.polylinesController removePolylineWithIdentifiers:idsToRemove]; +} + +- (void)updateTileOverlaysByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.tileOverlaysController addTileOverlays:toAdd]; + [self.controller.tileOverlaysController changeTileOverlays:toChange]; + [self.controller.tileOverlaysController removeTileOverlayWithIdentifiers:idsToRemove]; +} + +- (void)updateGroundOverlaysByAdding:(nonnull NSArray *)toAdd + changing:(nonnull NSArray *)toChange + removing:(nonnull NSArray *)idsToRemove + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + [self.controller.groundOverlaysController addGroundOverlays:toAdd]; + [self.controller.groundOverlaysController changeGroundOverlays:toChange]; + [self.controller.groundOverlaysController removeGroundOverlaysWithIdentifiers:idsToRemove]; +} + +- (nullable FGMPlatformLatLng *) + latLngForScreenCoordinate:(nonnull FGMPlatformPoint *)screenCoordinate + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + if (!self.controller.mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"getLatLng called prior to map initialization" + details:nil]; + return nil; + } + CGPoint point = FGMGetCGPointForPigeonPoint(screenCoordinate); + CLLocationCoordinate2D latlng = [self.controller.mapView.projection coordinateForPoint:point]; + return FGMGetPigeonLatLngForCoordinate(latlng); +} + +- (nullable FGMPlatformPoint *) + screenCoordinatesForLatLng:(nonnull FGMPlatformLatLng *)latLng + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + if (!self.controller.mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"getScreenCoordinate called prior to map initialization" + details:nil]; + return nil; + } + CLLocationCoordinate2D location = FGMGetCoordinateForPigeonLatLng(latLng); + CGPoint point = [self.controller.mapView.projection pointForCoordinate:location]; + return FGMGetPigeonPointForCGPoint(point); +} + +- (nullable FGMPlatformLatLngBounds *)visibleMapRegion: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + if (!self.controller.mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"getVisibleRegion called prior to map initialization" + details:nil]; + return nil; + } + GMSVisibleRegion visibleRegion = self.controller.mapView.projection.visibleRegion; + GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithRegion:visibleRegion]; + return FGMGetPigeonLatLngBoundsForCoordinateBounds(bounds); +} + +- (void)moveCameraWithUpdate:(nonnull FGMPlatformCameraUpdate *)cameraUpdate + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSCameraUpdate *update = FGMGetCameraUpdateForPigeonCameraUpdate(cameraUpdate); + if (!update) { + *error = [FlutterError errorWithCode:@"Invalid update" + message:@"Unrecognized camera update" + details:nil]; + return; + } + [self.controller.mapView moveCamera:update]; +} + +- (void)animateCameraWithUpdate:(nonnull FGMPlatformCameraUpdate *)cameraUpdate + duration:(nullable NSNumber *)durationMilliseconds + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSCameraUpdate *update = FGMGetCameraUpdateForPigeonCameraUpdate(cameraUpdate); + if (!update) { + *error = [FlutterError errorWithCode:@"Invalid update" + message:@"Unrecognized camera update" + details:nil]; + return; + } + FGMCATransactionWrapper *transaction = + durationMilliseconds != nil ? self.transactionWrapper : nil; + [transaction begin]; + [transaction setAnimationDuration:[durationMilliseconds doubleValue] / 1000]; + [self.controller.mapView animateWithCameraUpdate:update]; + [transaction commit]; +} + +- (nullable NSNumber *)currentZoomLevel:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.camera.zoom); +} + +- (void)showInfoWindowForMarkerWithIdentifier:(nonnull NSString *)markerId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + [self.controller.markersController showMarkerInfoWindowWithIdentifier:markerId error:error]; +} + +- (void)hideInfoWindowForMarkerWithIdentifier:(nonnull NSString *)markerId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + [self.controller.markersController hideMarkerInfoWindowWithIdentifier:markerId error:error]; +} + +- (nullable NSNumber *) + isShowingInfoWindowForMarkerWithIdentifier:(nonnull NSString *)markerId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + return [self.controller.markersController isInfoWindowShownForMarkerWithIdentifier:markerId + error:error]; +} + +- (nullable NSString *)setStyle:(nonnull NSString *)style + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [self.controller setMapStyle:style]; +} + +- (nullable NSString *)lastStyleError:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return self.controller.styleError; +} + +- (void)clearTileCacheForOverlayWithIdentifier:(nonnull NSString *)tileOverlayId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + [self.controller.tileOverlaysController clearTileCacheWithIdentifier:tileOverlayId]; +} + +- (nullable FlutterStandardTypedData *)takeSnapshotWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSMapView *mapView = self.controller.mapView; + if (!mapView) { + *error = [FlutterError errorWithCode:@"GoogleMap uninitialized" + message:@"takeSnapshot called prior to map initialization" + details:nil]; + return nil; + } + UIGraphicsImageRenderer *renderer = + [[UIGraphicsImageRenderer alloc] initWithSize:mapView.bounds.size]; + // For some unknown reason mapView.layer::renderInContext API returns a blank image on iOS 17. + // So we have to use drawViewHierarchyInRect API. + UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *context) { + [mapView drawViewHierarchyInRect:mapView.bounds afterScreenUpdates:YES]; + }]; + NSData *imageData = UIImagePNGRepresentation(image); + return imageData ? [FlutterStandardTypedData typedDataWithBytes:imageData] : nil; +} + +@end + +#pragma mark - + +/// Private declarations of the FGMMapInspector. +@implementation FGMMapInspector + +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix { + self = [super init]; + if (self) { + _controller = controller; + _messenger = messenger; + _pigeonSuffix = suffix; + } + return self; +} + +- (nullable NSNumber *)areBuildingsEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.buildingsEnabled); +} + +- (nullable NSNumber *)areRotateGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.rotateGestures); +} + +- (nullable NSNumber *)areScrollGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.scrollGestures); +} + +- (nullable NSNumber *)areTiltGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.tiltGestures); +} + +- (nullable NSNumber *)areZoomGesturesEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.zoomGestures); +} + +- (nullable FGMPlatformTileLayer *) + tileOverlayWithIdentifier:(nonnull NSString *)tileOverlayId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + GMSTileLayer *layer = + [self.controller.tileOverlaysController tileOverlayWithIdentifier:tileOverlayId].layer; + if (!layer) { + return nil; + } + return [FGMPlatformTileLayer makeWithVisible:(layer.map != nil) + fadeIn:layer.fadeIn + opacity:layer.opacity + zIndex:layer.zIndex]; +} + +- (nullable FGMPlatformHeatmap *) + heatmapWithIdentifier:(nonnull NSString *)heatmapId + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [self.controller.heatmapsController heatmapWithIdentifier:heatmapId]; +} + +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)clusterManagerId + error:(FlutterError *_Nullable *_Nonnull)error { + return [self.controller.clusterManagersController clustersWithIdentifier:clusterManagerId + error:error]; +} + +- (nullable NSNumber *)isCompassEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.compassButton); +} + +- (nullable NSNumber *)isMyLocationButtonEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.settings.myLocationButton); +} + +- (nullable NSNumber *)isTrafficEnabledWithError: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return @(self.controller.mapView.trafficEnabled); +} + +- (nullable FGMPlatformZoomRange *)zoomRange: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return [FGMPlatformZoomRange makeWithMin:@(self.controller.mapView.minZoom) + max:@(self.controller.mapView.maxZoom)]; +} + +- (nullable FGMPlatformGroundOverlay *) + groundOverlayWithIdentifier:(NSString *)groundOverlayId + error:(FlutterError *_Nullable __autoreleasing *)error { + return [self.controller.groundOverlaysController groundOverlayWithIdentifier:groundOverlayId]; +} + +- (nullable FGMPlatformCameraPosition *)cameraPosition: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + return FGMGetPigeonCameraPositionForPosition(self.controller.mapView.camera); +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m new file mode 100644 index 000000000000..ed3aabd7fc10 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m @@ -0,0 +1,343 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapMarkerController.h" +#import "GoogleMapMarkerController_Test.h" + +#import "FGMConversionUtils.h" +#import "FGMImageUtils.h" +#import "FGMMarkerUserData.h" + +@interface FLTGoogleMapMarkerController () + +@property(strong, nonatomic, readwrite) GMSMarker *marker; +@property(weak, nonatomic) GMSMapView *mapView; +@property(assign, nonatomic, readwrite) BOOL consumeTapEvents; +/// The unique identifier for the cluster manager. +@property(copy, nonatomic, nullable) NSString *clusterManagerIdentifier; +/// The unique identifier for the marker. +@property(copy, nonatomic) NSString *markerIdentifier; + +@end + +@implementation FLTGoogleMapMarkerController + +- (instancetype)initWithMarker:(GMSMarker *)marker + markerIdentifier:(NSString *)markerIdentifier + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _marker = marker; + _markerIdentifier = [markerIdentifier copy]; + _mapView = mapView; + } + return self; +} + +- (void)showInfoWindow { + self.mapView.selectedMarker = self.marker; +} + +- (void)hideInfoWindow { + if (self.mapView.selectedMarker == self.marker) { + self.mapView.selectedMarker = nil; + } +} + +- (BOOL)isInfoWindowShown { + return self.mapView.selectedMarker == self.marker; +} + +- (void)removeMarker { + self.marker.map = nil; +} + +- (void)updateFromPlatformMarker:(FGMPlatformMarker *)platformMarker + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale { + self.clusterManagerIdentifier = platformMarker.clusterManagerId; + self.consumeTapEvents = platformMarker.consumeTapEvents; + + // Set the marker's user data with current identifiers. + FGMSetIdentifiersToMarkerUserData(self.markerIdentifier, self.clusterManagerIdentifier, + self.marker); + + // If marker belongs the cluster manager, visibility need to be controlled with the opacity + // as the cluster manager controls when marker is on the map and when not. + BOOL useOpacityForVisibility = self.clusterManagerIdentifier != nil; + [FLTGoogleMapMarkerController updateMarker:self.marker + fromPlatformMarker:platformMarker + withMapView:self.mapView + registrar:registrar + screenScale:screenScale + usingOpacityForVisibility:useOpacityForVisibility]; +} + ++ (void)updateMarker:(GMSMarker *)marker + fromPlatformMarker:(FGMPlatformMarker *)platformMarker + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingOpacityForVisibility:(BOOL)useOpacityForVisibility { + marker.groundAnchor = FGMGetCGPointForPigeonPoint(platformMarker.anchor); + marker.draggable = platformMarker.draggable; + UIImage *image = FGMIconFromBitmap(platformMarker.icon, registrar, screenScale); + marker.icon = image; + marker.flat = platformMarker.flat; + marker.position = FGMGetCoordinateForPigeonLatLng(platformMarker.position); + marker.rotation = platformMarker.rotation; + marker.zIndex = (int)platformMarker.zIndex; + FGMPlatformInfoWindow *infoWindow = platformMarker.infoWindow; + marker.infoWindowAnchor = FGMGetCGPointForPigeonPoint(infoWindow.anchor); + if (infoWindow.title) { + marker.title = infoWindow.title; + marker.snippet = infoWindow.snippet; + } + + // This must be done last, to avoid visual flickers of default property values. + if (useOpacityForVisibility) { + marker.opacity = platformMarker.visible ? platformMarker.alpha : 0.0f; + } else { + marker.opacity = platformMarker.alpha; + marker.map = platformMarker.visible ? mapView : nil; + } +} + +@end + +@interface FLTMarkersController () + +@property(strong, nonatomic, readwrite) NSMutableDictionary *markerIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +/// Controller for adding/removing/fetching cluster managers +@property(weak, nonatomic, nullable) FGMClusterManagersController *clusterManagersController; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTMarkersController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + clusterManagersController:(nullable FGMClusterManagersController *)clusterManagersController + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _clusterManagersController = clusterManagersController; + _markerIdentifierToController = [[NSMutableDictionary alloc] init]; + _registrar = registrar; + } + return self; +} + +- (void)addMarkers:(NSArray *)markersToAdd { + for (FGMPlatformMarker *marker in markersToAdd) { + [self addMarker:marker]; + } +} + +- (void)addMarker:(FGMPlatformMarker *)markerToAdd { + CLLocationCoordinate2D position = FGMGetCoordinateForPigeonLatLng(markerToAdd.position); + NSString *markerIdentifier = markerToAdd.markerId; + NSString *clusterManagerIdentifier = markerToAdd.clusterManagerId; + GMSMarker *marker = [GMSMarker markerWithPosition:position]; + FLTGoogleMapMarkerController *controller = + [[FLTGoogleMapMarkerController alloc] initWithMarker:marker + markerIdentifier:markerIdentifier + mapView:self.mapView]; + [controller updateFromPlatformMarker:markerToAdd + registrar:self.registrar + screenScale:[self getScreenScale]]; + if (clusterManagerIdentifier) { + GMUClusterManager *clusterManager = + [_clusterManagersController clusterManagerWithIdentifier:clusterManagerIdentifier]; + if ([marker conformsToProtocol:@protocol(GMUClusterItem)]) { + [clusterManager addItem:(id)marker]; + } + } + self.markerIdentifierToController[markerIdentifier] = controller; +} + +- (void)changeMarkers:(NSArray *)markersToChange { + for (FGMPlatformMarker *marker in markersToChange) { + [self changeMarker:marker]; + } +} + +- (void)changeMarker:(FGMPlatformMarker *)markerToChange { + NSString *markerIdentifier = markerToChange.markerId; + + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[markerIdentifier]; + if (!controller) { + return; + } + + NSString *clusterManagerIdentifier = markerToChange.clusterManagerId; + NSString *previousClusterManagerIdentifier = [controller clusterManagerIdentifier]; + [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]; + } + } +} + +- (void)removeMarkersWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + [self removeMarker:identifier]; + } +} + +- (void)removeMarker:(NSString *)identifier { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + NSString *clusterManagerIdentifier = [controller clusterManagerIdentifier]; + if (clusterManagerIdentifier) { + GMUClusterManager *clusterManager = + [_clusterManagersController clusterManagerWithIdentifier:clusterManagerIdentifier]; + [clusterManager removeItem:(id)controller.marker]; + } else { + [controller removeMarker]; + } + [self.markerIdentifierToController removeObjectForKey:identifier]; +} + +- (BOOL)didTapMarkerWithIdentifier:(NSString *)identifier { + if (!identifier) { + return NO; + } + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return NO; + } + [self.callbackHandler didTapMarkerWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; + return controller.consumeTapEvents; +} + +- (void)didStartDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + if (!identifier) { + return; + } + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler + didStartDragForMarkerWithIdentifier:identifier + atPosition:FGMGetPigeonLatLngForCoordinate(location) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)didDragMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + if (!identifier) { + return; + } + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didDragMarkerWithIdentifier:identifier + atPosition:FGMGetPigeonLatLngForCoordinate(location) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)didEndDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didEndDragForMarkerWithIdentifier:identifier + atPosition:FGMGetPigeonLatLngForCoordinate(location) + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)identifier { + if (identifier && self.markerIdentifierToController[identifier]) { + [self.callbackHandler didTapInfoWindowOfMarkerWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; + } +} + +- (void)showMarkerInfoWindowWithIdentifier:(NSString *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (controller) { + [controller showInfoWindow]; + } else { + *error = [FlutterError errorWithCode:@"Invalid markerId" + message:@"showInfoWindow called with invalid markerId" + details:nil]; + } +} + +- (void)hideMarkerInfoWindowWithIdentifier:(NSString *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (controller) { + [controller hideInfoWindow]; + } else { + *error = [FlutterError errorWithCode:@"Invalid markerId" + message:@"hideInfoWindow called with invalid markerId" + details:nil]; + } +} + +- (nullable NSNumber *) + isInfoWindowShownForMarkerWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull) + error { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; + if (controller) { + return @([controller isInfoWindowShown]); + } else { + *error = [FlutterError errorWithCode:@"Invalid markerId" + message:@"isInfoWindowShown called with invalid markerId" + details:nil]; + return nil; + } +} + +- (CGFloat)getScreenScale { + // TODO(jokerttu): This method is called on marker creation, which, for initial markers, is done + // before the view is added to the view hierarchy. This means that the traitCollection values may + // not be matching the right display where the map is finally shown. The solution should be + // revisited after the proper way to fetch the display scale is resolved for platform views. This + // should be done under the context of the following issue: + // https://github.com/flutter/flutter/issues/125496. + return self.mapView.traitCollection.displayScale; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m new file mode 100644 index 000000000000..12cbfeefecd7 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m @@ -0,0 +1,146 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolygonController.h" +#import "GoogleMapPolygonController_Test.h" + +#import "FGMConversionUtils.h" + +/// Converts a list of holes represented as CLLocation lists to GMSMutablePath lists. +static NSArray *FMGPathHolesFromLocationHoles( + NSArray *> *locationHoles) { + NSMutableArray *pathHoles = + [NSMutableArray arrayWithCapacity:locationHoles.count]; + for (NSArray *hole in locationHoles) { + [pathHoles addObject:FGMGetPathFromPoints(hole)]; + } + return pathHoles; +} + +@interface FLTGoogleMapPolygonController () + +@property(strong, nonatomic) GMSPolygon *polygon; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapPolygonController + +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _polygon = [GMSPolygon polygonWithPath:path]; + _mapView = mapView; + _polygon.userData = @[ identifier ]; + } + return self; +} + +- (void)removePolygon { + self.polygon.map = nil; +} + +- (void)updateFromPlatformPolygon:(FGMPlatformPolygon *)polygon { + [FLTGoogleMapPolygonController updatePolygon:self.polygon + fromPlatformPolygon:polygon + withMapView:self.mapView]; +} + ++ (void)updatePolygon:(GMSPolygon *)polygon + fromPlatformPolygon:(FGMPlatformPolygon *)platformPolygon + withMapView:(GMSMapView *)mapView { + polygon.tappable = platformPolygon.consumesTapEvents; + polygon.zIndex = (int)platformPolygon.zIndex; + polygon.path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(platformPolygon.points)); + polygon.holes = + FMGPathHolesFromLocationHoles(FGMGetHolesForPigeonLatLngArrays(platformPolygon.holes)); + polygon.fillColor = FGMGetColorForPigeonColor(platformPolygon.fillColor); + polygon.strokeColor = FGMGetColorForPigeonColor(platformPolygon.strokeColor); + polygon.strokeWidth = platformPolygon.strokeWidth; + + // This must be done last, to avoid visual flickers of default property values. + polygon.map = platformPolygon.visible ? mapView : nil; +} + +@end + +@interface FLTPolygonsController () + +@property(strong, nonatomic) NSMutableDictionary *polygonIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTPolygonsController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _polygonIdentifierToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _registrar = registrar; + } + return self; +} + +- (void)addPolygons:(NSArray *)polygonsToAdd { + for (FGMPlatformPolygon *polygon in polygonsToAdd) { + GMSMutablePath *path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(polygon.points)); + NSString *identifier = polygon.polygonId; + FLTGoogleMapPolygonController *controller = + [[FLTGoogleMapPolygonController alloc] initWithPath:path + identifier:identifier + mapView:self.mapView]; + [controller updateFromPlatformPolygon:polygon]; + self.polygonIdentifierToController[identifier] = controller; + } +} + +- (void)changePolygons:(NSArray *)polygonsToChange { + for (FGMPlatformPolygon *polygon in polygonsToChange) { + NSString *identifier = polygon.polygonId; + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; + [controller updateFromPlatformPolygon:polygon]; + } +} + +- (void)removePolygonWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; + if (!controller) { + continue; + } + [controller removePolygon]; + [self.polygonIdentifierToController removeObjectForKey:identifier]; + } +} + +- (void)didTapPolygonWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapPolygonWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (bool)hasPolygonWithIdentifier:(NSString *)identifier { + if (!identifier) { + return false; + } + return self.polygonIdentifierToController[identifier] != nil; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m new file mode 100644 index 000000000000..63a7f7b7b0fc --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m @@ -0,0 +1,140 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolylineController.h" +#import "GoogleMapPolylineController_Test.h" + +#import "FGMConversionUtils.h" + +@interface FLTGoogleMapPolylineController () + +@property(strong, nonatomic) GMSPolyline *polyline; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapPolylineController + +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView { + self = [super init]; + if (self) { + _polyline = [GMSPolyline polylineWithPath:path]; + _mapView = mapView; + _polyline.userData = @[ identifier ]; + } + return self; +} + +- (void)removePolyline { + self.polyline.map = nil; +} + +- (void)updateFromPlatformPolyline:(FGMPlatformPolyline *)polyline { + [FLTGoogleMapPolylineController updatePolyline:self.polyline + fromPlatformPolyline:polyline + withMapView:self.mapView]; +} + ++ (void)updatePolyline:(GMSPolyline *)polyline + fromPlatformPolyline:(FGMPlatformPolyline *)platformPolyline + withMapView:(GMSMapView *)mapView { + polyline.tappable = platformPolyline.consumesTapEvents; + polyline.zIndex = (int)platformPolyline.zIndex; + GMSMutablePath *path = + FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(platformPolyline.points)); + polyline.path = path; + UIColor *strokeColor = FGMGetColorForPigeonColor(platformPolyline.color); + polyline.strokeColor = strokeColor; + polyline.strokeWidth = platformPolyline.width; + polyline.geodesic = platformPolyline.geodesic; + polyline.spans = + GMSStyleSpans(path, FGMGetStrokeStylesFromPatterns(platformPolyline.patterns, strokeColor), + FGMGetSpanLengthsFromPatterns(platformPolyline.patterns), kGMSLengthRhumb); + + // This must be done last, to avoid visual flickers of default property values. + polyline.map = platformPolyline.visible ? mapView : nil; +} + +@end + +@interface FLTPolylinesController () + +@property(strong, nonatomic) NSMutableDictionary *polylineIdentifierToController; +@property(strong, nonatomic) FGMMapsCallbackApi *callbackHandler; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end +; + +@implementation FLTPolylinesController + +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar { + self = [super init]; + if (self) { + _callbackHandler = callbackHandler; + _mapView = mapView; + _polylineIdentifierToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _registrar = registrar; + } + return self; +} + +- (void)addPolylines:(NSArray *)polylinesToAdd { + for (FGMPlatformPolyline *polyline in polylinesToAdd) { + GMSMutablePath *path = FGMGetPathFromPoints(FGMGetPointsForPigeonLatLngs(polyline.points)); + NSString *identifier = polyline.polylineId; + FLTGoogleMapPolylineController *controller = + [[FLTGoogleMapPolylineController alloc] initWithPath:path + identifier:identifier + mapView:self.mapView]; + [controller updateFromPlatformPolyline:polyline]; + self.polylineIdentifierToController[identifier] = controller; + } +} + +- (void)changePolylines:(NSArray *)polylinesToChange { + for (FGMPlatformPolyline *polyline in polylinesToChange) { + NSString *identifier = polyline.polylineId; + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; + [controller updateFromPlatformPolyline:polyline]; + } +} + +- (void)removePolylineWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; + if (!controller) { + continue; + } + [controller removePolyline]; + [self.polylineIdentifierToController removeObjectForKey:identifier]; + } +} + +- (void)didTapPolylineWithIdentifier:(NSString *)identifier { + if (!identifier) { + return; + } + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; + if (!controller) { + return; + } + [self.callbackHandler didTapPolylineWithIdentifier:identifier + completion:^(FlutterError *_Nullable _){ + }]; +} + +- (bool)hasPolylineWithIdentifier:(NSString *)identifier { + if (!identifier) { + return false; + } + return self.polylineIdentifierToController[identifier] != nil; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 000000000000..7b4cbc597d31 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,123 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeCrashData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeDeviceID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypePerformanceData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeProductInteraction + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeUserID + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryDiskSpace + NSPrivacyAccessedAPITypeReasons + + 85F4.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + + diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m new file mode 100644 index 000000000000..e833e2f24f42 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m @@ -0,0 +1,3446 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#import "google_maps_flutter_pigeon_messages.g.h" + +#if TARGET_OS_OSX +#import +#else +#import +#endif + +#if !__has_feature(objc_arc) +#error File requires ARC to be enabled. +#endif + +static NSArray *wrapResult(id result, FlutterError *error) { + if (error) { + return @[ + error.code ?: [NSNull null], error.message ?: [NSNull null], error.details ?: [NSNull null] + ]; + } + return @[ result ?: [NSNull null] ]; +} + +static FlutterError *createConnectionError(NSString *channelName) { + return [FlutterError + errorWithCode:@"channel-error" + message:[NSString stringWithFormat:@"%@/%@/%@", + @"Unable to establish connection on channel: '", + channelName, @"'."] + details:@""]; +} + +static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { + id result = array[key]; + return (result == [NSNull null]) ? nil : result; +} + +/// Pigeon equivalent of MapType +@implementation FGMPlatformMapTypeBox +- (instancetype)initWithValue:(FGMPlatformMapType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +/// Join types for polyline joints. +@implementation FGMPlatformJointTypeBox +- (instancetype)initWithValue:(FGMPlatformJointType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +/// Enumeration of possible types for PatternItem. +@implementation FGMPlatformPatternItemTypeBox +- (instancetype)initWithValue:(FGMPlatformPatternItemType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +/// Pigeon equivalent of [MapBitmapScaling]. +@implementation FGMPlatformMapBitmapScalingBox +- (instancetype)initWithValue:(FGMPlatformMapBitmapScaling)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + +@interface FGMPlatformCameraPosition () ++ (FGMPlatformCameraPosition *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraPosition *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdate () ++ (FGMPlatformCameraUpdate *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdate *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewCameraPosition () ++ (FGMPlatformCameraUpdateNewCameraPosition *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewCameraPosition *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewLatLng () ++ (FGMPlatformCameraUpdateNewLatLng *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewLatLng *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewLatLngBounds () ++ (FGMPlatformCameraUpdateNewLatLngBounds *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewLatLngBounds *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateNewLatLngZoom () ++ (FGMPlatformCameraUpdateNewLatLngZoom *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateNewLatLngZoom *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateScrollBy () ++ (FGMPlatformCameraUpdateScrollBy *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateScrollBy *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateZoomBy () ++ (FGMPlatformCameraUpdateZoomBy *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateZoomBy *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateZoom () ++ (FGMPlatformCameraUpdateZoom *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateZoom *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraUpdateZoomTo () ++ (FGMPlatformCameraUpdateZoomTo *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraUpdateZoomTo *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCircle () ++ (FGMPlatformCircle *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCircle *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformHeatmap () ++ (FGMPlatformHeatmap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformHeatmap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformHeatmapGradient () ++ (FGMPlatformHeatmapGradient *)fromList:(NSArray *)list; ++ (nullable FGMPlatformHeatmapGradient *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformWeightedLatLng () ++ (FGMPlatformWeightedLatLng *)fromList:(NSArray *)list; ++ (nullable FGMPlatformWeightedLatLng *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformInfoWindow () ++ (FGMPlatformInfoWindow *)fromList:(NSArray *)list; ++ (nullable FGMPlatformInfoWindow *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCluster () ++ (FGMPlatformCluster *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCluster *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformClusterManager () ++ (FGMPlatformClusterManager *)fromList:(NSArray *)list; ++ (nullable FGMPlatformClusterManager *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformMarker () ++ (FGMPlatformMarker *)fromList:(NSArray *)list; ++ (nullable FGMPlatformMarker *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPolygon () ++ (FGMPlatformPolygon *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPolygon *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPolyline () ++ (FGMPlatformPolyline *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPolyline *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPatternItem () ++ (FGMPlatformPatternItem *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPatternItem *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformTile () ++ (FGMPlatformTile *)fromList:(NSArray *)list; ++ (nullable FGMPlatformTile *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformTileOverlay () ++ (FGMPlatformTileOverlay *)fromList:(NSArray *)list; ++ (nullable FGMPlatformTileOverlay *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformEdgeInsets () ++ (FGMPlatformEdgeInsets *)fromList:(NSArray *)list; ++ (nullable FGMPlatformEdgeInsets *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformLatLng () ++ (FGMPlatformLatLng *)fromList:(NSArray *)list; ++ (nullable FGMPlatformLatLng *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformLatLngBounds () ++ (FGMPlatformLatLngBounds *)fromList:(NSArray *)list; ++ (nullable FGMPlatformLatLngBounds *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformCameraTargetBounds () ++ (FGMPlatformCameraTargetBounds *)fromList:(NSArray *)list; ++ (nullable FGMPlatformCameraTargetBounds *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformGroundOverlay () ++ (FGMPlatformGroundOverlay *)fromList:(NSArray *)list; ++ (nullable FGMPlatformGroundOverlay *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformMapViewCreationParams () ++ (FGMPlatformMapViewCreationParams *)fromList:(NSArray *)list; ++ (nullable FGMPlatformMapViewCreationParams *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformMapConfiguration () ++ (FGMPlatformMapConfiguration *)fromList:(NSArray *)list; ++ (nullable FGMPlatformMapConfiguration *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformPoint () ++ (FGMPlatformPoint *)fromList:(NSArray *)list; ++ (nullable FGMPlatformPoint *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformSize () ++ (FGMPlatformSize *)fromList:(NSArray *)list; ++ (nullable FGMPlatformSize *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformColor () ++ (FGMPlatformColor *)fromList:(NSArray *)list; ++ (nullable FGMPlatformColor *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformTileLayer () ++ (FGMPlatformTileLayer *)fromList:(NSArray *)list; ++ (nullable FGMPlatformTileLayer *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformZoomRange () ++ (FGMPlatformZoomRange *)fromList:(NSArray *)list; ++ (nullable FGMPlatformZoomRange *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmap () ++ (FGMPlatformBitmap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapDefaultMarker () ++ (FGMPlatformBitmapDefaultMarker *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapDefaultMarker *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapBytes () ++ (FGMPlatformBitmapBytes *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapBytes *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapAsset () ++ (FGMPlatformBitmapAsset *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapAsset *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapAssetImage () ++ (FGMPlatformBitmapAssetImage *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapAssetImage *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapAssetMap () ++ (FGMPlatformBitmapAssetMap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapAssetMap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@interface FGMPlatformBitmapBytesMap () ++ (FGMPlatformBitmapBytesMap *)fromList:(NSArray *)list; ++ (nullable FGMPlatformBitmapBytesMap *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + +@implementation FGMPlatformCameraPosition ++ (instancetype)makeWithBearing:(double)bearing + target:(FGMPlatformLatLng *)target + tilt:(double)tilt + zoom:(double)zoom { + FGMPlatformCameraPosition *pigeonResult = [[FGMPlatformCameraPosition alloc] init]; + pigeonResult.bearing = bearing; + pigeonResult.target = target; + pigeonResult.tilt = tilt; + pigeonResult.zoom = zoom; + return pigeonResult; +} ++ (FGMPlatformCameraPosition *)fromList:(NSArray *)list { + FGMPlatformCameraPosition *pigeonResult = [[FGMPlatformCameraPosition alloc] init]; + pigeonResult.bearing = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.target = GetNullableObjectAtIndex(list, 1); + pigeonResult.tilt = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.zoom = [GetNullableObjectAtIndex(list, 3) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraPosition *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraPosition fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.bearing), + self.target ?: [NSNull null], + @(self.tilt), + @(self.zoom), + ]; +} +@end + +@implementation FGMPlatformCameraUpdate ++ (instancetype)makeWithCameraUpdate:(id)cameraUpdate { + FGMPlatformCameraUpdate *pigeonResult = [[FGMPlatformCameraUpdate alloc] init]; + pigeonResult.cameraUpdate = cameraUpdate; + return pigeonResult; +} ++ (FGMPlatformCameraUpdate *)fromList:(NSArray *)list { + FGMPlatformCameraUpdate *pigeonResult = [[FGMPlatformCameraUpdate alloc] init]; + pigeonResult.cameraUpdate = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdate *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdate fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.cameraUpdate ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewCameraPosition ++ (instancetype)makeWithCameraPosition:(FGMPlatformCameraPosition *)cameraPosition { + FGMPlatformCameraUpdateNewCameraPosition *pigeonResult = + [[FGMPlatformCameraUpdateNewCameraPosition alloc] init]; + pigeonResult.cameraPosition = cameraPosition; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewCameraPosition *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewCameraPosition *pigeonResult = + [[FGMPlatformCameraUpdateNewCameraPosition alloc] init]; + pigeonResult.cameraPosition = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewCameraPosition *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewCameraPosition fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.cameraPosition ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewLatLng ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng { + FGMPlatformCameraUpdateNewLatLng *pigeonResult = [[FGMPlatformCameraUpdateNewLatLng alloc] init]; + pigeonResult.latLng = latLng; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewLatLng *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewLatLng *pigeonResult = [[FGMPlatformCameraUpdateNewLatLng alloc] init]; + pigeonResult.latLng = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewLatLng *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewLatLng fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.latLng ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewLatLngBounds ++ (instancetype)makeWithBounds:(FGMPlatformLatLngBounds *)bounds padding:(double)padding { + FGMPlatformCameraUpdateNewLatLngBounds *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngBounds alloc] init]; + pigeonResult.bounds = bounds; + pigeonResult.padding = padding; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewLatLngBounds *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewLatLngBounds *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngBounds alloc] init]; + pigeonResult.bounds = GetNullableObjectAtIndex(list, 0); + pigeonResult.padding = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewLatLngBounds *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewLatLngBounds fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.bounds ?: [NSNull null], + @(self.padding), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateNewLatLngZoom ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng zoom:(double)zoom { + FGMPlatformCameraUpdateNewLatLngZoom *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngZoom alloc] init]; + pigeonResult.latLng = latLng; + pigeonResult.zoom = zoom; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateNewLatLngZoom *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateNewLatLngZoom *pigeonResult = + [[FGMPlatformCameraUpdateNewLatLngZoom alloc] init]; + pigeonResult.latLng = GetNullableObjectAtIndex(list, 0); + pigeonResult.zoom = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateNewLatLngZoom *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateNewLatLngZoom fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.latLng ?: [NSNull null], + @(self.zoom), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateScrollBy ++ (instancetype)makeWithDx:(double)dx dy:(double)dy { + FGMPlatformCameraUpdateScrollBy *pigeonResult = [[FGMPlatformCameraUpdateScrollBy alloc] init]; + pigeonResult.dx = dx; + pigeonResult.dy = dy; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateScrollBy *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateScrollBy *pigeonResult = [[FGMPlatformCameraUpdateScrollBy alloc] init]; + pigeonResult.dx = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.dy = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateScrollBy *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateScrollBy fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.dx), + @(self.dy), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateZoomBy ++ (instancetype)makeWithAmount:(double)amount focus:(nullable FGMPlatformPoint *)focus { + FGMPlatformCameraUpdateZoomBy *pigeonResult = [[FGMPlatformCameraUpdateZoomBy alloc] init]; + pigeonResult.amount = amount; + pigeonResult.focus = focus; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateZoomBy *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateZoomBy *pigeonResult = [[FGMPlatformCameraUpdateZoomBy alloc] init]; + pigeonResult.amount = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.focus = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateZoomBy *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateZoomBy fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.amount), + self.focus ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraUpdateZoom ++ (instancetype)makeWithOut:(BOOL)out { + FGMPlatformCameraUpdateZoom *pigeonResult = [[FGMPlatformCameraUpdateZoom alloc] init]; + pigeonResult.out = out; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateZoom *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateZoom *pigeonResult = [[FGMPlatformCameraUpdateZoom alloc] init]; + pigeonResult.out = [GetNullableObjectAtIndex(list, 0) boolValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateZoom *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateZoom fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.out), + ]; +} +@end + +@implementation FGMPlatformCameraUpdateZoomTo ++ (instancetype)makeWithZoom:(double)zoom { + FGMPlatformCameraUpdateZoomTo *pigeonResult = [[FGMPlatformCameraUpdateZoomTo alloc] init]; + pigeonResult.zoom = zoom; + return pigeonResult; +} ++ (FGMPlatformCameraUpdateZoomTo *)fromList:(NSArray *)list { + FGMPlatformCameraUpdateZoomTo *pigeonResult = [[FGMPlatformCameraUpdateZoomTo alloc] init]; + pigeonResult.zoom = [GetNullableObjectAtIndex(list, 0) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformCameraUpdateZoomTo *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraUpdateZoomTo fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.zoom), + ]; +} +@end + +@implementation FGMPlatformCircle ++ (instancetype)makeWithConsumeTapEvents:(BOOL)consumeTapEvents + fillColor:(FGMPlatformColor *)fillColor + strokeColor:(FGMPlatformColor *)strokeColor + visible:(BOOL)visible + strokeWidth:(NSInteger)strokeWidth + zIndex:(double)zIndex + center:(FGMPlatformLatLng *)center + radius:(double)radius + circleId:(NSString *)circleId { + FGMPlatformCircle *pigeonResult = [[FGMPlatformCircle alloc] init]; + pigeonResult.consumeTapEvents = consumeTapEvents; + pigeonResult.fillColor = fillColor; + pigeonResult.strokeColor = strokeColor; + pigeonResult.visible = visible; + pigeonResult.strokeWidth = strokeWidth; + pigeonResult.zIndex = zIndex; + pigeonResult.center = center; + pigeonResult.radius = radius; + pigeonResult.circleId = circleId; + return pigeonResult; +} ++ (FGMPlatformCircle *)fromList:(NSArray *)list { + FGMPlatformCircle *pigeonResult = [[FGMPlatformCircle alloc] init]; + pigeonResult.consumeTapEvents = [GetNullableObjectAtIndex(list, 0) boolValue]; + pigeonResult.fillColor = GetNullableObjectAtIndex(list, 1); + pigeonResult.strokeColor = GetNullableObjectAtIndex(list, 2); + pigeonResult.visible = [GetNullableObjectAtIndex(list, 3) boolValue]; + pigeonResult.strokeWidth = [GetNullableObjectAtIndex(list, 4) integerValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 5) doubleValue]; + pigeonResult.center = GetNullableObjectAtIndex(list, 6); + pigeonResult.radius = [GetNullableObjectAtIndex(list, 7) doubleValue]; + pigeonResult.circleId = GetNullableObjectAtIndex(list, 8); + return pigeonResult; +} ++ (nullable FGMPlatformCircle *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCircle fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.consumeTapEvents), + self.fillColor ?: [NSNull null], + self.strokeColor ?: [NSNull null], + @(self.visible), + @(self.strokeWidth), + @(self.zIndex), + self.center ?: [NSNull null], + @(self.radius), + self.circleId ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformHeatmap ++ (instancetype)makeWithHeatmapId:(NSString *)heatmapId + data:(NSArray *)data + gradient:(nullable FGMPlatformHeatmapGradient *)gradient + opacity:(double)opacity + radius:(NSInteger)radius + minimumZoomIntensity:(NSInteger)minimumZoomIntensity + maximumZoomIntensity:(NSInteger)maximumZoomIntensity { + FGMPlatformHeatmap *pigeonResult = [[FGMPlatformHeatmap alloc] init]; + pigeonResult.heatmapId = heatmapId; + pigeonResult.data = data; + pigeonResult.gradient = gradient; + pigeonResult.opacity = opacity; + pigeonResult.radius = radius; + pigeonResult.minimumZoomIntensity = minimumZoomIntensity; + pigeonResult.maximumZoomIntensity = maximumZoomIntensity; + return pigeonResult; +} ++ (FGMPlatformHeatmap *)fromList:(NSArray *)list { + FGMPlatformHeatmap *pigeonResult = [[FGMPlatformHeatmap alloc] init]; + pigeonResult.heatmapId = GetNullableObjectAtIndex(list, 0); + pigeonResult.data = GetNullableObjectAtIndex(list, 1); + pigeonResult.gradient = GetNullableObjectAtIndex(list, 2); + pigeonResult.opacity = [GetNullableObjectAtIndex(list, 3) doubleValue]; + pigeonResult.radius = [GetNullableObjectAtIndex(list, 4) integerValue]; + pigeonResult.minimumZoomIntensity = [GetNullableObjectAtIndex(list, 5) integerValue]; + pigeonResult.maximumZoomIntensity = [GetNullableObjectAtIndex(list, 6) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformHeatmap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformHeatmap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.heatmapId ?: [NSNull null], + self.data ?: [NSNull null], + self.gradient ?: [NSNull null], + @(self.opacity), + @(self.radius), + @(self.minimumZoomIntensity), + @(self.maximumZoomIntensity), + ]; +} +@end + +@implementation FGMPlatformHeatmapGradient ++ (instancetype)makeWithColors:(NSArray *)colors + startPoints:(NSArray *)startPoints + colorMapSize:(NSInteger)colorMapSize { + FGMPlatformHeatmapGradient *pigeonResult = [[FGMPlatformHeatmapGradient alloc] init]; + pigeonResult.colors = colors; + pigeonResult.startPoints = startPoints; + pigeonResult.colorMapSize = colorMapSize; + return pigeonResult; +} ++ (FGMPlatformHeatmapGradient *)fromList:(NSArray *)list { + FGMPlatformHeatmapGradient *pigeonResult = [[FGMPlatformHeatmapGradient alloc] init]; + pigeonResult.colors = GetNullableObjectAtIndex(list, 0); + pigeonResult.startPoints = GetNullableObjectAtIndex(list, 1); + pigeonResult.colorMapSize = [GetNullableObjectAtIndex(list, 2) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformHeatmapGradient *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformHeatmapGradient fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.colors ?: [NSNull null], + self.startPoints ?: [NSNull null], + @(self.colorMapSize), + ]; +} +@end + +@implementation FGMPlatformWeightedLatLng ++ (instancetype)makeWithPoint:(FGMPlatformLatLng *)point weight:(double)weight { + FGMPlatformWeightedLatLng *pigeonResult = [[FGMPlatformWeightedLatLng alloc] init]; + pigeonResult.point = point; + pigeonResult.weight = weight; + return pigeonResult; +} ++ (FGMPlatformWeightedLatLng *)fromList:(NSArray *)list { + FGMPlatformWeightedLatLng *pigeonResult = [[FGMPlatformWeightedLatLng alloc] init]; + pigeonResult.point = GetNullableObjectAtIndex(list, 0); + pigeonResult.weight = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformWeightedLatLng *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformWeightedLatLng fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.point ?: [NSNull null], + @(self.weight), + ]; +} +@end + +@implementation FGMPlatformInfoWindow ++ (instancetype)makeWithTitle:(nullable NSString *)title + snippet:(nullable NSString *)snippet + anchor:(FGMPlatformPoint *)anchor { + FGMPlatformInfoWindow *pigeonResult = [[FGMPlatformInfoWindow alloc] init]; + pigeonResult.title = title; + pigeonResult.snippet = snippet; + pigeonResult.anchor = anchor; + return pigeonResult; +} ++ (FGMPlatformInfoWindow *)fromList:(NSArray *)list { + FGMPlatformInfoWindow *pigeonResult = [[FGMPlatformInfoWindow alloc] init]; + pigeonResult.title = GetNullableObjectAtIndex(list, 0); + pigeonResult.snippet = GetNullableObjectAtIndex(list, 1); + pigeonResult.anchor = GetNullableObjectAtIndex(list, 2); + return pigeonResult; +} ++ (nullable FGMPlatformInfoWindow *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformInfoWindow fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.title ?: [NSNull null], + self.snippet ?: [NSNull null], + self.anchor ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCluster ++ (instancetype)makeWithClusterManagerId:(NSString *)clusterManagerId + position:(FGMPlatformLatLng *)position + bounds:(FGMPlatformLatLngBounds *)bounds + markerIds:(NSArray *)markerIds { + FGMPlatformCluster *pigeonResult = [[FGMPlatformCluster alloc] init]; + pigeonResult.clusterManagerId = clusterManagerId; + pigeonResult.position = position; + pigeonResult.bounds = bounds; + pigeonResult.markerIds = markerIds; + return pigeonResult; +} ++ (FGMPlatformCluster *)fromList:(NSArray *)list { + FGMPlatformCluster *pigeonResult = [[FGMPlatformCluster alloc] init]; + pigeonResult.clusterManagerId = GetNullableObjectAtIndex(list, 0); + pigeonResult.position = GetNullableObjectAtIndex(list, 1); + pigeonResult.bounds = GetNullableObjectAtIndex(list, 2); + pigeonResult.markerIds = GetNullableObjectAtIndex(list, 3); + return pigeonResult; +} ++ (nullable FGMPlatformCluster *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCluster fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.clusterManagerId ?: [NSNull null], + self.position ?: [NSNull null], + self.bounds ?: [NSNull null], + self.markerIds ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformClusterManager ++ (instancetype)makeWithIdentifier:(NSString *)identifier { + FGMPlatformClusterManager *pigeonResult = [[FGMPlatformClusterManager alloc] init]; + pigeonResult.identifier = identifier; + return pigeonResult; +} ++ (FGMPlatformClusterManager *)fromList:(NSArray *)list { + FGMPlatformClusterManager *pigeonResult = [[FGMPlatformClusterManager alloc] init]; + pigeonResult.identifier = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformClusterManager *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformClusterManager fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.identifier ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformMarker ++ (instancetype)makeWithAlpha:(double)alpha + anchor:(FGMPlatformPoint *)anchor + consumeTapEvents:(BOOL)consumeTapEvents + draggable:(BOOL)draggable + flat:(BOOL)flat + icon:(FGMPlatformBitmap *)icon + infoWindow:(FGMPlatformInfoWindow *)infoWindow + position:(FGMPlatformLatLng *)position + rotation:(double)rotation + visible:(BOOL)visible + zIndex:(NSInteger)zIndex + markerId:(NSString *)markerId + clusterManagerId:(nullable NSString *)clusterManagerId { + FGMPlatformMarker *pigeonResult = [[FGMPlatformMarker alloc] init]; + pigeonResult.alpha = alpha; + pigeonResult.anchor = anchor; + pigeonResult.consumeTapEvents = consumeTapEvents; + pigeonResult.draggable = draggable; + pigeonResult.flat = flat; + pigeonResult.icon = icon; + pigeonResult.infoWindow = infoWindow; + pigeonResult.position = position; + pigeonResult.rotation = rotation; + pigeonResult.visible = visible; + pigeonResult.zIndex = zIndex; + pigeonResult.markerId = markerId; + pigeonResult.clusterManagerId = clusterManagerId; + return pigeonResult; +} ++ (FGMPlatformMarker *)fromList:(NSArray *)list { + FGMPlatformMarker *pigeonResult = [[FGMPlatformMarker alloc] init]; + pigeonResult.alpha = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.anchor = GetNullableObjectAtIndex(list, 1); + pigeonResult.consumeTapEvents = [GetNullableObjectAtIndex(list, 2) boolValue]; + pigeonResult.draggable = [GetNullableObjectAtIndex(list, 3) boolValue]; + pigeonResult.flat = [GetNullableObjectAtIndex(list, 4) boolValue]; + pigeonResult.icon = GetNullableObjectAtIndex(list, 5); + pigeonResult.infoWindow = GetNullableObjectAtIndex(list, 6); + pigeonResult.position = GetNullableObjectAtIndex(list, 7); + pigeonResult.rotation = [GetNullableObjectAtIndex(list, 8) doubleValue]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 9) boolValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 10) integerValue]; + pigeonResult.markerId = GetNullableObjectAtIndex(list, 11); + pigeonResult.clusterManagerId = GetNullableObjectAtIndex(list, 12); + return pigeonResult; +} ++ (nullable FGMPlatformMarker *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformMarker fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.alpha), + self.anchor ?: [NSNull null], + @(self.consumeTapEvents), + @(self.draggable), + @(self.flat), + self.icon ?: [NSNull null], + self.infoWindow ?: [NSNull null], + self.position ?: [NSNull null], + @(self.rotation), + @(self.visible), + @(self.zIndex), + self.markerId ?: [NSNull null], + self.clusterManagerId ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformPolygon ++ (instancetype)makeWithPolygonId:(NSString *)polygonId + consumesTapEvents:(BOOL)consumesTapEvents + fillColor:(FGMPlatformColor *)fillColor + geodesic:(BOOL)geodesic + points:(NSArray *)points + holes:(NSArray *> *)holes + visible:(BOOL)visible + strokeColor:(FGMPlatformColor *)strokeColor + strokeWidth:(NSInteger)strokeWidth + zIndex:(NSInteger)zIndex { + FGMPlatformPolygon *pigeonResult = [[FGMPlatformPolygon alloc] init]; + pigeonResult.polygonId = polygonId; + pigeonResult.consumesTapEvents = consumesTapEvents; + pigeonResult.fillColor = fillColor; + pigeonResult.geodesic = geodesic; + pigeonResult.points = points; + pigeonResult.holes = holes; + pigeonResult.visible = visible; + pigeonResult.strokeColor = strokeColor; + pigeonResult.strokeWidth = strokeWidth; + pigeonResult.zIndex = zIndex; + return pigeonResult; +} ++ (FGMPlatformPolygon *)fromList:(NSArray *)list { + FGMPlatformPolygon *pigeonResult = [[FGMPlatformPolygon alloc] init]; + pigeonResult.polygonId = GetNullableObjectAtIndex(list, 0); + pigeonResult.consumesTapEvents = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.fillColor = GetNullableObjectAtIndex(list, 2); + pigeonResult.geodesic = [GetNullableObjectAtIndex(list, 3) boolValue]; + pigeonResult.points = GetNullableObjectAtIndex(list, 4); + pigeonResult.holes = GetNullableObjectAtIndex(list, 5); + pigeonResult.visible = [GetNullableObjectAtIndex(list, 6) boolValue]; + pigeonResult.strokeColor = GetNullableObjectAtIndex(list, 7); + pigeonResult.strokeWidth = [GetNullableObjectAtIndex(list, 8) integerValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 9) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformPolygon *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPolygon fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.polygonId ?: [NSNull null], + @(self.consumesTapEvents), + self.fillColor ?: [NSNull null], + @(self.geodesic), + self.points ?: [NSNull null], + self.holes ?: [NSNull null], + @(self.visible), + self.strokeColor ?: [NSNull null], + @(self.strokeWidth), + @(self.zIndex), + ]; +} +@end + +@implementation FGMPlatformPolyline ++ (instancetype)makeWithPolylineId:(NSString *)polylineId + consumesTapEvents:(BOOL)consumesTapEvents + color:(FGMPlatformColor *)color + geodesic:(BOOL)geodesic + jointType:(FGMPlatformJointType)jointType + patterns:(NSArray *)patterns + points:(NSArray *)points + visible:(BOOL)visible + width:(NSInteger)width + zIndex:(NSInteger)zIndex { + FGMPlatformPolyline *pigeonResult = [[FGMPlatformPolyline alloc] init]; + pigeonResult.polylineId = polylineId; + pigeonResult.consumesTapEvents = consumesTapEvents; + pigeonResult.color = color; + pigeonResult.geodesic = geodesic; + pigeonResult.jointType = jointType; + pigeonResult.patterns = patterns; + pigeonResult.points = points; + pigeonResult.visible = visible; + pigeonResult.width = width; + pigeonResult.zIndex = zIndex; + return pigeonResult; +} ++ (FGMPlatformPolyline *)fromList:(NSArray *)list { + FGMPlatformPolyline *pigeonResult = [[FGMPlatformPolyline alloc] init]; + pigeonResult.polylineId = GetNullableObjectAtIndex(list, 0); + pigeonResult.consumesTapEvents = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.color = GetNullableObjectAtIndex(list, 2); + pigeonResult.geodesic = [GetNullableObjectAtIndex(list, 3) boolValue]; + FGMPlatformJointTypeBox *boxedFGMPlatformJointType = GetNullableObjectAtIndex(list, 4); + pigeonResult.jointType = boxedFGMPlatformJointType.value; + pigeonResult.patterns = GetNullableObjectAtIndex(list, 5); + pigeonResult.points = GetNullableObjectAtIndex(list, 6); + pigeonResult.visible = [GetNullableObjectAtIndex(list, 7) boolValue]; + pigeonResult.width = [GetNullableObjectAtIndex(list, 8) integerValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 9) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformPolyline *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPolyline fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.polylineId ?: [NSNull null], + @(self.consumesTapEvents), + self.color ?: [NSNull null], + @(self.geodesic), + [[FGMPlatformJointTypeBox alloc] initWithValue:self.jointType], + self.patterns ?: [NSNull null], + self.points ?: [NSNull null], + @(self.visible), + @(self.width), + @(self.zIndex), + ]; +} +@end + +@implementation FGMPlatformPatternItem ++ (instancetype)makeWithType:(FGMPlatformPatternItemType)type length:(nullable NSNumber *)length { + FGMPlatformPatternItem *pigeonResult = [[FGMPlatformPatternItem alloc] init]; + pigeonResult.type = type; + pigeonResult.length = length; + return pigeonResult; +} ++ (FGMPlatformPatternItem *)fromList:(NSArray *)list { + FGMPlatformPatternItem *pigeonResult = [[FGMPlatformPatternItem alloc] init]; + FGMPlatformPatternItemTypeBox *boxedFGMPlatformPatternItemType = + GetNullableObjectAtIndex(list, 0); + pigeonResult.type = boxedFGMPlatformPatternItemType.value; + pigeonResult.length = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformPatternItem *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPatternItem fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + [[FGMPlatformPatternItemTypeBox alloc] initWithValue:self.type], + self.length ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformTile ++ (instancetype)makeWithWidth:(NSInteger)width + height:(NSInteger)height + data:(nullable FlutterStandardTypedData *)data { + FGMPlatformTile *pigeonResult = [[FGMPlatformTile alloc] init]; + pigeonResult.width = width; + pigeonResult.height = height; + pigeonResult.data = data; + return pigeonResult; +} ++ (FGMPlatformTile *)fromList:(NSArray *)list { + FGMPlatformTile *pigeonResult = [[FGMPlatformTile alloc] init]; + pigeonResult.width = [GetNullableObjectAtIndex(list, 0) integerValue]; + pigeonResult.height = [GetNullableObjectAtIndex(list, 1) integerValue]; + pigeonResult.data = GetNullableObjectAtIndex(list, 2); + return pigeonResult; +} ++ (nullable FGMPlatformTile *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformTile fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.width), + @(self.height), + self.data ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformTileOverlay ++ (instancetype)makeWithTileOverlayId:(NSString *)tileOverlayId + fadeIn:(BOOL)fadeIn + transparency:(double)transparency + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + tileSize:(NSInteger)tileSize { + FGMPlatformTileOverlay *pigeonResult = [[FGMPlatformTileOverlay alloc] init]; + pigeonResult.tileOverlayId = tileOverlayId; + pigeonResult.fadeIn = fadeIn; + pigeonResult.transparency = transparency; + pigeonResult.zIndex = zIndex; + pigeonResult.visible = visible; + pigeonResult.tileSize = tileSize; + return pigeonResult; +} ++ (FGMPlatformTileOverlay *)fromList:(NSArray *)list { + FGMPlatformTileOverlay *pigeonResult = [[FGMPlatformTileOverlay alloc] init]; + pigeonResult.tileOverlayId = GetNullableObjectAtIndex(list, 0); + pigeonResult.fadeIn = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.transparency = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 3) integerValue]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 4) boolValue]; + pigeonResult.tileSize = [GetNullableObjectAtIndex(list, 5) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformTileOverlay *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformTileOverlay fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.tileOverlayId ?: [NSNull null], + @(self.fadeIn), + @(self.transparency), + @(self.zIndex), + @(self.visible), + @(self.tileSize), + ]; +} +@end + +@implementation FGMPlatformEdgeInsets ++ (instancetype)makeWithTop:(double)top + bottom:(double)bottom + left:(double)left + right:(double)right { + FGMPlatformEdgeInsets *pigeonResult = [[FGMPlatformEdgeInsets alloc] init]; + pigeonResult.top = top; + pigeonResult.bottom = bottom; + pigeonResult.left = left; + pigeonResult.right = right; + return pigeonResult; +} ++ (FGMPlatformEdgeInsets *)fromList:(NSArray *)list { + FGMPlatformEdgeInsets *pigeonResult = [[FGMPlatformEdgeInsets alloc] init]; + pigeonResult.top = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.bottom = [GetNullableObjectAtIndex(list, 1) doubleValue]; + pigeonResult.left = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.right = [GetNullableObjectAtIndex(list, 3) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformEdgeInsets *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformEdgeInsets fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.top), + @(self.bottom), + @(self.left), + @(self.right), + ]; +} +@end + +@implementation FGMPlatformLatLng ++ (instancetype)makeWithLatitude:(double)latitude longitude:(double)longitude { + FGMPlatformLatLng *pigeonResult = [[FGMPlatformLatLng alloc] init]; + pigeonResult.latitude = latitude; + pigeonResult.longitude = longitude; + return pigeonResult; +} ++ (FGMPlatformLatLng *)fromList:(NSArray *)list { + FGMPlatformLatLng *pigeonResult = [[FGMPlatformLatLng alloc] init]; + pigeonResult.latitude = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.longitude = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformLatLng *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformLatLng fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.latitude), + @(self.longitude), + ]; +} +@end + +@implementation FGMPlatformLatLngBounds ++ (instancetype)makeWithNortheast:(FGMPlatformLatLng *)northeast + southwest:(FGMPlatformLatLng *)southwest { + FGMPlatformLatLngBounds *pigeonResult = [[FGMPlatformLatLngBounds alloc] init]; + pigeonResult.northeast = northeast; + pigeonResult.southwest = southwest; + return pigeonResult; +} ++ (FGMPlatformLatLngBounds *)fromList:(NSArray *)list { + FGMPlatformLatLngBounds *pigeonResult = [[FGMPlatformLatLngBounds alloc] init]; + pigeonResult.northeast = GetNullableObjectAtIndex(list, 0); + pigeonResult.southwest = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformLatLngBounds *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformLatLngBounds fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.northeast ?: [NSNull null], + self.southwest ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformCameraTargetBounds ++ (instancetype)makeWithBounds:(nullable FGMPlatformLatLngBounds *)bounds { + FGMPlatformCameraTargetBounds *pigeonResult = [[FGMPlatformCameraTargetBounds alloc] init]; + pigeonResult.bounds = bounds; + return pigeonResult; +} ++ (FGMPlatformCameraTargetBounds *)fromList:(NSArray *)list { + FGMPlatformCameraTargetBounds *pigeonResult = [[FGMPlatformCameraTargetBounds alloc] init]; + pigeonResult.bounds = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformCameraTargetBounds *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformCameraTargetBounds fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.bounds ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformGroundOverlay ++ (instancetype)makeWithGroundOverlayId:(NSString *)groundOverlayId + image:(FGMPlatformBitmap *)image + position:(nullable FGMPlatformLatLng *)position + bounds:(nullable FGMPlatformLatLngBounds *)bounds + anchor:(nullable FGMPlatformPoint *)anchor + transparency:(double)transparency + bearing:(double)bearing + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + clickable:(BOOL)clickable + zoomLevel:(nullable NSNumber *)zoomLevel { + FGMPlatformGroundOverlay *pigeonResult = [[FGMPlatformGroundOverlay alloc] init]; + pigeonResult.groundOverlayId = groundOverlayId; + pigeonResult.image = image; + pigeonResult.position = position; + pigeonResult.bounds = bounds; + pigeonResult.anchor = anchor; + pigeonResult.transparency = transparency; + pigeonResult.bearing = bearing; + pigeonResult.zIndex = zIndex; + pigeonResult.visible = visible; + pigeonResult.clickable = clickable; + pigeonResult.zoomLevel = zoomLevel; + return pigeonResult; +} ++ (FGMPlatformGroundOverlay *)fromList:(NSArray *)list { + FGMPlatformGroundOverlay *pigeonResult = [[FGMPlatformGroundOverlay alloc] init]; + pigeonResult.groundOverlayId = GetNullableObjectAtIndex(list, 0); + pigeonResult.image = GetNullableObjectAtIndex(list, 1); + pigeonResult.position = GetNullableObjectAtIndex(list, 2); + pigeonResult.bounds = GetNullableObjectAtIndex(list, 3); + pigeonResult.anchor = GetNullableObjectAtIndex(list, 4); + pigeonResult.transparency = [GetNullableObjectAtIndex(list, 5) doubleValue]; + pigeonResult.bearing = [GetNullableObjectAtIndex(list, 6) doubleValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 7) integerValue]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 8) boolValue]; + pigeonResult.clickable = [GetNullableObjectAtIndex(list, 9) boolValue]; + pigeonResult.zoomLevel = GetNullableObjectAtIndex(list, 10); + return pigeonResult; +} ++ (nullable FGMPlatformGroundOverlay *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformGroundOverlay fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.groundOverlayId ?: [NSNull null], + self.image ?: [NSNull null], + self.position ?: [NSNull null], + self.bounds ?: [NSNull null], + self.anchor ?: [NSNull null], + @(self.transparency), + @(self.bearing), + @(self.zIndex), + @(self.visible), + @(self.clickable), + self.zoomLevel ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformMapViewCreationParams ++ (instancetype) + makeWithInitialCameraPosition:(FGMPlatformCameraPosition *)initialCameraPosition + mapConfiguration:(FGMPlatformMapConfiguration *)mapConfiguration + initialCircles:(NSArray *)initialCircles + initialMarkers:(NSArray *)initialMarkers + initialPolygons:(NSArray *)initialPolygons + initialPolylines:(NSArray *)initialPolylines + initialHeatmaps:(NSArray *)initialHeatmaps + initialTileOverlays:(NSArray *)initialTileOverlays + initialClusterManagers:(NSArray *)initialClusterManagers + initialGroundOverlays:(NSArray *)initialGroundOverlays { + FGMPlatformMapViewCreationParams *pigeonResult = [[FGMPlatformMapViewCreationParams alloc] init]; + pigeonResult.initialCameraPosition = initialCameraPosition; + pigeonResult.mapConfiguration = mapConfiguration; + pigeonResult.initialCircles = initialCircles; + pigeonResult.initialMarkers = initialMarkers; + pigeonResult.initialPolygons = initialPolygons; + pigeonResult.initialPolylines = initialPolylines; + pigeonResult.initialHeatmaps = initialHeatmaps; + pigeonResult.initialTileOverlays = initialTileOverlays; + pigeonResult.initialClusterManagers = initialClusterManagers; + pigeonResult.initialGroundOverlays = initialGroundOverlays; + return pigeonResult; +} ++ (FGMPlatformMapViewCreationParams *)fromList:(NSArray *)list { + FGMPlatformMapViewCreationParams *pigeonResult = [[FGMPlatformMapViewCreationParams alloc] init]; + pigeonResult.initialCameraPosition = GetNullableObjectAtIndex(list, 0); + pigeonResult.mapConfiguration = GetNullableObjectAtIndex(list, 1); + pigeonResult.initialCircles = GetNullableObjectAtIndex(list, 2); + pigeonResult.initialMarkers = GetNullableObjectAtIndex(list, 3); + pigeonResult.initialPolygons = GetNullableObjectAtIndex(list, 4); + pigeonResult.initialPolylines = GetNullableObjectAtIndex(list, 5); + pigeonResult.initialHeatmaps = GetNullableObjectAtIndex(list, 6); + pigeonResult.initialTileOverlays = GetNullableObjectAtIndex(list, 7); + pigeonResult.initialClusterManagers = GetNullableObjectAtIndex(list, 8); + pigeonResult.initialGroundOverlays = GetNullableObjectAtIndex(list, 9); + return pigeonResult; +} ++ (nullable FGMPlatformMapViewCreationParams *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformMapViewCreationParams fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.initialCameraPosition ?: [NSNull null], + self.mapConfiguration ?: [NSNull null], + self.initialCircles ?: [NSNull null], + self.initialMarkers ?: [NSNull null], + self.initialPolygons ?: [NSNull null], + self.initialPolylines ?: [NSNull null], + self.initialHeatmaps ?: [NSNull null], + self.initialTileOverlays ?: [NSNull null], + self.initialClusterManagers ?: [NSNull null], + self.initialGroundOverlays ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformMapConfiguration ++ (instancetype)makeWithCompassEnabled:(nullable NSNumber *)compassEnabled + cameraTargetBounds:(nullable FGMPlatformCameraTargetBounds *)cameraTargetBounds + mapType:(nullable FGMPlatformMapTypeBox *)mapType + minMaxZoomPreference:(nullable FGMPlatformZoomRange *)minMaxZoomPreference + rotateGesturesEnabled:(nullable NSNumber *)rotateGesturesEnabled + scrollGesturesEnabled:(nullable NSNumber *)scrollGesturesEnabled + tiltGesturesEnabled:(nullable NSNumber *)tiltGesturesEnabled + trackCameraPosition:(nullable NSNumber *)trackCameraPosition + zoomGesturesEnabled:(nullable NSNumber *)zoomGesturesEnabled + myLocationEnabled:(nullable NSNumber *)myLocationEnabled + myLocationButtonEnabled:(nullable NSNumber *)myLocationButtonEnabled + padding:(nullable FGMPlatformEdgeInsets *)padding + indoorViewEnabled:(nullable NSNumber *)indoorViewEnabled + trafficEnabled:(nullable NSNumber *)trafficEnabled + buildingsEnabled:(nullable NSNumber *)buildingsEnabled + mapId:(nullable NSString *)mapId + style:(nullable NSString *)style { + FGMPlatformMapConfiguration *pigeonResult = [[FGMPlatformMapConfiguration alloc] init]; + pigeonResult.compassEnabled = compassEnabled; + pigeonResult.cameraTargetBounds = cameraTargetBounds; + pigeonResult.mapType = mapType; + pigeonResult.minMaxZoomPreference = minMaxZoomPreference; + pigeonResult.rotateGesturesEnabled = rotateGesturesEnabled; + pigeonResult.scrollGesturesEnabled = scrollGesturesEnabled; + pigeonResult.tiltGesturesEnabled = tiltGesturesEnabled; + pigeonResult.trackCameraPosition = trackCameraPosition; + pigeonResult.zoomGesturesEnabled = zoomGesturesEnabled; + pigeonResult.myLocationEnabled = myLocationEnabled; + pigeonResult.myLocationButtonEnabled = myLocationButtonEnabled; + pigeonResult.padding = padding; + pigeonResult.indoorViewEnabled = indoorViewEnabled; + pigeonResult.trafficEnabled = trafficEnabled; + pigeonResult.buildingsEnabled = buildingsEnabled; + pigeonResult.mapId = mapId; + pigeonResult.style = style; + return pigeonResult; +} ++ (FGMPlatformMapConfiguration *)fromList:(NSArray *)list { + FGMPlatformMapConfiguration *pigeonResult = [[FGMPlatformMapConfiguration alloc] init]; + pigeonResult.compassEnabled = GetNullableObjectAtIndex(list, 0); + pigeonResult.cameraTargetBounds = GetNullableObjectAtIndex(list, 1); + pigeonResult.mapType = GetNullableObjectAtIndex(list, 2); + pigeonResult.minMaxZoomPreference = GetNullableObjectAtIndex(list, 3); + pigeonResult.rotateGesturesEnabled = GetNullableObjectAtIndex(list, 4); + pigeonResult.scrollGesturesEnabled = GetNullableObjectAtIndex(list, 5); + pigeonResult.tiltGesturesEnabled = GetNullableObjectAtIndex(list, 6); + pigeonResult.trackCameraPosition = GetNullableObjectAtIndex(list, 7); + pigeonResult.zoomGesturesEnabled = GetNullableObjectAtIndex(list, 8); + pigeonResult.myLocationEnabled = GetNullableObjectAtIndex(list, 9); + pigeonResult.myLocationButtonEnabled = GetNullableObjectAtIndex(list, 10); + pigeonResult.padding = GetNullableObjectAtIndex(list, 11); + pigeonResult.indoorViewEnabled = GetNullableObjectAtIndex(list, 12); + pigeonResult.trafficEnabled = GetNullableObjectAtIndex(list, 13); + pigeonResult.buildingsEnabled = GetNullableObjectAtIndex(list, 14); + pigeonResult.mapId = GetNullableObjectAtIndex(list, 15); + pigeonResult.style = GetNullableObjectAtIndex(list, 16); + return pigeonResult; +} ++ (nullable FGMPlatformMapConfiguration *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformMapConfiguration fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.compassEnabled ?: [NSNull null], + self.cameraTargetBounds ?: [NSNull null], + self.mapType ?: [NSNull null], + self.minMaxZoomPreference ?: [NSNull null], + self.rotateGesturesEnabled ?: [NSNull null], + self.scrollGesturesEnabled ?: [NSNull null], + self.tiltGesturesEnabled ?: [NSNull null], + self.trackCameraPosition ?: [NSNull null], + self.zoomGesturesEnabled ?: [NSNull null], + self.myLocationEnabled ?: [NSNull null], + self.myLocationButtonEnabled ?: [NSNull null], + self.padding ?: [NSNull null], + self.indoorViewEnabled ?: [NSNull null], + self.trafficEnabled ?: [NSNull null], + self.buildingsEnabled ?: [NSNull null], + self.mapId ?: [NSNull null], + self.style ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformPoint ++ (instancetype)makeWithX:(double)x y:(double)y { + FGMPlatformPoint *pigeonResult = [[FGMPlatformPoint alloc] init]; + pigeonResult.x = x; + pigeonResult.y = y; + return pigeonResult; +} ++ (FGMPlatformPoint *)fromList:(NSArray *)list { + FGMPlatformPoint *pigeonResult = [[FGMPlatformPoint alloc] init]; + pigeonResult.x = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.y = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformPoint *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformPoint fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.x), + @(self.y), + ]; +} +@end + +@implementation FGMPlatformSize ++ (instancetype)makeWithWidth:(double)width height:(double)height { + FGMPlatformSize *pigeonResult = [[FGMPlatformSize alloc] init]; + pigeonResult.width = width; + pigeonResult.height = height; + return pigeonResult; +} ++ (FGMPlatformSize *)fromList:(NSArray *)list { + FGMPlatformSize *pigeonResult = [[FGMPlatformSize alloc] init]; + pigeonResult.width = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.height = [GetNullableObjectAtIndex(list, 1) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformSize *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformSize fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.width), + @(self.height), + ]; +} +@end + +@implementation FGMPlatformColor ++ (instancetype)makeWithRed:(double)red green:(double)green blue:(double)blue alpha:(double)alpha { + FGMPlatformColor *pigeonResult = [[FGMPlatformColor alloc] init]; + pigeonResult.red = red; + pigeonResult.green = green; + pigeonResult.blue = blue; + pigeonResult.alpha = alpha; + return pigeonResult; +} ++ (FGMPlatformColor *)fromList:(NSArray *)list { + FGMPlatformColor *pigeonResult = [[FGMPlatformColor alloc] init]; + pigeonResult.red = [GetNullableObjectAtIndex(list, 0) doubleValue]; + pigeonResult.green = [GetNullableObjectAtIndex(list, 1) doubleValue]; + pigeonResult.blue = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.alpha = [GetNullableObjectAtIndex(list, 3) doubleValue]; + return pigeonResult; +} ++ (nullable FGMPlatformColor *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformColor fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.red), + @(self.green), + @(self.blue), + @(self.alpha), + ]; +} +@end + +@implementation FGMPlatformTileLayer ++ (instancetype)makeWithVisible:(BOOL)visible + fadeIn:(BOOL)fadeIn + opacity:(double)opacity + zIndex:(NSInteger)zIndex { + FGMPlatformTileLayer *pigeonResult = [[FGMPlatformTileLayer alloc] init]; + pigeonResult.visible = visible; + pigeonResult.fadeIn = fadeIn; + pigeonResult.opacity = opacity; + pigeonResult.zIndex = zIndex; + return pigeonResult; +} ++ (FGMPlatformTileLayer *)fromList:(NSArray *)list { + FGMPlatformTileLayer *pigeonResult = [[FGMPlatformTileLayer alloc] init]; + pigeonResult.visible = [GetNullableObjectAtIndex(list, 0) boolValue]; + pigeonResult.fadeIn = [GetNullableObjectAtIndex(list, 1) boolValue]; + pigeonResult.opacity = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.zIndex = [GetNullableObjectAtIndex(list, 3) integerValue]; + return pigeonResult; +} ++ (nullable FGMPlatformTileLayer *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformTileLayer fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + @(self.visible), + @(self.fadeIn), + @(self.opacity), + @(self.zIndex), + ]; +} +@end + +@implementation FGMPlatformZoomRange ++ (instancetype)makeWithMin:(nullable NSNumber *)min max:(nullable NSNumber *)max { + FGMPlatformZoomRange *pigeonResult = [[FGMPlatformZoomRange alloc] init]; + pigeonResult.min = min; + pigeonResult.max = max; + return pigeonResult; +} ++ (FGMPlatformZoomRange *)fromList:(NSArray *)list { + FGMPlatformZoomRange *pigeonResult = [[FGMPlatformZoomRange alloc] init]; + pigeonResult.min = GetNullableObjectAtIndex(list, 0); + pigeonResult.max = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformZoomRange *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformZoomRange fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.min ?: [NSNull null], + self.max ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmap ++ (instancetype)makeWithBitmap:(id)bitmap { + FGMPlatformBitmap *pigeonResult = [[FGMPlatformBitmap alloc] init]; + pigeonResult.bitmap = bitmap; + return pigeonResult; +} ++ (FGMPlatformBitmap *)fromList:(NSArray *)list { + FGMPlatformBitmap *pigeonResult = [[FGMPlatformBitmap alloc] init]; + pigeonResult.bitmap = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformBitmap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.bitmap ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapDefaultMarker ++ (instancetype)makeWithHue:(nullable NSNumber *)hue { + FGMPlatformBitmapDefaultMarker *pigeonResult = [[FGMPlatformBitmapDefaultMarker alloc] init]; + pigeonResult.hue = hue; + return pigeonResult; +} ++ (FGMPlatformBitmapDefaultMarker *)fromList:(NSArray *)list { + FGMPlatformBitmapDefaultMarker *pigeonResult = [[FGMPlatformBitmapDefaultMarker alloc] init]; + pigeonResult.hue = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapDefaultMarker *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapDefaultMarker fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.hue ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapBytes ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + size:(nullable FGMPlatformSize *)size { + FGMPlatformBitmapBytes *pigeonResult = [[FGMPlatformBitmapBytes alloc] init]; + pigeonResult.byteData = byteData; + pigeonResult.size = size; + return pigeonResult; +} ++ (FGMPlatformBitmapBytes *)fromList:(NSArray *)list { + FGMPlatformBitmapBytes *pigeonResult = [[FGMPlatformBitmapBytes alloc] init]; + pigeonResult.byteData = GetNullableObjectAtIndex(list, 0); + pigeonResult.size = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapBytes *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapBytes fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.byteData ?: [NSNull null], + self.size ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapAsset ++ (instancetype)makeWithName:(NSString *)name pkg:(nullable NSString *)pkg { + FGMPlatformBitmapAsset *pigeonResult = [[FGMPlatformBitmapAsset alloc] init]; + pigeonResult.name = name; + pigeonResult.pkg = pkg; + return pigeonResult; +} ++ (FGMPlatformBitmapAsset *)fromList:(NSArray *)list { + FGMPlatformBitmapAsset *pigeonResult = [[FGMPlatformBitmapAsset alloc] init]; + pigeonResult.name = GetNullableObjectAtIndex(list, 0); + pigeonResult.pkg = GetNullableObjectAtIndex(list, 1); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapAsset *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapAsset fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.name ?: [NSNull null], + self.pkg ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapAssetImage ++ (instancetype)makeWithName:(NSString *)name + scale:(double)scale + size:(nullable FGMPlatformSize *)size { + FGMPlatformBitmapAssetImage *pigeonResult = [[FGMPlatformBitmapAssetImage alloc] init]; + pigeonResult.name = name; + pigeonResult.scale = scale; + pigeonResult.size = size; + return pigeonResult; +} ++ (FGMPlatformBitmapAssetImage *)fromList:(NSArray *)list { + FGMPlatformBitmapAssetImage *pigeonResult = [[FGMPlatformBitmapAssetImage alloc] init]; + pigeonResult.name = GetNullableObjectAtIndex(list, 0); + pigeonResult.scale = [GetNullableObjectAtIndex(list, 1) doubleValue]; + pigeonResult.size = GetNullableObjectAtIndex(list, 2); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapAssetImage *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapAssetImage fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.name ?: [NSNull null], + @(self.scale), + self.size ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapAssetMap ++ (instancetype)makeWithAssetName:(NSString *)assetName + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height { + FGMPlatformBitmapAssetMap *pigeonResult = [[FGMPlatformBitmapAssetMap alloc] init]; + pigeonResult.assetName = assetName; + pigeonResult.bitmapScaling = bitmapScaling; + pigeonResult.imagePixelRatio = imagePixelRatio; + pigeonResult.width = width; + pigeonResult.height = height; + return pigeonResult; +} ++ (FGMPlatformBitmapAssetMap *)fromList:(NSArray *)list { + FGMPlatformBitmapAssetMap *pigeonResult = [[FGMPlatformBitmapAssetMap alloc] init]; + pigeonResult.assetName = GetNullableObjectAtIndex(list, 0); + FGMPlatformMapBitmapScalingBox *boxedFGMPlatformMapBitmapScaling = + GetNullableObjectAtIndex(list, 1); + pigeonResult.bitmapScaling = boxedFGMPlatformMapBitmapScaling.value; + pigeonResult.imagePixelRatio = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.width = GetNullableObjectAtIndex(list, 3); + pigeonResult.height = GetNullableObjectAtIndex(list, 4); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapAssetMap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapAssetMap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.assetName ?: [NSNull null], + [[FGMPlatformMapBitmapScalingBox alloc] initWithValue:self.bitmapScaling], + @(self.imagePixelRatio), + self.width ?: [NSNull null], + self.height ?: [NSNull null], + ]; +} +@end + +@implementation FGMPlatformBitmapBytesMap ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height { + FGMPlatformBitmapBytesMap *pigeonResult = [[FGMPlatformBitmapBytesMap alloc] init]; + pigeonResult.byteData = byteData; + pigeonResult.bitmapScaling = bitmapScaling; + pigeonResult.imagePixelRatio = imagePixelRatio; + pigeonResult.width = width; + pigeonResult.height = height; + return pigeonResult; +} ++ (FGMPlatformBitmapBytesMap *)fromList:(NSArray *)list { + FGMPlatformBitmapBytesMap *pigeonResult = [[FGMPlatformBitmapBytesMap alloc] init]; + pigeonResult.byteData = GetNullableObjectAtIndex(list, 0); + FGMPlatformMapBitmapScalingBox *boxedFGMPlatformMapBitmapScaling = + GetNullableObjectAtIndex(list, 1); + pigeonResult.bitmapScaling = boxedFGMPlatformMapBitmapScaling.value; + pigeonResult.imagePixelRatio = [GetNullableObjectAtIndex(list, 2) doubleValue]; + pigeonResult.width = GetNullableObjectAtIndex(list, 3); + pigeonResult.height = GetNullableObjectAtIndex(list, 4); + return pigeonResult; +} ++ (nullable FGMPlatformBitmapBytesMap *)nullableFromList:(NSArray *)list { + return (list) ? [FGMPlatformBitmapBytesMap fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + self.byteData ?: [NSNull null], + [[FGMPlatformMapBitmapScalingBox alloc] initWithValue:self.bitmapScaling], + @(self.imagePixelRatio), + self.width ?: [NSNull null], + self.height ?: [NSNull null], + ]; +} +@end + +@interface FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReader : FlutterStandardReader +@end +@implementation FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReader +- (nullable id)readValueOfType:(UInt8)type { + switch (type) { + case 129: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil + ? nil + : [[FGMPlatformMapTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; + } + case 130: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil + ? nil + : [[FGMPlatformJointTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; + } + case 131: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil ? nil + : [[FGMPlatformPatternItemTypeBox alloc] + initWithValue:[enumAsNumber integerValue]]; + } + case 132: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil ? nil + : [[FGMPlatformMapBitmapScalingBox alloc] + initWithValue:[enumAsNumber integerValue]]; + } + case 133: + return [FGMPlatformCameraPosition fromList:[self readValue]]; + case 134: + return [FGMPlatformCameraUpdate fromList:[self readValue]]; + case 135: + return [FGMPlatformCameraUpdateNewCameraPosition fromList:[self readValue]]; + case 136: + return [FGMPlatformCameraUpdateNewLatLng fromList:[self readValue]]; + case 137: + return [FGMPlatformCameraUpdateNewLatLngBounds fromList:[self readValue]]; + case 138: + return [FGMPlatformCameraUpdateNewLatLngZoom fromList:[self readValue]]; + case 139: + return [FGMPlatformCameraUpdateScrollBy fromList:[self readValue]]; + case 140: + return [FGMPlatformCameraUpdateZoomBy fromList:[self readValue]]; + case 141: + return [FGMPlatformCameraUpdateZoom fromList:[self readValue]]; + case 142: + return [FGMPlatformCameraUpdateZoomTo fromList:[self readValue]]; + case 143: + return [FGMPlatformCircle fromList:[self readValue]]; + case 144: + return [FGMPlatformHeatmap fromList:[self readValue]]; + case 145: + return [FGMPlatformHeatmapGradient fromList:[self readValue]]; + case 146: + return [FGMPlatformWeightedLatLng fromList:[self readValue]]; + case 147: + return [FGMPlatformInfoWindow fromList:[self readValue]]; + case 148: + return [FGMPlatformCluster fromList:[self readValue]]; + case 149: + return [FGMPlatformClusterManager fromList:[self readValue]]; + case 150: + return [FGMPlatformMarker fromList:[self readValue]]; + case 151: + return [FGMPlatformPolygon fromList:[self readValue]]; + case 152: + return [FGMPlatformPolyline fromList:[self readValue]]; + case 153: + return [FGMPlatformPatternItem fromList:[self readValue]]; + case 154: + return [FGMPlatformTile fromList:[self readValue]]; + case 155: + return [FGMPlatformTileOverlay fromList:[self readValue]]; + case 156: + return [FGMPlatformEdgeInsets fromList:[self readValue]]; + case 157: + return [FGMPlatformLatLng fromList:[self readValue]]; + case 158: + return [FGMPlatformLatLngBounds fromList:[self readValue]]; + case 159: + return [FGMPlatformCameraTargetBounds fromList:[self readValue]]; + case 160: + return [FGMPlatformGroundOverlay fromList:[self readValue]]; + case 161: + return [FGMPlatformMapViewCreationParams fromList:[self readValue]]; + case 162: + return [FGMPlatformMapConfiguration fromList:[self readValue]]; + case 163: + return [FGMPlatformPoint fromList:[self readValue]]; + case 164: + return [FGMPlatformSize fromList:[self readValue]]; + case 165: + return [FGMPlatformColor fromList:[self readValue]]; + case 166: + return [FGMPlatformTileLayer fromList:[self readValue]]; + case 167: + return [FGMPlatformZoomRange fromList:[self readValue]]; + case 168: + return [FGMPlatformBitmap fromList:[self readValue]]; + case 169: + return [FGMPlatformBitmapDefaultMarker fromList:[self readValue]]; + case 170: + return [FGMPlatformBitmapBytes fromList:[self readValue]]; + case 171: + return [FGMPlatformBitmapAsset fromList:[self readValue]]; + case 172: + return [FGMPlatformBitmapAssetImage fromList:[self readValue]]; + case 173: + return [FGMPlatformBitmapAssetMap fromList:[self readValue]]; + case 174: + return [FGMPlatformBitmapBytesMap fromList:[self readValue]]; + default: + return [super readValueOfType:type]; + } +} +@end + +@interface FGMGoogleMapsFlutterPigeonMessagesPigeonCodecWriter : FlutterStandardWriter +@end +@implementation FGMGoogleMapsFlutterPigeonMessagesPigeonCodecWriter +- (void)writeValue:(id)value { + if ([value isKindOfClass:[FGMPlatformMapTypeBox class]]) { + FGMPlatformMapTypeBox *box = (FGMPlatformMapTypeBox *)value; + [self writeByte:129]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformJointTypeBox class]]) { + FGMPlatformJointTypeBox *box = (FGMPlatformJointTypeBox *)value; + [self writeByte:130]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformPatternItemTypeBox class]]) { + FGMPlatformPatternItemTypeBox *box = (FGMPlatformPatternItemTypeBox *)value; + [self writeByte:131]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformMapBitmapScalingBox class]]) { + FGMPlatformMapBitmapScalingBox *box = (FGMPlatformMapBitmapScalingBox *)value; + [self writeByte:132]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FGMPlatformCameraPosition class]]) { + [self writeByte:133]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdate class]]) { + [self writeByte:134]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewCameraPosition class]]) { + [self writeByte:135]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewLatLng class]]) { + [self writeByte:136]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewLatLngBounds class]]) { + [self writeByte:137]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateNewLatLngZoom class]]) { + [self writeByte:138]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateScrollBy class]]) { + [self writeByte:139]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateZoomBy class]]) { + [self writeByte:140]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateZoom class]]) { + [self writeByte:141]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraUpdateZoomTo class]]) { + [self writeByte:142]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCircle class]]) { + [self writeByte:143]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformHeatmap class]]) { + [self writeByte:144]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformHeatmapGradient class]]) { + [self writeByte:145]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformWeightedLatLng class]]) { + [self writeByte:146]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformInfoWindow class]]) { + [self writeByte:147]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCluster class]]) { + [self writeByte:148]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformClusterManager class]]) { + [self writeByte:149]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformMarker class]]) { + [self writeByte:150]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPolygon class]]) { + [self writeByte:151]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPolyline class]]) { + [self writeByte:152]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPatternItem class]]) { + [self writeByte:153]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformTile class]]) { + [self writeByte:154]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformTileOverlay class]]) { + [self writeByte:155]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformEdgeInsets class]]) { + [self writeByte:156]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformLatLng class]]) { + [self writeByte:157]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformLatLngBounds class]]) { + [self writeByte:158]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformCameraTargetBounds class]]) { + [self writeByte:159]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformGroundOverlay class]]) { + [self writeByte:160]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformMapViewCreationParams class]]) { + [self writeByte:161]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformMapConfiguration class]]) { + [self writeByte:162]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformPoint class]]) { + [self writeByte:163]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformSize class]]) { + [self writeByte:164]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformColor class]]) { + [self writeByte:165]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformTileLayer class]]) { + [self writeByte:166]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformZoomRange class]]) { + [self writeByte:167]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmap class]]) { + [self writeByte:168]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapDefaultMarker class]]) { + [self writeByte:169]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapBytes class]]) { + [self writeByte:170]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapAsset class]]) { + [self writeByte:171]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapAssetImage class]]) { + [self writeByte:172]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapAssetMap class]]) { + [self writeByte:173]; + [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[FGMPlatformBitmapBytesMap class]]) { + [self writeByte:174]; + [self writeValue:[value toList]]; + } else { + [super writeValue:value]; + } +} +@end + +@interface FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter : FlutterStandardReaderWriter +@end +@implementation FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter +- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { + return [[FGMGoogleMapsFlutterPigeonMessagesPigeonCodecWriter alloc] initWithData:data]; +} +- (FlutterStandardReader *)readerWithData:(NSData *)data { + return [[FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReader alloc] initWithData:data]; +} +@end + +NSObject *FGMGetGoogleMapsFlutterPigeonMessagesCodec(void) { + static FlutterStandardMessageCodec *sSharedObject = nil; + static dispatch_once_t sPred = 0; + dispatch_once(&sPred, ^{ + FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter *readerWriter = + [[FGMGoogleMapsFlutterPigeonMessagesPigeonCodecReaderWriter alloc] init]; + sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; + }); + return sSharedObject; +} +void SetUpFGMMapsApi(id binaryMessenger, NSObject *api) { + SetUpFGMMapsApiWithSuffix(binaryMessenger, api, @""); +} + +void SetUpFGMMapsApiWithSuffix(id binaryMessenger, + NSObject *api, NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; + /// Returns once the map instance is available. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.waitForMap", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(waitForMapWithError:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(waitForMapWithError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + [api waitForMapWithError:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateMapConfiguration", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(updateWithMapConfiguration:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(updateWithMapConfiguration:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformMapConfiguration *arg_configuration = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api updateWithMapConfiguration:arg_configuration error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of circles on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateCircles", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateCirclesByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateCirclesByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateCirclesByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of heatmaps on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateHeatmaps", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateHeatmapsByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateHeatmapsByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateHeatmapsByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of custer managers for clusters on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateClusterManagers", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateClusterManagersByAdding:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateClusterManagersByAdding:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + [api updateClusterManagersByAdding:arg_toAdd removing:arg_idsToRemove error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of markers on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateMarkers", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateMarkersByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateMarkersByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateMarkersByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of polygonss on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updatePolygons", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updatePolygonsByAdding:changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updatePolygonsByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updatePolygonsByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of polylines on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updatePolylines", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updatePolylinesByAdding: + changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updatePolylinesByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updatePolylinesByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of tile overlays on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateTileOverlays", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateTileOverlaysByAdding: + changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateTileOverlaysByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateTileOverlaysByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Updates the set of ground overlays on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.updateGroundOverlays", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(updateGroundOverlaysByAdding: + changing:removing:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(updateGroundOverlaysByAdding:changing:removing:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSArray *arg_toAdd = GetNullableObjectAtIndex(args, 0); + NSArray *arg_toChange = GetNullableObjectAtIndex(args, 1); + NSArray *arg_idsToRemove = GetNullableObjectAtIndex(args, 2); + FlutterError *error; + [api updateGroundOverlaysByAdding:arg_toAdd + changing:arg_toChange + removing:arg_idsToRemove + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the screen coordinate for the given map location. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.getScreenCoordinate", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(screenCoordinatesForLatLng:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(screenCoordinatesForLatLng:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformLatLng *arg_latLng = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformPoint *output = [api screenCoordinatesForLatLng:arg_latLng error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the map location for the given screen coordinate. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getLatLng", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(latLngForScreenCoordinate:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(latLngForScreenCoordinate:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformPoint *arg_screenCoordinate = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformLatLng *output = [api latLngForScreenCoordinate:arg_screenCoordinate + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the map region currently displayed on the map. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.getVisibleRegion", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(visibleMapRegion:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(visibleMapRegion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FGMPlatformLatLngBounds *output = [api visibleMapRegion:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.moveCamera", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(moveCameraWithUpdate:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(moveCameraWithUpdate:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformCameraUpdate *arg_cameraUpdate = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api moveCameraWithUpdate:arg_cameraUpdate error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Moves the camera according to [cameraUpdate], animating the update using a + /// duration in milliseconds if provided. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.animateCamera", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(animateCameraWithUpdate:duration:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(animateCameraWithUpdate:duration:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformCameraUpdate *arg_cameraUpdate = GetNullableObjectAtIndex(args, 0); + NSNumber *arg_durationMilliseconds = GetNullableObjectAtIndex(args, 1); + FlutterError *error; + [api animateCameraWithUpdate:arg_cameraUpdate + duration:arg_durationMilliseconds + error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Gets the current map zoom level. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getZoomLevel", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(currentZoomLevel:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(currentZoomLevel:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api currentZoomLevel:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Show the info window for the marker with the given ID. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.showInfoWindow", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(showInfoWindowForMarkerWithIdentifier:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(showInfoWindowForMarkerWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_markerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api showInfoWindowForMarkerWithIdentifier:arg_markerId error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Hide the info window for the marker with the given ID. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.hideInfoWindow", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(hideInfoWindowForMarkerWithIdentifier:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(hideInfoWindowForMarkerWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_markerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api hideInfoWindowForMarkerWithIdentifier:arg_markerId error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns true if the marker with the given ID is currently displaying its + /// info window. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.isInfoWindowShown", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(isShowingInfoWindowForMarkerWithIdentifier: + error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(isShowingInfoWindowForMarkerWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_markerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSNumber *output = [api isShowingInfoWindowForMarkerWithIdentifier:arg_markerId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Sets the style to the given map style string, where an empty string + /// indicates that the style should be cleared. + /// + /// If there was an error setting the style, such as an invalid style string, + /// returns the error message. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName: + [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.setStyle", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(setStyle:error:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(setStyle:error:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_style = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSString *output = [api setStyle:arg_style error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Returns the error string from the last attempt to set the map style, if + /// any. + /// + /// This allows checking asynchronously for initial style failures, as there + /// is no way to return failures from map initialization. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.getLastStyleError", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(lastStyleError:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(lastStyleError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSString *output = [api lastStyleError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Clears the cache of tiles previously requseted from the tile provider. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsApi.clearTileCache", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(clearTileCacheForOverlayWithIdentifier:error:)], + @"FGMMapsApi api (%@) doesn't respond to " + @"@selector(clearTileCacheForOverlayWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_tileOverlayId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api clearTileCacheForOverlayWithIdentifier:arg_tileOverlayId error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Takes a snapshot of the map and returns its image data. + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.takeSnapshot", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(takeSnapshotWithError:)], + @"FGMMapsApi api (%@) doesn't respond to @selector(takeSnapshotWithError:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FlutterStandardTypedData *output = [api takeSnapshotWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} +@interface FGMMapsCallbackApi () +@property(nonatomic, strong) NSObject *binaryMessenger; +@property(nonatomic, strong) NSString *messageChannelSuffix; +@end + +@implementation FGMMapsCallbackApi + +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger { + return [self initWithBinaryMessenger:binaryMessenger messageChannelSuffix:@""]; +} +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger + messageChannelSuffix:(nullable NSString *)messageChannelSuffix { + self = [self init]; + if (self) { + _binaryMessenger = binaryMessenger; + _messageChannelSuffix = [messageChannelSuffix length] == 0 + ? @"" + : [NSString stringWithFormat:@".%@", messageChannelSuffix]; + } + return self; +} +- (void)didStartCameraMoveWithCompletion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMoveStarted", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:nil + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didMoveCameraToPosition:(FGMPlatformCameraPosition *)arg_cameraPosition + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMove", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_cameraPosition ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didIdleCameraWithCompletion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraIdle", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:nil + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapAtPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didLongPressAtPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onLongPress", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapMarkerWithIdentifier:(NSString *)arg_markerId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didStartDragForMarkerWithIdentifier:(NSString *)arg_markerId + atPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null], arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didDragMarkerWithIdentifier:(NSString *)arg_markerId + atPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null], arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didEndDragForMarkerWithIdentifier:(NSString *)arg_markerId + atPosition:(FGMPlatformLatLng *)arg_position + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null], arg_position ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)arg_markerId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onInfoWindowTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_markerId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapCircleWithIdentifier:(NSString *)arg_circleId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCircleTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_circleId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapCluster:(FGMPlatformCluster *)arg_cluster + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_cluster ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapPolygonWithIdentifier:(NSString *)arg_polygonId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolygonTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_polygonId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapPolylineWithIdentifier:(NSString *)arg_polylineId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolylineTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_polylineId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)didTapGroundOverlayWithIdentifier:(NSString *)arg_groundOverlayId + completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onGroundOverlayTap", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ arg_groundOverlayId ?: [NSNull null] ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; +} +- (void)tileWithOverlayIdentifier:(NSString *)arg_tileOverlayId + location:(FGMPlatformPoint *)arg_location + zoom:(NSInteger)arg_zoom + completion:(void (^)(FGMPlatformTile *_Nullable, + FlutterError *_Nullable))completion { + NSString *channelName = [NSString + stringWithFormat: + @"%@%@", @"dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile", + _messageChannelSuffix]; + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + [channel sendMessage:@[ + arg_tileOverlayId ?: [NSNull null], arg_location ?: [NSNull null], @(arg_zoom) + ] + reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion(nil, [FlutterError errorWithCode:reply[0] + message:reply[1] + details:reply[2]]); + } else { + FGMPlatformTile *output = reply[0] == [NSNull null] ? nil : reply[0]; + completion(output, nil); + } + } else { + completion(nil, createConnectionError(channelName)); + } + }]; +} +@end + +void SetUpFGMMapsPlatformViewApi(id binaryMessenger, + NSObject *api) { + SetUpFGMMapsPlatformViewApiWithSuffix(binaryMessenger, api, @""); +} + +void SetUpFGMMapsPlatformViewApiWithSuffix(id binaryMessenger, + NSObject *api, + NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsPlatformViewApi.createView", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(createViewType:error:)], + @"FGMMapsPlatformViewApi api (%@) doesn't respond to @selector(createViewType:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FGMPlatformMapViewCreationParams *arg_type = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + [api createViewType:arg_type error:&error]; + callback(wrapResult(nil, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} +void SetUpFGMMapsInspectorApi(id binaryMessenger, + NSObject *api) { + SetUpFGMMapsInspectorApiWithSuffix(binaryMessenger, api, @""); +} + +void SetUpFGMMapsInspectorApiWithSuffix(id binaryMessenger, + NSObject *api, + NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 + ? [NSString stringWithFormat:@".%@", messageChannelSuffix] + : @""; + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areBuildingsEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areBuildingsEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areBuildingsEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areBuildingsEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areRotateGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areRotateGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areRotateGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areRotateGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areScrollGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areScrollGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areScrollGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areScrollGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areTiltGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areTiltGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areTiltGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areTiltGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.areZoomGesturesEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(areZoomGesturesEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(areZoomGesturesEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api areZoomGesturesEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.isCompassEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(isCompassEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(isCompassEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isCompassEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.isMyLocationButtonEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(isMyLocationButtonEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(isMyLocationButtonEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isMyLocationButtonEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.isTrafficEnabled", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert( + [api respondsToSelector:@selector(isTrafficEnabledWithError:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(isTrafficEnabledWithError:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + NSNumber *output = [api isTrafficEnabledWithError:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getTileOverlayInfo", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(tileOverlayWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(tileOverlayWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_tileOverlayId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformTileLayer *output = [api tileOverlayWithIdentifier:arg_tileOverlayId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getGroundOverlayInfo", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(groundOverlayWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(groundOverlayWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_groundOverlayId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformGroundOverlay *output = [api groundOverlayWithIdentifier:arg_groundOverlayId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getHeatmapInfo", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(heatmapWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(heatmapWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_heatmapId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + FGMPlatformHeatmap *output = [api heatmapWithIdentifier:arg_heatmapId error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getZoomRange", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(zoomRange:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(zoomRange:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FGMPlatformZoomRange *output = [api zoomRange:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getClusters", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(clustersWithIdentifier:error:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to " + @"@selector(clustersWithIdentifier:error:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_clusterManagerId = GetNullableObjectAtIndex(args, 0); + FlutterError *error; + NSArray *output = [api clustersWithIdentifier:arg_clusterManagerId + error:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", + @"dev.flutter.pigeon.google_maps_flutter_ios." + @"MapsInspectorApi.getCameraPosition", + messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FGMGetGoogleMapsFlutterPigeonMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(cameraPosition:)], + @"FGMMapsInspectorApi api (%@) doesn't respond to @selector(cameraPosition:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + FlutterError *error; + FGMPlatformCameraPosition *output = [api cameraPosition:&error]; + callback(wrapResult(output, error)); + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h new file mode 100644 index 000000000000..41df2dedd618 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Foundation; + +NS_ASSUME_NONNULL_BEGIN + +/// Protocol for CATransaction to allow mocking in tests. +@protocol FGMCATransactionProtocol +- (void)begin; +- (void)commit; +- (void)setAnimationDuration:(CFTimeInterval)duration; +@end + +/// Wrapper for CATransaction to allow mocking in tests. +@interface FGMCATransactionWrapper : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h new file mode 100644 index 000000000000..394f9e3d71e0 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h @@ -0,0 +1,56 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "GoogleMapsUtilsTrampoline.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// A controller that manages all of the cluster managers on a map. +@interface FGMClusterManagersController : NSObject + +/// Initializes cluster manager controller. +/// +/// @param callbackHandler A callback handler. +/// @param mapView A map view that will be used to display clustered markers. +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler; + +/// Creates cluster managers and initializes them. +/// +/// @param clusterManagersToAdd Array of cluster managers to add. +- (void)addClusterManagers:(NSArray *)clusterManagersToAdd; + +/// Removes requested cluster managers from the controller. +/// +/// @param identifiers Array of cluster manager IDs to remove. +- (void)removeClusterManagersWithIdentifiers:(NSArray *)identifiers; + +/// Returns the cluster managers for the given identifier. +/// +/// @param identifier The identifier of the cluster manager. +/// @return A cluster manager if found; otherwise, nil. +- (nullable GMUClusterManager *)clusterManagerWithIdentifier:(NSString *)identifier; + +/// Returns an array of clusters managed by the cluster manager. +/// +/// @param identifier The identifier of the cluster manager whose clusters are to be retrieved. +/// @return An array of clusters. Returns `nil` only if `error` is populated. +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error; + +/// Called when a cluster marker is tapped on the map. +/// +/// @param cluster The cluster that was tapped on. +- (void)didTapCluster:(GMUStaticCluster *)cluster; + +/// Calls the cluster method of all the cluster managers. +- (void)invokeClusteringForEachClusterManager; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h new file mode 100644 index 000000000000..45c13797099b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h @@ -0,0 +1,97 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import Foundation; +@import GoogleMaps; + +#import "GoogleMapsUtilsTrampoline.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Returns dict[key], or nil if dict[key] is NSNull. +extern id _Nullable FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key); + +/// Creates a CGPoint from its Pigeon equivalent. +extern CGPoint FGMGetCGPointForPigeonPoint(FGMPlatformPoint *point); + +/// Converts a CGPoint to its Pigeon equivalent. +extern FGMPlatformPoint *FGMGetPigeonPointForCGPoint(CGPoint point); + +/// Creates a CLLocationCoordinate2D from its Pigeon representation. +extern CLLocationCoordinate2D FGMGetCoordinateForPigeonLatLng(FGMPlatformLatLng *latLng); + +/// Converts a CLLocationCoordinate2D to its Pigeon representation. +extern FGMPlatformLatLng *FGMGetPigeonLatLngForCoordinate(CLLocationCoordinate2D coord); + +/// Creates a GMSCoordinateBounds from its Pigeon representation. +extern GMSCoordinateBounds *FGMGetCoordinateBoundsForPigeonLatLngBounds( + FGMPlatformLatLngBounds *bounds); + +/// Converts a GMSCoordinateBounds to its Pigeon representation. +extern FGMPlatformLatLngBounds *FGMGetPigeonLatLngBoundsForCoordinateBounds( + GMSCoordinateBounds *bounds); + +/// Converts a GMSCameraPosition to its Pigeon representation. +extern FGMPlatformCameraPosition *FGMGetPigeonCameraPositionForPosition( + GMSCameraPosition *position); + +/// Creates a GMSCameraPosition from its Pigeon representation. +extern GMSCameraPosition *FGMGetCameraPositionForPigeonCameraPosition( + FGMPlatformCameraPosition *position); + +/// Creates a CLLocation array from its Pigeon equivalent. +extern NSArray *FGMGetPointsForPigeonLatLngs(NSArray *points); + +/// Creates a CLLocation arary array, representing a set of holes, from its Pigeon equivalent. +extern NSArray *> *FGMGetHolesForPigeonLatLngArrays( + NSArray *> *points); + +extern GMSMutablePath *FGMGetPathFromPoints(NSArray *points); + +/// Creates a GMSMapViewType from its Pigeon representation. +extern GMSMapViewType FGMGetMapViewTypeForPigeonMapType(FGMPlatformMapType type); + +/// Converts a GMUStaticCluster to its Pigeon representation. +extern FGMPlatformCluster *FGMGetPigeonCluster(GMUStaticCluster *cluster, + NSString *clusterManagerIdentifier); + +/// Converts a GMSGroundOverlay to its Pigeon representation. +extern FGMPlatformGroundOverlay *FGMGetPigeonGroundOverlay(GMSGroundOverlay *groundOverlay, + NSString *overlayId, + BOOL isCreatedWithBounds, + NSNumber *_Nullable zoomLevel); + +extern GMUGradient *FGMGetGradientForPigeonHeatmapGradient(FGMPlatformHeatmapGradient *gradient); + +extern FGMPlatformHeatmapGradient *FGMGetPigeonHeatmapGradientForGradient(GMUGradient *gradient); + +/// Creates a GMUWeightedLatLng array from its Pigeon equivalent. +extern NSArray *FGMGetWeightedDataForPigeonWeightedData( + NSArray *weightedLatLngs); + +/// Converts a GMUWeightedLatLng array to its Pigeon equivalent. +extern NSArray *FGMGetPigeonWeightedDataForWeightedData( + NSArray *weightedLatLngs); + +/// Creates a GMSCameraUpdate from its Pigeon equivalent. +extern GMSCameraUpdate *_Nullable FGMGetCameraUpdateForPigeonCameraUpdate( + FGMPlatformCameraUpdate *update); + +/// Creates a UIColor from its Pigeon representation. +extern UIColor *FGMGetColorForPigeonColor(FGMPlatformColor *color); + +/// Converts a UIColor to its Pigeon representation. +extern FGMPlatformColor *FGMGetPigeonColorForColor(UIColor *color); + +/// Creates an array of GMSStrokeStyles using the given patterns and stroke color. +extern NSArray *FGMGetStrokeStylesFromPatterns( + NSArray *patterns, UIColor *strokeColor); + +/// Creates an array of span lengths using the given patterns. +extern NSArray *FGMGetSpanLengthsFromPatterns( + NSArray *patterns); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h new file mode 100644 index 000000000000..a5297f703b9e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h @@ -0,0 +1,64 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import CoreLocation; +@import Flutter; +@import Foundation; +@import GoogleMaps; +@import UIKit; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Controller of a single ground overlay on the map. +@interface FGMGroundOverlayController : NSObject + +/// The ground overlay this controller handles. +@property(strong, nonatomic) GMSGroundOverlay *groundOverlay; + +/// Whether ground overlay is created with bounds or position. +@property(nonatomic, assign, getter=isCreatedWithBounds) BOOL createdWithBounds; + +/// Zoom level when ground overlay is initialized with position. +@property(nonatomic, strong, nullable) NSNumber *zoomLevel; + +/// Initializes an instance of this class with a GMSGroundOverlay, a map view, and identifier. +- (instancetype)initWithGroundOverlay:(GMSGroundOverlay *)groundOverlay + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView + isCreatedWithBounds:(BOOL)isCreatedWithBounds; + +/// Removes this ground overlay from the map. +- (void)removeGroundOverlay; +@end + +/// Controller of multiple ground overlays on the map. +@interface FLTGroundOverlaysController : NSObject + +/// Initializes the controller with a GMSMapView, callback handler and registrar. +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; + +/// Adds ground overlays to the map. +- (void)addGroundOverlays:(NSArray *)groundOverlaysToAdd; + +/// Updates ground overlays on the map. +- (void)changeGroundOverlays:(NSArray *)groundOverlaysToChange; + +/// Removes ground overlays from the map. +- (void)removeGroundOverlaysWithIdentifiers:(NSArray *)identifiers; + +/// Called when a ground overlay is tapped on the map. +- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier; + +/// Returns true if a ground overlay with the given identifier exists on the map. +- (bool)hasGroundOverlaysWithIdentifier:(NSString *)identifier; + +/// Returns the ground overlay with the given identifier. +- (nullable FGMPlatformGroundOverlay *)groundOverlayWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h new file mode 100644 index 000000000000..87123539947d --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h @@ -0,0 +1,29 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FGMGroundOverlayController.h" + +/// Internal APIs exposed for unit testing +@interface FGMGroundOverlayController (Test) + +/// Ground Overlay instance the controller is attached to +@property(strong, nonatomic) GMSGroundOverlay *groundOverlay; + +/// Function to update the gms ground overlay from platform ground overlay. +- (void)updateFromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)groundOverlay + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale; + +/// Updates the underlying GMSGroundOverlay with the properties from the given +/// FGMPlatformGroundOverlay. +/// +/// Setting the ground overlay to visible will set its map to the given mapView. ++ (void)updateGroundOverlay:(GMSGroundOverlay *)groundOverlay + fromPlatformGroundOverlay:(FGMPlatformGroundOverlay *)groundOverlay + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingBounds:(BOOL)useBounds; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h new file mode 100644 index 000000000000..37a833d79d1e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Creates a UIImage from Pigeon bitmap. +UIImage *_Nullable FGMIconFromBitmap(FGMPlatformBitmap *platformBitmap, + NSObject *registrar, + CGFloat screenScale); +/// Returns a BOOL indicating whether image is considered scalable with the given scale factor from +/// size. +BOOL FGMIsScalableWithScaleFactorFromSize(CGSize originalSize, CGSize targetSize); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h new file mode 100644 index 000000000000..166241f3cb56 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import GoogleMaps; + +NS_ASSUME_NONNULL_BEGIN + +/// Defines user data object for markers. +@interface FGMMarkerUserData : NSObject + +/// The identifier of the marker. +@property(nonatomic, copy) NSString *markerIdentifier; + +/// The identifier of the cluster manager. +/// This property is set only if the marker is managed by a cluster manager. +@property(nonatomic, copy, nullable) NSString *clusterManagerIdentifier; + +@end + +/// Associates a marker identifier and optionally a cluster manager identifier with a marker's user +/// data. +extern void FGMSetIdentifiersToMarkerUserData(NSString *markerIdentifier, + NSString *_Nullable clusterManagerIdentifier, + GMSMarker *marker); + +/// Get the marker identifier from marker's user data. +/// +/// @return The marker identifier if found; otherwise, nil. +extern NSString *_Nullable FGMGetMarkerIdentifierFromMarker(GMSMarker *marker); + +/// Get the cluster manager identifier from marker's user data. +/// +/// @return The cluster manager identifier if found; otherwise, nil. +extern NSString *_Nullable FGMGetClusterManagerIdentifierFromMarker(GMSMarker *marker); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h new file mode 100644 index 000000000000..a9c306abe7c4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "GoogleMapsUtilsTrampoline.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Controller of a single Heatmap on the map. +@interface FLTGoogleMapHeatmapController : NSObject + +/// Initializes an instance of this class with a heatmap tile layer, a map view, and additional +/// configuration options. +/// +/// @param heatmap The heatmap data to display. +/// @param heatmapTileLayer The heatmap tile layer that will be used to display heatmap data on the +/// map. +/// @param mapView The map view where the heatmap layer will be overlaid. +/// +/// @return An initialized instance of this class, configured with the specified heatmap tile layer, +/// map view, and additional options. +- (instancetype)initWithHeatmap:(FGMPlatformHeatmap *)heatmap + tileLayer:(GMUHeatmapTileLayer *)heatmapTileLayer + mapView:(GMSMapView *)mapView; + +/// Removes this heatmap from the map. +- (void)removeHeatmap; + +/// Clears the tile cache in order to visually udpate this heatmap. +- (void)clearTileCache; +@end + +/// Controller of multiple Heatmaps on the map. +@interface FLTHeatmapsController : NSObject + +/// Initializes the controller with a GMSMapView. +- (instancetype)initWithMapView:(GMSMapView *)mapView; + +/// Adds heatmaps to the map. +- (void)addHeatmaps:(NSArray *)heatmapsToAdd; + +/// Updates heatmaps on the map. +- (void)changeHeatmaps:(NSArray *)heatmapsToChange; + +/// Removes heatmaps from the map. +- (void)removeHeatmapsWithIdentifiers:(NSArray *)identifiers; + +/// Returns true if a heatmap with the given identifier exists on the map. +- (BOOL)hasHeatmapWithIdentifier:(NSString *)identifier; + +/// Returns the heatmap with the given identifier. +- (nullable FGMPlatformHeatmap *)heatmapWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h new file mode 100644 index 000000000000..b00a48e3477f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapHeatmapController.h" + +/// Internal APIs exposed for unit testing +@interface FLTGoogleMapHeatmapController (Test) + +/// Updates the underlying GMUHeatmapTileLayer with the properties from the given platform heatmap. +/// +/// Setting the heatmap to visible will set its map to the given mapView. ++ (void)updateHeatmap:(GMUHeatmapTileLayer *)heatmapTileLayer + fromPlatformHeatmap:(FGMPlatformHeatmap *)platformHeatmap + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h new file mode 100644 index 000000000000..5c1b6e5418e8 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h @@ -0,0 +1,40 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTGoogleMapTileOverlayController : NSObject +/// The layer managed by this controller instance. +@property(readonly, nonatomic) GMSTileLayer *layer; + +- (instancetype)initWithTileOverlay:(FGMPlatformTileOverlay *)tileOverlay + tileLayer:(GMSTileLayer *)tileLayer + mapView:(GMSMapView *)mapView; +- (void)removeTileOverlay; +- (void)clearTileCache; +@end + +@interface FLTTileProviderController : GMSTileLayer +@property(copy, nonatomic, readonly) NSString *tileOverlayIdentifier; +- (instancetype)initWithTileOverlayIdentifier:(NSString *)identifier + callbackHandler:(FGMMapsCallbackApi *)callbackHandler; +@end + +@interface FLTTileOverlaysController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addTileOverlays:(NSArray *)tileOverlaysToAdd; +- (void)changeTileOverlays:(NSArray *)tileOverlaysToChange; +- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers; +- (void)clearTileCacheWithIdentifier:(NSString *)identifier; +- (nullable FLTGoogleMapTileOverlayController *)tileOverlayWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h new file mode 100644 index 000000000000..e753698cde45 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "FLTGoogleMapTileOverlayController.h" + +/// Internal APIs exposed for unit testing +@interface FLTGoogleMapTileOverlayController (Test) + +/// Updates the underlying GMSTileLayer with the properties from the given FGMPlatformTileOverlay. +/// +/// Setting the tile overlay to visible will set its map to the given mapView. ++ (void)updateTileLayer:(GMSTileLayer *)tileLayer + fromPlatformTileOverlay:(FGMPlatformTileOverlay *)platformOverlay + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h new file mode 100644 index 000000000000..a5a1d05a4cbd --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMClusterManagersController.h" +#import "GoogleMapCircleController.h" +#import "GoogleMapController.h" +#import "GoogleMapMarkerController.h" +#import "GoogleMapPolygonController.h" +#import "GoogleMapPolylineController.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTGoogleMapsPlugin : NSObject +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h new file mode 100644 index 000000000000..0cb21d926f6a --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h @@ -0,0 +1,30 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +// Defines circle controllable by Flutter. +@interface FLTGoogleMapCircleController : NSObject +- (instancetype)initCircleWithPlatformCircle:(FGMPlatformCircle *)circle + mapView:(GMSMapView *)mapView; +- (void)removeCircle; +@end + +@interface FLTCirclesController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addCircles:(NSArray *)circlesToAdd; +- (void)changeCircles:(NSArray *)circlesToChange; +- (void)removeCirclesWithIdentifiers:(NSArray *)identifiers; +- (void)didTapCircleWithIdentifier:(NSString *)identifier; +- (bool)hasCircleWithIdentifier:(NSString *)identifier; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h new file mode 100644 index 000000000000..1c72d2060dc1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h @@ -0,0 +1,21 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapCircleController.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Private methods exposed for testing. +@interface FLTGoogleMapCircleController (Test) + +/// Updates the underlying GMSCircle with the properties from the given FGMPlatformCircle. +/// +/// Setting the circle to visible will set its map to the given mapView. ++ (void)updateCircle:(GMSCircle *)circle + fromPlatformCircle:(FGMPlatformCircle *)platformCircle + withMapView:(GMSMapView *)mapView; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h new file mode 100644 index 000000000000..e9ea39630ebf --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMCATransactionWrapper.h" +#import "FGMClusterManagersController.h" +#import "GoogleMapCircleController.h" +#import "GoogleMapMarkerController.h" +#import "GoogleMapPolygonController.h" +#import "GoogleMapPolylineController.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +// Defines map overlay controllable from Flutter. +@interface FLTGoogleMapController : NSObject +- (instancetype)initWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *)registrar; +- (void)showAtOrigin:(CGPoint)origin; +- (void)hide; +- (nullable GMSCameraPosition *)cameraPosition; +@end + +// Allows the engine to create new Google Map instances. +@interface FLTGoogleMapFactory : NSObject +- (instancetype)initWithRegistrar:(NSObject *)registrar; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h new file mode 100644 index 000000000000..219a1ac246e9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h @@ -0,0 +1,59 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMCATransactionWrapper.h" +#import "GoogleMapController.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Implementation of the Pigeon maps API. +/// +/// This is a separate object from the maps controller because the Pigeon API registration keeps a +/// strong reference to the implementor, but as the FlutterPlatformView, the lifetime of the +/// FLTGoogleMapController instance is what needs to trigger Pigeon unregistration, so can't be +/// the target of the registration. +@interface FGMMapCallHandler : NSObject + +/// The transaction wrapper to use for camera animations. +@property(nonatomic, strong) id transactionWrapper; + +@end + +/// Implementation of the Pigeon maps inspector API. +/// +/// This is a separate object from the maps controller because the Pigeon API registration keeps a +/// strong reference to the implementor, but as the FlutterPlatformView, the lifetime of the +/// FLTGoogleMapController instance is what needs to trigger Pigeon unregistration, so can't be +/// the target of the registration. +@interface FGMMapInspector : NSObject + +/// Initializes a Pigeon API for inpector with a map controller. +- (instancetype)initWithMapController:(nonnull FLTGoogleMapController *)controller + messenger:(NSObject *)messenger + pigeonSuffix:(NSString *)suffix; + +@end + +@interface FLTGoogleMapController (Test) + +/// Initializes a map controller with a concrete map view. +/// +/// @param mapView A map view that will be displayed by the controller +/// @param viewId A unique identifier for the controller. +/// @param creationParameters Parameters for initialising the map view. +/// @param registrar The plugin registrar passed from Flutter. +- (instancetype)initWithMapView:(GMSMapView *)mapView + viewIdentifier:(int64_t)viewId + creationParameters:(FGMPlatformMapViewCreationParams *)creationParameters + registrar:(NSObject *)registrar; + +// The main Pigeon API implementation. +@property(nonatomic, strong, readonly) FGMMapCallHandler *callHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h new file mode 100644 index 000000000000..dcebcb1e2982 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "FGMClusterManagersController.h" +#import "GoogleMapController.h" +#import "google_maps_flutter_pigeon_messages.g.h" + +NS_ASSUME_NONNULL_BEGIN + +// Defines marker controllable by Flutter. +@interface FLTGoogleMapMarkerController : NSObject +@property(assign, nonatomic, readonly) BOOL consumeTapEvents; +- (instancetype)initWithMarker:(GMSMarker *)marker + markerIdentifier:(NSString *)markerIdentifier + mapView:(GMSMapView *)mapView; +- (void)showInfoWindow; +- (void)hideInfoWindow; +- (BOOL)isInfoWindowShown; +- (void)removeMarker; +@end + +@interface FLTMarkersController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + clusterManagersController:(nullable FGMClusterManagersController *)clusterManagersController + registrar:(NSObject *)registrar; +- (void)addMarkers:(NSArray *)markersToAdd; +- (void)changeMarkers:(NSArray *)markersToChange; +- (void)removeMarkersWithIdentifiers:(NSArray *)identifiers; +- (BOOL)didTapMarkerWithIdentifier:(NSString *)identifier; +- (void)didStartDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)coordinate; +- (void)didEndDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)coordinate; +- (void)didDragMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)coordinate; +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)identifier; +- (void)showMarkerInfoWindowWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error; +- (void)hideMarkerInfoWindowWithIdentifier:(NSString *)identifier + error:(FlutterError *_Nullable __autoreleasing *_Nonnull)error; +/// Returns whether or not the info window for the marker with the given identifier is shown. +/// +/// If there is no such marker, returns nil and sets error. +- (nullable NSNumber *) + isInfoWindowShownForMarkerWithIdentifier:(NSString *)identifier + error: + (FlutterError *_Nullable __autoreleasing *_Nonnull)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h new file mode 100644 index 000000000000..f6ff32e791e1 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h @@ -0,0 +1,31 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapMarkerController.h" + +/// Methods exposed for unit testing. +@interface FLTGoogleMapMarkerController (Test) + +/// The underlying controlled GMSMarker. +@property(strong, nonatomic, readonly) GMSMarker *marker; + +/// Updates the underlying GMSMarker with the properties from the given FGMPlatformMarker. +/// +/// Setting the marker to visible will set its map to the given mapView. ++ (void)updateMarker:(GMSMarker *)marker + fromPlatformMarker:(FGMPlatformMarker *)platformMarker + withMapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar + screenScale:(CGFloat)screenScale + usingOpacityForVisibility:(BOOL)useOpacityForVisibility; + +@end + +/// Methods exposed for unit testing. +@interface FLTMarkersController (Test) + +/// A mapping from marker identifiers to corresponding marker controllers. +@property(strong, nonatomic, readonly) NSMutableDictionary *markerIdentifierToController; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h new file mode 100644 index 000000000000..b26cf2416c5f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +// Defines polygon controllable by Flutter. +@interface FLTGoogleMapPolygonController : NSObject +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView; +- (void)removePolygon; +@end + +@interface FLTPolygonsController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addPolygons:(NSArray *)polygonsToAdd; +- (void)changePolygons:(NSArray *)polygonsToChange; +- (void)removePolygonWithIdentifiers:(NSArray *)identifiers; +- (void)didTapPolygonWithIdentifier:(NSString *)identifier; +- (bool)hasPolygonWithIdentifier:(NSString *)identifier; +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h new file mode 100644 index 000000000000..ab4cf60be224 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h @@ -0,0 +1,17 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolygonController.h" + +/// Methods exposed for unit testing. +@interface FLTGoogleMapPolygonController (Test) + +/// Updates the underlying GMSPolygon with the properties from the given FGMPlatformPolygon. +/// +/// Setting the polygon to visible will set its map to the given mapView. ++ (void)updatePolygon:(GMSPolygon *)polygon + fromPlatformPolygon:(FGMPlatformPolygon *)polygon + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h new file mode 100644 index 000000000000..5505ec54019b --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h @@ -0,0 +1,27 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +@import Flutter; +@import GoogleMaps; + +#import "google_maps_flutter_pigeon_messages.g.h" + +// Defines polyline controllable by Flutter. +@interface FLTGoogleMapPolylineController : NSObject +- (instancetype)initWithPath:(GMSMutablePath *)path + identifier:(NSString *)identifier + mapView:(GMSMapView *)mapView; +- (void)removePolyline; +@end + +@interface FLTPolylinesController : NSObject +- (instancetype)initWithMapView:(GMSMapView *)mapView + callbackHandler:(FGMMapsCallbackApi *)callbackHandler + registrar:(NSObject *)registrar; +- (void)addPolylines:(NSArray *)polylinesToAdd; +- (void)changePolylines:(NSArray *)polylinesToChange; +- (void)removePolylineWithIdentifiers:(NSArray *)identifiers; +- (void)didTapPolylineWithIdentifier:(NSString *)identifier; +- (bool)hasPolylineWithIdentifier:(NSString *)identifier; +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h new file mode 100644 index 000000000000..df9e31293951 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h @@ -0,0 +1,25 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "GoogleMapPolylineController.h" + +/// Internal APIs exposed for unit testing +@interface FLTGoogleMapPolylineController (Test) + +/// Polyline instance the controller is attached to +@property(strong, nonatomic) GMSPolyline *polyline; + +/// Updates the controller's polyline with the properties from the given FGMPlatformPolyline. +/// +/// Setting the polyline to visible will set its map to the controller's mapView. +- (void)updateFromPlatformPolyline:(FGMPlatformPolyline *)polyline; + +/// Updates the underlying GMSPolyline with the properties from the given FGMPlatformPolyline. +/// +/// Setting the polyline to visible will set its map to the given mapView. ++ (void)updatePolyline:(GMSPolyline *)polyline + fromPlatformPolyline:(FGMPlatformPolyline *)platformPolyline + withMapView:(GMSMapView *)mapView; + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h new file mode 100644 index 000000000000..cf6399b5b39e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h @@ -0,0 +1,12 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// If Swift Package Manager is in use, Objective-C headers are available under the +// GoogleMapsUtilsObjC package. When using CocoaPods, the headers are provided by the +// GoogleMapsUtils package. +#ifdef FGM_USING_COCOAPODS +@import GoogleMapsUtils; +#else +@import GoogleMapsUtilsObjC; +#endif diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h new file mode 100644 index 000000000000..db11f425c37c --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h @@ -0,0 +1,940 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +#import + +@protocol FlutterBinaryMessenger; +@protocol FlutterMessageCodec; +@class FlutterError; +@class FlutterStandardTypedData; + +NS_ASSUME_NONNULL_BEGIN + +/// Pigeon equivalent of MapType +typedef NS_ENUM(NSUInteger, FGMPlatformMapType) { + FGMPlatformMapTypeNone = 0, + FGMPlatformMapTypeNormal = 1, + FGMPlatformMapTypeSatellite = 2, + FGMPlatformMapTypeTerrain = 3, + FGMPlatformMapTypeHybrid = 4, +}; + +/// Wrapper for FGMPlatformMapType to allow for nullability. +@interface FGMPlatformMapTypeBox : NSObject +@property(nonatomic, assign) FGMPlatformMapType value; +- (instancetype)initWithValue:(FGMPlatformMapType)value; +@end + +/// Join types for polyline joints. +typedef NS_ENUM(NSUInteger, FGMPlatformJointType) { + FGMPlatformJointTypeMitered = 0, + FGMPlatformJointTypeBevel = 1, + FGMPlatformJointTypeRound = 2, +}; + +/// Wrapper for FGMPlatformJointType to allow for nullability. +@interface FGMPlatformJointTypeBox : NSObject +@property(nonatomic, assign) FGMPlatformJointType value; +- (instancetype)initWithValue:(FGMPlatformJointType)value; +@end + +/// Enumeration of possible types for PatternItem. +typedef NS_ENUM(NSUInteger, FGMPlatformPatternItemType) { + FGMPlatformPatternItemTypeDot = 0, + FGMPlatformPatternItemTypeDash = 1, + FGMPlatformPatternItemTypeGap = 2, +}; + +/// Wrapper for FGMPlatformPatternItemType to allow for nullability. +@interface FGMPlatformPatternItemTypeBox : NSObject +@property(nonatomic, assign) FGMPlatformPatternItemType value; +- (instancetype)initWithValue:(FGMPlatformPatternItemType)value; +@end + +/// Pigeon equivalent of [MapBitmapScaling]. +typedef NS_ENUM(NSUInteger, FGMPlatformMapBitmapScaling) { + FGMPlatformMapBitmapScalingAuto = 0, + FGMPlatformMapBitmapScalingNone = 1, +}; + +/// Wrapper for FGMPlatformMapBitmapScaling to allow for nullability. +@interface FGMPlatformMapBitmapScalingBox : NSObject +@property(nonatomic, assign) FGMPlatformMapBitmapScaling value; +- (instancetype)initWithValue:(FGMPlatformMapBitmapScaling)value; +@end + +@class FGMPlatformCameraPosition; +@class FGMPlatformCameraUpdate; +@class FGMPlatformCameraUpdateNewCameraPosition; +@class FGMPlatformCameraUpdateNewLatLng; +@class FGMPlatformCameraUpdateNewLatLngBounds; +@class FGMPlatformCameraUpdateNewLatLngZoom; +@class FGMPlatformCameraUpdateScrollBy; +@class FGMPlatformCameraUpdateZoomBy; +@class FGMPlatformCameraUpdateZoom; +@class FGMPlatformCameraUpdateZoomTo; +@class FGMPlatformCircle; +@class FGMPlatformHeatmap; +@class FGMPlatformHeatmapGradient; +@class FGMPlatformWeightedLatLng; +@class FGMPlatformInfoWindow; +@class FGMPlatformCluster; +@class FGMPlatformClusterManager; +@class FGMPlatformMarker; +@class FGMPlatformPolygon; +@class FGMPlatformPolyline; +@class FGMPlatformPatternItem; +@class FGMPlatformTile; +@class FGMPlatformTileOverlay; +@class FGMPlatformEdgeInsets; +@class FGMPlatformLatLng; +@class FGMPlatformLatLngBounds; +@class FGMPlatformCameraTargetBounds; +@class FGMPlatformGroundOverlay; +@class FGMPlatformMapViewCreationParams; +@class FGMPlatformMapConfiguration; +@class FGMPlatformPoint; +@class FGMPlatformSize; +@class FGMPlatformColor; +@class FGMPlatformTileLayer; +@class FGMPlatformZoomRange; +@class FGMPlatformBitmap; +@class FGMPlatformBitmapDefaultMarker; +@class FGMPlatformBitmapBytes; +@class FGMPlatformBitmapAsset; +@class FGMPlatformBitmapAssetImage; +@class FGMPlatformBitmapAssetMap; +@class FGMPlatformBitmapBytesMap; + +/// Pigeon representatation of a CameraPosition. +@interface FGMPlatformCameraPosition : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithBearing:(double)bearing + target:(FGMPlatformLatLng *)target + tilt:(double)tilt + zoom:(double)zoom; +@property(nonatomic, assign) double bearing; +@property(nonatomic, strong) FGMPlatformLatLng *target; +@property(nonatomic, assign) double tilt; +@property(nonatomic, assign) double zoom; +@end + +/// Pigeon representation of a CameraUpdate. +@interface FGMPlatformCameraUpdate : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithCameraUpdate:(id)cameraUpdate; +/// This Object must be one of the classes below prefixed with +/// PlatformCameraUpdate. Each such class represents a different type of +/// camera update, and each holds a different set of data, preventing the +/// use of a single unified class. +@property(nonatomic, strong) id cameraUpdate; +@end + +/// Pigeon equivalent of NewCameraPosition +@interface FGMPlatformCameraUpdateNewCameraPosition : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithCameraPosition:(FGMPlatformCameraPosition *)cameraPosition; +@property(nonatomic, strong) FGMPlatformCameraPosition *cameraPosition; +@end + +/// Pigeon equivalent of NewLatLng +@interface FGMPlatformCameraUpdateNewLatLng : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng; +@property(nonatomic, strong) FGMPlatformLatLng *latLng; +@end + +/// Pigeon equivalent of NewLatLngBounds +@interface FGMPlatformCameraUpdateNewLatLngBounds : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithBounds:(FGMPlatformLatLngBounds *)bounds padding:(double)padding; +@property(nonatomic, strong) FGMPlatformLatLngBounds *bounds; +@property(nonatomic, assign) double padding; +@end + +/// Pigeon equivalent of NewLatLngZoom +@interface FGMPlatformCameraUpdateNewLatLngZoom : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithLatLng:(FGMPlatformLatLng *)latLng zoom:(double)zoom; +@property(nonatomic, strong) FGMPlatformLatLng *latLng; +@property(nonatomic, assign) double zoom; +@end + +/// Pigeon equivalent of ScrollBy +@interface FGMPlatformCameraUpdateScrollBy : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithDx:(double)dx dy:(double)dy; +@property(nonatomic, assign) double dx; +@property(nonatomic, assign) double dy; +@end + +/// Pigeon equivalent of ZoomBy +@interface FGMPlatformCameraUpdateZoomBy : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAmount:(double)amount focus:(nullable FGMPlatformPoint *)focus; +@property(nonatomic, assign) double amount; +@property(nonatomic, strong, nullable) FGMPlatformPoint *focus; +@end + +/// Pigeon equivalent of ZoomIn/ZoomOut +@interface FGMPlatformCameraUpdateZoom : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithOut:(BOOL)out; +@property(nonatomic, assign) BOOL out; +@end + +/// Pigeon equivalent of ZoomTo +@interface FGMPlatformCameraUpdateZoomTo : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithZoom:(double)zoom; +@property(nonatomic, assign) double zoom; +@end + +/// Pigeon equivalent of the Circle class. +@interface FGMPlatformCircle : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithConsumeTapEvents:(BOOL)consumeTapEvents + fillColor:(FGMPlatformColor *)fillColor + strokeColor:(FGMPlatformColor *)strokeColor + visible:(BOOL)visible + strokeWidth:(NSInteger)strokeWidth + zIndex:(double)zIndex + center:(FGMPlatformLatLng *)center + radius:(double)radius + circleId:(NSString *)circleId; +@property(nonatomic, assign) BOOL consumeTapEvents; +@property(nonatomic, strong) FGMPlatformColor *fillColor; +@property(nonatomic, strong) FGMPlatformColor *strokeColor; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger strokeWidth; +@property(nonatomic, assign) double zIndex; +@property(nonatomic, strong) FGMPlatformLatLng *center; +@property(nonatomic, assign) double radius; +@property(nonatomic, copy) NSString *circleId; +@end + +/// Pigeon equivalent of the Heatmap class. +@interface FGMPlatformHeatmap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithHeatmapId:(NSString *)heatmapId + data:(NSArray *)data + gradient:(nullable FGMPlatformHeatmapGradient *)gradient + opacity:(double)opacity + radius:(NSInteger)radius + minimumZoomIntensity:(NSInteger)minimumZoomIntensity + maximumZoomIntensity:(NSInteger)maximumZoomIntensity; +@property(nonatomic, copy) NSString *heatmapId; +@property(nonatomic, copy) NSArray *data; +@property(nonatomic, strong, nullable) FGMPlatformHeatmapGradient *gradient; +@property(nonatomic, assign) double opacity; +@property(nonatomic, assign) NSInteger radius; +@property(nonatomic, assign) NSInteger minimumZoomIntensity; +@property(nonatomic, assign) NSInteger maximumZoomIntensity; +@end + +/// Pigeon equivalent of the HeatmapGradient class. +/// +/// The GMUGradient structure is slightly different from HeatmapGradient, so +/// this matches the iOS API so that conversion can be done on the Dart side +/// where the structures are easier to work with. +@interface FGMPlatformHeatmapGradient : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithColors:(NSArray *)colors + startPoints:(NSArray *)startPoints + colorMapSize:(NSInteger)colorMapSize; +@property(nonatomic, copy) NSArray *colors; +@property(nonatomic, copy) NSArray *startPoints; +@property(nonatomic, assign) NSInteger colorMapSize; +@end + +/// Pigeon equivalent of the WeightedLatLng class. +@interface FGMPlatformWeightedLatLng : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithPoint:(FGMPlatformLatLng *)point weight:(double)weight; +@property(nonatomic, strong) FGMPlatformLatLng *point; +@property(nonatomic, assign) double weight; +@end + +/// Pigeon equivalent of the InfoWindow class. +@interface FGMPlatformInfoWindow : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithTitle:(nullable NSString *)title + snippet:(nullable NSString *)snippet + anchor:(FGMPlatformPoint *)anchor; +@property(nonatomic, copy, nullable) NSString *title; +@property(nonatomic, copy, nullable) NSString *snippet; +@property(nonatomic, strong) FGMPlatformPoint *anchor; +@end + +/// Pigeon equivalent of Cluster. +@interface FGMPlatformCluster : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithClusterManagerId:(NSString *)clusterManagerId + position:(FGMPlatformLatLng *)position + bounds:(FGMPlatformLatLngBounds *)bounds + markerIds:(NSArray *)markerIds; +@property(nonatomic, copy) NSString *clusterManagerId; +@property(nonatomic, strong) FGMPlatformLatLng *position; +@property(nonatomic, strong) FGMPlatformLatLngBounds *bounds; +@property(nonatomic, copy) NSArray *markerIds; +@end + +/// Pigeon equivalent of the ClusterManager class. +@interface FGMPlatformClusterManager : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithIdentifier:(NSString *)identifier; +@property(nonatomic, copy) NSString *identifier; +@end + +/// Pigeon equivalent of the Marker class. +@interface FGMPlatformMarker : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAlpha:(double)alpha + anchor:(FGMPlatformPoint *)anchor + consumeTapEvents:(BOOL)consumeTapEvents + draggable:(BOOL)draggable + flat:(BOOL)flat + icon:(FGMPlatformBitmap *)icon + infoWindow:(FGMPlatformInfoWindow *)infoWindow + position:(FGMPlatformLatLng *)position + rotation:(double)rotation + visible:(BOOL)visible + zIndex:(NSInteger)zIndex + markerId:(NSString *)markerId + clusterManagerId:(nullable NSString *)clusterManagerId; +@property(nonatomic, assign) double alpha; +@property(nonatomic, strong) FGMPlatformPoint *anchor; +@property(nonatomic, assign) BOOL consumeTapEvents; +@property(nonatomic, assign) BOOL draggable; +@property(nonatomic, assign) BOOL flat; +@property(nonatomic, strong) FGMPlatformBitmap *icon; +@property(nonatomic, strong) FGMPlatformInfoWindow *infoWindow; +@property(nonatomic, strong) FGMPlatformLatLng *position; +@property(nonatomic, assign) double rotation; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger zIndex; +@property(nonatomic, copy) NSString *markerId; +@property(nonatomic, copy, nullable) NSString *clusterManagerId; +@end + +/// Pigeon equivalent of the Polygon class. +@interface FGMPlatformPolygon : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithPolygonId:(NSString *)polygonId + consumesTapEvents:(BOOL)consumesTapEvents + fillColor:(FGMPlatformColor *)fillColor + geodesic:(BOOL)geodesic + points:(NSArray *)points + holes:(NSArray *> *)holes + visible:(BOOL)visible + strokeColor:(FGMPlatformColor *)strokeColor + strokeWidth:(NSInteger)strokeWidth + zIndex:(NSInteger)zIndex; +@property(nonatomic, copy) NSString *polygonId; +@property(nonatomic, assign) BOOL consumesTapEvents; +@property(nonatomic, strong) FGMPlatformColor *fillColor; +@property(nonatomic, assign) BOOL geodesic; +@property(nonatomic, copy) NSArray *points; +@property(nonatomic, copy) NSArray *> *holes; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, strong) FGMPlatformColor *strokeColor; +@property(nonatomic, assign) NSInteger strokeWidth; +@property(nonatomic, assign) NSInteger zIndex; +@end + +/// Pigeon equivalent of the Polyline class. +@interface FGMPlatformPolyline : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithPolylineId:(NSString *)polylineId + consumesTapEvents:(BOOL)consumesTapEvents + color:(FGMPlatformColor *)color + geodesic:(BOOL)geodesic + jointType:(FGMPlatformJointType)jointType + patterns:(NSArray *)patterns + points:(NSArray *)points + visible:(BOOL)visible + width:(NSInteger)width + zIndex:(NSInteger)zIndex; +@property(nonatomic, copy) NSString *polylineId; +@property(nonatomic, assign) BOOL consumesTapEvents; +@property(nonatomic, strong) FGMPlatformColor *color; +@property(nonatomic, assign) BOOL geodesic; +/// The joint type. +@property(nonatomic, assign) FGMPlatformJointType jointType; +/// The pattern data, as a list of pattern items. +@property(nonatomic, copy) NSArray *patterns; +@property(nonatomic, copy) NSArray *points; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger width; +@property(nonatomic, assign) NSInteger zIndex; +@end + +/// Pigeon equivalent of the PatternItem class. +@interface FGMPlatformPatternItem : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithType:(FGMPlatformPatternItemType)type length:(nullable NSNumber *)length; +@property(nonatomic, assign) FGMPlatformPatternItemType type; +@property(nonatomic, strong, nullable) NSNumber *length; +@end + +/// Pigeon equivalent of the Tile class. +@interface FGMPlatformTile : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithWidth:(NSInteger)width + height:(NSInteger)height + data:(nullable FlutterStandardTypedData *)data; +@property(nonatomic, assign) NSInteger width; +@property(nonatomic, assign) NSInteger height; +@property(nonatomic, strong, nullable) FlutterStandardTypedData *data; +@end + +/// Pigeon equivalent of the TileOverlay class. +@interface FGMPlatformTileOverlay : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithTileOverlayId:(NSString *)tileOverlayId + fadeIn:(BOOL)fadeIn + transparency:(double)transparency + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + tileSize:(NSInteger)tileSize; +@property(nonatomic, copy) NSString *tileOverlayId; +@property(nonatomic, assign) BOOL fadeIn; +@property(nonatomic, assign) double transparency; +@property(nonatomic, assign) NSInteger zIndex; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) NSInteger tileSize; +@end + +/// Pigeon equivalent of Flutter's EdgeInsets. +@interface FGMPlatformEdgeInsets : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithTop:(double)top bottom:(double)bottom left:(double)left right:(double)right; +@property(nonatomic, assign) double top; +@property(nonatomic, assign) double bottom; +@property(nonatomic, assign) double left; +@property(nonatomic, assign) double right; +@end + +/// Pigeon equivalent of LatLng. +@interface FGMPlatformLatLng : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithLatitude:(double)latitude longitude:(double)longitude; +@property(nonatomic, assign) double latitude; +@property(nonatomic, assign) double longitude; +@end + +/// Pigeon equivalent of LatLngBounds. +@interface FGMPlatformLatLngBounds : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithNortheast:(FGMPlatformLatLng *)northeast + southwest:(FGMPlatformLatLng *)southwest; +@property(nonatomic, strong) FGMPlatformLatLng *northeast; +@property(nonatomic, strong) FGMPlatformLatLng *southwest; +@end + +/// Pigeon equivalent of CameraTargetBounds. +/// +/// As with the Dart version, it exists to distinguish between not setting a +/// a target, and having an explicitly unbounded target (null [bounds]). +@interface FGMPlatformCameraTargetBounds : NSObject ++ (instancetype)makeWithBounds:(nullable FGMPlatformLatLngBounds *)bounds; +@property(nonatomic, strong, nullable) FGMPlatformLatLngBounds *bounds; +@end + +/// Pigeon equivalent of the GroundOverlay class. +@interface FGMPlatformGroundOverlay : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithGroundOverlayId:(NSString *)groundOverlayId + image:(FGMPlatformBitmap *)image + position:(nullable FGMPlatformLatLng *)position + bounds:(nullable FGMPlatformLatLngBounds *)bounds + anchor:(nullable FGMPlatformPoint *)anchor + transparency:(double)transparency + bearing:(double)bearing + zIndex:(NSInteger)zIndex + visible:(BOOL)visible + clickable:(BOOL)clickable + zoomLevel:(nullable NSNumber *)zoomLevel; +@property(nonatomic, copy) NSString *groundOverlayId; +@property(nonatomic, strong) FGMPlatformBitmap *image; +@property(nonatomic, strong, nullable) FGMPlatformLatLng *position; +@property(nonatomic, strong, nullable) FGMPlatformLatLngBounds *bounds; +@property(nonatomic, strong, nullable) FGMPlatformPoint *anchor; +@property(nonatomic, assign) double transparency; +@property(nonatomic, assign) double bearing; +@property(nonatomic, assign) NSInteger zIndex; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) BOOL clickable; +@property(nonatomic, strong, nullable) NSNumber *zoomLevel; +@end + +/// Information passed to the platform view creation. +@interface FGMPlatformMapViewCreationParams : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype) + makeWithInitialCameraPosition:(FGMPlatformCameraPosition *)initialCameraPosition + mapConfiguration:(FGMPlatformMapConfiguration *)mapConfiguration + initialCircles:(NSArray *)initialCircles + initialMarkers:(NSArray *)initialMarkers + initialPolygons:(NSArray *)initialPolygons + initialPolylines:(NSArray *)initialPolylines + initialHeatmaps:(NSArray *)initialHeatmaps + initialTileOverlays:(NSArray *)initialTileOverlays + initialClusterManagers:(NSArray *)initialClusterManagers + initialGroundOverlays:(NSArray *)initialGroundOverlays; +@property(nonatomic, strong) FGMPlatformCameraPosition *initialCameraPosition; +@property(nonatomic, strong) FGMPlatformMapConfiguration *mapConfiguration; +@property(nonatomic, copy) NSArray *initialCircles; +@property(nonatomic, copy) NSArray *initialMarkers; +@property(nonatomic, copy) NSArray *initialPolygons; +@property(nonatomic, copy) NSArray *initialPolylines; +@property(nonatomic, copy) NSArray *initialHeatmaps; +@property(nonatomic, copy) NSArray *initialTileOverlays; +@property(nonatomic, copy) NSArray *initialClusterManagers; +@property(nonatomic, copy) NSArray *initialGroundOverlays; +@end + +/// Pigeon equivalent of MapConfiguration. +@interface FGMPlatformMapConfiguration : NSObject ++ (instancetype)makeWithCompassEnabled:(nullable NSNumber *)compassEnabled + cameraTargetBounds:(nullable FGMPlatformCameraTargetBounds *)cameraTargetBounds + mapType:(nullable FGMPlatformMapTypeBox *)mapType + minMaxZoomPreference:(nullable FGMPlatformZoomRange *)minMaxZoomPreference + rotateGesturesEnabled:(nullable NSNumber *)rotateGesturesEnabled + scrollGesturesEnabled:(nullable NSNumber *)scrollGesturesEnabled + tiltGesturesEnabled:(nullable NSNumber *)tiltGesturesEnabled + trackCameraPosition:(nullable NSNumber *)trackCameraPosition + zoomGesturesEnabled:(nullable NSNumber *)zoomGesturesEnabled + myLocationEnabled:(nullable NSNumber *)myLocationEnabled + myLocationButtonEnabled:(nullable NSNumber *)myLocationButtonEnabled + padding:(nullable FGMPlatformEdgeInsets *)padding + indoorViewEnabled:(nullable NSNumber *)indoorViewEnabled + trafficEnabled:(nullable NSNumber *)trafficEnabled + buildingsEnabled:(nullable NSNumber *)buildingsEnabled + mapId:(nullable NSString *)mapId + style:(nullable NSString *)style; +@property(nonatomic, strong, nullable) NSNumber *compassEnabled; +@property(nonatomic, strong, nullable) FGMPlatformCameraTargetBounds *cameraTargetBounds; +@property(nonatomic, strong, nullable) FGMPlatformMapTypeBox *mapType; +@property(nonatomic, strong, nullable) FGMPlatformZoomRange *minMaxZoomPreference; +@property(nonatomic, strong, nullable) NSNumber *rotateGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *scrollGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *tiltGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *trackCameraPosition; +@property(nonatomic, strong, nullable) NSNumber *zoomGesturesEnabled; +@property(nonatomic, strong, nullable) NSNumber *myLocationEnabled; +@property(nonatomic, strong, nullable) NSNumber *myLocationButtonEnabled; +@property(nonatomic, strong, nullable) FGMPlatformEdgeInsets *padding; +@property(nonatomic, strong, nullable) NSNumber *indoorViewEnabled; +@property(nonatomic, strong, nullable) NSNumber *trafficEnabled; +@property(nonatomic, strong, nullable) NSNumber *buildingsEnabled; +@property(nonatomic, copy, nullable) NSString *mapId; +@property(nonatomic, copy, nullable) NSString *style; +@end + +/// Pigeon representation of an x,y coordinate. +@interface FGMPlatformPoint : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithX:(double)x y:(double)y; +@property(nonatomic, assign) double x; +@property(nonatomic, assign) double y; +@end + +/// Pigeon representation of a size. +@interface FGMPlatformSize : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithWidth:(double)width height:(double)height; +@property(nonatomic, assign) double width; +@property(nonatomic, assign) double height; +@end + +/// Pigeon representation of a color. +@interface FGMPlatformColor : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithRed:(double)red green:(double)green blue:(double)blue alpha:(double)alpha; +@property(nonatomic, assign) double red; +@property(nonatomic, assign) double green; +@property(nonatomic, assign) double blue; +@property(nonatomic, assign) double alpha; +@end + +/// Pigeon equivalent of GMSTileLayer properties. +@interface FGMPlatformTileLayer : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithVisible:(BOOL)visible + fadeIn:(BOOL)fadeIn + opacity:(double)opacity + zIndex:(NSInteger)zIndex; +@property(nonatomic, assign) BOOL visible; +@property(nonatomic, assign) BOOL fadeIn; +@property(nonatomic, assign) double opacity; +@property(nonatomic, assign) NSInteger zIndex; +@end + +/// Pigeon equivalent of MinMaxZoomPreference. +@interface FGMPlatformZoomRange : NSObject ++ (instancetype)makeWithMin:(nullable NSNumber *)min max:(nullable NSNumber *)max; +@property(nonatomic, strong, nullable) NSNumber *min; +@property(nonatomic, strong, nullable) NSNumber *max; +@end + +/// Pigeon equivalent of [BitmapDescriptor]. As there are multiple disjoint +/// types of [BitmapDescriptor], [PlatformBitmap] contains a single field which +/// may hold the pigeon equivalent type of any of them. +@interface FGMPlatformBitmap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithBitmap:(id)bitmap; +/// One of [PlatformBitmapAssetMap], [PlatformBitmapAsset], +/// [PlatformBitmapAssetImage], [PlatformBitmapBytesMap], +/// [PlatformBitmapBytes], or [PlatformBitmapDefaultMarker]. +/// As Pigeon does not currently support data class inheritance, this +/// approach allows for the different bitmap implementations to be valid +/// argument and return types of the API methods. See +/// https://github.com/flutter/flutter/issues/117819. +@property(nonatomic, strong) id bitmap; +@end + +/// Pigeon equivalent of [DefaultMarker]. +@interface FGMPlatformBitmapDefaultMarker : NSObject ++ (instancetype)makeWithHue:(nullable NSNumber *)hue; +@property(nonatomic, strong, nullable) NSNumber *hue; +@end + +/// Pigeon equivalent of [BytesBitmap]. +@interface FGMPlatformBitmapBytes : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + size:(nullable FGMPlatformSize *)size; +@property(nonatomic, strong) FlutterStandardTypedData *byteData; +@property(nonatomic, strong, nullable) FGMPlatformSize *size; +@end + +/// Pigeon equivalent of [AssetBitmap]. +@interface FGMPlatformBitmapAsset : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithName:(NSString *)name pkg:(nullable NSString *)pkg; +@property(nonatomic, copy) NSString *name; +@property(nonatomic, copy, nullable) NSString *pkg; +@end + +/// Pigeon equivalent of [AssetImageBitmap]. +@interface FGMPlatformBitmapAssetImage : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithName:(NSString *)name + scale:(double)scale + size:(nullable FGMPlatformSize *)size; +@property(nonatomic, copy) NSString *name; +@property(nonatomic, assign) double scale; +@property(nonatomic, strong, nullable) FGMPlatformSize *size; +@end + +/// Pigeon equivalent of [AssetMapBitmap]. +@interface FGMPlatformBitmapAssetMap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithAssetName:(NSString *)assetName + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height; +@property(nonatomic, copy) NSString *assetName; +@property(nonatomic, assign) FGMPlatformMapBitmapScaling bitmapScaling; +@property(nonatomic, assign) double imagePixelRatio; +@property(nonatomic, strong, nullable) NSNumber *width; +@property(nonatomic, strong, nullable) NSNumber *height; +@end + +/// Pigeon equivalent of [BytesMapBitmap]. +@interface FGMPlatformBitmapBytesMap : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithByteData:(FlutterStandardTypedData *)byteData + bitmapScaling:(FGMPlatformMapBitmapScaling)bitmapScaling + imagePixelRatio:(double)imagePixelRatio + width:(nullable NSNumber *)width + height:(nullable NSNumber *)height; +@property(nonatomic, strong) FlutterStandardTypedData *byteData; +@property(nonatomic, assign) FGMPlatformMapBitmapScaling bitmapScaling; +@property(nonatomic, assign) double imagePixelRatio; +@property(nonatomic, strong, nullable) NSNumber *width; +@property(nonatomic, strong, nullable) NSNumber *height; +@end + +/// The codec used by all APIs. +NSObject *FGMGetGoogleMapsFlutterPigeonMessagesCodec(void); + +/// Interface for non-test interactions with the native SDK. +/// +/// For test-only state queries, see [MapsInspectorApi]. +@protocol FGMMapsApi +/// Returns once the map instance is available. +- (void)waitForMapWithError:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the map's configuration options. +/// +/// Only non-null configuration values will result in updates; options with +/// null values will remain unchanged. +- (void)updateWithMapConfiguration:(FGMPlatformMapConfiguration *)configuration + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of circles on the map. +- (void)updateCirclesByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of heatmaps on the map. +- (void)updateHeatmapsByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of custer managers for clusters on the map. +- (void)updateClusterManagersByAdding:(NSArray *)toAdd + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of markers on the map. +- (void)updateMarkersByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of polygonss on the map. +- (void)updatePolygonsByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of polylines on the map. +- (void)updatePolylinesByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of tile overlays on the map. +- (void)updateTileOverlaysByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Updates the set of ground overlays on the map. +- (void)updateGroundOverlaysByAdding:(NSArray *)toAdd + changing:(NSArray *)toChange + removing:(NSArray *)idsToRemove + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the screen coordinate for the given map location. +/// +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformPoint *)screenCoordinatesForLatLng:(FGMPlatformLatLng *)latLng + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the map location for the given screen coordinate. +/// +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformLatLng *)latLngForScreenCoordinate:(FGMPlatformPoint *)screenCoordinate + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the map region currently displayed on the map. +/// +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformLatLngBounds *)visibleMapRegion:(FlutterError *_Nullable *_Nonnull)error; +/// Moves the camera according to [cameraUpdate] immediately, with no +/// animation. +- (void)moveCameraWithUpdate:(FGMPlatformCameraUpdate *)cameraUpdate + error:(FlutterError *_Nullable *_Nonnull)error; +/// Moves the camera according to [cameraUpdate], animating the update using a +/// duration in milliseconds if provided. +- (void)animateCameraWithUpdate:(FGMPlatformCameraUpdate *)cameraUpdate + duration:(nullable NSNumber *)durationMilliseconds + error:(FlutterError *_Nullable *_Nonnull)error; +/// Gets the current map zoom level. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)currentZoomLevel:(FlutterError *_Nullable *_Nonnull)error; +/// Show the info window for the marker with the given ID. +- (void)showInfoWindowForMarkerWithIdentifier:(NSString *)markerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Hide the info window for the marker with the given ID. +- (void)hideInfoWindowForMarkerWithIdentifier:(NSString *)markerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns true if the marker with the given ID is currently displaying its +/// info window. +/// +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *) + isShowingInfoWindowForMarkerWithIdentifier:(NSString *)markerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Sets the style to the given map style string, where an empty string +/// indicates that the style should be cleared. +/// +/// If there was an error setting the style, such as an invalid style string, +/// returns the error message. +- (nullable NSString *)setStyle:(NSString *)style error:(FlutterError *_Nullable *_Nonnull)error; +/// Returns the error string from the last attempt to set the map style, if +/// any. +/// +/// This allows checking asynchronously for initial style failures, as there +/// is no way to return failures from map initialization. +- (nullable NSString *)lastStyleError:(FlutterError *_Nullable *_Nonnull)error; +/// Clears the cache of tiles previously requseted from the tile provider. +- (void)clearTileCacheForOverlayWithIdentifier:(NSString *)tileOverlayId + error:(FlutterError *_Nullable *_Nonnull)error; +/// Takes a snapshot of the map and returns its image data. +- (nullable FlutterStandardTypedData *)takeSnapshotWithError: + (FlutterError *_Nullable *_Nonnull)error; +@end + +extern void SetUpFGMMapsApi(id binaryMessenger, + NSObject *_Nullable api); + +extern void SetUpFGMMapsApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); + +/// Interface for calls from the native SDK to Dart. +@interface FGMMapsCallbackApi : NSObject +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger; +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger + messageChannelSuffix:(nullable NSString *)messageChannelSuffix; +/// Called when the map camera starts moving. +- (void)didStartCameraMoveWithCompletion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map camera moves. +- (void)didMoveCameraToPosition:(FGMPlatformCameraPosition *)cameraPosition + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map camera stops moving. +- (void)didIdleCameraWithCompletion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map, not a specifc map object, is tapped. +- (void)didTapAtPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when the map, not a specifc map object, is long pressed. +- (void)didLongPressAtPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker is tapped. +- (void)didTapMarkerWithIdentifier:(NSString *)markerId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker drag starts. +- (void)didStartDragForMarkerWithIdentifier:(NSString *)markerId + atPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker drag updates. +- (void)didDragMarkerWithIdentifier:(NSString *)markerId + atPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker drag ends. +- (void)didEndDragForMarkerWithIdentifier:(NSString *)markerId + atPosition:(FGMPlatformLatLng *)position + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker's info window is tapped. +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)markerId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a circle is tapped. +- (void)didTapCircleWithIdentifier:(NSString *)circleId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a marker cluster is tapped. +- (void)didTapCluster:(FGMPlatformCluster *)cluster + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a polygon is tapped. +- (void)didTapPolygonWithIdentifier:(NSString *)polygonId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a polyline is tapped. +- (void)didTapPolylineWithIdentifier:(NSString *)polylineId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called when a ground overlay is tapped. +- (void)didTapGroundOverlayWithIdentifier:(NSString *)groundOverlayId + completion:(void (^)(FlutterError *_Nullable))completion; +/// Called to get data for a map tile. +- (void)tileWithOverlayIdentifier:(NSString *)tileOverlayId + location:(FGMPlatformPoint *)location + zoom:(NSInteger)zoom + completion:(void (^)(FGMPlatformTile *_Nullable, + FlutterError *_Nullable))completion; +@end + +/// Dummy interface to force generation of the platform view creation params, +/// which are not used in any Pigeon calls, only the platform view creation +/// call made internally by Flutter. +@protocol FGMMapsPlatformViewApi +- (void)createViewType:(nullable FGMPlatformMapViewCreationParams *)type + error:(FlutterError *_Nullable *_Nonnull)error; +@end + +extern void SetUpFGMMapsPlatformViewApi(id binaryMessenger, + NSObject *_Nullable api); + +extern void SetUpFGMMapsPlatformViewApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); + +/// Inspector API only intended for use in integration tests. +@protocol FGMMapsInspectorApi +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areBuildingsEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areRotateGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areScrollGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areTiltGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)areZoomGesturesEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isCompassEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isMyLocationButtonEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSNumber *)isTrafficEnabledWithError:(FlutterError *_Nullable *_Nonnull)error; +- (nullable FGMPlatformTileLayer *)tileOverlayWithIdentifier:(NSString *)tileOverlayId + error: + (FlutterError *_Nullable *_Nonnull)error; +- (nullable FGMPlatformGroundOverlay *) + groundOverlayWithIdentifier:(NSString *)groundOverlayId + error:(FlutterError *_Nullable *_Nonnull)error; +- (nullable FGMPlatformHeatmap *)heatmapWithIdentifier:(NSString *)heatmapId + error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformZoomRange *)zoomRange:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable NSArray *) + clustersWithIdentifier:(NSString *)clusterManagerId + error:(FlutterError *_Nullable *_Nonnull)error; +/// @return `nil` only when `error != nil`. +- (nullable FGMPlatformCameraPosition *)cameraPosition:(FlutterError *_Nullable *_Nonnull)error; +@end + +extern void SetUpFGMMapsInspectorApi(id binaryMessenger, + NSObject *_Nullable api); + +extern void SetUpFGMMapsInspectorApiWithSuffix(id binaryMessenger, + NSObject *_Nullable api, + NSString *messageChannelSuffix); + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/google_maps_flutter_ios_sdk9.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/google_maps_flutter_ios_sdk9.dart new file mode 100644 index 000000000000..082ba90196cc --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/google_maps_flutter_ios_sdk9.dart @@ -0,0 +1,5 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +export 'src/google_maps_flutter_ios.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_map_inspector_ios.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_map_inspector_ios.dart new file mode 100644 index 000000000000..a0057b9fdc54 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_map_inspector_ios.dart @@ -0,0 +1,277 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; +import 'package:flutter/foundation.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; + +import 'google_maps_flutter_ios.dart'; +import 'messages.g.dart'; + +/// An Android of implementation of [GoogleMapsInspectorPlatform]. +@visibleForTesting +class GoogleMapsInspectorIOS extends GoogleMapsInspectorPlatform { + /// Creates an inspector API instance for a given map ID from + /// [inspectorProvider]. + GoogleMapsInspectorIOS( + MapsInspectorApi? Function(int mapId) inspectorProvider, + ) : _inspectorProvider = inspectorProvider; + + final MapsInspectorApi? Function(int mapId) _inspectorProvider; + + @override + Future areBuildingsEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areBuildingsEnabled(); + } + + @override + Future areRotateGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areRotateGesturesEnabled(); + } + + @override + Future areScrollGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areScrollGesturesEnabled(); + } + + @override + Future areTiltGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areTiltGesturesEnabled(); + } + + @override + Future areZoomControlsEnabled({required int mapId}) async { + // Does not exist on iOS. + return false; + } + + @override + Future areZoomGesturesEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.areZoomGesturesEnabled(); + } + + @override + Future getMinMaxZoomLevels({required int mapId}) async { + final PlatformZoomRange zoomLevels = await _inspectorProvider( + mapId, + )!.getZoomRange(); + return MinMaxZoomPreference(zoomLevels.min, zoomLevels.max); + } + + @override + Future getTileOverlayInfo( + TileOverlayId tileOverlayId, { + required int mapId, + }) async { + final PlatformTileLayer? tileInfo = await _inspectorProvider( + mapId, + )!.getTileOverlayInfo(tileOverlayId.value); + if (tileInfo == null) { + return null; + } + return TileOverlay( + tileOverlayId: tileOverlayId, + fadeIn: tileInfo.fadeIn, + transparency: 1.0 - tileInfo.opacity, + visible: tileInfo.visible, + zIndex: tileInfo.zIndex, + ); + } + + @override + bool supportsGettingHeatmapInfo() => true; + + @override + Future getHeatmapInfo( + HeatmapId heatmapId, { + required int mapId, + }) async { + final PlatformHeatmap? heatmapInfo = await _inspectorProvider( + mapId, + )!.getHeatmapInfo(heatmapId.value); + if (heatmapInfo == null) { + return null; + } + + return Heatmap( + heatmapId: heatmapId, + data: heatmapInfo.data.map(_deserializeWeightedLatLng).toList(), + gradient: _deserializeHeatmapGradient(heatmapInfo.gradient), + opacity: heatmapInfo.opacity, + radius: HeatmapRadius.fromPixels(heatmapInfo.radius), + minimumZoomIntensity: heatmapInfo.minimumZoomIntensity, + maximumZoomIntensity: heatmapInfo.maximumZoomIntensity, + ); + } + + @override + bool supportsGettingGroundOverlayInfo() => true; + + @override + Future getGroundOverlayInfo( + GroundOverlayId groundOverlayId, { + required int mapId, + }) async { + final PlatformGroundOverlay? groundOverlayInfo = await _inspectorProvider( + mapId, + )!.getGroundOverlayInfo(groundOverlayId.value); + + if (groundOverlayInfo == null) { + return null; + } + + // Create dummy image to represent the image of the ground overlay. + final dummyImage = BytesMapBitmap( + Uint8List.fromList([0]), + bitmapScaling: MapBitmapScaling.none, + ); + + final PlatformLatLng? position = groundOverlayInfo.position; + final PlatformLatLngBounds? bounds = groundOverlayInfo.bounds; + + if (position != null) { + return GroundOverlay.fromPosition( + groundOverlayId: groundOverlayId, + position: LatLng(position.latitude, position.longitude), + image: dummyImage, + zIndex: groundOverlayInfo.zIndex, + bearing: groundOverlayInfo.bearing, + transparency: groundOverlayInfo.transparency, + visible: groundOverlayInfo.visible, + clickable: groundOverlayInfo.clickable, + anchor: Offset( + groundOverlayInfo.anchor!.x, + groundOverlayInfo.anchor!.y, + ), + zoomLevel: groundOverlayInfo.zoomLevel, + ); + } else if (bounds != null) { + return GroundOverlay.fromBounds( + groundOverlayId: groundOverlayId, + bounds: LatLngBounds( + southwest: LatLng( + bounds.southwest.latitude, + bounds.southwest.longitude, + ), + northeast: LatLng( + bounds.northeast.latitude, + bounds.northeast.longitude, + ), + ), + image: dummyImage, + zIndex: groundOverlayInfo.zIndex, + bearing: groundOverlayInfo.bearing, + transparency: groundOverlayInfo.transparency, + visible: groundOverlayInfo.visible, + clickable: groundOverlayInfo.clickable, + ); + } + return null; + } + + @override + Future isCompassEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.isCompassEnabled(); + } + + @override + Future isLiteModeEnabled({required int mapId}) async { + // Does not exist on iOS. + return false; + } + + @override + Future isMapToolbarEnabled({required int mapId}) async { + // Does not exist on iOS. + return false; + } + + @override + Future isMyLocationButtonEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.isMyLocationButtonEnabled(); + } + + @override + Future isTrafficEnabled({required int mapId}) async { + return _inspectorProvider(mapId)!.isTrafficEnabled(); + } + + @override + Future> getClusters({ + required int mapId, + required ClusterManagerId clusterManagerId, + }) async { + return (await _inspectorProvider( + mapId, + )!.getClusters(clusterManagerId.value)) + .map( + (PlatformCluster cluster) => + GoogleMapsFlutterIOS.clusterFromPlatformCluster(cluster), + ) + .toList(); + } + + @override + bool supportsGettingGameraPosition() => true; + + @override + Future getCameraPosition({required int mapId}) async { + final PlatformCameraPosition cameraPosition = await _inspectorProvider( + mapId, + )!.getCameraPosition(); + return CameraPosition( + target: LatLng( + cameraPosition.target.latitude, + cameraPosition.target.longitude, + ), + bearing: cameraPosition.bearing, + tilt: cameraPosition.tilt, + zoom: cameraPosition.zoom, + ); + } + + static HeatmapGradient? _deserializeHeatmapGradient( + PlatformHeatmapGradient? gradient, + ) { + if (gradient == null) { + return null; + } + return HeatmapGradient( + // Zip the colors and start points together, since they are parallel + // arrays on the platform side. + _mapEnumerated( + gradient.colors, + (PlatformColor color, int i) => HeatmapGradientColor( + Color.from( + red: color.red, + green: color.green, + blue: color.blue, + alpha: color.alpha, + ), + gradient.startPoints[i], + ), + ).toList(), + colorMapSize: gradient.colorMapSize, + ); + } + + static WeightedLatLng _deserializeWeightedLatLng( + PlatformWeightedLatLng weightedLatLng, + ) { + return WeightedLatLng( + LatLng(weightedLatLng.point.latitude, weightedLatLng.point.longitude), + weight: weightedLatLng.weight, + ); + } +} + +Iterable _mapEnumerated( + Iterable iterable, + E Function(T, int) fn, +) sync* { + var index = 0; + for (final item in iterable) { + yield fn(item, index++); + } +} 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 new file mode 100644 index 000000000000..c7e469ad1491 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/google_maps_flutter_ios.dart @@ -0,0 +1,1467 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:stream_transform/stream_transform.dart'; + +import 'google_map_inspector_ios.dart'; +import 'messages.g.dart'; + +/// The non-test implementation of `_apiProvider`. +MapsApi _productionApiProvider(int mapId) { + return MapsApi(messageChannelSuffix: mapId.toString()); +} + +/// Error thrown when an unknown map ID is provided to a method channel API. +class UnknownMapIDError extends Error { + /// Creates an assertion error with the provided [mapId] and optional + /// [message]. + UnknownMapIDError(this.mapId, [this.message]); + + /// The unknown ID. + final int mapId; + + /// Message describing the assertion error. + final Object? message; + + @override + String toString() { + if (message != null) { + return 'Unknown map ID $mapId: ${Error.safeToString(message)}'; + } + return 'Unknown map ID $mapId'; + } +} + +/// An implementation of [GoogleMapsFlutterPlatform] for iOS. +class GoogleMapsFlutterIOS extends GoogleMapsFlutterPlatform { + /// Creates a new Android maps implementation instance. + GoogleMapsFlutterIOS({ + @visibleForTesting MapsApi Function(int mapId)? apiProvider, + }) : _apiProvider = apiProvider ?? _productionApiProvider; + + /// Registers the iOS implementation of GoogleMapsFlutterPlatform. + static void registerWith() { + GoogleMapsFlutterPlatform.instance = GoogleMapsFlutterIOS(); + } + + final Map _hostMaps = {}; + + // A method to create MapsApi instances, which can be overridden for testing. + final MapsApi Function(int mapId) _apiProvider; + + /// The per-map handlers for callbacks from the host side. + @visibleForTesting + final Map hostMapHandlers = + {}; + + /// Accesses the MapsApi associated to the passed mapId. + MapsApi _hostApi(int mapId) { + final MapsApi? api = _hostMaps[mapId]; + if (api == null) { + throw UnknownMapIDError(mapId); + } + return api; + } + + // Keep a collection of mapId to a map of TileOverlays. + final Map> _tileOverlays = + >{}; + + /// Returns the handler for [mapId], creating it if it doesn't already exist. + @visibleForTesting + HostMapMessageHandler ensureHandlerInitialized(int mapId) { + HostMapMessageHandler? handler = hostMapHandlers[mapId]; + if (handler == null) { + handler = HostMapMessageHandler( + mapId, + _mapEventStreamController, + tileOverlayProvider: (TileOverlayId tileOverlayId) { + final Map? tileOverlaysForMap = + _tileOverlays[mapId]; + return tileOverlaysForMap?[tileOverlayId]; + }, + ); + hostMapHandlers[mapId] = handler; + } + return handler; + } + + /// Returns the API instance for [mapId], creating it if it doesn't already + /// exist. + @visibleForTesting + MapsApi ensureApiInitialized(int mapId) { + MapsApi? api = _hostMaps[mapId]; + if (api == null) { + api = _apiProvider(mapId); + _hostMaps[mapId] ??= api; + } + return api; + } + + @override + Future init(int mapId) { + ensureHandlerInitialized(mapId); + final MapsApi hostApi = ensureApiInitialized(mapId); + return hostApi.waitForMap(); + } + + @override + void dispose({required int mapId}) { + // Noop! + } + + // The controller we need to broadcast the different events coming + // from handleMethodCall. + // + // It is a `broadcast` because multiple controllers will connect to + // different stream views of this Controller. + final StreamController> _mapEventStreamController = + StreamController>.broadcast(); + + // Returns a filtered view of the events in the _controller, by mapId. + Stream> _events(int mapId) => _mapEventStreamController + .stream + .where((MapEvent event) => event.mapId == mapId); + + @override + Stream onCameraMoveStarted({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onCameraMove({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onCameraIdle({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onInfoWindowTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerDragStart({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerDrag({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onMarkerDragEnd({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onPolylineTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onPolygonTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onCircleTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onGroundOverlayTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onLongPress({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Stream onClusterTap({required int mapId}) { + return _events(mapId).whereType(); + } + + @override + Future updateMapConfiguration( + MapConfiguration configuration, { + required int mapId, + }) { + return _hostApi(mapId).updateMapConfiguration( + _platformMapConfigurationFromMapConfiguration(configuration), + ); + } + + @override + Future updateMapOptions( + Map optionsUpdate, { + required int mapId, + }) { + return _hostApi(mapId).updateMapConfiguration( + _platformMapConfigurationFromOptionsJson(optionsUpdate), + ); + } + + @override + Future updateMarkers( + MarkerUpdates markerUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateMarkers( + markerUpdates.markersToAdd.map(_platformMarkerFromMarker).toList(), + markerUpdates.markersToChange.map(_platformMarkerFromMarker).toList(), + markerUpdates.markerIdsToRemove.map((MarkerId id) => id.value).toList(), + ); + } + + @override + Future updatePolygons( + PolygonUpdates polygonUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updatePolygons( + polygonUpdates.polygonsToAdd.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonsToChange.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonIdsToRemove + .map((PolygonId id) => id.value) + .toList(), + ); + } + + @override + Future updatePolylines( + PolylineUpdates polylineUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updatePolylines( + polylineUpdates.polylinesToAdd + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylinesToChange + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylineIdsToRemove + .map((PolylineId id) => id.value) + .toList(), + ); + } + + @override + Future updateCircles( + CircleUpdates circleUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateCircles( + circleUpdates.circlesToAdd.map(_platformCircleFromCircle).toList(), + circleUpdates.circlesToChange.map(_platformCircleFromCircle).toList(), + circleUpdates.circleIdsToRemove.map((CircleId id) => id.value).toList(), + ); + } + + @override + Future updateHeatmaps( + HeatmapUpdates heatmapUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateHeatmaps( + heatmapUpdates.heatmapsToAdd.map(_platformHeatmapFromHeatmap).toList(), + heatmapUpdates.heatmapsToChange.map(_platformHeatmapFromHeatmap).toList(), + heatmapUpdates.heatmapIdsToRemove + .map((HeatmapId id) => id.value) + .toList(), + ); + } + + @override + Future updateTileOverlays({ + required Set newTileOverlays, + required int mapId, + }) { + final Map? currentTileOverlays = + _tileOverlays[mapId]; + final Set previousSet = currentTileOverlays != null + ? currentTileOverlays.values.toSet() + : {}; + final updates = _TileOverlayUpdates.from(previousSet, newTileOverlays); + _tileOverlays[mapId] = keyTileOverlayId(newTileOverlays); + return _hostApi(mapId).updateTileOverlays( + updates.tileOverlaysToAdd + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlaysToChange + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlayIdsToRemove + .map((TileOverlayId id) => id.value) + .toList(), + ); + } + + @override + Future updateClusterManagers( + ClusterManagerUpdates clusterManagerUpdates, { + required int mapId, + }) { + return _hostApi(mapId).updateClusterManagers( + clusterManagerUpdates.clusterManagersToAdd + .map(_platformClusterManagerFromClusterManager) + .toList(), + clusterManagerUpdates.clusterManagerIdsToRemove + .map((ClusterManagerId id) => id.value) + .toList(), + ); + } + + @override + Future updateGroundOverlays( + GroundOverlayUpdates groundOverlayUpdates, { + required int mapId, + }) { + assert( + groundOverlayUpdates.groundOverlaysToAdd.every( + (GroundOverlay groundOverlay) => + groundOverlay.position == null || groundOverlay.zoomLevel != null, + ), + 'On iOS zoom level must be set when position is set for ground overlays.', + ); + + return _hostApi(mapId).updateGroundOverlays( + groundOverlayUpdates.groundOverlaysToAdd + .map(_platformGroundOverlayFromGroundOverlay) + .toList(), + groundOverlayUpdates.groundOverlaysToChange + .map(_platformGroundOverlayFromGroundOverlay) + .toList(), + groundOverlayUpdates.groundOverlayIdsToRemove + .map((GroundOverlayId id) => id.value) + .toList(), + ); + } + + @override + Future clearTileCache( + TileOverlayId tileOverlayId, { + required int mapId, + }) { + return _hostApi(mapId).clearTileCache(tileOverlayId.value); + } + + @override + Future animateCamera(CameraUpdate cameraUpdate, {required int mapId}) { + return animateCameraWithConfiguration( + cameraUpdate, + const CameraUpdateAnimationConfiguration(), + mapId: mapId, + ); + } + + @override + Future animateCameraWithConfiguration( + CameraUpdate cameraUpdate, + CameraUpdateAnimationConfiguration configuration, { + required int mapId, + }) { + return _hostApi(mapId).animateCamera( + _platformCameraUpdateFromCameraUpdate(cameraUpdate), + configuration.duration?.inMilliseconds, + ); + } + + @override + Future moveCamera(CameraUpdate cameraUpdate, {required int mapId}) { + return _hostApi( + mapId, + ).moveCamera(_platformCameraUpdateFromCameraUpdate(cameraUpdate)); + } + + @override + Future setMapStyle(String? mapStyle, {required int mapId}) async { + final String? errorDescription = await _hostApi( + mapId, + ).setStyle(mapStyle ?? ''); + if (errorDescription != null) { + throw MapStyleException(errorDescription); + } + } + + @override + Future getVisibleRegion({required int mapId}) async { + return _latLngBoundsFromPlatformLatLngBounds( + await _hostApi(mapId).getVisibleRegion(), + ); + } + + @override + Future getScreenCoordinate( + LatLng latLng, { + required int mapId, + }) async { + return _screenCoordinateFromPlatformPoint( + await _hostApi( + mapId, + ).getScreenCoordinate(_platformLatLngFromLatLng(latLng)), + ); + } + + @override + Future getLatLng( + ScreenCoordinate screenCoordinate, { + required int mapId, + }) async { + return _latLngFromPlatformLatLng( + await _hostApi( + mapId, + ).getLatLng(_platformPointFromScreenCoordinate(screenCoordinate)), + ); + } + + @override + Future showMarkerInfoWindow(MarkerId markerId, {required int mapId}) { + return _hostApi(mapId).showInfoWindow(markerId.value); + } + + @override + Future hideMarkerInfoWindow(MarkerId markerId, {required int mapId}) { + return _hostApi(mapId).hideInfoWindow(markerId.value); + } + + @override + Future isMarkerInfoWindowShown( + MarkerId markerId, { + required int mapId, + }) { + return _hostApi(mapId).isInfoWindowShown(markerId.value); + } + + @override + Future getZoomLevel({required int mapId}) { + return _hostApi(mapId).getZoomLevel(); + } + + @override + Future takeSnapshot({required int mapId}) { + return _hostApi(mapId).takeSnapshot(); + } + + @override + Future getStyleError({required int mapId}) { + return _hostApi(mapId).getLastStyleError(); + } + + Widget _buildView( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required PlatformMapConfiguration mapConfiguration, + required MapWidgetConfiguration widgetConfiguration, + MapObjects mapObjects = const MapObjects(), + }) { + assert( + mapObjects.groundOverlays.every( + (GroundOverlay groundOverlay) => + groundOverlay.position == null || groundOverlay.zoomLevel != null, + ), + 'On iOS zoom level must be set when position is set for ground overlays.', + ); + + final creationParams = PlatformMapViewCreationParams( + initialCameraPosition: _platformCameraPositionFromCameraPosition( + widgetConfiguration.initialCameraPosition, + ), + mapConfiguration: mapConfiguration, + initialMarkers: mapObjects.markers + .map(_platformMarkerFromMarker) + .toList(), + initialPolygons: mapObjects.polygons + .map(_platformPolygonFromPolygon) + .toList(), + initialPolylines: mapObjects.polylines + .map(_platformPolylineFromPolyline) + .toList(), + initialCircles: mapObjects.circles + .map(_platformCircleFromCircle) + .toList(), + initialHeatmaps: mapObjects.heatmaps + .map(_platformHeatmapFromHeatmap) + .toList(), + initialTileOverlays: mapObjects.tileOverlays + .map(_platformTileOverlayFromTileOverlay) + .toList(), + initialClusterManagers: mapObjects.clusterManagers + .map(_platformClusterManagerFromClusterManager) + .toList(), + initialGroundOverlays: mapObjects.groundOverlays + .map(_platformGroundOverlayFromGroundOverlay) + .toList(), + ); + + return UiKitView( + viewType: 'plugins.flutter.dev/google_maps_ios', + onPlatformViewCreated: onPlatformViewCreated, + gestureRecognizers: widgetConfiguration.gestureRecognizers, + creationParams: creationParams, + creationParamsCodec: MapsApi.pigeonChannelCodec, + ); + } + + @override + Widget buildViewWithConfiguration( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required MapWidgetConfiguration widgetConfiguration, + MapConfiguration mapConfiguration = const MapConfiguration(), + MapObjects mapObjects = const MapObjects(), + }) { + return _buildView( + creationId, + onPlatformViewCreated, + widgetConfiguration: widgetConfiguration, + mapObjects: mapObjects, + mapConfiguration: _platformMapConfigurationFromMapConfiguration( + mapConfiguration, + ), + ); + } + + @override + Widget buildViewWithTextDirection( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required CameraPosition initialCameraPosition, + required TextDirection textDirection, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set>? gestureRecognizers, + Map mapOptions = const {}, + }) { + return _buildView( + creationId, + onPlatformViewCreated, + widgetConfiguration: MapWidgetConfiguration( + initialCameraPosition: initialCameraPosition, + textDirection: textDirection, + ), + mapObjects: MapObjects( + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + tileOverlays: tileOverlays, + ), + mapConfiguration: _platformMapConfigurationFromOptionsJson(mapOptions), + ); + } + + @override + Widget buildView( + int creationId, + PlatformViewCreatedCallback onPlatformViewCreated, { + required CameraPosition initialCameraPosition, + Set markers = const {}, + Set polygons = const {}, + Set polylines = const {}, + Set circles = const {}, + Set tileOverlays = const {}, + Set>? gestureRecognizers, + Map mapOptions = const {}, + }) { + return buildViewWithTextDirection( + creationId, + onPlatformViewCreated, + initialCameraPosition: initialCameraPosition, + textDirection: TextDirection.ltr, + markers: markers, + polygons: polygons, + polylines: polylines, + circles: circles, + tileOverlays: tileOverlays, + gestureRecognizers: gestureRecognizers, + mapOptions: mapOptions, + ); + } + + @override + @visibleForTesting + void enableDebugInspection() { + GoogleMapsInspectorPlatform.instance = GoogleMapsInspectorIOS( + (int mapId) => MapsInspectorApi(messageChannelSuffix: mapId.toString()), + ); + } + + /// Converts a Pigeon [PlatformCluster] to the corresponding [Cluster]. + static Cluster clusterFromPlatformCluster(PlatformCluster cluster) { + return Cluster( + ClusterManagerId(cluster.clusterManagerId), + cluster.markerIds.map((String markerId) => MarkerId(markerId)).toList(), + position: _latLngFromPlatformLatLng(cluster.position), + bounds: _latLngBoundsFromPlatformLatLngBounds(cluster.bounds), + ); + } + + static ScreenCoordinate _screenCoordinateFromPlatformPoint( + PlatformPoint point, + ) { + return ScreenCoordinate(x: point.x.round(), y: point.y.round()); + } + + static PlatformPoint _platformPointFromScreenCoordinate( + ScreenCoordinate coordinate, + ) { + return PlatformPoint( + x: coordinate.x.toDouble(), + y: coordinate.y.toDouble(), + ); + } + + static PlatformPoint _platformPointFromOffset(Offset offset) { + return PlatformPoint(x: offset.dx, y: offset.dy); + } + + static PlatformSize _platformSizeFromSize(Size size) { + return PlatformSize(width: size.width, height: size.height); + } + + static PlatformCircle _platformCircleFromCircle(Circle circle) { + return PlatformCircle( + consumeTapEvents: circle.consumeTapEvents, + fillColor: PlatformColor( + red: circle.fillColor.r, + green: circle.fillColor.g, + blue: circle.fillColor.b, + alpha: circle.fillColor.a, + ), + strokeColor: PlatformColor( + red: circle.strokeColor.r, + green: circle.strokeColor.g, + blue: circle.strokeColor.b, + alpha: circle.strokeColor.a, + ), + visible: circle.visible, + strokeWidth: circle.strokeWidth, + zIndex: circle.zIndex.toDouble(), + center: _platformLatLngFromLatLng(circle.center), + radius: circle.radius, + circleId: circle.circleId.value, + ); + } + + static PlatformHeatmap _platformHeatmapFromHeatmap(Heatmap heatmap) { + final HeatmapGradient? gradient = heatmap.gradient; + return PlatformHeatmap( + heatmapId: heatmap.heatmapId.value, + data: heatmap.data + .map(_platformWeightedLatLngFromWeightedLatLng) + .toList(), + gradient: _platformHeatmapGradientFromHeatmapGradient(gradient), + opacity: heatmap.opacity, + radius: heatmap.radius.radius, + minimumZoomIntensity: heatmap.minimumZoomIntensity, + maximumZoomIntensity: heatmap.maximumZoomIntensity, + ); + } + + static PlatformHeatmapGradient? _platformHeatmapGradientFromHeatmapGradient( + HeatmapGradient? gradient, + ) { + if (gradient == null) { + return null; + } + return PlatformHeatmapGradient( + colors: gradient.colors + .map( + (HeatmapGradientColor c) => PlatformColor( + red: c.color.r, + green: c.color.g, + blue: c.color.b, + alpha: c.color.a, + ), + ) + .toList(), + startPoints: gradient.colors + .map((HeatmapGradientColor c) => c.startPoint) + .toList(), + colorMapSize: gradient.colorMapSize, + ); + } + + static PlatformInfoWindow _platformInfoWindowFromInfoWindow( + InfoWindow window, + ) { + return PlatformInfoWindow( + title: window.title, + snippet: window.snippet, + anchor: _platformPointFromOffset(window.anchor), + ); + } + + static PlatformMarker _platformMarkerFromMarker(Marker marker) { + return PlatformMarker( + alpha: marker.alpha, + anchor: _platformPointFromOffset(marker.anchor), + consumeTapEvents: marker.consumeTapEvents, + draggable: marker.draggable, + flat: marker.flat, + icon: platformBitmapFromBitmapDescriptor(marker.icon), + infoWindow: _platformInfoWindowFromInfoWindow(marker.infoWindow), + position: _platformLatLngFromLatLng(marker.position), + rotation: marker.rotation, + visible: marker.visible, + zIndex: marker.zIndexInt, + markerId: marker.markerId.value, + clusterManagerId: marker.clusterManagerId?.value, + ); + } + + static PlatformGroundOverlay _platformGroundOverlayFromGroundOverlay( + GroundOverlay groundOverlay, + ) { + return PlatformGroundOverlay( + groundOverlayId: groundOverlay.groundOverlayId.value, + anchor: groundOverlay.anchor != null + ? _platformPointFromOffset(groundOverlay.anchor!) + : null, + image: platformBitmapFromBitmapDescriptor(groundOverlay.image), + position: groundOverlay.position != null + ? _platformLatLngFromLatLng(groundOverlay.position!) + : null, + bounds: _platformLatLngBoundsFromLatLngBounds(groundOverlay.bounds), + visible: groundOverlay.visible, + zIndex: groundOverlay.zIndex, + bearing: groundOverlay.bearing, + clickable: groundOverlay.clickable, + transparency: groundOverlay.transparency, + zoomLevel: groundOverlay.zoomLevel, + ); + } + + static PlatformPolygon _platformPolygonFromPolygon(Polygon polygon) { + final List points = polygon.points + .map(_platformLatLngFromLatLng) + .toList(); + final List> holes = polygon.holes.map(( + List hole, + ) { + return hole.map(_platformLatLngFromLatLng).toList(); + }).toList(); + return PlatformPolygon( + polygonId: polygon.polygonId.value, + fillColor: PlatformColor( + red: polygon.fillColor.r, + green: polygon.fillColor.g, + blue: polygon.fillColor.b, + alpha: polygon.fillColor.a, + ), + geodesic: polygon.geodesic, + consumesTapEvents: polygon.consumeTapEvents, + points: points, + holes: holes, + strokeColor: PlatformColor( + red: polygon.strokeColor.r, + green: polygon.strokeColor.g, + blue: polygon.strokeColor.b, + alpha: polygon.strokeColor.a, + ), + strokeWidth: polygon.strokeWidth, + zIndex: polygon.zIndex, + visible: polygon.visible, + ); + } + + static PlatformPolyline _platformPolylineFromPolyline(Polyline polyline) { + final List points = polyline.points + .map(_platformLatLngFromLatLng) + .toList(); + final List pattern = polyline.patterns + .map(platformPatternItemFromPatternItem) + .toList(); + return PlatformPolyline( + polylineId: polyline.polylineId.value, + consumesTapEvents: polyline.consumeTapEvents, + color: PlatformColor( + red: polyline.color.r, + green: polyline.color.g, + blue: polyline.color.b, + alpha: polyline.color.a, + ), + geodesic: polyline.geodesic, + visible: polyline.visible, + width: polyline.width, + zIndex: polyline.zIndex, + points: points, + jointType: platformJointTypeFromJointType(polyline.jointType), + patterns: pattern, + ); + } + + static PlatformTileOverlay _platformTileOverlayFromTileOverlay( + TileOverlay tileOverlay, + ) { + return PlatformTileOverlay( + tileOverlayId: tileOverlay.tileOverlayId.value, + fadeIn: tileOverlay.fadeIn, + transparency: tileOverlay.transparency, + zIndex: tileOverlay.zIndex, + visible: tileOverlay.visible, + tileSize: tileOverlay.tileSize, + ); + } + + static PlatformClusterManager _platformClusterManagerFromClusterManager( + ClusterManager clusterManager, + ) { + return PlatformClusterManager( + identifier: clusterManager.clusterManagerId.value, + ); + } + + static PlatformCameraUpdate _platformCameraUpdateFromCameraUpdate( + CameraUpdate update, + ) { + switch (update.updateType) { + case CameraUpdateType.newCameraPosition: + update as CameraUpdateNewCameraPosition; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewCameraPosition( + cameraPosition: _platformCameraPositionFromCameraPosition( + update.cameraPosition, + ), + ), + ); + case CameraUpdateType.newLatLng: + update as CameraUpdateNewLatLng; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewLatLng( + latLng: _platformLatLngFromLatLng(update.latLng), + ), + ); + case CameraUpdateType.newLatLngZoom: + update as CameraUpdateNewLatLngZoom; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewLatLngZoom( + latLng: _platformLatLngFromLatLng(update.latLng), + zoom: update.zoom, + ), + ); + case CameraUpdateType.newLatLngBounds: + update as CameraUpdateNewLatLngBounds; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateNewLatLngBounds( + bounds: _platformLatLngBoundsFromLatLngBounds(update.bounds)!, + padding: update.padding, + ), + ); + case CameraUpdateType.zoomTo: + update as CameraUpdateZoomTo; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoomTo(zoom: update.zoom), + ); + case CameraUpdateType.zoomBy: + update as CameraUpdateZoomBy; + final Offset? focus = update.focus; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoomBy( + amount: update.amount, + focus: focus == null ? null : _platformPointFromOffset(focus), + ), + ); + case CameraUpdateType.zoomIn: + update as CameraUpdateZoomIn; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoom(out: false), + ); + case CameraUpdateType.zoomOut: + update as CameraUpdateZoomOut; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateZoom(out: true), + ); + case CameraUpdateType.scrollBy: + update as CameraUpdateScrollBy; + return PlatformCameraUpdate( + cameraUpdate: PlatformCameraUpdateScrollBy( + dx: update.dx, + dy: update.dy, + ), + ); + } + } + + /// Converts [MapBitmapScaling] from platform interface to [PlatformMapBitmapScaling] Pigeon. + @visibleForTesting + static PlatformMapBitmapScaling platformMapBitmapScalingFromScaling( + MapBitmapScaling scaling, + ) { + switch (scaling) { + case MapBitmapScaling.auto: + return PlatformMapBitmapScaling.auto; + case MapBitmapScaling.none: + return PlatformMapBitmapScaling.none; + } + + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformMapBitmapScaling.auto; + } + + /// Converts [BitmapDescriptor] from platform interface to [PlatformBitmap] pigeon. + @visibleForTesting + static PlatformBitmap platformBitmapFromBitmapDescriptor( + BitmapDescriptor bitmap, + ) { + switch (bitmap) { + case final DefaultMarker marker: + return PlatformBitmap( + bitmap: PlatformBitmapDefaultMarker(hue: marker.hue?.toDouble()), + ); + // Clients may still use this deprecated format, so it must be supported. + // ignore: deprecated_member_use + case final BytesBitmap bytes: + final Size? size = bytes.size; + return PlatformBitmap( + bitmap: PlatformBitmapBytes( + byteData: bytes.byteData, + size: (size == null) ? null : _platformSizeFromSize(size), + ), + ); + case final AssetBitmap asset: + return PlatformBitmap( + bitmap: PlatformBitmapAsset(name: asset.name, pkg: asset.package), + ); + // Clients may still use this deprecated format, so it must be supported. + // ignore: deprecated_member_use + case final AssetImageBitmap asset: + final Size? size = asset.size; + return PlatformBitmap( + bitmap: PlatformBitmapAssetImage( + name: asset.name, + scale: asset.scale, + size: (size == null) ? null : _platformSizeFromSize(size), + ), + ); + case final AssetMapBitmap asset: + return PlatformBitmap( + bitmap: PlatformBitmapAssetMap( + assetName: asset.assetName, + bitmapScaling: platformMapBitmapScalingFromScaling( + asset.bitmapScaling, + ), + imagePixelRatio: asset.imagePixelRatio, + width: asset.width, + height: asset.height, + ), + ); + case final BytesMapBitmap bytes: + return PlatformBitmap( + bitmap: PlatformBitmapBytesMap( + byteData: bytes.byteData, + bitmapScaling: platformMapBitmapScalingFromScaling( + bytes.bitmapScaling, + ), + imagePixelRatio: bytes.imagePixelRatio, + width: bytes.width, + height: bytes.height, + ), + ); + default: + throw ArgumentError( + 'Unrecognized type of bitmap ${bitmap.runtimeType}', + 'bitmap', + ); + } + } +} + +/// Callback handler for map events from the platform host. +@visibleForTesting +class HostMapMessageHandler implements MapsCallbackApi { + /// Creates a new handler that listens for events from map [mapId], and + /// broadcasts them to [streamController]. + HostMapMessageHandler( + this.mapId, + this.streamController, { + required this.tileOverlayProvider, + }) { + MapsCallbackApi.setUp(this, messageChannelSuffix: mapId.toString()); + } + + /// Removes the handler for native messages. + void dispose() { + MapsCallbackApi.setUp(null, messageChannelSuffix: mapId.toString()); + } + + /// The map ID this handler listens for events from. + final int mapId; + + /// The controller used to broadcast map events coming from the + /// host platform. + final StreamController> streamController; + + /// The callback to get a tile overlay for the corresponding map. + final TileOverlay? Function(TileOverlayId tileOverlayId) tileOverlayProvider; + + @override + Future getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ) async { + final TileOverlay? tileOverlay = tileOverlayProvider( + TileOverlayId(tileOverlayId), + ); + final TileProvider? tileProvider = tileOverlay?.tileProvider; + final Tile tile = tileProvider == null + ? TileProvider.noTile + : await tileProvider.getTile( + location.x.round(), + location.y.round(), + zoom, + ); + return _platformTileFromTile(tile); + } + + @override + void onCameraIdle() { + streamController.add(CameraIdleEvent(mapId)); + } + + @override + void onCameraMove(PlatformCameraPosition cameraPosition) { + streamController.add( + CameraMoveEvent( + mapId, + CameraPosition( + target: _latLngFromPlatformLatLng(cameraPosition.target), + bearing: cameraPosition.bearing, + tilt: cameraPosition.tilt, + zoom: cameraPosition.zoom, + ), + ), + ); + } + + @override + void onCameraMoveStarted() { + streamController.add(CameraMoveStartedEvent(mapId)); + } + + @override + void onCircleTap(String circleId) { + streamController.add(CircleTapEvent(mapId, CircleId(circleId))); + } + + @override + void onClusterTap(PlatformCluster cluster) { + streamController.add( + ClusterTapEvent( + mapId, + GoogleMapsFlutterIOS.clusterFromPlatformCluster(cluster), + ), + ); + } + + @override + void onInfoWindowTap(String markerId) { + streamController.add(InfoWindowTapEvent(mapId, MarkerId(markerId))); + } + + @override + void onLongPress(PlatformLatLng position) { + streamController.add( + MapLongPressEvent(mapId, _latLngFromPlatformLatLng(position)), + ); + } + + @override + void onMarkerDrag(String markerId, PlatformLatLng position) { + streamController.add( + MarkerDragEvent( + mapId, + _latLngFromPlatformLatLng(position), + MarkerId(markerId), + ), + ); + } + + @override + void onMarkerDragStart(String markerId, PlatformLatLng position) { + streamController.add( + MarkerDragStartEvent( + mapId, + _latLngFromPlatformLatLng(position), + MarkerId(markerId), + ), + ); + } + + @override + void onMarkerDragEnd(String markerId, PlatformLatLng position) { + streamController.add( + MarkerDragEndEvent( + mapId, + _latLngFromPlatformLatLng(position), + MarkerId(markerId), + ), + ); + } + + @override + void onMarkerTap(String markerId) { + streamController.add(MarkerTapEvent(mapId, MarkerId(markerId))); + } + + @override + void onPolygonTap(String polygonId) { + streamController.add(PolygonTapEvent(mapId, PolygonId(polygonId))); + } + + @override + void onPolylineTap(String polylineId) { + streamController.add(PolylineTapEvent(mapId, PolylineId(polylineId))); + } + + @override + void onGroundOverlayTap(String groundOverlayId) { + streamController.add( + GroundOverlayTapEvent(mapId, GroundOverlayId(groundOverlayId)), + ); + } + + @override + void onTap(PlatformLatLng position) { + streamController.add( + MapTapEvent(mapId, _latLngFromPlatformLatLng(position)), + ); + } +} + +LatLng _latLngFromPlatformLatLng(PlatformLatLng latLng) { + return LatLng(latLng.latitude, latLng.longitude); +} + +LatLngBounds _latLngBoundsFromPlatformLatLngBounds( + PlatformLatLngBounds bounds, +) { + return LatLngBounds( + southwest: _latLngFromPlatformLatLng(bounds.southwest), + northeast: _latLngFromPlatformLatLng(bounds.northeast), + ); +} + +PlatformLatLng _platformLatLngFromLatLng(LatLng latLng) { + return PlatformLatLng(latitude: latLng.latitude, longitude: latLng.longitude); +} + +PlatformLatLngBounds? _platformLatLngBoundsFromLatLngBounds( + LatLngBounds? bounds, +) { + if (bounds == null) { + return null; + } + return PlatformLatLngBounds( + northeast: _platformLatLngFromLatLng(bounds.northeast), + southwest: _platformLatLngFromLatLng(bounds.southwest), + ); +} + +PlatformWeightedLatLng _platformWeightedLatLngFromWeightedLatLng( + WeightedLatLng weightedLatLng, +) { + return PlatformWeightedLatLng( + point: _platformLatLngFromLatLng(weightedLatLng.point), + weight: weightedLatLng.weight, + ); +} + +PlatformCameraTargetBounds? _platformCameraTargetBoundsFromCameraTargetBounds( + CameraTargetBounds? bounds, +) { + return bounds == null + ? null + : PlatformCameraTargetBounds( + bounds: _platformLatLngBoundsFromLatLngBounds(bounds.bounds), + ); +} + +PlatformTile _platformTileFromTile(Tile tile) { + return PlatformTile(width: tile.width, height: tile.height, data: tile.data); +} + +PlatformMapType? _platformMapTypeFromMapType(MapType? type) { + switch (type) { + case null: + return null; + case MapType.none: + return PlatformMapType.none; + case MapType.normal: + return PlatformMapType.normal; + case MapType.satellite: + return PlatformMapType.satellite; + case MapType.terrain: + return PlatformMapType.terrain; + case MapType.hybrid: + return PlatformMapType.hybrid; + } + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformMapType.normal; +} + +PlatformZoomRange? _platformZoomRangeFromMinMaxZoomPreference( + MinMaxZoomPreference? zoomPref, +) { + return zoomPref == null + ? null + : PlatformZoomRange(min: zoomPref.minZoom, max: zoomPref.maxZoom); +} + +PlatformEdgeInsets? _platformEdgeInsetsFromEdgeInsets(EdgeInsets? insets) { + return insets == null + ? null + : PlatformEdgeInsets( + top: insets.top, + bottom: insets.bottom, + left: insets.left, + right: insets.right, + ); +} + +PlatformMapConfiguration _platformMapConfigurationFromMapConfiguration( + MapConfiguration config, +) { + return PlatformMapConfiguration( + compassEnabled: config.compassEnabled, + cameraTargetBounds: _platformCameraTargetBoundsFromCameraTargetBounds( + config.cameraTargetBounds, + ), + mapType: _platformMapTypeFromMapType(config.mapType), + minMaxZoomPreference: _platformZoomRangeFromMinMaxZoomPreference( + config.minMaxZoomPreference, + ), + rotateGesturesEnabled: config.rotateGesturesEnabled, + scrollGesturesEnabled: config.scrollGesturesEnabled, + tiltGesturesEnabled: config.tiltGesturesEnabled, + trackCameraPosition: config.trackCameraPosition, + zoomGesturesEnabled: config.zoomGesturesEnabled, + myLocationEnabled: config.myLocationEnabled, + myLocationButtonEnabled: config.myLocationButtonEnabled, + padding: _platformEdgeInsetsFromEdgeInsets(config.padding), + indoorViewEnabled: config.indoorViewEnabled, + trafficEnabled: config.trafficEnabled, + buildingsEnabled: config.buildingsEnabled, + mapId: config.mapId, + style: config.style, + ); +} + +// For supporting the deprecated updateMapOptions API. +PlatformMapConfiguration _platformMapConfigurationFromOptionsJson( + Map options, +) { + // All of these hard-coded values and structures come from + // google_maps_flutter_platform_interface/lib/src/types/utils/map_configuration_serialization.dart + // to support this legacy API that relied on cross-package magic strings. + final List? padding = (options['padding'] as List?) + ?.cast(); + final mapType = options['mapType'] as int?; + return PlatformMapConfiguration( + compassEnabled: options['compassEnabled'] as bool?, + cameraTargetBounds: _platformCameraTargetBoundsFromCameraTargetBoundsJson( + options['cameraTargetBounds'], + ), + mapType: mapType == null ? null : _platformMapTypeFromMapTypeIndex(mapType), + minMaxZoomPreference: _platformZoomRangeFromMinMaxZoomPreferenceJson( + options['minMaxZoomPreference'], + ), + rotateGesturesEnabled: options['rotateGesturesEnabled'] as bool?, + scrollGesturesEnabled: options['scrollGesturesEnabled'] as bool?, + tiltGesturesEnabled: options['tiltGesturesEnabled'] as bool?, + trackCameraPosition: options['trackCameraPosition'] as bool?, + zoomGesturesEnabled: options['zoomGesturesEnabled'] as bool?, + myLocationEnabled: options['myLocationEnabled'] as bool?, + myLocationButtonEnabled: options['myLocationButtonEnabled'] as bool?, + padding: padding == null + ? null + : PlatformEdgeInsets( + top: padding[0], + left: padding[1], + bottom: padding[2], + right: padding[3], + ), + indoorViewEnabled: options['indoorEnabled'] as bool?, + trafficEnabled: options['trafficEnabled'] as bool?, + buildingsEnabled: options['buildingsEnabled'] as bool?, + mapId: options['cloudMapId'] as String?, + style: options['style'] as String?, + ); +} + +PlatformCameraPosition _platformCameraPositionFromCameraPosition( + CameraPosition position, +) { + return PlatformCameraPosition( + bearing: position.bearing, + target: _platformLatLngFromLatLng(position.target), + tilt: position.tilt, + zoom: position.zoom, + ); +} + +PlatformMapType _platformMapTypeFromMapTypeIndex(int index) { + // This is inherently fragile, but see comment in updateMapOptions. + return switch (index) { + 0 => PlatformMapType.none, + 1 => PlatformMapType.normal, + 2 => PlatformMapType.satellite, + 3 => PlatformMapType.terrain, + 4 => PlatformMapType.hybrid, + // For a new, unsupported type, just use normal. + _ => PlatformMapType.normal, + }; +} + +PlatformLatLng _platformLatLngFromLatLngJson(Object latLngJson) { + // See `LatLng.toJson`. + final List list = (latLngJson as List).cast(); + return PlatformLatLng(latitude: list[0], longitude: list[1]); +} + +PlatformLatLngBounds? _platformLatLngBoundsFromLatLngBoundsJson( + Object? boundsJson, +) { + if (boundsJson == null) { + return null; + } + // See `LatLngBounds.toJson`. + final List boundsList = (boundsJson as List).cast(); + return PlatformLatLngBounds( + southwest: _platformLatLngFromLatLngJson(boundsList[0]), + northeast: _platformLatLngFromLatLngJson(boundsList[1]), + ); +} + +PlatformCameraTargetBounds? +_platformCameraTargetBoundsFromCameraTargetBoundsJson(Object? targetJson) { + if (targetJson == null) { + return null; + } + // See `CameraTargetBounds.toJson`. + return PlatformCameraTargetBounds( + bounds: _platformLatLngBoundsFromLatLngBoundsJson( + (targetJson as List)[0], + ), + ); +} + +PlatformZoomRange? _platformZoomRangeFromMinMaxZoomPreferenceJson( + Object? zoomPrefsJson, +) { + if (zoomPrefsJson == null) { + return null; + } + // See `MinMaxZoomPreference.toJson`. + final List minMaxZoom = (zoomPrefsJson as List) + .cast(); + return PlatformZoomRange(min: minMaxZoom[0], max: minMaxZoom[1]); +} + +/// Converts platform interface's JointType to Pigeon's PlatformJointType. +@visibleForTesting +PlatformJointType platformJointTypeFromJointType(JointType jointType) { + switch (jointType) { + case JointType.mitered: + return PlatformJointType.mitered; + case JointType.bevel: + return PlatformJointType.bevel; + case JointType.round: + return PlatformJointType.round; + } + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformJointType.mitered; +} + +/// Converts a PatternItem to Pigeon's PlatformPatternItem for PlatformPolyline +/// pattern member. +@visibleForTesting +PlatformPatternItem platformPatternItemFromPatternItem(PatternItem item) { + switch (item.type) { + case PatternItemType.dot: + return PlatformPatternItem(type: PlatformPatternItemType.dot); + case PatternItemType.dash: + final double length = (item as VariableLengthPatternItem).length; + return PlatformPatternItem( + type: PlatformPatternItemType.dash, + length: length, + ); + case PatternItemType.gap: + final double length = (item as VariableLengthPatternItem).length; + return PlatformPatternItem( + type: PlatformPatternItemType.gap, + length: length, + ); + } + + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformPatternItem(type: PlatformPatternItemType.dot); +} + +/// Update specification for a set of [TileOverlay]s. +// TODO(stuartmorgan): Fix the missing export of this class in the platform +// interface, and remove this copy. +class _TileOverlayUpdates extends MapsObjectUpdates { + /// Computes [TileOverlayUpdates] given previous and current [TileOverlay]s. + _TileOverlayUpdates.from(super.previous, super.current) + : super.from(objectName: 'tileOverlay'); + + /// Set of TileOverlays to be added in this update. + Set get tileOverlaysToAdd => objectsToAdd; + + /// Set of TileOverlayIds to be removed in this update. + Set get tileOverlayIdsToRemove => + objectIdsToRemove.cast(); + + /// Set of TileOverlays to be changed in this update. + Set get tileOverlaysToChange => objectsToChange; +} 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 new file mode 100644 index 000000000000..bd54d5f62322 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/src/messages.g.dart @@ -0,0 +1,4311 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// Autogenerated from Pigeon (v26.1.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, omit_obvious_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers + +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +PlatformException _createConnectionError(String channelName) { + return PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); +} + +List wrapResponse({ + Object? result, + PlatformException? error, + bool empty = false, +}) { + if (empty) { + return []; + } + if (error == null) { + return [result]; + } + return [error.code, error.message, error.details]; +} + +bool _deepEquals(Object? a, Object? b) { + if (a is List && b is List) { + return a.length == b.length && + a.indexed.every( + ((int, dynamic) item) => _deepEquals(item.$2, b[item.$1]), + ); + } + if (a is Map && b is Map) { + return a.length == b.length && + a.entries.every( + (MapEntry entry) => + (b as Map).containsKey(entry.key) && + _deepEquals(entry.value, b[entry.key]), + ); + } + return a == b; +} + +/// Pigeon equivalent of MapType +enum PlatformMapType { none, normal, satellite, terrain, hybrid } + +/// Join types for polyline joints. +enum PlatformJointType { mitered, bevel, round } + +/// Enumeration of possible types for PatternItem. +enum PlatformPatternItemType { dot, dash, gap } + +/// Pigeon equivalent of [MapBitmapScaling]. +enum PlatformMapBitmapScaling { auto, none } + +/// Pigeon representatation of a CameraPosition. +class PlatformCameraPosition { + PlatformCameraPosition({ + required this.bearing, + required this.target, + required this.tilt, + required this.zoom, + }); + + double bearing; + + PlatformLatLng target; + + double tilt; + + double zoom; + + List _toList() { + return [bearing, target, tilt, zoom]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraPosition decode(Object result) { + result as List; + return PlatformCameraPosition( + bearing: result[0]! as double, + target: result[1]! as PlatformLatLng, + tilt: result[2]! as double, + zoom: result[3]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraPosition || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate({required this.cameraUpdate}); + + /// This Object must be one of the classes below prefixed with + /// PlatformCameraUpdate. Each such class represents a different type of + /// camera update, and each holds a different set of data, preventing the + /// use of a single unified class. + Object cameraUpdate; + + List _toList() { + return [cameraUpdate]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdate decode(Object result) { + result as List; + return PlatformCameraUpdate(cameraUpdate: result[0]!); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdate || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewCameraPosition +class PlatformCameraUpdateNewCameraPosition { + PlatformCameraUpdateNewCameraPosition({required this.cameraPosition}); + + PlatformCameraPosition cameraPosition; + + List _toList() { + return [cameraPosition]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewCameraPosition decode(Object result) { + result as List; + return PlatformCameraUpdateNewCameraPosition( + cameraPosition: result[0]! as PlatformCameraPosition, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewCameraPosition || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewLatLng +class PlatformCameraUpdateNewLatLng { + PlatformCameraUpdateNewLatLng({required this.latLng}); + + PlatformLatLng latLng; + + List _toList() { + return [latLng]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewLatLng decode(Object result) { + result as List; + return PlatformCameraUpdateNewLatLng(latLng: result[0]! as PlatformLatLng); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewLatLng || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewLatLngBounds +class PlatformCameraUpdateNewLatLngBounds { + PlatformCameraUpdateNewLatLngBounds({ + required this.bounds, + required this.padding, + }); + + PlatformLatLngBounds bounds; + + double padding; + + List _toList() { + return [bounds, padding]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewLatLngBounds decode(Object result) { + result as List; + return PlatformCameraUpdateNewLatLngBounds( + bounds: result[0]! as PlatformLatLngBounds, + padding: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewLatLngBounds || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of NewLatLngZoom +class PlatformCameraUpdateNewLatLngZoom { + PlatformCameraUpdateNewLatLngZoom({required this.latLng, required this.zoom}); + + PlatformLatLng latLng; + + double zoom; + + List _toList() { + return [latLng, zoom]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateNewLatLngZoom decode(Object result) { + result as List; + return PlatformCameraUpdateNewLatLngZoom( + latLng: result[0]! as PlatformLatLng, + zoom: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateNewLatLngZoom || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ScrollBy +class PlatformCameraUpdateScrollBy { + PlatformCameraUpdateScrollBy({required this.dx, required this.dy}); + + double dx; + + double dy; + + List _toList() { + return [dx, dy]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateScrollBy decode(Object result) { + result as List; + return PlatformCameraUpdateScrollBy( + dx: result[0]! as double, + dy: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateScrollBy || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ZoomBy +class PlatformCameraUpdateZoomBy { + PlatformCameraUpdateZoomBy({required this.amount, this.focus}); + + double amount; + + PlatformPoint? focus; + + List _toList() { + return [amount, focus]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateZoomBy decode(Object result) { + result as List; + return PlatformCameraUpdateZoomBy( + amount: result[0]! as double, + focus: result[1] as PlatformPoint?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateZoomBy || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ZoomIn/ZoomOut +class PlatformCameraUpdateZoom { + PlatformCameraUpdateZoom({required this.out}); + + bool out; + + List _toList() { + return [out]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateZoom decode(Object result) { + result as List; + return PlatformCameraUpdateZoom(out: result[0]! as bool); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateZoom || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of ZoomTo +class PlatformCameraUpdateZoomTo { + PlatformCameraUpdateZoomTo({required this.zoom}); + + double zoom; + + List _toList() { + return [zoom]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraUpdateZoomTo decode(Object result) { + result as List; + return PlatformCameraUpdateZoomTo(zoom: result[0]! as double); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraUpdateZoomTo || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle({ + this.consumeTapEvents = false, + required this.fillColor, + required this.strokeColor, + this.visible = true, + this.strokeWidth = 10, + this.zIndex = 0.0, + required this.center, + this.radius = 0, + required this.circleId, + }); + + bool consumeTapEvents; + + PlatformColor fillColor; + + PlatformColor strokeColor; + + bool visible; + + int strokeWidth; + + double zIndex; + + PlatformLatLng center; + + double radius; + + String circleId; + + List _toList() { + return [ + consumeTapEvents, + fillColor, + strokeColor, + visible, + strokeWidth, + zIndex, + center, + radius, + circleId, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformCircle decode(Object result) { + result as List; + return PlatformCircle( + consumeTapEvents: result[0]! as bool, + fillColor: result[1]! as PlatformColor, + strokeColor: result[2]! as PlatformColor, + visible: result[3]! as bool, + strokeWidth: result[4]! as int, + zIndex: result[5]! as double, + center: result[6]! as PlatformLatLng, + radius: result[7]! as double, + circleId: result[8]! as String, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCircle || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Heatmap class. +class PlatformHeatmap { + PlatformHeatmap({ + required this.heatmapId, + required this.data, + this.gradient, + required this.opacity, + required this.radius, + required this.minimumZoomIntensity, + required this.maximumZoomIntensity, + }); + + String heatmapId; + + List data; + + PlatformHeatmapGradient? gradient; + + double opacity; + + int radius; + + int minimumZoomIntensity; + + int maximumZoomIntensity; + + List _toList() { + return [ + heatmapId, + data, + gradient, + opacity, + radius, + minimumZoomIntensity, + maximumZoomIntensity, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformHeatmap decode(Object result) { + result as List; + return PlatformHeatmap( + heatmapId: result[0]! as String, + data: (result[1] as List?)!.cast(), + gradient: result[2] as PlatformHeatmapGradient?, + opacity: result[3]! as double, + radius: result[4]! as int, + minimumZoomIntensity: result[5]! as int, + maximumZoomIntensity: result[6]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformHeatmap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the HeatmapGradient class. +/// +/// The GMUGradient structure is slightly different from HeatmapGradient, so +/// this matches the iOS API so that conversion can be done on the Dart side +/// where the structures are easier to work with. +class PlatformHeatmapGradient { + PlatformHeatmapGradient({ + required this.colors, + required this.startPoints, + required this.colorMapSize, + }); + + List colors; + + List startPoints; + + int colorMapSize; + + List _toList() { + return [colors, startPoints, colorMapSize]; + } + + Object encode() { + return _toList(); + } + + static PlatformHeatmapGradient decode(Object result) { + result as List; + return PlatformHeatmapGradient( + colors: (result[0] as List?)!.cast(), + startPoints: (result[1] as List?)!.cast(), + colorMapSize: result[2]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformHeatmapGradient || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the WeightedLatLng class. +class PlatformWeightedLatLng { + PlatformWeightedLatLng({required this.point, required this.weight}); + + PlatformLatLng point; + + double weight; + + List _toList() { + return [point, weight]; + } + + Object encode() { + return _toList(); + } + + static PlatformWeightedLatLng decode(Object result) { + result as List; + return PlatformWeightedLatLng( + point: result[0]! as PlatformLatLng, + weight: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformWeightedLatLng || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the InfoWindow class. +class PlatformInfoWindow { + PlatformInfoWindow({this.title, this.snippet, required this.anchor}); + + String? title; + + String? snippet; + + PlatformPoint anchor; + + List _toList() { + return [title, snippet, anchor]; + } + + Object encode() { + return _toList(); + } + + static PlatformInfoWindow decode(Object result) { + result as List; + return PlatformInfoWindow( + title: result[0] as String?, + snippet: result[1] as String?, + anchor: result[2]! as PlatformPoint, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformInfoWindow || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of Cluster. +class PlatformCluster { + PlatformCluster({ + required this.clusterManagerId, + required this.position, + required this.bounds, + required this.markerIds, + }); + + String clusterManagerId; + + PlatformLatLng position; + + PlatformLatLngBounds bounds; + + List markerIds; + + List _toList() { + return [clusterManagerId, position, bounds, markerIds]; + } + + Object encode() { + return _toList(); + } + + static PlatformCluster decode(Object result) { + result as List; + return PlatformCluster( + clusterManagerId: result[0]! as String, + position: result[1]! as PlatformLatLng, + bounds: result[2]! as PlatformLatLngBounds, + markerIds: (result[3] as List?)!.cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCluster || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({required this.identifier}); + + String identifier; + + List _toList() { + return [identifier]; + } + + Object encode() { + return _toList(); + } + + static PlatformClusterManager decode(Object result) { + result as List; + return PlatformClusterManager(identifier: result[0]! as String); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformClusterManager || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker({ + this.alpha = 1.0, + required this.anchor, + this.consumeTapEvents = false, + this.draggable = false, + this.flat = false, + required this.icon, + required this.infoWindow, + required this.position, + this.rotation = 0.0, + this.visible = true, + this.zIndex = 0, + required this.markerId, + this.clusterManagerId, + }); + + double alpha; + + PlatformPoint anchor; + + bool consumeTapEvents; + + bool draggable; + + bool flat; + + PlatformBitmap icon; + + PlatformInfoWindow infoWindow; + + PlatformLatLng position; + + double rotation; + + bool visible; + + int zIndex; + + String markerId; + + String? clusterManagerId; + + List _toList() { + return [ + alpha, + anchor, + consumeTapEvents, + draggable, + flat, + icon, + infoWindow, + position, + rotation, + visible, + zIndex, + markerId, + clusterManagerId, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformMarker decode(Object result) { + result as List; + return PlatformMarker( + alpha: result[0]! as double, + anchor: result[1]! as PlatformPoint, + consumeTapEvents: result[2]! as bool, + draggable: result[3]! as bool, + flat: result[4]! as bool, + icon: result[5]! as PlatformBitmap, + infoWindow: result[6]! as PlatformInfoWindow, + position: result[7]! as PlatformLatLng, + rotation: result[8]! as double, + visible: result[9]! as bool, + zIndex: result[10]! as int, + markerId: result[11]! as String, + clusterManagerId: result[12] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformMarker || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon({ + required this.polygonId, + required this.consumesTapEvents, + required this.fillColor, + required this.geodesic, + required this.points, + required this.holes, + required this.visible, + required this.strokeColor, + required this.strokeWidth, + required this.zIndex, + }); + + String polygonId; + + bool consumesTapEvents; + + PlatformColor fillColor; + + bool geodesic; + + List points; + + List> holes; + + bool visible; + + PlatformColor strokeColor; + + int strokeWidth; + + int zIndex; + + List _toList() { + return [ + polygonId, + consumesTapEvents, + fillColor, + geodesic, + points, + holes, + visible, + strokeColor, + strokeWidth, + zIndex, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformPolygon decode(Object result) { + result as List; + return PlatformPolygon( + polygonId: result[0]! as String, + consumesTapEvents: result[1]! as bool, + fillColor: result[2]! as PlatformColor, + geodesic: result[3]! as bool, + points: (result[4] as List?)!.cast(), + holes: (result[5] as List?)!.cast>(), + visible: result[6]! as bool, + strokeColor: result[7]! as PlatformColor, + strokeWidth: result[8]! as int, + zIndex: result[9]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPolygon || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline({ + required this.polylineId, + required this.consumesTapEvents, + required this.color, + required this.geodesic, + required this.jointType, + required this.patterns, + required this.points, + required this.visible, + required this.width, + required this.zIndex, + }); + + String polylineId; + + bool consumesTapEvents; + + PlatformColor color; + + bool geodesic; + + /// The joint type. + PlatformJointType jointType; + + /// The pattern data, as a list of pattern items. + List patterns; + + List points; + + bool visible; + + int width; + + int zIndex; + + List _toList() { + return [ + polylineId, + consumesTapEvents, + color, + geodesic, + jointType, + patterns, + points, + visible, + width, + zIndex, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformPolyline decode(Object result) { + result as List; + return PlatformPolyline( + polylineId: result[0]! as String, + consumesTapEvents: result[1]! as bool, + color: result[2]! as PlatformColor, + geodesic: result[3]! as bool, + jointType: result[4]! as PlatformJointType, + patterns: (result[5] as List?)!.cast(), + points: (result[6] as List?)!.cast(), + visible: result[7]! as bool, + width: result[8]! as int, + zIndex: result[9]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPolyline || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the PatternItem class. +class PlatformPatternItem { + PlatformPatternItem({required this.type, this.length}); + + PlatformPatternItemType type; + + double? length; + + List _toList() { + return [type, length]; + } + + Object encode() { + return _toList(); + } + + static PlatformPatternItem decode(Object result) { + result as List; + return PlatformPatternItem( + type: result[0]! as PlatformPatternItemType, + length: result[1] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPatternItem || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the Tile class. +class PlatformTile { + PlatformTile({required this.width, required this.height, this.data}); + + int width; + + int height; + + Uint8List? data; + + List _toList() { + return [width, height, data]; + } + + Object encode() { + return _toList(); + } + + static PlatformTile decode(Object result) { + result as List; + return PlatformTile( + width: result[0]! as int, + height: result[1]! as int, + data: result[2] as Uint8List?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTile || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay({ + required this.tileOverlayId, + required this.fadeIn, + required this.transparency, + required this.zIndex, + required this.visible, + required this.tileSize, + }); + + String tileOverlayId; + + bool fadeIn; + + double transparency; + + int zIndex; + + bool visible; + + int tileSize; + + List _toList() { + return [ + tileOverlayId, + fadeIn, + transparency, + zIndex, + visible, + tileSize, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformTileOverlay decode(Object result) { + result as List; + return PlatformTileOverlay( + tileOverlayId: result[0]! as String, + fadeIn: result[1]! as bool, + transparency: result[2]! as double, + zIndex: result[3]! as int, + visible: result[4]! as bool, + tileSize: result[5]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTileOverlay || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of Flutter's EdgeInsets. +class PlatformEdgeInsets { + PlatformEdgeInsets({ + required this.top, + required this.bottom, + required this.left, + required this.right, + }); + + double top; + + double bottom; + + double left; + + double right; + + List _toList() { + return [top, bottom, left, right]; + } + + Object encode() { + return _toList(); + } + + static PlatformEdgeInsets decode(Object result) { + result as List; + return PlatformEdgeInsets( + top: result[0]! as double, + bottom: result[1]! as double, + left: result[2]! as double, + right: result[3]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformEdgeInsets || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of LatLng. +class PlatformLatLng { + PlatformLatLng({required this.latitude, required this.longitude}); + + double latitude; + + double longitude; + + List _toList() { + return [latitude, longitude]; + } + + Object encode() { + return _toList(); + } + + static PlatformLatLng decode(Object result) { + result as List; + return PlatformLatLng( + latitude: result[0]! as double, + longitude: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformLatLng || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of LatLngBounds. +class PlatformLatLngBounds { + PlatformLatLngBounds({required this.northeast, required this.southwest}); + + PlatformLatLng northeast; + + PlatformLatLng southwest; + + List _toList() { + return [northeast, southwest]; + } + + Object encode() { + return _toList(); + } + + static PlatformLatLngBounds decode(Object result) { + result as List; + return PlatformLatLngBounds( + northeast: result[0]! as PlatformLatLng, + southwest: result[1]! as PlatformLatLng, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformLatLngBounds || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of CameraTargetBounds. +/// +/// As with the Dart version, it exists to distinguish between not setting a +/// a target, and having an explicitly unbounded target (null [bounds]). +class PlatformCameraTargetBounds { + PlatformCameraTargetBounds({this.bounds}); + + PlatformLatLngBounds? bounds; + + List _toList() { + return [bounds]; + } + + Object encode() { + return _toList(); + } + + static PlatformCameraTargetBounds decode(Object result) { + result as List; + return PlatformCameraTargetBounds( + bounds: result[0] as PlatformLatLngBounds?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformCameraTargetBounds || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of the GroundOverlay class. +class PlatformGroundOverlay { + PlatformGroundOverlay({ + required this.groundOverlayId, + required this.image, + this.position, + this.bounds, + this.anchor, + required this.transparency, + required this.bearing, + required this.zIndex, + required this.visible, + required this.clickable, + this.zoomLevel, + }); + + String groundOverlayId; + + PlatformBitmap image; + + PlatformLatLng? position; + + PlatformLatLngBounds? bounds; + + PlatformPoint? anchor; + + double transparency; + + double bearing; + + int zIndex; + + bool visible; + + bool clickable; + + double? zoomLevel; + + List _toList() { + return [ + groundOverlayId, + image, + position, + bounds, + anchor, + transparency, + bearing, + zIndex, + visible, + clickable, + zoomLevel, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformGroundOverlay decode(Object result) { + result as List; + return PlatformGroundOverlay( + groundOverlayId: result[0]! as String, + image: result[1]! as PlatformBitmap, + position: result[2] as PlatformLatLng?, + bounds: result[3] as PlatformLatLngBounds?, + anchor: result[4] as PlatformPoint?, + transparency: result[5]! as double, + bearing: result[6]! as double, + zIndex: result[7]! as int, + visible: result[8]! as bool, + clickable: result[9]! as bool, + zoomLevel: result[10] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformGroundOverlay || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Information passed to the platform view creation. +class PlatformMapViewCreationParams { + PlatformMapViewCreationParams({ + required this.initialCameraPosition, + required this.mapConfiguration, + required this.initialCircles, + required this.initialMarkers, + required this.initialPolygons, + required this.initialPolylines, + required this.initialHeatmaps, + required this.initialTileOverlays, + required this.initialClusterManagers, + required this.initialGroundOverlays, + }); + + PlatformCameraPosition initialCameraPosition; + + PlatformMapConfiguration mapConfiguration; + + List initialCircles; + + List initialMarkers; + + List initialPolygons; + + List initialPolylines; + + List initialHeatmaps; + + List initialTileOverlays; + + List initialClusterManagers; + + List initialGroundOverlays; + + List _toList() { + return [ + initialCameraPosition, + mapConfiguration, + initialCircles, + initialMarkers, + initialPolygons, + initialPolylines, + initialHeatmaps, + initialTileOverlays, + initialClusterManagers, + initialGroundOverlays, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformMapViewCreationParams decode(Object result) { + result as List; + return PlatformMapViewCreationParams( + initialCameraPosition: result[0]! as PlatformCameraPosition, + mapConfiguration: result[1]! as PlatformMapConfiguration, + initialCircles: (result[2] as List?)!.cast(), + initialMarkers: (result[3] as List?)!.cast(), + initialPolygons: (result[4] as List?)!.cast(), + initialPolylines: (result[5] as List?)!.cast(), + initialHeatmaps: (result[6] as List?)!.cast(), + initialTileOverlays: (result[7] as List?)! + .cast(), + initialClusterManagers: (result[8] as List?)! + .cast(), + initialGroundOverlays: (result[9] as List?)! + .cast(), + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformMapViewCreationParams || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({ + this.compassEnabled, + this.cameraTargetBounds, + this.mapType, + this.minMaxZoomPreference, + this.rotateGesturesEnabled, + this.scrollGesturesEnabled, + this.tiltGesturesEnabled, + this.trackCameraPosition, + this.zoomGesturesEnabled, + this.myLocationEnabled, + this.myLocationButtonEnabled, + this.padding, + this.indoorViewEnabled, + this.trafficEnabled, + this.buildingsEnabled, + this.mapId, + this.style, + }); + + bool? compassEnabled; + + PlatformCameraTargetBounds? cameraTargetBounds; + + PlatformMapType? mapType; + + PlatformZoomRange? minMaxZoomPreference; + + bool? rotateGesturesEnabled; + + bool? scrollGesturesEnabled; + + bool? tiltGesturesEnabled; + + bool? trackCameraPosition; + + bool? zoomGesturesEnabled; + + bool? myLocationEnabled; + + bool? myLocationButtonEnabled; + + PlatformEdgeInsets? padding; + + bool? indoorViewEnabled; + + bool? trafficEnabled; + + bool? buildingsEnabled; + + String? mapId; + + String? style; + + List _toList() { + return [ + compassEnabled, + cameraTargetBounds, + mapType, + minMaxZoomPreference, + rotateGesturesEnabled, + scrollGesturesEnabled, + tiltGesturesEnabled, + trackCameraPosition, + zoomGesturesEnabled, + myLocationEnabled, + myLocationButtonEnabled, + padding, + indoorViewEnabled, + trafficEnabled, + buildingsEnabled, + mapId, + style, + ]; + } + + Object encode() { + return _toList(); + } + + static PlatformMapConfiguration decode(Object result) { + result as List; + return PlatformMapConfiguration( + compassEnabled: result[0] as bool?, + cameraTargetBounds: result[1] as PlatformCameraTargetBounds?, + mapType: result[2] as PlatformMapType?, + minMaxZoomPreference: result[3] as PlatformZoomRange?, + rotateGesturesEnabled: result[4] as bool?, + scrollGesturesEnabled: result[5] as bool?, + tiltGesturesEnabled: result[6] as bool?, + trackCameraPosition: result[7] as bool?, + zoomGesturesEnabled: result[8] as bool?, + myLocationEnabled: result[9] as bool?, + myLocationButtonEnabled: result[10] as bool?, + padding: result[11] as PlatformEdgeInsets?, + indoorViewEnabled: result[12] as bool?, + trafficEnabled: result[13] as bool?, + buildingsEnabled: result[14] as bool?, + mapId: result[15] as String?, + style: result[16] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformMapConfiguration || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of an x,y coordinate. +class PlatformPoint { + PlatformPoint({required this.x, required this.y}); + + double x; + + double y; + + List _toList() { + return [x, y]; + } + + Object encode() { + return _toList(); + } + + static PlatformPoint decode(Object result) { + result as List; + return PlatformPoint(x: result[0]! as double, y: result[1]! as double); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformPoint || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of a size. +class PlatformSize { + PlatformSize({required this.width, required this.height}); + + double width; + + double height; + + List _toList() { + return [width, height]; + } + + Object encode() { + return _toList(); + } + + static PlatformSize decode(Object result) { + result as List; + return PlatformSize( + width: result[0]! as double, + height: result[1]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformSize || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon representation of a color. +class PlatformColor { + PlatformColor({ + required this.red, + required this.green, + required this.blue, + required this.alpha, + }); + + double red; + + double green; + + double blue; + + double alpha; + + List _toList() { + return [red, green, blue, alpha]; + } + + Object encode() { + return _toList(); + } + + static PlatformColor decode(Object result) { + result as List; + return PlatformColor( + red: result[0]! as double, + green: result[1]! as double, + blue: result[2]! as double, + alpha: result[3]! as double, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformColor || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of GMSTileLayer properties. +class PlatformTileLayer { + PlatformTileLayer({ + required this.visible, + required this.fadeIn, + required this.opacity, + required this.zIndex, + }); + + bool visible; + + bool fadeIn; + + double opacity; + + int zIndex; + + List _toList() { + return [visible, fadeIn, opacity, zIndex]; + } + + Object encode() { + return _toList(); + } + + static PlatformTileLayer decode(Object result) { + result as List; + return PlatformTileLayer( + visible: result[0]! as bool, + fadeIn: result[1]! as bool, + opacity: result[2]! as double, + zIndex: result[3]! as int, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformTileLayer || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of MinMaxZoomPreference. +class PlatformZoomRange { + PlatformZoomRange({this.min, this.max}); + + double? min; + + double? max; + + List _toList() { + return [min, max]; + } + + Object encode() { + return _toList(); + } + + static PlatformZoomRange decode(Object result) { + result as List; + return PlatformZoomRange( + min: result[0] as double?, + max: result[1] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformZoomRange || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [BitmapDescriptor]. As there are multiple disjoint +/// types of [BitmapDescriptor], [PlatformBitmap] contains a single field which +/// may hold the pigeon equivalent type of any of them. +class PlatformBitmap { + PlatformBitmap({required this.bitmap}); + + /// One of [PlatformBitmapAssetMap], [PlatformBitmapAsset], + /// [PlatformBitmapAssetImage], [PlatformBitmapBytesMap], + /// [PlatformBitmapBytes], or [PlatformBitmapDefaultMarker]. + /// As Pigeon does not currently support data class inheritance, this + /// approach allows for the different bitmap implementations to be valid + /// argument and return types of the API methods. See + /// https://github.com/flutter/flutter/issues/117819. + Object bitmap; + + List _toList() { + return [bitmap]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmap decode(Object result) { + result as List; + return PlatformBitmap(bitmap: result[0]!); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [DefaultMarker]. +class PlatformBitmapDefaultMarker { + PlatformBitmapDefaultMarker({this.hue}); + + double? hue; + + List _toList() { + return [hue]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapDefaultMarker decode(Object result) { + result as List; + return PlatformBitmapDefaultMarker(hue: result[0] as double?); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapDefaultMarker || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [BytesBitmap]. +class PlatformBitmapBytes { + PlatformBitmapBytes({required this.byteData, this.size}); + + Uint8List byteData; + + PlatformSize? size; + + List _toList() { + return [byteData, size]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapBytes decode(Object result) { + result as List; + return PlatformBitmapBytes( + byteData: result[0]! as Uint8List, + size: result[1] as PlatformSize?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapBytes || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [AssetBitmap]. +class PlatformBitmapAsset { + PlatformBitmapAsset({required this.name, this.pkg}); + + String name; + + String? pkg; + + List _toList() { + return [name, pkg]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapAsset decode(Object result) { + result as List; + return PlatformBitmapAsset( + name: result[0]! as String, + pkg: result[1] as String?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapAsset || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [AssetImageBitmap]. +class PlatformBitmapAssetImage { + PlatformBitmapAssetImage({ + required this.name, + required this.scale, + this.size, + }); + + String name; + + double scale; + + PlatformSize? size; + + List _toList() { + return [name, scale, size]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapAssetImage decode(Object result) { + result as List; + return PlatformBitmapAssetImage( + name: result[0]! as String, + scale: result[1]! as double, + size: result[2] as PlatformSize?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapAssetImage || + other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [AssetMapBitmap]. +class PlatformBitmapAssetMap { + PlatformBitmapAssetMap({ + required this.assetName, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + + String assetName; + + PlatformMapBitmapScaling bitmapScaling; + + double imagePixelRatio; + + double? width; + + double? height; + + List _toList() { + return [assetName, bitmapScaling, imagePixelRatio, width, height]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapAssetMap decode(Object result) { + result as List; + return PlatformBitmapAssetMap( + assetName: result[0]! as String, + bitmapScaling: result[1]! as PlatformMapBitmapScaling, + imagePixelRatio: result[2]! as double, + width: result[3] as double?, + height: result[4] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapAssetMap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +/// Pigeon equivalent of [BytesMapBitmap]. +class PlatformBitmapBytesMap { + PlatformBitmapBytesMap({ + required this.byteData, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + + Uint8List byteData; + + PlatformMapBitmapScaling bitmapScaling; + + double imagePixelRatio; + + double? width; + + double? height; + + List _toList() { + return [byteData, bitmapScaling, imagePixelRatio, width, height]; + } + + Object encode() { + return _toList(); + } + + static PlatformBitmapBytesMap decode(Object result) { + result as List; + return PlatformBitmapBytesMap( + byteData: result[0]! as Uint8List, + bitmapScaling: result[1]! as PlatformMapBitmapScaling, + imagePixelRatio: result[2]! as double, + width: result[3] as double?, + height: result[4] as double?, + ); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is! PlatformBitmapBytesMap || other.runtimeType != runtimeType) { + return false; + } + if (identical(this, other)) { + return true; + } + return _deepEquals(encode(), other.encode()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Object.hashAll(_toList()); +} + +class _PigeonCodec extends StandardMessageCodec { + const _PigeonCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is int) { + buffer.putUint8(4); + buffer.putInt64(value); + } else if (value is PlatformMapType) { + buffer.putUint8(129); + writeValue(buffer, value.index); + } else if (value is PlatformJointType) { + buffer.putUint8(130); + writeValue(buffer, value.index); + } else if (value is PlatformPatternItemType) { + buffer.putUint8(131); + writeValue(buffer, value.index); + } else if (value is PlatformMapBitmapScaling) { + buffer.putUint8(132); + writeValue(buffer, value.index); + } else if (value is PlatformCameraPosition) { + buffer.putUint8(133); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdate) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewCameraPosition) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewLatLng) { + buffer.putUint8(136); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewLatLngBounds) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateNewLatLngZoom) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateScrollBy) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateZoomBy) { + buffer.putUint8(140); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateZoom) { + buffer.putUint8(141); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraUpdateZoomTo) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); + } else if (value is PlatformCircle) { + buffer.putUint8(143); + writeValue(buffer, value.encode()); + } else if (value is PlatformHeatmap) { + buffer.putUint8(144); + writeValue(buffer, value.encode()); + } else if (value is PlatformHeatmapGradient) { + buffer.putUint8(145); + writeValue(buffer, value.encode()); + } else if (value is PlatformWeightedLatLng) { + buffer.putUint8(146); + writeValue(buffer, value.encode()); + } else if (value is PlatformInfoWindow) { + buffer.putUint8(147); + writeValue(buffer, value.encode()); + } else if (value is PlatformCluster) { + buffer.putUint8(148); + writeValue(buffer, value.encode()); + } else if (value is PlatformClusterManager) { + buffer.putUint8(149); + writeValue(buffer, value.encode()); + } else if (value is PlatformMarker) { + buffer.putUint8(150); + writeValue(buffer, value.encode()); + } else if (value is PlatformPolygon) { + buffer.putUint8(151); + writeValue(buffer, value.encode()); + } else if (value is PlatformPolyline) { + buffer.putUint8(152); + writeValue(buffer, value.encode()); + } else if (value is PlatformPatternItem) { + buffer.putUint8(153); + writeValue(buffer, value.encode()); + } else if (value is PlatformTile) { + buffer.putUint8(154); + writeValue(buffer, value.encode()); + } else if (value is PlatformTileOverlay) { + buffer.putUint8(155); + writeValue(buffer, value.encode()); + } else if (value is PlatformEdgeInsets) { + buffer.putUint8(156); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLng) { + buffer.putUint8(157); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLngBounds) { + buffer.putUint8(158); + writeValue(buffer, value.encode()); + } else if (value is PlatformCameraTargetBounds) { + buffer.putUint8(159); + writeValue(buffer, value.encode()); + } else if (value is PlatformGroundOverlay) { + buffer.putUint8(160); + writeValue(buffer, value.encode()); + } else if (value is PlatformMapViewCreationParams) { + buffer.putUint8(161); + writeValue(buffer, value.encode()); + } else if (value is PlatformMapConfiguration) { + buffer.putUint8(162); + writeValue(buffer, value.encode()); + } else if (value is PlatformPoint) { + buffer.putUint8(163); + writeValue(buffer, value.encode()); + } else if (value is PlatformSize) { + buffer.putUint8(164); + writeValue(buffer, value.encode()); + } else if (value is PlatformColor) { + buffer.putUint8(165); + writeValue(buffer, value.encode()); + } else if (value is PlatformTileLayer) { + buffer.putUint8(166); + writeValue(buffer, value.encode()); + } else if (value is PlatformZoomRange) { + buffer.putUint8(167); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmap) { + buffer.putUint8(168); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapDefaultMarker) { + buffer.putUint8(169); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapBytes) { + buffer.putUint8(170); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapAsset) { + buffer.putUint8(171); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapAssetImage) { + buffer.putUint8(172); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapAssetMap) { + buffer.putUint8(173); + writeValue(buffer, value.encode()); + } else if (value is PlatformBitmapBytesMap) { + buffer.putUint8(174); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 129: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformMapType.values[value]; + case 130: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformJointType.values[value]; + case 131: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformPatternItemType.values[value]; + case 132: + final value = readValue(buffer) as int?; + return value == null ? null : PlatformMapBitmapScaling.values[value]; + case 133: + return PlatformCameraPosition.decode(readValue(buffer)!); + case 134: + return PlatformCameraUpdate.decode(readValue(buffer)!); + case 135: + return PlatformCameraUpdateNewCameraPosition.decode(readValue(buffer)!); + case 136: + return PlatformCameraUpdateNewLatLng.decode(readValue(buffer)!); + case 137: + return PlatformCameraUpdateNewLatLngBounds.decode(readValue(buffer)!); + case 138: + return PlatformCameraUpdateNewLatLngZoom.decode(readValue(buffer)!); + case 139: + return PlatformCameraUpdateScrollBy.decode(readValue(buffer)!); + case 140: + return PlatformCameraUpdateZoomBy.decode(readValue(buffer)!); + case 141: + return PlatformCameraUpdateZoom.decode(readValue(buffer)!); + case 142: + return PlatformCameraUpdateZoomTo.decode(readValue(buffer)!); + case 143: + return PlatformCircle.decode(readValue(buffer)!); + case 144: + return PlatformHeatmap.decode(readValue(buffer)!); + case 145: + return PlatformHeatmapGradient.decode(readValue(buffer)!); + case 146: + return PlatformWeightedLatLng.decode(readValue(buffer)!); + case 147: + return PlatformInfoWindow.decode(readValue(buffer)!); + case 148: + return PlatformCluster.decode(readValue(buffer)!); + case 149: + return PlatformClusterManager.decode(readValue(buffer)!); + case 150: + return PlatformMarker.decode(readValue(buffer)!); + case 151: + return PlatformPolygon.decode(readValue(buffer)!); + case 152: + return PlatformPolyline.decode(readValue(buffer)!); + case 153: + return PlatformPatternItem.decode(readValue(buffer)!); + case 154: + return PlatformTile.decode(readValue(buffer)!); + case 155: + return PlatformTileOverlay.decode(readValue(buffer)!); + case 156: + return PlatformEdgeInsets.decode(readValue(buffer)!); + case 157: + return PlatformLatLng.decode(readValue(buffer)!); + case 158: + return PlatformLatLngBounds.decode(readValue(buffer)!); + case 159: + return PlatformCameraTargetBounds.decode(readValue(buffer)!); + case 160: + return PlatformGroundOverlay.decode(readValue(buffer)!); + case 161: + return PlatformMapViewCreationParams.decode(readValue(buffer)!); + case 162: + return PlatformMapConfiguration.decode(readValue(buffer)!); + case 163: + return PlatformPoint.decode(readValue(buffer)!); + case 164: + return PlatformSize.decode(readValue(buffer)!); + case 165: + return PlatformColor.decode(readValue(buffer)!); + case 166: + return PlatformTileLayer.decode(readValue(buffer)!); + case 167: + return PlatformZoomRange.decode(readValue(buffer)!); + case 168: + return PlatformBitmap.decode(readValue(buffer)!); + case 169: + return PlatformBitmapDefaultMarker.decode(readValue(buffer)!); + case 170: + return PlatformBitmapBytes.decode(readValue(buffer)!); + case 171: + return PlatformBitmapAsset.decode(readValue(buffer)!); + case 172: + return PlatformBitmapAssetImage.decode(readValue(buffer)!); + case 173: + return PlatformBitmapAssetMap.decode(readValue(buffer)!); + case 174: + return PlatformBitmapBytesMap.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// Interface for non-test interactions with the native SDK. +/// +/// For test-only state queries, see [MapsInspectorApi]. +class MapsApi { + /// Constructor for [MapsApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + /// Returns once the map instance is available. + Future waitForMap() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.waitForMap$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + Future updateMapConfiguration( + PlatformMapConfiguration configuration, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateMapConfiguration$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [configuration], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of circles on the map. + Future updateCircles( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateCircles$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of heatmaps on the map. + Future updateHeatmaps( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateHeatmaps$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of custer managers for clusters on the map. + Future updateClusterManagers( + List toAdd, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateClusterManagers$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of markers on the map. + Future updateMarkers( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateMarkers$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polygonss on the map. + Future updatePolygons( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updatePolygons$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polylines on the map. + Future updatePolylines( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updatePolylines$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of tile overlays on the map. + Future updateTileOverlays( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateTileOverlays$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of ground overlays on the map. + Future updateGroundOverlays( + List toAdd, + List toChange, + List idsToRemove, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.updateGroundOverlays$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [toAdd, toChange, idsToRemove], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Gets the screen coordinate for the given map location. + Future getScreenCoordinate(PlatformLatLng latLng) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getScreenCoordinate$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [latLng], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformPoint?)!; + } + } + + /// Gets the map location for the given screen coordinate. + Future getLatLng(PlatformPoint screenCoordinate) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getLatLng$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [screenCoordinate], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformLatLng?)!; + } + } + + /// Gets the map region currently displayed on the map. + Future getVisibleRegion() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getVisibleRegion$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformLatLngBounds?)!; + } + } + + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + Future moveCamera(PlatformCameraUpdate cameraUpdate) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.moveCamera$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [cameraUpdate], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Moves the camera according to [cameraUpdate], animating the update using a + /// duration in milliseconds if provided. + Future animateCamera( + PlatformCameraUpdate cameraUpdate, + int? durationMilliseconds, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.animateCamera$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [cameraUpdate, durationMilliseconds], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Gets the current map zoom level. + Future getZoomLevel() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getZoomLevel$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as double?)!; + } + } + + /// Show the info window for the marker with the given ID. + Future showInfoWindow(String markerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.showInfoWindow$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [markerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Hide the info window for the marker with the given ID. + Future hideInfoWindow(String markerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.hideInfoWindow$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [markerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Returns true if the marker with the given ID is currently displaying its + /// info window. + Future isInfoWindowShown(String markerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.isInfoWindowShown$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [markerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + /// Sets the style to the given map style string, where an empty string + /// indicates that the style should be cleared. + /// + /// If there was an error setting the style, such as an invalid style string, + /// returns the error message. + Future setStyle(String style) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.setStyle$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [style], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Returns the error string from the last attempt to set the map style, if + /// any. + /// + /// This allows checking asynchronously for initial style failures, as there + /// is no way to return failures from map initialization. + Future getLastStyleError() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.getLastStyleError$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as String?); + } + } + + /// Clears the cache of tiles previously requseted from the tile provider. + Future clearTileCache(String tileOverlayId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.clearTileCache$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [tileOverlayId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Takes a snapshot of the map and returns its image data. + Future takeSnapshot() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsApi.takeSnapshot$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as Uint8List?); + } + } +} + +/// Interface for calls from the native SDK to Dart. +abstract class MapsCallbackApi { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + /// Called when the map camera starts moving. + void onCameraMoveStarted(); + + /// Called when the map camera moves. + void onCameraMove(PlatformCameraPosition cameraPosition); + + /// Called when the map camera stops moving. + void onCameraIdle(); + + /// Called when the map, not a specifc map object, is tapped. + void onTap(PlatformLatLng position); + + /// Called when the map, not a specifc map object, is long pressed. + void onLongPress(PlatformLatLng position); + + /// Called when a marker is tapped. + void onMarkerTap(String markerId); + + /// Called when a marker drag starts. + void onMarkerDragStart(String markerId, PlatformLatLng position); + + /// Called when a marker drag updates. + void onMarkerDrag(String markerId, PlatformLatLng position); + + /// Called when a marker drag ends. + void onMarkerDragEnd(String markerId, PlatformLatLng position); + + /// Called when a marker's info window is tapped. + void onInfoWindowTap(String markerId); + + /// Called when a circle is tapped. + void onCircleTap(String circleId); + + /// Called when a marker cluster is tapped. + void onClusterTap(PlatformCluster cluster); + + /// Called when a polygon is tapped. + void onPolygonTap(String polygonId); + + /// Called when a polyline is tapped. + void onPolylineTap(String polylineId); + + /// Called when a ground overlay is tapped. + void onGroundOverlayTap(String groundOverlayId); + + /// Called to get data for a map tile. + Future getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ); + + static void setUp( + MapsCallbackApi? api, { + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + { + final pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMoveStarted$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onCameraMoveStarted(); + 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.onCameraMove$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMove was null.', + ); + final List args = (message as List?)!; + final PlatformCameraPosition? arg_cameraPosition = + (args[0] as PlatformCameraPosition?); + assert( + arg_cameraPosition != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCameraMove was null, expected non-null PlatformCameraPosition.', + ); + try { + api.onCameraMove(arg_cameraPosition!); + 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.onCameraIdle$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + try { + api.onCameraIdle(); + 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.onTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onTap was null.', + ); + final List args = (message as List?)!; + final PlatformLatLng? arg_position = (args[0] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onTap was null, expected non-null PlatformLatLng.', + ); + try { + api.onTap(arg_position!); + 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.onLongPress$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onLongPress was null.', + ); + final List args = (message as List?)!; + final PlatformLatLng? arg_position = (args[0] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onLongPress was null, expected non-null PlatformLatLng.', + ); + try { + api.onLongPress(arg_position!); + 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.onMarkerTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerTap was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerTap was null, expected non-null String.', + ); + try { + api.onMarkerTap(arg_markerId!); + 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.onMarkerDragStart$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart was null, expected non-null String.', + ); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragStart was null, expected non-null PlatformLatLng.', + ); + try { + api.onMarkerDragStart(arg_markerId!, arg_position!); + 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.onMarkerDrag$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag was null, expected non-null String.', + ); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDrag was null, expected non-null PlatformLatLng.', + ); + try { + api.onMarkerDrag(arg_markerId!, arg_position!); + 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.onMarkerDragEnd$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd was null, expected non-null String.', + ); + final PlatformLatLng? arg_position = (args[1] as PlatformLatLng?); + assert( + arg_position != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onMarkerDragEnd was null, expected non-null PlatformLatLng.', + ); + try { + api.onMarkerDragEnd(arg_markerId!, arg_position!); + 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.onInfoWindowTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onInfoWindowTap was null.', + ); + final List args = (message as List?)!; + final String? arg_markerId = (args[0] as String?); + assert( + arg_markerId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onInfoWindowTap was null, expected non-null String.', + ); + try { + api.onInfoWindowTap(arg_markerId!); + 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.onCircleTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCircleTap was null.', + ); + final List args = (message as List?)!; + final String? arg_circleId = (args[0] as String?); + assert( + arg_circleId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onCircleTap was null, expected non-null String.', + ); + try { + api.onCircleTap(arg_circleId!); + 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', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap was null.', + ); + final List args = (message as List?)!; + final PlatformCluster? arg_cluster = (args[0] as PlatformCluster?); + assert( + arg_cluster != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onClusterTap was null, expected non-null PlatformCluster.', + ); + try { + api.onClusterTap(arg_cluster!); + 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.onPolygonTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolygonTap was null.', + ); + final List args = (message as List?)!; + final String? arg_polygonId = (args[0] as String?); + assert( + arg_polygonId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolygonTap was null, expected non-null String.', + ); + try { + api.onPolygonTap(arg_polygonId!); + 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.onPolylineTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolylineTap was null.', + ); + final List args = (message as List?)!; + final String? arg_polylineId = (args[0] as String?); + assert( + arg_polylineId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onPolylineTap was null, expected non-null String.', + ); + try { + api.onPolylineTap(arg_polylineId!); + 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.onGroundOverlayTap$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onGroundOverlayTap was null.', + ); + final List args = (message as List?)!; + final String? arg_groundOverlayId = (args[0] as String?); + assert( + arg_groundOverlayId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.onGroundOverlayTap was null, expected non-null String.', + ); + try { + api.onGroundOverlayTap(arg_groundOverlayId!); + 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.getTileOverlayTile$messageChannelSuffix', + pigeonChannelCodec, + binaryMessenger: binaryMessenger, + ); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert( + message != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null.', + ); + final List args = (message as List?)!; + final String? arg_tileOverlayId = (args[0] as String?); + assert( + arg_tileOverlayId != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null, expected non-null String.', + ); + final PlatformPoint? arg_location = (args[1] as PlatformPoint?); + assert( + arg_location != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null, expected non-null PlatformPoint.', + ); + final int? arg_zoom = (args[2] as int?); + assert( + arg_zoom != null, + 'Argument for dev.flutter.pigeon.google_maps_flutter_ios.MapsCallbackApi.getTileOverlayTile was null, expected non-null int.', + ); + try { + final PlatformTile output = await api.getTileOverlayTile( + arg_tileOverlayId!, + arg_location!, + arg_zoom!, + ); + return wrapResponse(result: output); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString()), + ); + } + }); + } + } + } +} + +/// Dummy interface to force generation of the platform view creation params, +/// which are not used in any Pigeon calls, only the platform view creation +/// call made internally by Flutter. +class MapsPlatformViewApi { + /// Constructor for [MapsPlatformViewApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsPlatformViewApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future createView(PlatformMapViewCreationParams? type) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsPlatformViewApi.createView$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [type], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } +} + +/// Inspector API only intended for use in integration tests. +class MapsInspectorApi { + /// Constructor for [MapsInspectorApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsInspectorApi({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty + ? '.$messageChannelSuffix' + : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future areBuildingsEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areBuildingsEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areRotateGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areRotateGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areScrollGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areScrollGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areTiltGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areTiltGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future areZoomGesturesEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.areZoomGesturesEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future isCompassEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.isCompassEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future isMyLocationButtonEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.isMyLocationButtonEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future isTrafficEnabled() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.isTrafficEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + + Future getTileOverlayInfo(String tileOverlayId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getTileOverlayInfo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [tileOverlayId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as PlatformTileLayer?); + } + } + + Future getGroundOverlayInfo( + String groundOverlayId, + ) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getGroundOverlayInfo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [groundOverlayId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as PlatformGroundOverlay?); + } + } + + Future getHeatmapInfo(String heatmapId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getHeatmapInfo$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [heatmapId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return (pigeonVar_replyList[0] as PlatformHeatmap?); + } + } + + Future getZoomRange() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getZoomRange$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformZoomRange?)!; + } + } + + Future> getClusters(String clusterManagerId) async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getClusters$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send( + [clusterManagerId], + ); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as List?)! + .cast(); + } + } + + Future getCameraPosition() async { + final pigeonVar_channelName = + 'dev.flutter.pigeon.google_maps_flutter_ios.MapsInspectorApi.getCameraPosition$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final Future pigeonVar_sendFuture = pigeonVar_channel.send(null); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as PlatformCameraPosition?)!; + } + } +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/copyright.txt b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/copyright.txt new file mode 100644 index 000000000000..07e5f8598a80 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/copyright.txt @@ -0,0 +1,3 @@ +Copyright 2013 The Flutter Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. 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 new file mode 100644 index 000000000000..50c2bee1fdcf --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pigeons/messages.dart @@ -0,0 +1,871 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + dartOut: 'lib/src/messages.g.dart', + // This uses a different output name to avoid conflicts with the pigeon + // files in other packages, without having to use full relative paths + // in #includes (which would make source sharing harder to manage). + objcHeaderOut: + 'ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h', + objcSourceOut: + 'ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m', + objcOptions: ObjcOptions(prefix: 'FGM'), + copyrightHeader: 'pigeons/copyright.txt', + // Use the base package name so that the generated code can be shared + // across the implementation copies. + dartPackageName: 'google_maps_flutter_ios', + ), +) +/// Pigeon equivalent of MapType +enum PlatformMapType { none, normal, satellite, terrain, hybrid } + +/// Pigeon representatation of a CameraPosition. +class PlatformCameraPosition { + PlatformCameraPosition({ + required this.bearing, + required this.target, + required this.tilt, + required this.zoom, + }); + + final double bearing; + final PlatformLatLng target; + final double tilt; + final double zoom; +} + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate(this.cameraUpdate); + + /// This Object must be one of the classes below prefixed with + /// PlatformCameraUpdate. Each such class represents a different type of + /// camera update, and each holds a different set of data, preventing the + /// use of a single unified class. + // Pigeon does not support inheritance, which prevents a more strict type + // bound. See https://github.com/flutter/flutter/issues/117819. + final Object cameraUpdate; +} + +/// Pigeon equivalent of NewCameraPosition +class PlatformCameraUpdateNewCameraPosition { + PlatformCameraUpdateNewCameraPosition(this.cameraPosition); + final PlatformCameraPosition cameraPosition; +} + +/// Pigeon equivalent of NewLatLng +class PlatformCameraUpdateNewLatLng { + PlatformCameraUpdateNewLatLng(this.latLng); + final PlatformLatLng latLng; +} + +/// Pigeon equivalent of NewLatLngBounds +class PlatformCameraUpdateNewLatLngBounds { + PlatformCameraUpdateNewLatLngBounds(this.bounds, this.padding); + final PlatformLatLngBounds bounds; + final double padding; +} + +/// Pigeon equivalent of NewLatLngZoom +class PlatformCameraUpdateNewLatLngZoom { + PlatformCameraUpdateNewLatLngZoom(this.latLng, this.zoom); + final PlatformLatLng latLng; + final double zoom; +} + +/// Pigeon equivalent of ScrollBy +class PlatformCameraUpdateScrollBy { + PlatformCameraUpdateScrollBy(this.dx, this.dy); + final double dx; + final double dy; +} + +/// Pigeon equivalent of ZoomBy +class PlatformCameraUpdateZoomBy { + PlatformCameraUpdateZoomBy(this.amount, [this.focus]); + final double amount; + final PlatformPoint? focus; +} + +/// Pigeon equivalent of ZoomIn/ZoomOut +class PlatformCameraUpdateZoom { + PlatformCameraUpdateZoom(this.out); + final bool out; +} + +/// Pigeon equivalent of ZoomTo +class PlatformCameraUpdateZoomTo { + PlatformCameraUpdateZoomTo(this.zoom); + final double zoom; +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle({ + required this.circleId, + required this.center, + required this.fillColor, + required this.strokeColor, + this.consumeTapEvents = false, + this.visible = true, + this.strokeWidth = 10, + this.zIndex = 0.0, + this.radius = 0, + }); + + final bool consumeTapEvents; + final PlatformColor fillColor; + final PlatformColor strokeColor; + final bool visible; + final int strokeWidth; + final double zIndex; + final PlatformLatLng center; + final double radius; + final String circleId; +} + +/// Pigeon equivalent of the Heatmap class. +class PlatformHeatmap { + PlatformHeatmap({ + required this.heatmapId, + required this.data, + this.gradient, + required this.opacity, + required this.radius, + required this.minimumZoomIntensity, + required this.maximumZoomIntensity, + }); + + final String heatmapId; + final List data; + final PlatformHeatmapGradient? gradient; + final double opacity; + final int radius; + final int minimumZoomIntensity; + final int maximumZoomIntensity; +} + +/// Pigeon equivalent of the HeatmapGradient class. +/// +/// The GMUGradient structure is slightly different from HeatmapGradient, so +/// this matches the iOS API so that conversion can be done on the Dart side +/// where the structures are easier to work with. +class PlatformHeatmapGradient { + PlatformHeatmapGradient({ + required this.colors, + required this.startPoints, + required this.colorMapSize, + }); + + final List colors; + final List startPoints; + final int colorMapSize; +} + +/// Pigeon equivalent of the WeightedLatLng class. +class PlatformWeightedLatLng { + PlatformWeightedLatLng({required this.point, required this.weight}); + + final PlatformLatLng point; + final double weight; +} + +/// Pigeon equivalent of the InfoWindow class. +class PlatformInfoWindow { + PlatformInfoWindow({required this.anchor, this.title, this.snippet}); + + final String? title; + final String? snippet; + final PlatformPoint anchor; +} + +/// Pigeon equivalent of Cluster. +class PlatformCluster { + PlatformCluster({ + required this.clusterManagerId, + required this.position, + required this.bounds, + required this.markerIds, + }); + + final String clusterManagerId; + final PlatformLatLng position; + final PlatformLatLngBounds bounds; + final List markerIds; +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({required this.identifier}); + + final String identifier; +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker({ + required this.markerId, + required this.icon, + this.alpha = 1.0, + required this.anchor, + this.consumeTapEvents = false, + this.draggable = false, + this.flat = false, + required this.infoWindow, + required this.position, + this.rotation = 0.0, + this.visible = true, + this.zIndex = 0, + this.clusterManagerId, + }); + + final double alpha; + final PlatformPoint anchor; + final bool consumeTapEvents; + final bool draggable; + final bool flat; + + final PlatformBitmap icon; + final PlatformInfoWindow infoWindow; + final PlatformLatLng position; + final double rotation; + final bool visible; + final int zIndex; + final String markerId; + final String? clusterManagerId; +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon({ + required this.polygonId, + required this.consumesTapEvents, + required this.fillColor, + required this.geodesic, + required this.points, + required this.holes, + required this.visible, + required this.strokeColor, + required this.strokeWidth, + required this.zIndex, + }); + + final String polygonId; + final bool consumesTapEvents; + final PlatformColor fillColor; + final bool geodesic; + final List points; + final List> holes; + final bool visible; + final PlatformColor strokeColor; + final int strokeWidth; + final int zIndex; +} + +/// Join types for polyline joints. +enum PlatformJointType { mitered, bevel, round } + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline({ + required this.polylineId, + required this.consumesTapEvents, + required this.color, + required this.geodesic, + required this.jointType, + required this.patterns, + required this.points, + required this.visible, + required this.width, + required this.zIndex, + }); + + final String polylineId; + final bool consumesTapEvents; + final PlatformColor color; + final bool geodesic; + + /// The joint type. + final PlatformJointType jointType; + + /// The pattern data, as a list of pattern items. + final List patterns; + final List points; + + final bool visible; + final int width; + final int zIndex; +} + +/// Enumeration of possible types for PatternItem. +enum PlatformPatternItemType { dot, dash, gap } + +/// Pigeon equivalent of the PatternItem class. +class PlatformPatternItem { + PlatformPatternItem({required this.type, this.length}); + + final PlatformPatternItemType type; + final double? length; +} + +/// Pigeon equivalent of the Tile class. +class PlatformTile { + PlatformTile({required this.width, required this.height, required this.data}); + + final int width; + final int height; + final Uint8List? data; +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay({ + required this.tileOverlayId, + required this.fadeIn, + required this.transparency, + required this.zIndex, + required this.visible, + required this.tileSize, + }); + + final String tileOverlayId; + final bool fadeIn; + final double transparency; + final int zIndex; + final bool visible; + final int tileSize; +} + +/// Pigeon equivalent of Flutter's EdgeInsets. +class PlatformEdgeInsets { + PlatformEdgeInsets({ + required this.top, + required this.bottom, + required this.left, + required this.right, + }); + + final double top; + final double bottom; + final double left; + final double right; +} + +/// Pigeon equivalent of LatLng. +class PlatformLatLng { + PlatformLatLng({required this.latitude, required this.longitude}); + + final double latitude; + final double longitude; +} + +/// Pigeon equivalent of LatLngBounds. +class PlatformLatLngBounds { + PlatformLatLngBounds({required this.northeast, required this.southwest}); + + final PlatformLatLng northeast; + final PlatformLatLng southwest; +} + +/// Pigeon equivalent of CameraTargetBounds. +/// +/// As with the Dart version, it exists to distinguish between not setting a +/// a target, and having an explicitly unbounded target (null [bounds]). +class PlatformCameraTargetBounds { + PlatformCameraTargetBounds({required this.bounds}); + + final PlatformLatLngBounds? bounds; +} + +/// Pigeon equivalent of the GroundOverlay class. +class PlatformGroundOverlay { + PlatformGroundOverlay({ + required this.groundOverlayId, + required this.image, + required this.position, + required this.bounds, + required this.anchor, + required this.transparency, + required this.bearing, + required this.zIndex, + required this.visible, + required this.clickable, + required this.zoomLevel, + }); + + final String groundOverlayId; + final PlatformBitmap image; + final PlatformLatLng? position; + final PlatformLatLngBounds? bounds; + final PlatformPoint? anchor; + final double transparency; + final double bearing; + final int zIndex; + final bool visible; + final bool clickable; + final double? zoomLevel; +} + +/// Information passed to the platform view creation. +class PlatformMapViewCreationParams { + PlatformMapViewCreationParams({ + required this.initialCameraPosition, + required this.mapConfiguration, + required this.initialCircles, + required this.initialMarkers, + required this.initialPolygons, + required this.initialPolylines, + required this.initialHeatmaps, + required this.initialTileOverlays, + required this.initialClusterManagers, + required this.initialGroundOverlays, + }); + + final PlatformCameraPosition initialCameraPosition; + final PlatformMapConfiguration mapConfiguration; + final List initialCircles; + final List initialMarkers; + final List initialPolygons; + final List initialPolylines; + final List initialHeatmaps; + final List initialTileOverlays; + final List initialClusterManagers; + final List initialGroundOverlays; +} + +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({ + required this.compassEnabled, + required this.cameraTargetBounds, + required this.mapType, + required this.minMaxZoomPreference, + required this.rotateGesturesEnabled, + required this.scrollGesturesEnabled, + required this.tiltGesturesEnabled, + required this.trackCameraPosition, + required this.zoomGesturesEnabled, + required this.myLocationEnabled, + required this.myLocationButtonEnabled, + required this.padding, + required this.indoorViewEnabled, + required this.trafficEnabled, + required this.buildingsEnabled, + required this.mapId, + required this.style, + }); + + final bool? compassEnabled; + final PlatformCameraTargetBounds? cameraTargetBounds; + final PlatformMapType? mapType; + final PlatformZoomRange? minMaxZoomPreference; + final bool? rotateGesturesEnabled; + final bool? scrollGesturesEnabled; + final bool? tiltGesturesEnabled; + final bool? trackCameraPosition; + final bool? zoomGesturesEnabled; + final bool? myLocationEnabled; + final bool? myLocationButtonEnabled; + final PlatformEdgeInsets? padding; + final bool? indoorViewEnabled; + final bool? trafficEnabled; + final bool? buildingsEnabled; + final String? mapId; + final String? style; +} + +/// Pigeon representation of an x,y coordinate. +class PlatformPoint { + PlatformPoint({required this.x, required this.y}); + + final double x; + final double y; +} + +/// Pigeon representation of a size. +class PlatformSize { + PlatformSize({required this.width, required this.height}); + + final double width; + final double height; +} + +/// Pigeon representation of a color. +class PlatformColor { + PlatformColor({ + required this.red, + required this.green, + required this.blue, + required this.alpha, + }); + + final double red; + final double green; + final double blue; + final double alpha; +} + +/// Pigeon equivalent of GMSTileLayer properties. +class PlatformTileLayer { + PlatformTileLayer({ + required this.visible, + required this.fadeIn, + required this.opacity, + required this.zIndex, + }); + + final bool visible; + final bool fadeIn; + final double opacity; + final int zIndex; +} + +/// Pigeon equivalent of MinMaxZoomPreference. +class PlatformZoomRange { + PlatformZoomRange({required this.min, required this.max}); + + final double? min; + final double? max; +} + +/// Pigeon equivalent of [BitmapDescriptor]. As there are multiple disjoint +/// types of [BitmapDescriptor], [PlatformBitmap] contains a single field which +/// may hold the pigeon equivalent type of any of them. +class PlatformBitmap { + PlatformBitmap({required this.bitmap}); + + /// One of [PlatformBitmapAssetMap], [PlatformBitmapAsset], + /// [PlatformBitmapAssetImage], [PlatformBitmapBytesMap], + /// [PlatformBitmapBytes], or [PlatformBitmapDefaultMarker]. + /// As Pigeon does not currently support data class inheritance, this + /// approach allows for the different bitmap implementations to be valid + /// argument and return types of the API methods. See + /// https://github.com/flutter/flutter/issues/117819. + final Object bitmap; +} + +/// Pigeon equivalent of [DefaultMarker]. +class PlatformBitmapDefaultMarker { + PlatformBitmapDefaultMarker({this.hue}); + + final double? hue; +} + +/// Pigeon equivalent of [BytesBitmap]. +class PlatformBitmapBytes { + PlatformBitmapBytes({required this.byteData, this.size}); + + final Uint8List byteData; + final PlatformSize? size; +} + +/// Pigeon equivalent of [AssetBitmap]. +class PlatformBitmapAsset { + PlatformBitmapAsset({required this.name, this.pkg}); + + final String name; + final String? pkg; +} + +/// Pigeon equivalent of [AssetImageBitmap]. +class PlatformBitmapAssetImage { + PlatformBitmapAssetImage({ + required this.name, + required this.scale, + this.size, + }); + final String name; + final double scale; + final PlatformSize? size; +} + +/// Pigeon equivalent of [AssetMapBitmap]. +class PlatformBitmapAssetMap { + PlatformBitmapAssetMap({ + required this.assetName, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + final String assetName; + final PlatformMapBitmapScaling bitmapScaling; + final double imagePixelRatio; + final double? width; + final double? height; +} + +/// Pigeon equivalent of [BytesMapBitmap]. +class PlatformBitmapBytesMap { + PlatformBitmapBytesMap({ + required this.byteData, + required this.bitmapScaling, + required this.imagePixelRatio, + this.width, + this.height, + }); + final Uint8List byteData; + final PlatformMapBitmapScaling bitmapScaling; + final double imagePixelRatio; + final double? width; + final double? height; +} + +/// Pigeon equivalent of [MapBitmapScaling]. +enum PlatformMapBitmapScaling { auto, none } + +/// Interface for non-test interactions with the native SDK. +/// +/// For test-only state queries, see [MapsInspectorApi]. +@HostApi() +abstract class MapsApi { + /// Returns once the map instance is available. + void waitForMap(); + + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + @ObjCSelector('updateWithMapConfiguration:') + void updateMapConfiguration(PlatformMapConfiguration configuration); + + /// Updates the set of circles on the map. + @ObjCSelector('updateCirclesByAdding:changing:removing:') + void updateCircles( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of heatmaps on the map. + @ObjCSelector('updateHeatmapsByAdding:changing:removing:') + void updateHeatmaps( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of custer managers for clusters on the map. + @ObjCSelector('updateClusterManagersByAdding:removing:') + void updateClusterManagers( + List toAdd, + List idsToRemove, + ); + + /// Updates the set of markers on the map. + @ObjCSelector('updateMarkersByAdding:changing:removing:') + void updateMarkers( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of polygonss on the map. + @ObjCSelector('updatePolygonsByAdding:changing:removing:') + void updatePolygons( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of polylines on the map. + @ObjCSelector('updatePolylinesByAdding:changing:removing:') + void updatePolylines( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of tile overlays on the map. + @ObjCSelector('updateTileOverlaysByAdding:changing:removing:') + void updateTileOverlays( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Updates the set of ground overlays on the map. + @ObjCSelector('updateGroundOverlaysByAdding:changing:removing:') + void updateGroundOverlays( + List toAdd, + List toChange, + List idsToRemove, + ); + + /// Gets the screen coordinate for the given map location. + @ObjCSelector('screenCoordinatesForLatLng:') + PlatformPoint getScreenCoordinate(PlatformLatLng latLng); + + /// Gets the map location for the given screen coordinate. + @ObjCSelector('latLngForScreenCoordinate:') + PlatformLatLng getLatLng(PlatformPoint screenCoordinate); + + /// Gets the map region currently displayed on the map. + @ObjCSelector('visibleMapRegion') + PlatformLatLngBounds getVisibleRegion(); + + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + @ObjCSelector('moveCameraWithUpdate:') + void moveCamera(PlatformCameraUpdate cameraUpdate); + + /// Moves the camera according to [cameraUpdate], animating the update using a + /// duration in milliseconds if provided. + @ObjCSelector('animateCameraWithUpdate:duration:') + void animateCamera( + PlatformCameraUpdate cameraUpdate, + int? durationMilliseconds, + ); + + /// Gets the current map zoom level. + @ObjCSelector('currentZoomLevel') + double getZoomLevel(); + + /// Show the info window for the marker with the given ID. + @ObjCSelector('showInfoWindowForMarkerWithIdentifier:') + void showInfoWindow(String markerId); + + /// Hide the info window for the marker with the given ID. + @ObjCSelector('hideInfoWindowForMarkerWithIdentifier:') + void hideInfoWindow(String markerId); + + /// Returns true if the marker with the given ID is currently displaying its + /// info window. + @ObjCSelector('isShowingInfoWindowForMarkerWithIdentifier:') + bool isInfoWindowShown(String markerId); + + /// Sets the style to the given map style string, where an empty string + /// indicates that the style should be cleared. + /// + /// If there was an error setting the style, such as an invalid style string, + /// returns the error message. + @ObjCSelector('setStyle:') + String? setStyle(String style); + + /// Returns the error string from the last attempt to set the map style, if + /// any. + /// + /// This allows checking asynchronously for initial style failures, as there + /// is no way to return failures from map initialization. + @ObjCSelector('lastStyleError') + String? getLastStyleError(); + + /// Clears the cache of tiles previously requseted from the tile provider. + @ObjCSelector('clearTileCacheForOverlayWithIdentifier:') + void clearTileCache(String tileOverlayId); + + /// Takes a snapshot of the map and returns its image data. + Uint8List? takeSnapshot(); +} + +/// Interface for calls from the native SDK to Dart. +@FlutterApi() +abstract class MapsCallbackApi { + /// Called when the map camera starts moving. + @ObjCSelector('didStartCameraMoveWithCompletion') + void onCameraMoveStarted(); + + /// Called when the map camera moves. + @ObjCSelector('didMoveCameraToPosition:') + void onCameraMove(PlatformCameraPosition cameraPosition); + + /// Called when the map camera stops moving. + @ObjCSelector('didIdleCameraWithCompletion') + void onCameraIdle(); + + /// Called when the map, not a specifc map object, is tapped. + @ObjCSelector('didTapAtPosition:') + void onTap(PlatformLatLng position); + + /// Called when the map, not a specifc map object, is long pressed. + @ObjCSelector('didLongPressAtPosition:') + void onLongPress(PlatformLatLng position); + + /// Called when a marker is tapped. + @ObjCSelector('didTapMarkerWithIdentifier:') + void onMarkerTap(String markerId); + + /// Called when a marker drag starts. + @ObjCSelector('didStartDragForMarkerWithIdentifier:atPosition:') + void onMarkerDragStart(String markerId, PlatformLatLng position); + + /// Called when a marker drag updates. + @ObjCSelector('didDragMarkerWithIdentifier:atPosition:') + void onMarkerDrag(String markerId, PlatformLatLng position); + + /// Called when a marker drag ends. + @ObjCSelector('didEndDragForMarkerWithIdentifier:atPosition:') + void onMarkerDragEnd(String markerId, PlatformLatLng position); + + /// Called when a marker's info window is tapped. + @ObjCSelector('didTapInfoWindowOfMarkerWithIdentifier:') + void onInfoWindowTap(String markerId); + + /// Called when a circle is tapped. + @ObjCSelector('didTapCircleWithIdentifier:') + void onCircleTap(String circleId); + + /// Called when a marker cluster is tapped. + @ObjCSelector('didTapCluster:') + void onClusterTap(PlatformCluster cluster); + + /// Called when a polygon is tapped. + @ObjCSelector('didTapPolygonWithIdentifier:') + void onPolygonTap(String polygonId); + + /// Called when a polyline is tapped. + @ObjCSelector('didTapPolylineWithIdentifier:') + void onPolylineTap(String polylineId); + + /// Called when a ground overlay is tapped. + @ObjCSelector('didTapGroundOverlayWithIdentifier:') + void onGroundOverlayTap(String groundOverlayId); + + /// Called to get data for a map tile. + @async + @ObjCSelector('tileWithOverlayIdentifier:location:zoom:') + PlatformTile getTileOverlayTile( + String tileOverlayId, + PlatformPoint location, + int zoom, + ); +} + +/// Dummy interface to force generation of the platform view creation params, +/// which are not used in any Pigeon calls, only the platform view creation +/// call made internally by Flutter. +@HostApi() +abstract class MapsPlatformViewApi { + // This is never actually called. + void createView(PlatformMapViewCreationParams? type); +} + +/// Inspector API only intended for use in integration tests. +@HostApi() +abstract class MapsInspectorApi { + bool areBuildingsEnabled(); + bool areRotateGesturesEnabled(); + bool areScrollGesturesEnabled(); + bool areTiltGesturesEnabled(); + bool areZoomGesturesEnabled(); + bool isCompassEnabled(); + bool isMyLocationButtonEnabled(); + bool isTrafficEnabled(); + @ObjCSelector('tileOverlayWithIdentifier:') + PlatformTileLayer? getTileOverlayInfo(String tileOverlayId); + @ObjCSelector('groundOverlayWithIdentifier:') + PlatformGroundOverlay? getGroundOverlayInfo(String groundOverlayId); + @ObjCSelector('heatmapWithIdentifier:') + PlatformHeatmap? getHeatmapInfo(String heatmapId); + @ObjCSelector('zoomRange') + PlatformZoomRange getZoomRange(); + @ObjCSelector('clustersWithIdentifier:') + List getClusters(String clusterManagerId); + @ObjCSelector('cameraPosition') + PlatformCameraPosition getCameraPosition(); +} 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 new file mode 100644 index 000000000000..136ccda24364 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/pubspec.yaml @@ -0,0 +1,39 @@ +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.16.1 + +environment: + sdk: ^3.9.0 + flutter: ">=3.35.0" + +flutter: + plugin: + implements: google_maps_flutter + platforms: + ios: + pluginClass: FLTGoogleMapsPlugin + dartPluginClass: GoogleMapsFlutterIOS + +dependencies: + flutter: + sdk: flutter + google_maps_flutter_platform_interface: ^2.13.0 + stream_transform: ^2.0.0 + +dev_dependencies: + async: ^2.5.0 + build_runner: ^2.4.11 + flutter_test: + sdk: flutter + mockito: ^5.4.4 + path: ^1.8.0 + pigeon: ^26.1.0 + plugin_platform_interface: ^2.1.7 + process: ^5.0.5 + +topics: + - google-maps + - google-maps-flutter + - map 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 new file mode 100644 index 000000000000..4dee18297412 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.dart @@ -0,0 +1,1357 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +import 'dart:async'; + +import 'package:async/async.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'google_maps_flutter_ios_test.mocks.dart'; +import 'package_specific_test_import.dart'; + +@GenerateNiceMocks(>[MockSpec()]) +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + (GoogleMapsFlutterIOS, MockMapsApi) setUpMockMap({required int mapId}) { + final api = MockMapsApi(); + final maps = GoogleMapsFlutterIOS(apiProvider: (_) => api); + maps.ensureApiInitialized(mapId); + return (maps, api); + } + + test('registers instance', () async { + GoogleMapsFlutterIOS.registerWith(); + expect(GoogleMapsFlutterPlatform.instance, isA()); + }); + + test('init calls waitForMap', () async { + final api = MockMapsApi(); + final maps = GoogleMapsFlutterIOS(apiProvider: (_) => api); + + await maps.init(1); + + verify(api.waitForMap()); + }); + + test('getScreenCoordinate converts and passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Arbitrary values that are all different from each other. + const latLng = LatLng(10, 20); + const expectedCoord = ScreenCoordinate(x: 30, y: 40); + when(api.getScreenCoordinate(any)).thenAnswer( + (_) async => PlatformPoint( + x: expectedCoord.x.toDouble(), + y: expectedCoord.y.toDouble(), + ), + ); + + final ScreenCoordinate coord = await maps.getScreenCoordinate( + latLng, + mapId: mapId, + ); + expect(coord, expectedCoord); + final VerificationResult verification = verify( + api.getScreenCoordinate(captureAny), + ); + final passedLatLng = verification.captured[0] as PlatformLatLng; + expect(passedLatLng.latitude, latLng.latitude); + expect(passedLatLng.longitude, latLng.longitude); + }); + + test('getLatLng converts and passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Arbitrary values that are all different from each other. + const expectedLatLng = LatLng(10, 20); + const coord = ScreenCoordinate(x: 30, y: 40); + when(api.getLatLng(any)).thenAnswer( + (_) async => PlatformLatLng( + latitude: expectedLatLng.latitude, + longitude: expectedLatLng.longitude, + ), + ); + + final LatLng latLng = await maps.getLatLng(coord, mapId: mapId); + expect(latLng, expectedLatLng); + final VerificationResult verification = verify(api.getLatLng(captureAny)); + final passedCoord = verification.captured[0] as PlatformPoint; + expect(passedCoord.x, coord.x); + expect(passedCoord.y, coord.y); + }); + + test('getVisibleRegion converts and passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Arbitrary values that are all different from each other. + final expectedBounds = LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ); + when(api.getVisibleRegion()).thenAnswer( + (_) async => PlatformLatLngBounds( + southwest: PlatformLatLng( + latitude: expectedBounds.southwest.latitude, + longitude: expectedBounds.southwest.longitude, + ), + northeast: PlatformLatLng( + latitude: expectedBounds.northeast.latitude, + longitude: expectedBounds.northeast.longitude, + ), + ), + ); + + final LatLngBounds bounds = await maps.getVisibleRegion(mapId: mapId); + expect(bounds, expectedBounds); + }); + + test('moveCamera calls through with expected scrollBy', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final scroll = passedUpdate.cameraUpdate as PlatformCameraUpdateScrollBy; + update as CameraUpdateScrollBy; + expect(scroll.dx, update.dx); + expect(scroll.dy, update.dy); + }); + + test('animateCamera calls through with expected scrollBy', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.animateCamera(update, mapId: mapId); + + final VerificationResult verification = verify( + api.animateCamera(captureAny, captureAny), + ); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final scroll = passedUpdate.cameraUpdate as PlatformCameraUpdateScrollBy; + update as CameraUpdateScrollBy; + expect(scroll.dx, update.dx); + expect(scroll.dy, update.dy); + expect(verification.captured[1], isNull); + }); + + test('animateCameraWithConfiguration calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + const configuration = CameraUpdateAnimationConfiguration( + duration: Duration(seconds: 1), + ); + expect(configuration.duration?.inSeconds, 1); + await maps.animateCameraWithConfiguration( + update, + configuration, + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.animateCamera(captureAny, captureAny), + ); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final scroll = passedUpdate.cameraUpdate as PlatformCameraUpdateScrollBy; + update as CameraUpdateScrollBy; + expect(scroll.dx, update.dx); + expect(scroll.dy, update.dy); + + final passedDuration = verification.captured[1] as int?; + expect(passedDuration, configuration.duration?.inMilliseconds); + }); + + test('getZoomLevel passes values correctly', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const expectedZoom = 4.2; + when(api.getZoomLevel()).thenAnswer((_) async => expectedZoom); + + final double zoom = await maps.getZoomLevel(mapId: mapId); + expect(zoom, expectedZoom); + }); + + test('showInfoWindow calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const markedId = 'a_marker'; + await maps.showMarkerInfoWindow(const MarkerId(markedId), mapId: mapId); + + verify(api.showInfoWindow(markedId)); + }); + + test('hideInfoWindow calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const markedId = 'a_marker'; + await maps.hideMarkerInfoWindow(const MarkerId(markedId), mapId: mapId); + + verify(api.hideInfoWindow(markedId)); + }); + + test('isInfoWindowShown calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const markedId = 'a_marker'; + when(api.isInfoWindowShown(markedId)).thenAnswer((_) async => true); + + expect( + await maps.isMarkerInfoWindowShown( + const MarkerId(markedId), + mapId: mapId, + ), + true, + ); + }); + + test('takeSnapshot calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final fakeSnapshot = Uint8List(10); + when(api.takeSnapshot()).thenAnswer((_) async => fakeSnapshot); + + expect(await maps.takeSnapshot(mapId: mapId), fakeSnapshot); + }); + + test('clearTileCache calls through', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const tileOverlayId = 'overlay'; + await maps.clearTileCache(const TileOverlayId(tileOverlayId), mapId: mapId); + + verify(api.clearTileCache(tileOverlayId)); + }); + + test('updateMapConfiguration passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Set some arbitrary options. + final cameraBounds = CameraTargetBounds( + LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + ); + final config = MapConfiguration( + compassEnabled: true, + mapType: MapType.terrain, + cameraTargetBounds: cameraBounds, + ); + await maps.updateMapConfiguration(config, mapId: mapId); + + final VerificationResult verification = verify( + api.updateMapConfiguration(captureAny), + ); + final passedConfig = verification.captured[0] as PlatformMapConfiguration; + // Each set option should be present. + expect(passedConfig.compassEnabled, true); + expect(passedConfig.mapType, PlatformMapType.terrain); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.latitude, + cameraBounds.bounds?.northeast.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.longitude, + cameraBounds.bounds?.northeast.longitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.latitude, + cameraBounds.bounds?.southwest.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.longitude, + cameraBounds.bounds?.southwest.longitude, + ); + // Spot-check that unset options are not be present. + expect(passedConfig.myLocationEnabled, isNull); + expect(passedConfig.minMaxZoomPreference, isNull); + expect(passedConfig.padding, isNull); + }); + + test('updateMapOptions passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + // Set some arbitrary options. + final cameraBounds = CameraTargetBounds( + LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + ); + final config = { + 'compassEnabled': true, + 'mapType': MapType.terrain.index, + 'cameraTargetBounds': cameraBounds.toJson(), + }; + await maps.updateMapOptions(config, mapId: mapId); + + final VerificationResult verification = verify( + api.updateMapConfiguration(captureAny), + ); + final passedConfig = verification.captured[0] as PlatformMapConfiguration; + // Each set option should be present. + expect(passedConfig.compassEnabled, true); + expect(passedConfig.mapType, PlatformMapType.terrain); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.latitude, + cameraBounds.bounds?.northeast.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.northeast.longitude, + cameraBounds.bounds?.northeast.longitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.latitude, + cameraBounds.bounds?.southwest.latitude, + ); + expect( + passedConfig.cameraTargetBounds?.bounds?.southwest.longitude, + cameraBounds.bounds?.southwest.longitude, + ); + // Spot-check that unset options are not be present. + expect(passedConfig.myLocationEnabled, isNull); + expect(passedConfig.minMaxZoomPreference, isNull); + expect(passedConfig.padding, isNull); + }); + + test('updateCircles passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Circle(circleId: CircleId('1')); + const object2old = Circle(circleId: CircleId('2')); + final Circle object2new = object2old.copyWith(radiusParam: 42); + const object3 = Circle(circleId: CircleId('3')); + await maps.updateCircles( + CircleUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateCircles(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.circleId.value); + // Object two should be changed. + { + expect(toChange.length, 1); + final PlatformCircle firstChanged = toChange.first; + expect(firstChanged.consumeTapEvents, object2new.consumeTapEvents); + _expectColorsEqual(firstChanged.fillColor, object2new.fillColor); + _expectColorsEqual(firstChanged.strokeColor, object2new.strokeColor); + expect(firstChanged.visible, object2new.visible); + expect(firstChanged.strokeWidth, object2new.strokeWidth); + expect(firstChanged.zIndex, object2new.zIndex.toDouble()); + expect(firstChanged.center.latitude, object2new.center.latitude); + expect(firstChanged.center.longitude, object2new.center.longitude); + expect(firstChanged.radius, object2new.radius); + expect(firstChanged.circleId, object2new.circleId.value); + } + // Object 3 should be added. + { + expect(toAdd.length, 1); + final PlatformCircle firstAdded = toAdd.first; + expect(firstAdded.consumeTapEvents, object3.consumeTapEvents); + _expectColorsEqual(firstAdded.fillColor, object3.fillColor); + _expectColorsEqual(firstAdded.strokeColor, object3.strokeColor); + expect(firstAdded.visible, object3.visible); + expect(firstAdded.strokeWidth, object3.strokeWidth); + expect(firstAdded.zIndex, object3.zIndex.toDouble()); + expect(firstAdded.center.latitude, object3.center.latitude); + expect(firstAdded.center.longitude, object3.center.longitude); + expect(firstAdded.radius, object3.radius); + expect(firstAdded.circleId, object3.circleId.value); + } + }); + + test('updateClusterManagers passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = ClusterManager(clusterManagerId: ClusterManagerId('1')); + const object3 = ClusterManager(clusterManagerId: ClusterManagerId('3')); + await maps.updateClusterManagers( + ClusterManagerUpdates.from( + {object1}, + {object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateClusterManagers(captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toRemove = verification.captured[1] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.clusterManagerId.value); + // Unlike other map object types, changes are not possible for cluster + // managers, since they have no non-ID properties. + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first.identifier, object3.clusterManagerId.value); + }); + + test('updateMarkers passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Marker(markerId: MarkerId('1')); + const object2old = Marker(markerId: MarkerId('2')); + final Marker object2new = object2old.copyWith(rotationParam: 42); + const object3 = Marker(markerId: MarkerId('3')); + await maps.updateMarkers( + MarkerUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateMarkers(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.markerId.value); + // Object two should be changed. + { + expect(toChange.length, 1); + final PlatformMarker firstChanged = toChange.first; + expect(firstChanged.alpha, object2new.alpha); + expect(firstChanged.anchor.x, object2new.anchor.dx); + expect(firstChanged.anchor.y, object2new.anchor.dy); + expect(firstChanged.consumeTapEvents, object2new.consumeTapEvents); + expect(firstChanged.draggable, object2new.draggable); + expect(firstChanged.flat, object2new.flat); + expect( + firstChanged.icon.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object2new.icon, + ).bitmap.runtimeType, + ); + expect(firstChanged.infoWindow.title, object2new.infoWindow.title); + expect(firstChanged.infoWindow.snippet, object2new.infoWindow.snippet); + expect(firstChanged.infoWindow.anchor.x, object2new.infoWindow.anchor.dx); + expect(firstChanged.infoWindow.anchor.y, object2new.infoWindow.anchor.dy); + expect(firstChanged.position.latitude, object2new.position.latitude); + expect(firstChanged.position.longitude, object2new.position.longitude); + expect(firstChanged.rotation, object2new.rotation); + expect(firstChanged.visible, object2new.visible); + expect(firstChanged.zIndex, object2new.zIndexInt); + expect(firstChanged.markerId, object2new.markerId.value); + expect(firstChanged.clusterManagerId, object2new.clusterManagerId?.value); + } + // Object 3 should be added. + { + expect(toAdd.length, 1); + final PlatformMarker firstAdded = toAdd.first; + expect(firstAdded.alpha, object3.alpha); + expect(firstAdded.anchor.x, object3.anchor.dx); + expect(firstAdded.anchor.y, object3.anchor.dy); + expect(firstAdded.consumeTapEvents, object3.consumeTapEvents); + expect(firstAdded.draggable, object3.draggable); + expect(firstAdded.flat, object3.flat); + expect( + firstAdded.icon.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object3.icon, + ).bitmap.runtimeType, + ); + expect(firstAdded.infoWindow.title, object3.infoWindow.title); + expect(firstAdded.infoWindow.snippet, object3.infoWindow.snippet); + expect(firstAdded.infoWindow.anchor.x, object3.infoWindow.anchor.dx); + expect(firstAdded.infoWindow.anchor.y, object3.infoWindow.anchor.dy); + expect(firstAdded.position.latitude, object3.position.latitude); + expect(firstAdded.position.longitude, object3.position.longitude); + expect(firstAdded.rotation, object3.rotation); + expect(firstAdded.visible, object3.visible); + expect(firstAdded.zIndex, object3.zIndexInt); + expect(firstAdded.markerId, object3.markerId.value); + expect(firstAdded.clusterManagerId, object3.clusterManagerId?.value); + } + }); + + test('updatePolygons passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Polygon(polygonId: PolygonId('1')); + const object2old = Polygon(polygonId: PolygonId('2')); + final Polygon object2new = object2old.copyWith(strokeWidthParam: 42); + const object3 = Polygon(polygonId: PolygonId('3')); + await maps.updatePolygons( + PolygonUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updatePolygons(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polygonId.value); + void expectPolygon(PlatformPolygon actual, Polygon expected) { + expect(actual.polygonId, expected.polygonId.value); + expect(actual.consumesTapEvents, expected.consumeTapEvents); + _expectColorsEqual(actual.fillColor, expected.fillColor); + expect(actual.geodesic, expected.geodesic); + expect(actual.points.length, expected.points.length); + for (final (int i, PlatformLatLng? point) in actual.points.indexed) { + expect(point?.latitude, expected.points[i].latitude); + expect(point?.longitude, expected.points[i].longitude); + } + expect(actual.holes.length, expected.holes.length); + for (final (int i, List? hole) in actual.holes.indexed) { + final List expectedHole = expected.holes[i]; + for (final (int j, PlatformLatLng? point) in hole!.indexed) { + expect(point?.latitude, expectedHole[j].latitude); + expect(point?.longitude, expectedHole[j].longitude); + } + } + expect(actual.visible, expected.visible); + _expectColorsEqual(actual.strokeColor, expected.strokeColor); + expect(actual.strokeWidth, expected.strokeWidth); + expect(actual.zIndex, expected.zIndex); + } + + // Object two should be changed. + expect(toChange.length, 1); + expectPolygon(toChange.first, object2new); + // Object 3 should be added. + expect(toAdd.length, 1); + expectPolygon(toAdd.first, object3); + }); + + test('updatePolylines passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = Polyline(polylineId: PolylineId('1')); + const object2old = Polyline(polylineId: PolylineId('2')); + final Polyline object2new = object2old.copyWith( + widthParam: 42, + startCapParam: Cap.squareCap, + endCapParam: Cap.buttCap, + ); + final Cap customCap = Cap.customCapFromBitmap( + BitmapDescriptor.defaultMarker, + refWidth: 15, + ); + final object3 = Polyline( + polylineId: const PolylineId('3'), + startCap: customCap, + endCap: Cap.roundCap, + ); + await maps.updatePolylines( + PolylineUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updatePolylines(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + void expectPolyline(PlatformPolyline actual, Polyline expected) { + expect(actual.polylineId, expected.polylineId.value); + expect(actual.consumesTapEvents, expected.consumeTapEvents); + _expectColorsEqual(actual.color, expected.color); + expect(actual.geodesic, expected.geodesic); + expect( + actual.jointType, + platformJointTypeFromJointType(expected.jointType), + ); + expect(actual.visible, expected.visible); + expect(actual.width, expected.width); + expect(actual.zIndex, expected.zIndex); + expect(actual.points.length, expected.points.length); + for (final (int i, PlatformLatLng? point) in actual.points.indexed) { + expect(point?.latitude, actual.points[i].latitude); + expect(point?.longitude, actual.points[i].longitude); + } + expect(actual.patterns.length, expected.patterns.length); + for (final (int i, PlatformPatternItem? pattern) + in actual.patterns.indexed) { + expect( + pattern?.encode(), + platformPatternItemFromPatternItem(expected.patterns[i]).encode(), + ); + } + } + + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polylineId.value); + // Object two should be changed. + expect(toChange.length, 1); + expectPolyline(toChange.first, object2new); + // Object 3 should be added. + expect(toAdd.length, 1); + expectPolyline(toAdd.first, object3); + }); + + test('updateTileOverlays passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const object1 = TileOverlay(tileOverlayId: TileOverlayId('1')); + const object2old = TileOverlay(tileOverlayId: TileOverlayId('2')); + final TileOverlay object2new = object2old.copyWith(zIndexParam: 42); + const object3 = TileOverlay(tileOverlayId: TileOverlayId('3')); + // Pre-set the initial state, since this update method doesn't take the old + // state. + await maps.updateTileOverlays( + newTileOverlays: {object1, object2old}, + mapId: mapId, + ); + clearInteractions(api); + + await maps.updateTileOverlays( + newTileOverlays: {object2new, object3}, + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateTileOverlays(captureAny, captureAny, captureAny), + ); + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + void expectTileOverlay(PlatformTileOverlay actual, TileOverlay expected) { + expect(actual.tileOverlayId, expected.tileOverlayId.value); + expect(actual.fadeIn, expected.fadeIn); + expect(actual.transparency, expected.transparency); + expect(actual.zIndex, expected.zIndex); + expect(actual.visible, expected.visible); + expect(actual.tileSize, expected.tileSize); + } + + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.tileOverlayId.value); + // Object two should be changed. + expect(toChange.length, 1); + expectTileOverlay(toChange.first, object2new); + // Object 3 should be added. + expect(toAdd.length, 1); + expectTileOverlay(toAdd.first, object3); + }); + + test('updateGroundOverlays passes expected arguments', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final image = AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ); + + final object1 = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('1'), + bounds: LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + image: image, + ); + final object2old = GroundOverlay.fromBounds( + groundOverlayId: const GroundOverlayId('2'), + bounds: LatLngBounds( + southwest: const LatLng(10, 20), + northeast: const LatLng(30, 40), + ), + image: image, + ); + final GroundOverlay object2new = object2old.copyWith( + visibleParam: false, + bearingParam: 10, + clickableParam: false, + transparencyParam: 0.5, + zIndexParam: 100, + ); + final object3 = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('3'), + position: const LatLng(10, 20), + width: 100, + image: image, + zoomLevel: 14.0, + ); + await maps.updateGroundOverlays( + GroundOverlayUpdates.from( + {object1, object2old}, + {object2new, object3}, + ), + mapId: mapId, + ); + + final VerificationResult verification = verify( + api.updateGroundOverlays(captureAny, captureAny, captureAny), + ); + + final toAdd = verification.captured[0] as List; + final toChange = verification.captured[1] as List; + final toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.groundOverlayId.value); + // Object two should be changed. + { + expect(toChange.length, 1); + final PlatformGroundOverlay firstChanged = toChange.first; + expect(firstChanged.anchor?.x, object2new.anchor?.dx); + expect(firstChanged.anchor?.y, object2new.anchor?.dy); + expect(firstChanged.bearing, object2new.bearing); + expect( + firstChanged.bounds?.northeast.latitude, + object2new.bounds?.northeast.latitude, + ); + expect( + firstChanged.bounds?.northeast.longitude, + object2new.bounds?.northeast.longitude, + ); + expect( + firstChanged.bounds?.southwest.latitude, + object2new.bounds?.southwest.latitude, + ); + expect( + firstChanged.bounds?.southwest.longitude, + object2new.bounds?.southwest.longitude, + ); + expect(firstChanged.visible, object2new.visible); + expect(firstChanged.clickable, object2new.clickable); + expect(firstChanged.zIndex, object2new.zIndex); + expect(firstChanged.position?.latitude, object2new.position?.latitude); + expect(firstChanged.position?.longitude, object2new.position?.longitude); + expect(firstChanged.zoomLevel, object2new.zoomLevel); + expect(firstChanged.transparency, object2new.transparency); + expect( + firstChanged.image.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object2new.image, + ).bitmap.runtimeType, + ); + } + // Object three should be added. + { + expect(toAdd.length, 1); + final PlatformGroundOverlay firstAdded = toAdd.first; + expect(firstAdded.anchor?.x, object3.anchor?.dx); + expect(firstAdded.anchor?.y, object3.anchor?.dy); + expect(firstAdded.bearing, object3.bearing); + expect( + firstAdded.bounds?.northeast.latitude, + object3.bounds?.northeast.latitude, + ); + expect( + firstAdded.bounds?.northeast.longitude, + object3.bounds?.northeast.longitude, + ); + expect( + firstAdded.bounds?.southwest.latitude, + object3.bounds?.southwest.latitude, + ); + expect( + firstAdded.bounds?.southwest.longitude, + object3.bounds?.southwest.longitude, + ); + expect(firstAdded.visible, object3.visible); + expect(firstAdded.clickable, object3.clickable); + expect(firstAdded.zIndex, object3.zIndex); + expect(firstAdded.position?.latitude, object3.position?.latitude); + expect(firstAdded.position?.longitude, object3.position?.longitude); + expect(firstAdded.zoomLevel, object3.zoomLevel); + expect(firstAdded.transparency, object3.transparency); + expect( + firstAdded.image.bitmap.runtimeType, + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor( + object3.image, + ).bitmap.runtimeType, + ); + } + }); + + test( + 'updateGroundOverlays throws assertion error on unsupported ground overlays', + () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final image = AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + bitmapScaling: MapBitmapScaling.none, + ); + + final object3 = GroundOverlay.fromPosition( + groundOverlayId: const GroundOverlayId('1'), + position: const LatLng(10, 20), + // Assert should be thrown because zoomLevel is not set for position-based + // ground overlay on iOS. + // ignore: avoid_redundant_argument_values + zoomLevel: null, + image: image, + ); + + expect( + () async => maps.updateGroundOverlays( + GroundOverlayUpdates.from(const {}, { + object3, + }), + mapId: mapId, + ), + throwsAssertionError, + ); + }, + ); + + test('markers send drag event to correct streams', () async { + const mapId = 1; + const dragStartId = 'drag-start-marker'; + const dragId = 'drag-marker'; + const dragEndId = 'drag-end-marker'; + final fakePosition = PlatformLatLng(latitude: 1.0, longitude: 1.0); + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final markerDragStartStream = StreamQueue( + maps.onMarkerDragStart(mapId: mapId), + ); + final markerDragStream = StreamQueue( + maps.onMarkerDrag(mapId: mapId), + ); + final markerDragEndStream = StreamQueue( + maps.onMarkerDragEnd(mapId: mapId), + ); + + // Simulate messages from the native side. + callbackHandler.onMarkerDragStart(dragStartId, fakePosition); + callbackHandler.onMarkerDrag(dragId, fakePosition); + callbackHandler.onMarkerDragEnd(dragEndId, fakePosition); + + expect((await markerDragStartStream.next).value.value, equals(dragStartId)); + expect((await markerDragStream.next).value.value, equals(dragId)); + expect((await markerDragEndStream.next).value.value, equals(dragEndId)); + }); + + test('markers send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue(maps.onMarkerTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onMarkerTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('circles send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue(maps.onCircleTap(mapId: mapId)); + + // Simulate message from the native side. + callbackHandler.onCircleTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('clusters send tap events to correct stream', () async { + const mapId = 1; + const managerId = 'manager-id'; + final fakePosition = PlatformLatLng(latitude: 10, longitude: 20); + final fakeBounds = PlatformLatLngBounds( + southwest: PlatformLatLng(latitude: 30, longitude: 40), + northeast: PlatformLatLng(latitude: 50, longitude: 60), + ); + const markerIds = ['marker-1', 'marker-2']; + final cluster = PlatformCluster( + clusterManagerId: managerId, + position: fakePosition, + bounds: fakeBounds, + markerIds: markerIds, + ); + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onClusterTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onClusterTap(cluster); + + final Cluster eventValue = (await stream.next).value; + expect(eventValue.clusterManagerId.value, managerId); + expect(eventValue.position.latitude, fakePosition.latitude); + expect(eventValue.position.longitude, fakePosition.longitude); + expect(eventValue.bounds.southwest.latitude, fakeBounds.southwest.latitude); + expect( + eventValue.bounds.southwest.longitude, + fakeBounds.southwest.longitude, + ); + expect(eventValue.bounds.northeast.latitude, fakeBounds.northeast.latitude); + expect( + eventValue.bounds.northeast.longitude, + fakeBounds.northeast.longitude, + ); + expect(eventValue.markerIds.length, markerIds.length); + expect(eventValue.markerIds.first.value, markerIds.first); + }); + + test('polygons send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onPolygonTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onPolygonTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('polylines send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onPolylineTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onPolylineTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('ground overlays send tap events to correct stream', () async { + const mapId = 1; + const objectId = 'object-id'; + + final maps = GoogleMapsFlutterIOS(); + final HostMapMessageHandler callbackHandler = maps.ensureHandlerInitialized( + mapId, + ); + + final stream = StreamQueue( + maps.onGroundOverlayTap(mapId: mapId), + ); + + // Simulate message from the native side. + callbackHandler.onGroundOverlayTap(objectId); + + expect((await stream.next).value.value, equals(objectId)); + }); + + test('moveCamera calls through with expected newCameraPosition', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const latLng = LatLng(10.0, 20.0); + const position = CameraPosition(target: latLng); + final CameraUpdate update = CameraUpdate.newCameraPosition(position); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewCameraPosition; + update as CameraUpdateNewCameraPosition; + expect( + typedUpdate.cameraPosition.target.latitude, + update.cameraPosition.target.latitude, + ); + expect( + typedUpdate.cameraPosition.target.longitude, + update.cameraPosition.target.longitude, + ); + }); + + test('moveCamera calls through with expected newLatLng', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const latLng = LatLng(10.0, 20.0); + final CameraUpdate update = CameraUpdate.newLatLng(latLng); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewLatLng; + update as CameraUpdateNewLatLng; + expect(typedUpdate.latLng.latitude, update.latLng.latitude); + expect(typedUpdate.latLng.longitude, update.latLng.longitude); + }); + + test('moveCamera calls through with expected newLatLngBounds', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final latLng = LatLngBounds( + northeast: const LatLng(10.0, 20.0), + southwest: const LatLng(9.0, 21.0), + ); + final CameraUpdate update = CameraUpdate.newLatLngBounds(latLng, 1.0); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewLatLngBounds; + update as CameraUpdateNewLatLngBounds; + expect( + typedUpdate.bounds.northeast.latitude, + update.bounds.northeast.latitude, + ); + expect( + typedUpdate.bounds.northeast.longitude, + update.bounds.northeast.longitude, + ); + expect( + typedUpdate.bounds.southwest.latitude, + update.bounds.southwest.latitude, + ); + expect( + typedUpdate.bounds.southwest.longitude, + update.bounds.southwest.longitude, + ); + expect(typedUpdate.padding, update.padding); + }); + + test('moveCamera calls through with expected newLatLngZoom', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const latLng = LatLng(10.0, 20.0); + final CameraUpdate update = CameraUpdate.newLatLngZoom(latLng, 2.0); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = + passedUpdate.cameraUpdate as PlatformCameraUpdateNewLatLngZoom; + update as CameraUpdateNewLatLngZoom; + expect(typedUpdate.latLng.latitude, update.latLng.latitude); + expect(typedUpdate.latLng.longitude, update.latLng.longitude); + expect(typedUpdate.zoom, update.zoom); + }); + + test('moveCamera calls through with expected zoomBy', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + const focus = Offset(10.0, 20.0); + final CameraUpdate update = CameraUpdate.zoomBy(2.0, focus); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoomBy; + update as CameraUpdateZoomBy; + expect(typedUpdate.focus?.x, update.focus?.dx); + expect(typedUpdate.focus?.y, update.focus?.dy); + expect(typedUpdate.amount, update.amount); + }); + + test('moveCamera calls through with expected zoomTo', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.zoomTo(2.0); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoomTo; + update as CameraUpdateZoomTo; + expect(typedUpdate.zoom, update.zoom); + }); + + test('moveCamera calls through with expected zoomIn', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.zoomIn(); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoom; + expect(typedUpdate.out, false); + }); + + test('moveCamera calls through with expected zoomOut', () async { + const mapId = 1; + final (GoogleMapsFlutterIOS maps, MockMapsApi api) = setUpMockMap( + mapId: mapId, + ); + + final CameraUpdate update = CameraUpdate.zoomOut(); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final passedUpdate = verification.captured[0] as PlatformCameraUpdate; + final typedUpdate = passedUpdate.cameraUpdate as PlatformCameraUpdateZoom; + expect(typedUpdate.out, true); + }); + + test('MapBitmapScaling to PlatformMapBitmapScaling', () { + expect( + GoogleMapsFlutterIOS.platformMapBitmapScalingFromScaling( + MapBitmapScaling.auto, + ), + PlatformMapBitmapScaling.auto, + ); + expect( + GoogleMapsFlutterIOS.platformMapBitmapScalingFromScaling( + MapBitmapScaling.none, + ), + PlatformMapBitmapScaling.none, + ); + }); + + test('DefaultMarker bitmap to PlatformBitmap', () { + final BitmapDescriptor bitmap = BitmapDescriptor.defaultMarkerWithHue(10.0); + final PlatformBitmap platformBitmap = + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor(bitmap); + expect(platformBitmap.bitmap, isA()); + final typedBitmap = platformBitmap.bitmap as PlatformBitmapDefaultMarker; + expect(typedBitmap.hue, 10.0); + }); + + test('BytesMapBitmap bitmap to PlatformBitmap', () { + final data = Uint8List.fromList([1, 2, 3, 4]); + final BytesMapBitmap bitmap = BitmapDescriptor.bytes( + data, + imagePixelRatio: 2.0, + width: 100.0, + height: 200.0, + ); + final PlatformBitmap platformBitmap = + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor(bitmap); + expect(platformBitmap.bitmap, isA()); + final typedBitmap = platformBitmap.bitmap as PlatformBitmapBytesMap; + expect(typedBitmap.byteData, data); + expect(typedBitmap.bitmapScaling, PlatformMapBitmapScaling.auto); + expect(typedBitmap.imagePixelRatio, 2.0); + expect(typedBitmap.width, 100.0); + expect(typedBitmap.height, 200.0); + }); + + test('AssetMapBitmap bitmap to PlatformBitmap', () { + const assetName = 'fake_asset_name'; + final bitmap = AssetMapBitmap( + assetName, + imagePixelRatio: 2.0, + width: 100.0, + height: 200.0, + ); + final PlatformBitmap platformBitmap = + GoogleMapsFlutterIOS.platformBitmapFromBitmapDescriptor(bitmap); + expect(platformBitmap.bitmap, isA()); + final typedBitmap = platformBitmap.bitmap as PlatformBitmapAssetMap; + expect(typedBitmap.assetName, assetName); + expect(typedBitmap.bitmapScaling, PlatformMapBitmapScaling.auto); + expect(typedBitmap.imagePixelRatio, 2.0); + expect(typedBitmap.width, 100.0); + expect(typedBitmap.height, 200.0); + }); + + testWidgets('mapId is passed', (WidgetTester tester) async { + const cloudMapId = '000000000000000'; // Dummy map ID. + final passedCloudMapIdCompleter = Completer(); + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(SystemChannels.platform_views, ( + MethodCall methodCall, + ) { + if (methodCall.method == 'create') { + final args = Map.from( + methodCall.arguments as Map, + ); + if (args.containsKey('params')) { + final paramsUint8List = args['params'] as Uint8List; + final byteData = ByteData.sublistView(paramsUint8List); + final creationParams = + MapsApi.pigeonChannelCodec.decodeMessage(byteData) + as PlatformMapViewCreationParams?; + if (creationParams != null) { + final String? passedMapId = + creationParams.mapConfiguration.mapId; + if (passedMapId != null) { + passedCloudMapIdCompleter.complete(passedMapId); + } + } + } + } + return null; + }); + + final maps = GoogleMapsFlutterIOS(); + + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: maps.buildViewWithConfiguration( + 1, + (int id) {}, + widgetConfiguration: const MapWidgetConfiguration( + initialCameraPosition: CameraPosition( + target: LatLng(0, 0), + zoom: 1, + ), + textDirection: TextDirection.ltr, + ), + mapConfiguration: const MapConfiguration(mapId: cloudMapId), + ), + ), + ); + + expect( + await passedCloudMapIdCompleter.future, + cloudMapId, + reason: 'Should pass mapId on PlatformView creation message', + ); + }); +} + +void _expectColorsEqual(PlatformColor actual, Color expected) { + expect(actual.red, expected.r); + expect(actual.green, expected.g); + expect(actual.blue, expected.b); + expect(actual.alpha, expected.a); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.mocks.dart new file mode 100644 index 000000000000..428e096b78eb --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.mocks.dart @@ -0,0 +1,351 @@ +// Mocks generated by Mockito 5.4.5 from annotations +// in google_maps_flutter_ios/test/google_maps_flutter_ios_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i4; +import 'dart:typed_data' as _i5; + +import 'package:google_maps_flutter_ios_sdk9/src/messages.g.dart' as _i2; +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i3; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakePlatformPoint_0 extends _i1.SmartFake implements _i2.PlatformPoint { + _FakePlatformPoint_0(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakePlatformLatLng_1 extends _i1.SmartFake + implements _i2.PlatformLatLng { + _FakePlatformLatLng_1(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +class _FakePlatformLatLngBounds_2 extends _i1.SmartFake + implements _i2.PlatformLatLngBounds { + _FakePlatformLatLngBounds_2(Object parent, Invocation parentInvocation) + : super(parent, parentInvocation); +} + +/// A class which mocks [MapsApi]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockMapsApi extends _i1.Mock implements _i2.MapsApi { + @override + String get pigeonVar_messageChannelSuffix => + (super.noSuchMethod( + Invocation.getter(#pigeonVar_messageChannelSuffix), + returnValue: _i3.dummyValue( + this, + Invocation.getter(#pigeonVar_messageChannelSuffix), + ), + returnValueForMissingStub: _i3.dummyValue( + this, + Invocation.getter(#pigeonVar_messageChannelSuffix), + ), + ) + as String); + + @override + _i4.Future waitForMap() => + (super.noSuchMethod( + Invocation.method(#waitForMap, []), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateMapConfiguration( + _i2.PlatformMapConfiguration? configuration, + ) => + (super.noSuchMethod( + Invocation.method(#updateMapConfiguration, [configuration]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateCircles( + List<_i2.PlatformCircle>? toAdd, + List<_i2.PlatformCircle>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateCircles, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateHeatmaps( + List<_i2.PlatformHeatmap>? toAdd, + List<_i2.PlatformHeatmap>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateHeatmaps, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateClusterManagers( + List<_i2.PlatformClusterManager>? toAdd, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateClusterManagers, [toAdd, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateMarkers( + List<_i2.PlatformMarker>? toAdd, + List<_i2.PlatformMarker>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateMarkers, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updatePolygons( + List<_i2.PlatformPolygon>? toAdd, + List<_i2.PlatformPolygon>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updatePolygons, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updatePolylines( + List<_i2.PlatformPolyline>? toAdd, + List<_i2.PlatformPolyline>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updatePolylines, [toAdd, toChange, idsToRemove]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateTileOverlays( + List<_i2.PlatformTileOverlay>? toAdd, + List<_i2.PlatformTileOverlay>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateTileOverlays, [ + toAdd, + toChange, + idsToRemove, + ]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future updateGroundOverlays( + List<_i2.PlatformGroundOverlay>? toAdd, + List<_i2.PlatformGroundOverlay>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method(#updateGroundOverlays, [ + toAdd, + toChange, + idsToRemove, + ]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future<_i2.PlatformPoint> getScreenCoordinate( + _i2.PlatformLatLng? latLng, + ) => + (super.noSuchMethod( + Invocation.method(#getScreenCoordinate, [latLng]), + returnValue: _i4.Future<_i2.PlatformPoint>.value( + _FakePlatformPoint_0( + this, + Invocation.method(#getScreenCoordinate, [latLng]), + ), + ), + returnValueForMissingStub: _i4.Future<_i2.PlatformPoint>.value( + _FakePlatformPoint_0( + this, + Invocation.method(#getScreenCoordinate, [latLng]), + ), + ), + ) + as _i4.Future<_i2.PlatformPoint>); + + @override + _i4.Future<_i2.PlatformLatLng> getLatLng( + _i2.PlatformPoint? screenCoordinate, + ) => + (super.noSuchMethod( + Invocation.method(#getLatLng, [screenCoordinate]), + returnValue: _i4.Future<_i2.PlatformLatLng>.value( + _FakePlatformLatLng_1( + this, + Invocation.method(#getLatLng, [screenCoordinate]), + ), + ), + returnValueForMissingStub: _i4.Future<_i2.PlatformLatLng>.value( + _FakePlatformLatLng_1( + this, + Invocation.method(#getLatLng, [screenCoordinate]), + ), + ), + ) + as _i4.Future<_i2.PlatformLatLng>); + + @override + _i4.Future<_i2.PlatformLatLngBounds> getVisibleRegion() => + (super.noSuchMethod( + Invocation.method(#getVisibleRegion, []), + returnValue: _i4.Future<_i2.PlatformLatLngBounds>.value( + _FakePlatformLatLngBounds_2( + this, + Invocation.method(#getVisibleRegion, []), + ), + ), + returnValueForMissingStub: + _i4.Future<_i2.PlatformLatLngBounds>.value( + _FakePlatformLatLngBounds_2( + this, + Invocation.method(#getVisibleRegion, []), + ), + ), + ) + as _i4.Future<_i2.PlatformLatLngBounds>); + + @override + _i4.Future moveCamera(_i2.PlatformCameraUpdate? cameraUpdate) => + (super.noSuchMethod( + Invocation.method(#moveCamera, [cameraUpdate]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future animateCamera( + _i2.PlatformCameraUpdate? cameraUpdate, + int? durationMilliseconds, + ) => + (super.noSuchMethod( + Invocation.method(#animateCamera, [ + cameraUpdate, + durationMilliseconds, + ]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future getZoomLevel() => + (super.noSuchMethod( + Invocation.method(#getZoomLevel, []), + returnValue: _i4.Future.value(0.0), + returnValueForMissingStub: _i4.Future.value(0.0), + ) + as _i4.Future); + + @override + _i4.Future showInfoWindow(String? markerId) => + (super.noSuchMethod( + Invocation.method(#showInfoWindow, [markerId]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future hideInfoWindow(String? markerId) => + (super.noSuchMethod( + Invocation.method(#hideInfoWindow, [markerId]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future isInfoWindowShown(String? markerId) => + (super.noSuchMethod( + Invocation.method(#isInfoWindowShown, [markerId]), + returnValue: _i4.Future.value(false), + returnValueForMissingStub: _i4.Future.value(false), + ) + as _i4.Future); + + @override + _i4.Future setStyle(String? style) => + (super.noSuchMethod( + Invocation.method(#setStyle, [style]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future getLastStyleError() => + (super.noSuchMethod( + Invocation.method(#getLastStyleError, []), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future clearTileCache(String? tileOverlayId) => + (super.noSuchMethod( + Invocation.method(#clearTileCache, [tileOverlayId]), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) + as _i4.Future); + + @override + _i4.Future<_i5.Uint8List?> takeSnapshot() => + (super.noSuchMethod( + Invocation.method(#takeSnapshot, []), + returnValue: _i4.Future<_i5.Uint8List?>.value(), + returnValueForMissingStub: _i4.Future<_i5.Uint8List?>.value(), + ) + as _i4.Future<_i5.Uint8List?>); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/package_specific_test_import.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/package_specific_test_import.dart new file mode 100644 index 000000000000..2f86f15121d5 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/package_specific_test_import.dart @@ -0,0 +1,11 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This is a separate file so that all test files that need to import the +// implementation package can do so without causing diffs among the shared code +// due to the package names being different. This way, all the test files can +// be shared exactly, and only this file needs to diverge between the packages. + +export 'package:google_maps_flutter_ios_sdk9/google_maps_flutter_ios_sdk9.dart'; +export 'package:google_maps_flutter_ios_sdk9/src/messages.g.dart'; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/run_tests.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/run_tests.dart new file mode 100644 index 000000000000..114db5c7b00f --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/run_tests.dart @@ -0,0 +1,102 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: avoid_print + +// Ensures that all files that are intended to be shared between +// google_maps_flutter_ios_* packages are in sync with the shared source of +// truth. See google_maps_flutter_ios_shared_code/README.md for details. +// +// Called from the custom-tests CI action. + +import 'dart:async'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +import 'utils.dart'; + +Future main(List args) async { + // There's no reason to run this on multiple platforms in CI, so limit it to + // macOS where local development of this package will be happening. + if (!Platform.isMacOS) { + print('Skipping for non-macOS host'); + exit(0); + } + + final Directory packageRoot = Directory( + p.dirname(Platform.script.path), + ).parent; + final String packageName = p.basename(packageRoot.path); + final sharedSourceRoot = Directory( + p.join(packageRoot.parent.path, 'google_maps_flutter_ios_shared_code'), + ); + + var failed = false; + for (final FileSystemEntity entity in sharedSourceRoot.listSync( + recursive: true, + )) { + if (entity is! File) { + continue; + } + final String relativePath = p.relative( + entity.path, + from: sharedSourceRoot.path, + ); + // The shared source README.md is not part of the shared source of truth, + // just an explanation of this source-sharing system. + if (relativePath == 'README.md') { + continue; + } + + // Adjust the paths to account for the package name being part of the + // directory structure for Swift packages. + final String packagePath = p.join( + packageRoot.path, + packageRelativePathForSharedSourceRelativePath(packageName, relativePath), + ); + + print('Validating $relativePath'); + final packageFile = File(packagePath); + if (!packageFile.existsSync()) { + print(' File $relativePath does not exist in $packageName'); + failed = true; + continue; + } + final String expectedContents = normalizedFileContents(entity); + final String contents = normalizedFileContents(packageFile); + if (contents != expectedContents) { + print(' File $relativePath does not match expected contents:'); + await _printDiff(entity, packageFile); + failed = true; + } + } + + if (failed) { + print(''' + +If the changes you made should be shared with other copies of the +implementation, copy the changes to google_maps_flutter_ios_* directories: + dart run tool/sync_shared_files.dart +To validate that the changes have been shared correctly, run this tool again. + +If the changes you made should only be made to one copy of the implementation, +discuss with your reviewer or #hackers-ecosystem on Discord about the best +approach to sharing as much code as can still be shared. + +For more information on the code sharing structure used by this package, see +the google_maps_flutter_ios_shared_code/README.md file. + '''); + exit(1); + } +} + +Future _printDiff(File expected, File actual) async { + final Process process = await Process.start('diff', [ + '-u', + expected.absolute.path, + actual.absolute.path, + ], mode: ProcessStartMode.inheritStdio); + await process.exitCode; +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart new file mode 100644 index 000000000000..1a423bba92e6 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart @@ -0,0 +1,198 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ignore_for_file: avoid_print + +// Synchronizes files that are intended to be shared between +// google_maps_flutter_ios_* packages with the shared source of truth and other +// copies. See google_maps_flutter_ios_shared_code/README.md for details. + +import 'dart:async'; +import 'dart:io'; + +import 'package:path/path.dart' as p; + +import 'utils.dart'; + +const String _sharedSourceRootName = 'google_maps_flutter_ios_shared_code'; + +Future main(List args) async { + final Directory packageRoot = Directory( + p.dirname(Platform.script.path), + ).parent; + final String packageName = p.basename(packageRoot.path); + final sharedSourceRoot = Directory( + p.join(packageRoot.parent.path, _sharedSourceRootName), + ); + + _syncSharedFiles(packageRoot, packageName, sharedSourceRoot); + _reportUnsharedFiles(packageRoot, packageName, sharedSourceRoot); +} + +void _syncSharedFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List otherImplementationPackages = sharedSourceRoot.parent + .listSync() + .whereType() + .map((e) => p.basename(e.path)) + .where( + (name) => + name.startsWith('google_maps_flutter_ios') && + name != _sharedSourceRootName && + name != packageName, + ) + .toList(); + + final copiedFiles = []; + final missingFiles = []; + for (final FileSystemEntity entity in sharedSourceRoot.listSync( + recursive: true, + )) { + if (entity is! File) { + continue; + } + final String relativePath = p.relative( + entity.path, + from: sharedSourceRoot.path, + ); + // The shared source README.md is not part of the shared source of truth, + // just an explanation of this source-sharing system. + if (relativePath == 'README.md') { + continue; + } + + // Adjust the paths to account for the package name being part of the + // directory structure for Swift packages. + final String packagePath = p.join( + packageRoot.path, + packageRelativePathForSharedSourceRelativePath(packageName, relativePath), + ); + + final packageFile = File(packagePath); + if (!packageFile.existsSync()) { + missingFiles.add(relativePath); + continue; + } + final String sharedContents = normalizedFileContents(entity); + final String newContents = normalizedFileContents(packageFile); + if (newContents != sharedContents) { + copiedFiles.add(relativePath); + // Copy to shared source. + _syncFile(packageFile, entity.path, 'google_maps_flutter_ios'); + // Copy to other implementation packages. + for (final otherPackageName in otherImplementationPackages) { + final String otherPackagePath = p.join( + packageRoot.parent.path, + otherPackageName, + packageRelativePathForSharedSourceRelativePath( + otherPackageName, + relativePath, + ), + ); + _syncFile(packageFile, otherPackagePath, otherPackageName); + } + } + } + + if (copiedFiles.isNotEmpty) { + print('Copied files:'); + for (final file in copiedFiles) { + print(' $file'); + } + } + if (missingFiles.isNotEmpty) { + print( + 'This package is missing the following files from the shared source:', + ); + for (final file in missingFiles) { + print(' $file'); + } + print( + 'If these files should no longer be shared, remove them from the shared source.', + ); + } +} + +/// Syncs a file from the given source to a destination package. +/// +/// If the file needs special handling of package names that appear within the +/// contents of the file, it will update the package name in the file to match +/// the destination package name. +void _syncFile( + File source, + String destinationPath, + String destinationPackageName, +) { + source.copySync(destinationPath); + if ([ + // The Pigeon definition file has output paths that must use the + // package name, to follow Swift package naming rules. + '/pigeons/', + // The mock needs to import the package. + '.mocks.dart', + ].any((pattern) => source.absolute.path.contains(pattern))) { + updatePackageNameInPathReferences( + File(destinationPath), + destinationPackageName, + ); + } +} + +void _reportUnsharedFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List codeFiles = packageRoot + .listSync(recursive: true) + .whereType() + // Only report code files. + .where( + (file) => + ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), + ) + // Flutter-generated files aren't expected to be shared. + .where((file) => !file.path.contains('GeneratedPluginRegistrant')) + // Ignore intermediate file directories. + .where((file) => !_isInIntermediateDirectory(file.path)) + .toList(); + + final unsharedFiles = []; + for (final file in codeFiles) { + final String relativePath = p.relative(file.path, from: packageRoot.path); + final String sharedPath = p.join( + sharedSourceRoot.path, + sharedSourceRelativePathForPackagePath(relativePath), + ); + final sharedFile = File(sharedPath); + if (!sharedFile.existsSync()) { + unsharedFiles.add(relativePath); + } + } + + if (unsharedFiles.isNotEmpty) { + print('\nThe following code files are not shared with other packages:'); + for (final file in unsharedFiles) { + print(' $file'); + } + print( + 'If this is not intentional, copy the relevant files to ' + '$_sharedSourceRootName, then re-run this tool.', + ); + } +} + +bool _isInIntermediateDirectory(String path) { + return [ + '.dart_tool', + '.symlinks', + '.build', + 'build', + 'ephemeral', + 'Pods', + ].any((dir) => path.contains('/$dir/')); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart new file mode 100644 index 000000000000..d311e4f64891 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io'; + +/// Adjusts a package-relative path to account for the package name being part of +/// the directory structure for Swift packages. +String sharedSourceRelativePathForPackagePath(String packageRelativePath) { + return packageRelativePath.replaceAll( + RegExp(r'/google_maps_flutter_ios[_\w\d]*/'), + '/google_maps_flutter_ios/', + ); +} + +/// Adjusts a shared-source-relative path to account for the package name being +/// part of the directory structure for Swift packages. +String packageRelativePathForSharedSourceRelativePath( + String packageName, + String sharedSourceRelativePath, +) { + return sharedSourceRelativePath.replaceAll( + '/google_maps_flutter_ios/', + '/$packageName/', + ); +} + +/// Returns the contents of the file with any differences caused only by the +/// package name removed. +String normalizedFileContents(File file) { + return file + .readAsStringSync() + // Ignore differences caused only by the package name. + .replaceAll( + RegExp(r'google_maps_flutter_ios_[\w\d]+'), + 'google_maps_flutter_ios', + ) + // Package name diffs could change line wrapping, so collapse whitespace. + .replaceAll(RegExp(r'[\s\n]+'), ' ') + .trim(); +} + +/// Updates the contents of [file] to replace any occurrences of variants of the +/// package name in things that look like paths with [packageName]. +/// +/// This should only be used on files where this is the only option, and where +/// the diffs are known to be safe, as not all instances of the package name +/// should be replaced in all files. +void updatePackageNameInPathReferences(File file, String packageName) { + final String newContents = file.readAsStringSync().replaceAllMapped( + RegExp(r'google_maps_flutter_ios[_\w\d]*([:/])'), + (match) => '$packageName${match.group(1)}', + ); + file.writeAsStringSync(newContents); +} From aeaecee57a63436c225a909d2b8dd1adf8feb497 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 09:39:38 -0500 Subject: [PATCH 05/19] Renames, name change, dependency and min version updates --- .../example/ios/Podfile | 2 +- .../ios/Runner.xcodeproj/project.pbxproj | 8 +++---- .../example/pubspec.yaml | 4 ++-- ... => google_maps_flutter_ios_sdk10.podspec} | 21 +++++++++---------- .../Package.swift | 18 +++++++++------- .../FGMCATransactionWrapper.m | 0 .../FGMClusterManagersController.m | 0 .../FGMConversionUtils.m | 0 .../FGMGroundOverlayController.m | 0 .../FGMImageUtils.m | 0 .../FGMMarkerUserData.m | 0 .../FLTGoogleMapHeatmapController.m | 0 .../FLTGoogleMapTileOverlayController.m | 0 .../FLTGoogleMapsPlugin.m | 0 .../GoogleMapCircleController.m | 0 .../GoogleMapController.m | 0 .../GoogleMapMarkerController.m | 0 .../GoogleMapPolygonController.m | 0 .../GoogleMapPolylineController.m | 0 .../Resources/PrivacyInfo.xcprivacy | 0 .../google_maps_flutter_pigeon_messages.g.m | 0 .../FGMCATransactionWrapper.h | 0 .../FGMClusterManagersController.h | 0 .../FGMConversionUtils.h | 0 .../FGMGroundOverlayController.h | 0 .../FGMGroundOverlayController_Test.h | 0 .../FGMImageUtils.h | 0 .../FGMMarkerUserData.h | 0 .../FLTGoogleMapHeatmapController.h | 0 .../FLTGoogleMapHeatmapController_Test.h | 0 .../FLTGoogleMapTileOverlayController.h | 0 .../FLTGoogleMapTileOverlayController_Test.h | 0 .../FLTGoogleMapsPlugin.h | 0 .../GoogleMapCircleController.h | 0 .../GoogleMapCircleController_Test.h | 0 .../GoogleMapController.h | 0 .../GoogleMapController_Test.h | 0 .../GoogleMapMarkerController.h | 0 .../GoogleMapMarkerController_Test.h | 0 .../GoogleMapPolygonController.h | 0 .../GoogleMapPolygonController_Test.h | 0 .../GoogleMapPolylineController.h | 0 .../GoogleMapPolylineController_Test.h | 0 .../GoogleMapsUtilsTrampoline.h | 0 .../google_maps_flutter_pigeon_messages.g.h | 0 ...art => google_maps_flutter_ios_sdk10.dart} | 0 .../pigeons/messages.dart | 4 ++-- .../pubspec.yaml | 6 +++--- .../google_maps_flutter_ios_test.mocks.dart | 2 +- .../test/package_specific_test_import.dart | 4 ++-- 50 files changed, 35 insertions(+), 34 deletions(-) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9.podspec => google_maps_flutter_ios_sdk10.podspec} (65%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10}/Package.swift (63%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/FGMCATransactionWrapper.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/FGMClusterManagersController.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/FGMConversionUtils.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/FGMGroundOverlayController.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/FGMImageUtils.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/FGMMarkerUserData.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/FLTGoogleMapHeatmapController.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/FLTGoogleMapTileOverlayController.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/FLTGoogleMapsPlugin.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/GoogleMapCircleController.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/GoogleMapController.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/GoogleMapMarkerController.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/GoogleMapPolygonController.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/GoogleMapPolylineController.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/Resources/PrivacyInfo.xcprivacy (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10}/google_maps_flutter_pigeon_messages.g.m (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FGMCATransactionWrapper.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FGMClusterManagersController.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FGMConversionUtils.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FGMGroundOverlayController.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FGMGroundOverlayController_Test.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FGMImageUtils.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FGMMarkerUserData.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FLTGoogleMapHeatmapController.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FLTGoogleMapHeatmapController_Test.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FLTGoogleMapTileOverlayController.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FLTGoogleMapTileOverlayController_Test.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/FLTGoogleMapsPlugin.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapCircleController.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapCircleController_Test.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapController.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapController_Test.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapMarkerController.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapMarkerController_Test.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapPolygonController.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapPolygonController_Test.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapPolylineController.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapPolylineController_Test.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/GoogleMapsUtilsTrampoline.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/{google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9 => google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10}/google_maps_flutter_pigeon_messages.g.h (100%) rename packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/{google_maps_flutter_ios_sdk9.dart => google_maps_flutter_ios_sdk10.dart} (100%) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Podfile b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Podfile index 37d20e51d606..2622c5abadcd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Podfile +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '15.0' +platform :ios, '16.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj index 27d1133df09f..0189321194f4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj @@ -436,12 +436,12 @@ inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/GoogleMaps/GoogleMapsResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/google_maps_flutter_ios_sdk9/google_maps_flutter_ios_sdk9_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/google_maps_flutter_ios_sdk10/google_maps_flutter_ios_sdk10_privacy.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMapsResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/google_maps_flutter_ios_sdk9_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/google_maps_flutter_ios_sdk10_privacy.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -611,7 +611,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -662,7 +662,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; 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 d439bbf8cd46..302a7e8014aa 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 @@ -11,9 +11,9 @@ dependencies: flutter: sdk: flutter flutter_plugin_android_lifecycle: ^2.0.1 - google_maps_flutter_ios_sdk9: + google_maps_flutter_ios_sdk10: # When depending on this package from a real application you should use: - # google_maps_flutter_ios_sdk9: ^x.y.z + # google_maps_flutter_ios_sdk10: ^x.y.z # See https://dart.dev/tools/pub/dependencies#version-constraints # 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. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9.podspec b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10.podspec similarity index 65% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9.podspec rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10.podspec index 7f45f35b59e8..d0f2dd1e2102 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9.podspec +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10.podspec @@ -2,7 +2,7 @@ # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html # Pod::Spec.new do |s| - s.name = 'google_maps_flutter_ios_sdk9' + s.name = 'google_maps_flutter_ios_sdk10' s.version = '0.0.1' s.summary = 'Google Maps for Flutter' s.description = <<-DESC @@ -12,17 +12,16 @@ Downloaded by pub (not CocoaPods). s.homepage = 'https://github.com/flutter/packages' s.license = { :type => 'BSD', :file => '../LICENSE' } s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } - s.source = { :http => 'https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios_sdk9' } - s.documentation_url = 'https://pub.dev/packages/google_maps_flutter_ios_sdk9' - s.source_files = 'google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/**/*.{h,m}' - s.public_header_files = 'google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/**/*.h' + s.source = { :http => 'https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios_sdk10' } + s.documentation_url = 'https://pub.dev/packages/google_maps_flutter_ios_sdk10' + s.source_files = 'google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/**/*.{h,m}' + s.public_header_files = 'google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/**/*.h' s.dependency 'Flutter' - s.dependency 'GoogleMaps', '~> 9.0' - # Google-Maps-iOS-Utils 6.0 and 6.1.0 support GoogleMaps 9.x. The next release - # was 6.1.3, which switched to GoogleMaps 10.x without a major version change. - s.dependency 'Google-Maps-iOS-Utils', '>= 6.0', '<= 6.1.0' + s.dependency 'GoogleMaps', '~> 10.0' + # 6.1.3 was the first version to support GoogleMaps 10.x. + s.dependency 'Google-Maps-iOS-Utils', '~> 6.1.3' s.static_framework = true - s.platform = :ios, '15.0' + s.platform = :ios, '16.0' # "Google-Maps-iOS-Utils" is static and contains Swift classes. # Find the Swift runtime when these plugins are built as libraries without `use_frameworks!` s.swift_version = '5.9' @@ -33,5 +32,5 @@ Downloaded by pub (not CocoaPods). 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) FGM_USING_COCOAPODS=1', } s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } - s.resource_bundles = {'google_maps_flutter_ios_sdk9_privacy' => ['google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy']} + s.resource_bundles = {'google_maps_flutter_ios_sdk10_privacy' => ['google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/Resources/PrivacyInfo.xcprivacy']} end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Package.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift similarity index 63% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Package.swift rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift index 6df0b1cc1ba5..c52597727702 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Package.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift @@ -8,21 +8,23 @@ import PackageDescription let package = Package( - name: "google_maps_flutter_ios_sdk9", + name: "google_maps_flutter_ios_sdk10", platforms: [ - .iOS(.v15) + .iOS(.v16) ], products: [ - .library(name: "google-maps-flutter-ios-sdk9", type: .static, targets: ["google_maps_flutter_ios_sdk9"]) + .library(name: "google-maps-flutter-ios-sdk10", type: .static, targets: ["google_maps_flutter_ios_sdk10"]) ], dependencies: [ - .package(url: "https://github.com/googlemaps/ios-maps-sdk", "9.0.0"..<"10.0.0"), - // 6.1.3+ requires SDK 10. - .package(url: "https://github.com/googlemaps/google-maps-ios-utils", "6.0.0"..<"6.1.3"), + .package(url: "https://github.com/googlemaps/ios-maps-sdk", "10.0.0"..<"11.0.0"), + // 6.1.3 switched from GoogleMaps 9.x to 10.x without a major version + // change, so pin an exact version to avoid breakage if the same thing + // happens with SDK 11 in the future. + .package(url: "https://github.com/googlemaps/google-maps-ios-utils", exact: "6.1.3"), ], targets: [ .target( - name: "google_maps_flutter_ios_sdk9", + name: "google_maps_flutter_ios_sdk10", dependencies: [ .product( name: "GoogleMapsUtils", @@ -37,7 +39,7 @@ let package = Package( .process("Resources") ], cSettings: [ - .headerSearchPath("include/google_maps_flutter_ios_sdk9") + .headerSearchPath("include/google_maps_flutter_ios_sdk10") ] ) ] diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMCATransactionWrapper.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMCATransactionWrapper.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMClusterManagersController.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMClusterManagersController.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMClusterManagersController.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMConversionUtils.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMConversionUtils.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMConversionUtils.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMGroundOverlayController.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMGroundOverlayController.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMImageUtils.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMImageUtils.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMImageUtils.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMMarkerUserData.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMMarkerUserData.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMMarkerUserData.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FLTGoogleMapHeatmapController.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FLTGoogleMapHeatmapController.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FLTGoogleMapTileOverlayController.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FLTGoogleMapTileOverlayController.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FLTGoogleMapsPlugin.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FLTGoogleMapsPlugin.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapCircleController.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapCircleController.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapCircleController.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapController.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapController.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapController.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapMarkerController.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapMarkerController.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapPolygonController.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapPolygonController.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapPolylineController.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapPolylineController.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/Resources/PrivacyInfo.xcprivacy similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/Resources/PrivacyInfo.xcprivacy rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/Resources/PrivacyInfo.xcprivacy diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/google_maps_flutter_pigeon_messages.g.m similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/google_maps_flutter_pigeon_messages.g.m diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMCATransactionWrapper.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMCATransactionWrapper.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMCATransactionWrapper.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMClusterManagersController.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMClusterManagersController.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMClusterManagersController.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMConversionUtils.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMConversionUtils.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMConversionUtils.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMGroundOverlayController.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMGroundOverlayController.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMGroundOverlayController_Test.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMGroundOverlayController_Test.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMGroundOverlayController_Test.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMImageUtils.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMImageUtils.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMImageUtils.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMMarkerUserData.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FGMMarkerUserData.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FGMMarkerUserData.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapHeatmapController.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapHeatmapController.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapHeatmapController_Test.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapHeatmapController_Test.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapHeatmapController_Test.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapTileOverlayController.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapTileOverlayController.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapTileOverlayController_Test.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapTileOverlayController_Test.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapTileOverlayController_Test.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapsPlugin.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/FLTGoogleMapsPlugin.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/FLTGoogleMapsPlugin.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapCircleController.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapCircleController.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapCircleController_Test.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapCircleController_Test.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapCircleController_Test.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapController.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapController.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapController_Test.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapController_Test.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapController_Test.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapMarkerController.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapMarkerController.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapMarkerController_Test.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapMarkerController_Test.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapMarkerController_Test.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapPolygonController.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapPolygonController.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapPolygonController_Test.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolygonController_Test.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapPolygonController_Test.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapPolylineController.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapPolylineController.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapPolylineController_Test.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapPolylineController_Test.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapPolylineController_Test.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapsUtilsTrampoline.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/GoogleMapsUtilsTrampoline.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/GoogleMapsUtilsTrampoline.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/google_maps_flutter_pigeon_messages.g.h similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/google_maps_flutter_pigeon_messages.g.h diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/google_maps_flutter_ios_sdk9.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/google_maps_flutter_ios_sdk10.dart similarity index 100% rename from packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/google_maps_flutter_ios_sdk9.dart rename to packages/google_maps_flutter/google_maps_flutter_ios_sdk10/lib/google_maps_flutter_ios_sdk10.dart 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 50c2bee1fdcf..1f8875feac82 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 @@ -11,9 +11,9 @@ import 'package:pigeon/pigeon.dart'; // files in other packages, without having to use full relative paths // in #includes (which would make source sharing harder to manage). objcHeaderOut: - 'ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/include/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.h', + 'ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/include/google_maps_flutter_ios_sdk10/google_maps_flutter_pigeon_messages.g.h', objcSourceOut: - 'ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/google_maps_flutter_pigeon_messages.g.m', + 'ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/google_maps_flutter_pigeon_messages.g.m', objcOptions: ObjcOptions(prefix: 'FGM'), copyrightHeader: 'pigeons/copyright.txt', // Use the base package name so that the generated code can be shared 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 136ccda24364..cc2bd18c59fc 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 @@ -1,6 +1,6 @@ -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 +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.16.1 diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.mocks.dart index 428e096b78eb..e8862052ae88 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.mocks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/google_maps_flutter_ios_test.mocks.dart @@ -6,7 +6,7 @@ import 'dart:async' as _i4; import 'dart:typed_data' as _i5; -import 'package:google_maps_flutter_ios_sdk9/src/messages.g.dart' as _i2; +import 'package:google_maps_flutter_ios_sdk10/src/messages.g.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/src/dummies.dart' as _i3; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/package_specific_test_import.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/package_specific_test_import.dart index 2f86f15121d5..cc9d8dd7dca7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/package_specific_test_import.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/test/package_specific_test_import.dart @@ -7,5 +7,5 @@ // due to the package names being different. This way, all the test files can // be shared exactly, and only this file needs to diverge between the packages. -export 'package:google_maps_flutter_ios_sdk9/google_maps_flutter_ios_sdk9.dart'; -export 'package:google_maps_flutter_ios_sdk9/src/messages.g.dart'; +export 'package:google_maps_flutter_ios_sdk10/google_maps_flutter_ios_sdk10.dart'; +export 'package:google_maps_flutter_ios_sdk10/src/messages.g.dart'; From 6280461acdb7df34bc3b638530b4fe1893a31682 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 10:20:06 -0500 Subject: [PATCH 06/19] Sync versions, update CHANGELOGs --- .../CHANGELOG.md | 217 +----------------- .../pubspec.yaml | 2 +- .../google_maps_flutter_ios_sdk9/CHANGELOG.md | 217 +----------------- .../google_maps_flutter_ios_sdk9/pubspec.yaml | 2 +- 4 files changed, 6 insertions(+), 432 deletions(-) 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 fa6e19caf286..aaf6a0484e74 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,216 +1,3 @@ -## 2.16.1 +## 2.17.1 -* Updates heatmaps passed between Dart and native to use typed data. - -## 2.16.0 - -* Adds compatibility with SDK version 10.x for apps targeting iOS 16+. - -## 2.15.8 - -* Replaces internal use of deprecated methods. - -## 2.15.7 - -* Updates to Pigeon 26. - -## 2.15.6 - -* Fixes potential flickers of default property values when adding objects to - the map. -* Updates minimum supported SDK version to Flutter 3.32/Dart 3.8. - -## 2.15.5 - -* Fixes `kCGImageAlphaPremultipliedLast` implicit conversion from enumeration type warning. - -## 2.15.4 - -* Deprecates `zIndex` parameter in Marker in favor of `zIndexInt`. - -## 2.15.3 - -* Fixes new analysis warnings. -* Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. - -## 2.15.2 - -* Fixes regression where updating a marker hides its info window. - -## 2.15.1 - -* Fixes regression in displaying info windows. - -## 2.15.0 - -* Adds support for animating the camera with a duration. - -## 2.14.0 - -* Adds support for ground overlay. -* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. - -## 2.13.2 - -* Updates most objects passed from Dart to native to use typed data. - -## 2.13.1 - -* Updates Pigeon for non-nullable collection type support. - -## 2.13.0 - -* Updates map configuration and platform view creation parameters to use Pigeon. -* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. - -## 2.12.0 - -* Adds support for marker clustering. - -## 2.11.0 - -* Adds support for heatmap layers. - -## 2.10.0 - -* Converts Obj-C->Dart calls to Pigeon. - -## 2.9.0 - -* Converts additional platform calls to Pigeon. - -## 2.8.2 - -* Converts inspector interface platform calls to Pigeon. - -## 2.8.1 - -* Improves Objective-C type handling. - -## 2.8.0 - -* Adds compatibility with SDK version 9.x for apps targetting iOS 15+. - -## 2.7.0 - -* Adds support for BitmapDescriptor classes `AssetMapBitmap` and `BytesMapBitmap`. - -## 2.6.1 - -* Adds support for patterns in polylines. - -## 2.6.0 - -* Updates the minimum allowed verison of the Google Maps SDK to 8.4, for privacy - manifest support. - * This means that applications using this package can no longer support - iOS 13 or 14, as the versions of the Google Maps SDK that support those - versions do not have privacy manifests, so cannot be used in published - applications once the new App Store enforcement of manifests takes effect. -* Includes the Google Maps SDK's [GoogleMapsPrivacy bundle](https://developers.google.com/maps/documentation/ios-sdk/config#add-apple-privacy-manifest-file) - manifest entries direct in the plugin, so that package clients do not need to - manually add that privacy bundle to the application build. - -## 2.5.2 - -* Fixes the tile overlay not correctly displaying on physical ios devices. - -## 2.5.1 - -* Makes the tile overlay callback invoke the platform channel on the platform thread. - -## 2.5.0 - -* Adds support for `MapConfiguration.style`. -* Adds support for `getStyleError`. - -## 2.4.2 - -* Fixes a bug in "takeSnapshot" function that incorrectly returns a blank image on iOS 17. - -## 2.4.1 - -* Restores the workaround to exclude arm64 simulator builds, as it is still necessary for applications targeting iOS 12. - -## 2.4.0 - -* Adds support for arm64 simulators. -* Updates minimum supported SDK version to Flutter 3.16.6. -* Removes support for iOS 11. - -## 2.3.6 - -* Adds privacy manifest. - -## 2.3.5 - -* Updates minimum required plugin_platform_interface version to 2.1.7. - -## 2.3.4 - -* Fixes new lint warnings. - -## 2.3.3 - -* Adds support for version 8 of the Google Maps SDK in apps targeting iOS 14+. -* Updates minimum supported SDK version to Flutter 3.10/Dart 3.0. - -## 2.3.2 - -* Fixes an issue where the onDragEnd callback for marker is not called. - -## 2.3.1 - -* Adds pub topics to package metadata. - -## 2.3.0 - -* Adds implementation for `cloudMapId` parameter to support cloud-based maps styling. -* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. -* Fixes unawaited_futures violations. - -## 2.2.3 - -* Removes obsolete null checks on non-nullable values. -* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. - -## 2.2.2 - -* Sets an upper bound on the `GoogleMaps` SDK version that can be used, to - avoid future breakage. - -## 2.2.1 - -* Clarifies explanation of endorsement in README. -* Aligns Dart and Flutter SDK constraints. - -## 2.2.0 - -* Updates minimum Flutter version to 3.3 and iOS 11. - -## 2.1.14 - -* Updates links for the merge of flutter/plugins into flutter/packages. - -## 2.1.13 - -* Updates code for stricter lint checks. -* Updates code for new analysis options. -* Re-enable XCUITests: testUserInterface. -* Remove unnecessary `RunnerUITests` target from Podfile of the example app. - -## 2.1.12 - -* Updates imports for `prefer_relative_imports`. -* Updates minimum Flutter version to 2.10. -* Fixes violations of new analysis option use_named_constants. -* Fixes avoid_redundant_argument_values lint warnings and minor typos. - -## 2.1.11 - -* Precaches Google Maps services initialization and syncing. - -## 2.1.10 - -* Splits iOS implementation out of `google_maps_flutter` as a federated - implementation. +* Initial release, based on 2.17.1 of `google_maps_flutter_ios`. 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 cc2bd18c59fc..911677d137e1 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.16.1 +version: 2.17.1 environment: sdk: ^3.9.0 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 fa6e19caf286..aaf6a0484e74 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,216 +1,3 @@ -## 2.16.1 +## 2.17.1 -* Updates heatmaps passed between Dart and native to use typed data. - -## 2.16.0 - -* Adds compatibility with SDK version 10.x for apps targeting iOS 16+. - -## 2.15.8 - -* Replaces internal use of deprecated methods. - -## 2.15.7 - -* Updates to Pigeon 26. - -## 2.15.6 - -* Fixes potential flickers of default property values when adding objects to - the map. -* Updates minimum supported SDK version to Flutter 3.32/Dart 3.8. - -## 2.15.5 - -* Fixes `kCGImageAlphaPremultipliedLast` implicit conversion from enumeration type warning. - -## 2.15.4 - -* Deprecates `zIndex` parameter in Marker in favor of `zIndexInt`. - -## 2.15.3 - -* Fixes new analysis warnings. -* Updates minimum supported SDK version to Flutter 3.27/Dart 3.6. - -## 2.15.2 - -* Fixes regression where updating a marker hides its info window. - -## 2.15.1 - -* Fixes regression in displaying info windows. - -## 2.15.0 - -* Adds support for animating the camera with a duration. - -## 2.14.0 - -* Adds support for ground overlay. -* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. - -## 2.13.2 - -* Updates most objects passed from Dart to native to use typed data. - -## 2.13.1 - -* Updates Pigeon for non-nullable collection type support. - -## 2.13.0 - -* Updates map configuration and platform view creation parameters to use Pigeon. -* Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. - -## 2.12.0 - -* Adds support for marker clustering. - -## 2.11.0 - -* Adds support for heatmap layers. - -## 2.10.0 - -* Converts Obj-C->Dart calls to Pigeon. - -## 2.9.0 - -* Converts additional platform calls to Pigeon. - -## 2.8.2 - -* Converts inspector interface platform calls to Pigeon. - -## 2.8.1 - -* Improves Objective-C type handling. - -## 2.8.0 - -* Adds compatibility with SDK version 9.x for apps targetting iOS 15+. - -## 2.7.0 - -* Adds support for BitmapDescriptor classes `AssetMapBitmap` and `BytesMapBitmap`. - -## 2.6.1 - -* Adds support for patterns in polylines. - -## 2.6.0 - -* Updates the minimum allowed verison of the Google Maps SDK to 8.4, for privacy - manifest support. - * This means that applications using this package can no longer support - iOS 13 or 14, as the versions of the Google Maps SDK that support those - versions do not have privacy manifests, so cannot be used in published - applications once the new App Store enforcement of manifests takes effect. -* Includes the Google Maps SDK's [GoogleMapsPrivacy bundle](https://developers.google.com/maps/documentation/ios-sdk/config#add-apple-privacy-manifest-file) - manifest entries direct in the plugin, so that package clients do not need to - manually add that privacy bundle to the application build. - -## 2.5.2 - -* Fixes the tile overlay not correctly displaying on physical ios devices. - -## 2.5.1 - -* Makes the tile overlay callback invoke the platform channel on the platform thread. - -## 2.5.0 - -* Adds support for `MapConfiguration.style`. -* Adds support for `getStyleError`. - -## 2.4.2 - -* Fixes a bug in "takeSnapshot" function that incorrectly returns a blank image on iOS 17. - -## 2.4.1 - -* Restores the workaround to exclude arm64 simulator builds, as it is still necessary for applications targeting iOS 12. - -## 2.4.0 - -* Adds support for arm64 simulators. -* Updates minimum supported SDK version to Flutter 3.16.6. -* Removes support for iOS 11. - -## 2.3.6 - -* Adds privacy manifest. - -## 2.3.5 - -* Updates minimum required plugin_platform_interface version to 2.1.7. - -## 2.3.4 - -* Fixes new lint warnings. - -## 2.3.3 - -* Adds support for version 8 of the Google Maps SDK in apps targeting iOS 14+. -* Updates minimum supported SDK version to Flutter 3.10/Dart 3.0. - -## 2.3.2 - -* Fixes an issue where the onDragEnd callback for marker is not called. - -## 2.3.1 - -* Adds pub topics to package metadata. - -## 2.3.0 - -* Adds implementation for `cloudMapId` parameter to support cloud-based maps styling. -* Updates minimum supported SDK version to Flutter 3.7/Dart 2.19. -* Fixes unawaited_futures violations. - -## 2.2.3 - -* Removes obsolete null checks on non-nullable values. -* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. - -## 2.2.2 - -* Sets an upper bound on the `GoogleMaps` SDK version that can be used, to - avoid future breakage. - -## 2.2.1 - -* Clarifies explanation of endorsement in README. -* Aligns Dart and Flutter SDK constraints. - -## 2.2.0 - -* Updates minimum Flutter version to 3.3 and iOS 11. - -## 2.1.14 - -* Updates links for the merge of flutter/plugins into flutter/packages. - -## 2.1.13 - -* Updates code for stricter lint checks. -* Updates code for new analysis options. -* Re-enable XCUITests: testUserInterface. -* Remove unnecessary `RunnerUITests` target from Podfile of the example app. - -## 2.1.12 - -* Updates imports for `prefer_relative_imports`. -* Updates minimum Flutter version to 2.10. -* Fixes violations of new analysis option use_named_constants. -* Fixes avoid_redundant_argument_values lint warnings and minor typos. - -## 2.1.11 - -* Precaches Google Maps services initialization and syncing. - -## 2.1.10 - -* Splits iOS implementation out of `google_maps_flutter` as a federated - implementation. +* Initial release, based on 2.17.1 of `google_maps_flutter_ios`. 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 136ccda24364..7dac0641eca5 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.16.1 +version: 2.17.1 environment: sdk: ^3.9.0 From 9e4f7db5d11887d1285c5b5c2ce0aac90dcfde3a Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 10:44:27 -0500 Subject: [PATCH 07/19] Update SDK-specific READMEs --- .../google_maps_flutter_ios_sdk10/README.md | 32 ++++++++++++++----- .../example/README.md | 4 --- .../google_maps_flutter_ios_sdk9/README.md | 32 ++++++++++++++----- .../example/README.md | 4 --- 4 files changed, 48 insertions(+), 24 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/README.md index 20fae87c8855..01b91741a142 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/README.md @@ -1,15 +1,29 @@ -# google\_maps\_flutter\_ios +# google\_maps\_flutter\_ios\_sdk10 -The iOS implementation of [`google_maps_flutter`][1]. +An iOS implementation of [`google_maps_flutter`][1] using +[Google Maps SDK 10.x][2]. ## Usage -This package is [endorsed][2], which means you can simply use -`google_maps_flutter` normally. This package will be automatically included in -your app when you do, so you do not need to add it to your `pubspec.yaml`. +This package is not the default [endorsed][3] version, so to select this SDK +version for your implementation you must add a dependency on this package in +your application's pubspec.yaml. Once you do, it will automatically replace the +default implementation, then you can use `google_maps_flutter` as normal. -However, if you `import` this package to use any of its APIs directly, you -should add it to your `pubspec.yaml` as usual. +### Package Dependencies + +If you are authoring a package, please *do not* depend on one of these specific +implementation packages unless you have a compelling reason to do so. Instead, +just depend on `google_maps_flutter`, so that application developers can +select the appropriate SDK version for their minimum iOS version target. + +## Minimum iOS Version + +Google Maps SDK 10.x requires iOS 16, so if your application does not already +require iOS 16 you must update your minimum iOS deployment version. + +Alternatively, you could use a [different SDK version][4] +with a lower iOS version requirement. ## Supported Heatmap Options @@ -22,4 +36,6 @@ should add it to your `pubspec.yaml` as usual. | HeatmapGradient.colorMapSize | ✓ | [1]: https://pub.dev/packages/google_maps_flutter -[2]: https://flutter.dev/to/endorsed-federated-plugin +[2]: https://developers.google.com/maps/documentation/ios-sdk/release-notes +[3]: https://flutter.dev/to/endorsed-federated-plugin +[4]: https://pub.dev/packages?q=implements-federated-plugin%3Agoogle_maps_flutter+platform%3Aios diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/README.md index 2d527ff468c8..96b8bb17dbff 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/README.md @@ -7,7 +7,3 @@ package. Unless you are making changes to this implementation package, this example is very unlikely to be relevant. - -## Versions - -This example requires iOS 14, so will select a 8.x GoogleMaps SDK version. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/README.md index 20fae87c8855..1b84bb30e60b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/README.md @@ -1,15 +1,29 @@ -# google\_maps\_flutter\_ios +# google\_maps\_flutter\_ios\_sdk10 -The iOS implementation of [`google_maps_flutter`][1]. +An iOS implementation of [`google_maps_flutter`][1] using +[Google Maps SDK 9.x][2]. ## Usage -This package is [endorsed][2], which means you can simply use -`google_maps_flutter` normally. This package will be automatically included in -your app when you do, so you do not need to add it to your `pubspec.yaml`. +This package is not the default [endorsed][3] version, so to select this SDK +version for your implementation you must add a dependency on this package in +your application's pubspec.yaml. Once you do, it will automatically replace the +default implementation, then you can use `google_maps_flutter` as normal. -However, if you `import` this package to use any of its APIs directly, you -should add it to your `pubspec.yaml` as usual. +### Package Dependencies + +If you are authoring a package, please *do not* depend on one of these specific +implementation packages unless you have a compelling reason to do so. Instead, +just depend on `google_maps_flutter`, so that application developers can +select the appropriate SDK version for their minimum iOS version target. + +## Minimum iOS Version + +Google Maps SDK 9.x requires iOS 15, so if your application does not already +require iOS 15 you must update your minimum iOS deployment version. + +Alternatively, you could use [`google_maps_flutter_ios`][4] to support +iOS 14. ## Supported Heatmap Options @@ -22,4 +36,6 @@ should add it to your `pubspec.yaml` as usual. | HeatmapGradient.colorMapSize | ✓ | [1]: https://pub.dev/packages/google_maps_flutter -[2]: https://flutter.dev/to/endorsed-federated-plugin +[2]: https://developers.google.com/maps/documentation/ios-sdk/release-notes +[3]: https://flutter.dev/to/endorsed-federated-plugin +[4]: https://pub.dev/packages/google_maps_flutter_ios diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/README.md b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/README.md index 2d527ff468c8..96b8bb17dbff 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/README.md @@ -7,7 +7,3 @@ package. Unless you are making changes to this implementation package, this example is very unlikely to be relevant. - -## Versions - -This example requires iOS 14, so will select a 8.x GoogleMaps SDK version. From 157da4e2b751c3c7e94fa5b5d17432d75e000415 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 10:57:05 -0500 Subject: [PATCH 08/19] Add note to default implementation package's README --- .../google_maps_flutter_ios/CHANGELOG.md | 5 +++++ .../google_maps_flutter_ios/README.md | 15 ++++++++++++++- .../google_maps_flutter_ios/pubspec.yaml | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) 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 5e577772cba2..6c932ffe79dc 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,8 @@ +## 2.17.1 + +* Adds a README section about Swift Package Manager and the new + `google_maps_flutter_ios_sdk*` packages. + ## 2.17.0 * Restructures code to prepare for SwiftPM support. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/README.md b/packages/google_maps_flutter/google_maps_flutter_ios/README.md index 20fae87c8855..056403950aa1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/README.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios/README.md @@ -1,6 +1,9 @@ # google\_maps\_flutter\_ios -The iOS implementation of [`google_maps_flutter`][1]. +The default iOS implementation of [`google_maps_flutter`][1]. + +This package will use Google Maps SDK 8.4, 9.x, or 10.x, depending on your +application's minimum deployment target. ## Usage @@ -11,6 +14,15 @@ your app when you do, so you do not need to add it to your `pubspec.yaml`. However, if you `import` this package to use any of its APIs directly, you should add it to your `pubspec.yaml` as usual. +## Swift Package Manager + +This package cannot support Swift Package Manager, as Swift Package Manager +does not support automatically selecting the appropriate version of the +Google Maps SDK based on the minimum deployment target. For Swift Package +Manager compatibility, you should use the appropriate +[`google_maps_flutter_ios_sdk*` package][3] instead. + + ## Supported Heatmap Options | Field | Supported | @@ -23,3 +35,4 @@ should add it to your `pubspec.yaml` as usual. [1]: https://pub.dev/packages/google_maps_flutter [2]: https://flutter.dev/to/endorsed-federated-plugin +[3]: https://pub.dev/packages?q=implements-federated-plugin%3Agoogle_maps_flutter+platform%3Aios 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 29172616d2d7..172ca4922985 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.17.0 +version: 2.17.1 environment: sdk: ^3.9.0 From 5f5793c324d45959f8fc7232cd328f419a3310f2 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 11:00:33 -0500 Subject: [PATCH 09/19] Swift autoformat --- .../ios/google_maps_flutter_ios_sdk10/Package.swift | 7 ++++--- .../ios/google_maps_flutter_ios_sdk9/Package.swift | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift index c52597727702..0e34e0fabad9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift @@ -1,7 +1,6 @@ // swift-tools-version: 5.9 -// The swift-tools-version declares the minimum version of Swift required to build this package. -// Copyright 2013 The Flutter Authors. All rights reserved. +// Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,7 +12,9 @@ let package = Package( .iOS(.v16) ], products: [ - .library(name: "google-maps-flutter-ios-sdk10", type: .static, targets: ["google_maps_flutter_ios_sdk10"]) + .library( + name: "google-maps-flutter-ios-sdk10", type: .static, + targets: ["google_maps_flutter_ios_sdk10"]) ], dependencies: [ .package(url: "https://github.com/googlemaps/ios-maps-sdk", "10.0.0"..<"11.0.0"), diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift index 6df0b1cc1ba5..d20487697e53 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift @@ -1,7 +1,6 @@ // swift-tools-version: 5.9 -// The swift-tools-version declares the minimum version of Swift required to build this package. -// Copyright 2013 The Flutter Authors. All rights reserved. +// Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -13,7 +12,9 @@ let package = Package( .iOS(.v15) ], products: [ - .library(name: "google-maps-flutter-ios-sdk9", type: .static, targets: ["google_maps_flutter_ios_sdk9"]) + .library( + name: "google-maps-flutter-ios-sdk9", type: .static, targets: ["google_maps_flutter_ios_sdk9"] + ) ], dependencies: [ .package(url: "https://github.com/googlemaps/ios-maps-sdk", "9.0.0"..<"10.0.0"), From 1a6aefc62500397bf9adea3c50304f583c9e06ea Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 11:39:41 -0500 Subject: [PATCH 10/19] Fix build-all --- script/configs/exclude_all_packages_app.yaml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/script/configs/exclude_all_packages_app.yaml b/script/configs/exclude_all_packages_app.yaml index f9ac561b8d6f..b071b9ca5b0a 100644 --- a/script/configs/exclude_all_packages_app.yaml +++ b/script/configs/exclude_all_packages_app.yaml @@ -11,6 +11,15 @@ # This is a permanent entry, as it should never be a direct app dependency. - plugin_platform_interface -# Temporarily excluded since it hasn't been updated for the major version -# change in google_sign_in. https://github.com/flutter/flutter/issues/171048 -- extension_google_sign_in_as_googleapis_auth +# An application cannot depend directly on multiple federated implementations +# of the same plugin for the same platform, which means the app cannot +# directly depend on both camera_android and camera_android_androidx. +# Since google_maps_flutter_ios is endorsed, it will be included transitively +# already, so exclude it from the direct dependency list to allow including +# google_maps_flutter_ios_sdk10 to ensure that they don't conflict at build +# time (if they did, it would be impossible to select the SDK-specific +# version). +- google_maps_flutter_ios +# We can't test both SDK 9 and SDK 10, so arbitrarly use the latest as +# the test of overriding the endorsement. +- google_maps_flutter_ios_sdk9 From 0fa16a07dd7658f6fc337736b711e745dcc88b13 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 11:41:53 -0500 Subject: [PATCH 11/19] Fix license block --- .../ios/google_maps_flutter_ios_sdk10/Package.swift | 1 + .../ios/google_maps_flutter_ios_sdk9/Package.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift index 0e34e0fabad9..6bf9b327cbb9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Package.swift @@ -1,4 +1,5 @@ // swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift index d20487697e53..cfae007ad590 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Package.swift @@ -1,4 +1,5 @@ // swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. // Copyright 2013 The Flutter Authors // Use of this source code is governed by a BSD-style license that can be From 1ff53a3f4777dff232affe26043069bc82702e4a Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 11:43:09 -0500 Subject: [PATCH 12/19] Add CODEOWNERs --- CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index f9b1a8acd61d..49fca1929c82 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -88,6 +88,8 @@ packages/camera/camera_avfoundation/** @hellohuanlin @lou packages/file_selector/file_selector_ios/** @okorohelijah @vashworth packages/file_selector/file_selector_macos/** @okorohelijah @vashworth packages/google_maps_flutter/google_maps_flutter_ios/** @vashworth @LongCatIsLooong +packages/google_maps_flutter/google_maps_flutter_ios_sdk9/** @vashworth @LongCatIsLooong +packages/google_maps_flutter/google_maps_flutter_ios_sdk10/** @vashworth @LongCatIsLooong packages/google_sign_in/google_sign_in_ios/** @LongCatIsLooong @okorohelijah packages/image_picker/image_picker_ios/** @okorohelijah @vashworth packages/image_picker/image_picker_macos/** @okorohelijah @vashworth From 6570b75f07be00015ca9f3c3e6d00b65ca2b6932 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 14:41:59 -0500 Subject: [PATCH 13/19] Add the CocoaPods indicator build flag to the original package --- .../google_maps_flutter_ios/ios/google_maps_flutter_ios.podspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios.podspec b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios.podspec index d18e53fac837..529c229438cd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios.podspec +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/google_maps_flutter_ios.podspec @@ -38,6 +38,8 @@ Downloaded by pub (not CocoaPods). s.xcconfig = { 'LIBRARY_SEARCH_PATHS' => '$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)/ $(SDKROOT)/usr/lib/swift', 'LD_RUNPATH_SEARCH_PATHS' => '$(inherited) /usr/lib/swift', + # To handle the difference in framework names between CocoaPods and Swift Package Manager in shared code. + 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) FGM_USING_COCOAPODS=1', } s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } s.resource_bundles = {'google_maps_flutter_ios_privacy' => ['google_maps_flutter_ios/Sources/google_maps_flutter_ios/Resources/PrivacyInfo.xcprivacy']} From c5e5dbf4c089e17c0d9282423749f087ee81eb59 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 14:49:54 -0500 Subject: [PATCH 14/19] Raise min iOS version for the build-all app --- script/configs/exclude_all_packages_app.yaml | 7 ++++--- script/tool/lib/src/create_all_packages_app_command.dart | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/script/configs/exclude_all_packages_app.yaml b/script/configs/exclude_all_packages_app.yaml index b071b9ca5b0a..5351a46a12d9 100644 --- a/script/configs/exclude_all_packages_app.yaml +++ b/script/configs/exclude_all_packages_app.yaml @@ -20,6 +20,7 @@ # time (if they did, it would be impossible to select the SDK-specific # version). - google_maps_flutter_ios -# We can't test both SDK 9 and SDK 10, so arbitrarly use the latest as -# the test of overriding the endorsement. -- google_maps_flutter_ios_sdk9 +# We can't test both SDK 9 and SDK 10; use 9 (excluding everything but 9) +# so that the min iOS version of the build-all app doesn't need to be +# raised any higher than necessary. +- google_maps_flutter_ios_sdk10 diff --git a/script/tool/lib/src/create_all_packages_app_command.dart b/script/tool/lib/src/create_all_packages_app_command.dart index e766b0810607..6223f708c84e 100644 --- a/script/tool/lib/src/create_all_packages_app_command.dart +++ b/script/tool/lib/src/create_all_packages_app_command.dart @@ -457,9 +457,9 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)} _adjustFile( pbxprojFile, replacements: >{ - // iOS 14 is required by google_maps_flutter. + // iOS 15 is required by google_maps_flutter_ios_sdk9. 'IPHONEOS_DEPLOYMENT_TARGET': [ - ' IPHONEOS_DEPLOYMENT_TARGET = 14.0;', + ' IPHONEOS_DEPLOYMENT_TARGET = 15.0;', ], }, ); From 516ff22d8ce5ee5283ece932d66ceefb5807465c Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 16:30:05 -0500 Subject: [PATCH 15/19] Update repo tool unit test --- script/tool/test/create_all_packages_app_command_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/tool/test/create_all_packages_app_command_test.dart b/script/tool/test/create_all_packages_app_command_test.dart index 4e3b4c638ce2..a20aac6444f1 100644 --- a/script/tool/test/create_all_packages_app_command_test.dart +++ b/script/tool/test/create_all_packages_app_command_test.dart @@ -491,7 +491,7 @@ android { everyElement( (String line) => !line.contains('IPHONEOS_DEPLOYMENT_TARGET') || - line.contains('14.0'), + line.contains('15.0'), ), ); }); From 2141066a6e790412d193de5cca10c0bbe31877b5 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 22 Jan 2026 16:30:27 -0500 Subject: [PATCH 16/19] Update native unit test imports, and sync script to handle it --- .../ios/RunnerTests/ExtractIconFromDataTests.m | 1 - .../FGMClusterManagersControllerTests.m | 3 ++- .../ios/RunnerTests/FGMConversionsUtilsTests.m | 3 ++- .../FLTGoogleMapHeatmapControllerTests.m | 2 +- .../RunnerTests/FLTTileProviderControllerTests.m | 4 ++-- .../GoogleMapsCircleControllerTests.m | 2 +- .../GoogleMapsGroundOverlayControllerTests.m | 3 ++- .../GoogleMapsMarkerControllerTests.m | 2 +- .../GoogleMapsPolygonControllerTests.m | 2 +- .../GoogleMapsPolylineControllerTests.m | 3 ++- .../example/ios/RunnerTests/GoogleMapsTests.m | 4 ++-- .../GoogleMapsTileOverlayControllerTests.m | 2 +- .../tool/sync_shared_files.dart | 4 ++++ .../google_maps_flutter_ios/tool/utils.dart | 16 ++++++++++++++++ .../ios/RunnerTests/ExtractIconFromDataTests.m | 3 +-- .../FGMClusterManagersControllerTests.m | 5 +++-- .../ios/RunnerTests/FGMConversionsUtilsTests.m | 5 +++-- .../FLTGoogleMapHeatmapControllerTests.m | 4 ++-- .../RunnerTests/FLTTileProviderControllerTests.m | 4 ++-- .../GoogleMapsCircleControllerTests.m | 4 ++-- .../GoogleMapsGroundOverlayControllerTests.m | 5 +++-- .../GoogleMapsMarkerControllerTests.m | 4 ++-- .../GoogleMapsPolygonControllerTests.m | 4 ++-- .../GoogleMapsPolylineControllerTests.m | 5 +++-- .../example/ios/RunnerTests/GoogleMapsTests.m | 6 +++--- .../GoogleMapsTileOverlayControllerTests.m | 4 ++-- .../tool/sync_shared_files.dart | 4 ++++ .../tool/utils.dart | 16 ++++++++++++++++ .../ios/RunnerTests/ExtractIconFromDataTests.m | 3 +-- .../FGMClusterManagersControllerTests.m | 5 +++-- .../ios/RunnerTests/FGMConversionsUtilsTests.m | 5 +++-- .../FLTGoogleMapHeatmapControllerTests.m | 4 ++-- .../RunnerTests/FLTTileProviderControllerTests.m | 4 ++-- .../GoogleMapsCircleControllerTests.m | 4 ++-- .../GoogleMapsGroundOverlayControllerTests.m | 5 +++-- .../GoogleMapsMarkerControllerTests.m | 4 ++-- .../GoogleMapsPolygonControllerTests.m | 4 ++-- .../GoogleMapsPolylineControllerTests.m | 5 +++-- .../example/ios/RunnerTests/GoogleMapsTests.m | 6 +++--- .../GoogleMapsTileOverlayControllerTests.m | 4 ++-- .../tool/sync_shared_files.dart | 4 ++++ .../google_maps_flutter_ios_sdk9/tool/utils.dart | 16 ++++++++++++++++ .../ios/RunnerTests/ExtractIconFromDataTests.m | 1 - .../FGMClusterManagersControllerTests.m | 3 ++- .../ios/RunnerTests/FGMConversionsUtilsTests.m | 3 ++- .../FLTGoogleMapHeatmapControllerTests.m | 2 +- .../RunnerTests/FLTTileProviderControllerTests.m | 4 ++-- .../GoogleMapsCircleControllerTests.m | 2 +- .../GoogleMapsGroundOverlayControllerTests.m | 3 ++- .../GoogleMapsMarkerControllerTests.m | 2 +- .../GoogleMapsPolygonControllerTests.m | 2 +- .../GoogleMapsPolylineControllerTests.m | 3 ++- .../example/ios/RunnerTests/GoogleMapsTests.m | 4 ++-- .../GoogleMapsTileOverlayControllerTests.m | 2 +- .../tool/sync_shared_files.dart | 4 ++++ .../tool/utils.dart | 16 ++++++++++++++++ 56 files changed, 170 insertions(+), 78 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/ExtractIconFromDataTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/ExtractIconFromDataTests.m index 4d7da98cac59..1f9696128aa9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/ExtractIconFromDataTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/ExtractIconFromDataTests.m @@ -6,7 +6,6 @@ @import XCTest; #import -#import @interface ExtractIconFromDataTests : XCTestCase - (UIImage *)createOnePixelImage; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FGMClusterManagersControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FGMClusterManagersControllerTests.m index f9baaa10184b..94c2ca5369d0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FGMClusterManagersControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FGMClusterManagersControllerTests.m @@ -3,11 +3,12 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import #import + #import "PartiallyMockedMapView.h" @interface FGMClusterManagersControllerTests : XCTestCase diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FGMConversionsUtilsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FGMConversionsUtilsTests.m index ea39943cf571..3408305e80e3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FGMConversionsUtilsTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FGMConversionsUtilsTests.m @@ -3,10 +3,11 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" @interface FGMConversionUtilsTests : XCTestCase diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m index 2b0134d3ef9b..1cc2a2a1ed2e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m @@ -3,9 +3,9 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; @import GoogleMapsUtils; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FLTTileProviderControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FLTTileProviderControllerTests.m index 3c7f43b3c206..8971708a23b1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FLTTileProviderControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/FLTTileProviderControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import XCTest; -@import GoogleMaps; @import google_maps_flutter_ios; +@import GoogleMaps; +@import XCTest; #import diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m index 7514a70704f5..ea03ce5ca5d4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m @@ -3,8 +3,8 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m index 9169d6064956..b57035f84705 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -3,10 +3,11 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" /// A GMSGroundOverlay that ensures that property updates are made before the map is set. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m index bac3fb2cc84e..03110f1da242 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -3,8 +3,8 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m index 2cb386e0fc55..0db5e5364b6d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m @@ -3,8 +3,8 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; /// A GMSPolygon that ensures that property updates are made before the map is set. @interface PropertyOrderValidatingPolygon : GMSPolygon { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m index 19ca6e84a266..dd31352492a6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m @@ -3,10 +3,11 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" /// A GMSPolyline that ensures that property updates are made before the map is set. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTests.m index ecbef7b3924e..f43667e510ff 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTests.m @@ -3,11 +3,11 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import -#import "FGMCATransactionWrapper.h" + #import "PartiallyMockedMapView.h" @interface FLTGoogleMapFactory (Test) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m index e7b1118a8d56..32c2b1e6d6ba 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m @@ -3,8 +3,8 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart index 1a423bba92e6..f2858929cea3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart @@ -140,6 +140,10 @@ void _syncFile( destinationPackageName, ); } + // Native unit tests need to import the Swift package. + if (source.absolute.path.contains('/RunnerTests/')) { + updatePackageNameInImports(File(destinationPath), destinationPackageName); + } } void _reportUnsharedFiles( diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart index d311e4f64891..21a6ec647250 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart @@ -53,3 +53,19 @@ void updatePackageNameInPathReferences(File file, String packageName) { ); file.writeAsStringSync(newContents); } + +/// Updates the contents of [file] to replace any occurrences of variants of the +/// package name in Obj-C or Swift import statements. +/// +/// This is necessary for native unit tests, which need to import the Swift +/// package by name. +void updatePackageNameInImports(File file, String packageName) { + final String newContents = file.readAsStringSync().replaceAllMapped( + RegExp( + r'^(@?)import google_maps_flutter_ios[_\w\d]*(;?)$', + multiLine: true, + ), + (match) => '${match.group(1)}import $packageName${match.group(2)}', + ); + file.writeAsStringSync(newContents); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/ExtractIconFromDataTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/ExtractIconFromDataTests.m index 4d7da98cac59..fc715628c052 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/ExtractIconFromDataTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/ExtractIconFromDataTests.m @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; +@import google_maps_flutter_ios_sdk10; @import XCTest; #import -#import @interface ExtractIconFromDataTests : XCTestCase - (UIImage *)createOnePixelImage; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMClusterManagersControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMClusterManagersControllerTests.m index f9baaa10184b..50b54fe2794c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMClusterManagersControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMClusterManagersControllerTests.m @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; +@import XCTest; #import #import + #import "PartiallyMockedMapView.h" @interface FGMClusterManagersControllerTests : XCTestCase diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMConversionsUtilsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMConversionsUtilsTests.m index ea39943cf571..6dd141a27285 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMConversionsUtilsTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FGMConversionsUtilsTests.m @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" @interface FGMConversionUtilsTests : XCTestCase diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m index 2b0134d3ef9b..71414f43034d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; @import GoogleMapsUtils; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTTileProviderControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTTileProviderControllerTests.m index 3c7f43b3c206..9690ce5ad136 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTTileProviderControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/FLTTileProviderControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; -@import google_maps_flutter_ios; +@import XCTest; #import diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m index 7514a70704f5..a7ee1e4285c2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m index 9169d6064956..8ea299d8ffa2 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" /// A GMSGroundOverlay that ensures that property updates are made before the map is set. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m index bac3fb2cc84e..9ee1f147e4a8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; +@import XCTest; #import diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m index 2cb386e0fc55..fdbdb7541b25 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; +@import XCTest; /// A GMSPolygon that ensures that property updates are made before the map is set. @interface PropertyOrderValidatingPolygon : GMSPolygon { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m index 19ca6e84a266..02bb68012111 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" /// A GMSPolyline that ensures that property updates are made before the map is set. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.m index ecbef7b3924e..64945148a8dc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTests.m @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; +@import XCTest; #import -#import "FGMCATransactionWrapper.h" + #import "PartiallyMockedMapView.h" @interface FLTGoogleMapFactory (Test) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m index e7b1118a8d56..7d6fe235c784 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk10; @import GoogleMaps; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart index 1a423bba92e6..f2858929cea3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart @@ -140,6 +140,10 @@ void _syncFile( destinationPackageName, ); } + // Native unit tests need to import the Swift package. + if (source.absolute.path.contains('/RunnerTests/')) { + updatePackageNameInImports(File(destinationPath), destinationPackageName); + } } void _reportUnsharedFiles( diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart index d311e4f64891..21a6ec647250 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart @@ -53,3 +53,19 @@ void updatePackageNameInPathReferences(File file, String packageName) { ); file.writeAsStringSync(newContents); } + +/// Updates the contents of [file] to replace any occurrences of variants of the +/// package name in Obj-C or Swift import statements. +/// +/// This is necessary for native unit tests, which need to import the Swift +/// package by name. +void updatePackageNameInImports(File file, String packageName) { + final String newContents = file.readAsStringSync().replaceAllMapped( + RegExp( + r'^(@?)import google_maps_flutter_ios[_\w\d]*(;?)$', + multiLine: true, + ), + (match) => '${match.group(1)}import $packageName${match.group(2)}', + ); + file.writeAsStringSync(newContents); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/ExtractIconFromDataTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/ExtractIconFromDataTests.m index 4d7da98cac59..64a889cf7ad7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/ExtractIconFromDataTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/ExtractIconFromDataTests.m @@ -2,11 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; +@import google_maps_flutter_ios_sdk9; @import XCTest; #import -#import @interface ExtractIconFromDataTests : XCTestCase - (UIImage *)createOnePixelImage; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMClusterManagersControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMClusterManagersControllerTests.m index f9baaa10184b..2df282dc9c05 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMClusterManagersControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMClusterManagersControllerTests.m @@ -2,12 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; +@import XCTest; #import #import + #import "PartiallyMockedMapView.h" @interface FGMClusterManagersControllerTests : XCTestCase diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMConversionsUtilsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMConversionsUtilsTests.m index ea39943cf571..b8540567d83c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMConversionsUtilsTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FGMConversionsUtilsTests.m @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" @interface FGMConversionUtilsTests : XCTestCase diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m index 2b0134d3ef9b..211b4f4ebbfc 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; @import GoogleMapsUtils; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTTileProviderControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTTileProviderControllerTests.m index 3c7f43b3c206..ca2a75cffde3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTTileProviderControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/FLTTileProviderControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; -@import google_maps_flutter_ios; +@import XCTest; #import diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m index 7514a70704f5..9549e4dc58ba 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m index 9169d6064956..4f4987af64da 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" /// A GMSGroundOverlay that ensures that property updates are made before the map is set. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m index bac3fb2cc84e..3227a67c32aa 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; +@import XCTest; #import diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m index 2cb386e0fc55..f369408dbefe 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; +@import XCTest; /// A GMSPolygon that ensures that property updates are made before the map is set. @interface PropertyOrderValidatingPolygon : GMSPolygon { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m index 19ca6e84a266..04c21e44aa93 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m @@ -2,11 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" /// A GMSPolyline that ensures that property updates are made before the map is set. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.m index ecbef7b3924e..daf5cab55731 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTests.m @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; +@import XCTest; #import -#import "FGMCATransactionWrapper.h" + #import "PartiallyMockedMapView.h" @interface FLTGoogleMapFactory (Test) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m index e7b1118a8d56..be6469d0ecfb 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import google_maps_flutter_ios; -@import XCTest; +@import google_maps_flutter_ios_sdk9; @import GoogleMaps; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart index 1a423bba92e6..f2858929cea3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart @@ -140,6 +140,10 @@ void _syncFile( destinationPackageName, ); } + // Native unit tests need to import the Swift package. + if (source.absolute.path.contains('/RunnerTests/')) { + updatePackageNameInImports(File(destinationPath), destinationPackageName); + } } void _reportUnsharedFiles( diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart index d311e4f64891..21a6ec647250 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart @@ -53,3 +53,19 @@ void updatePackageNameInPathReferences(File file, String packageName) { ); file.writeAsStringSync(newContents); } + +/// Updates the contents of [file] to replace any occurrences of variants of the +/// package name in Obj-C or Swift import statements. +/// +/// This is necessary for native unit tests, which need to import the Swift +/// package by name. +void updatePackageNameInImports(File file, String packageName) { + final String newContents = file.readAsStringSync().replaceAllMapped( + RegExp( + r'^(@?)import google_maps_flutter_ios[_\w\d]*(;?)$', + multiLine: true, + ), + (match) => '${match.group(1)}import $packageName${match.group(2)}', + ); + file.writeAsStringSync(newContents); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/ExtractIconFromDataTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/ExtractIconFromDataTests.m index 4d7da98cac59..1f9696128aa9 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/ExtractIconFromDataTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/ExtractIconFromDataTests.m @@ -6,7 +6,6 @@ @import XCTest; #import -#import @interface ExtractIconFromDataTests : XCTestCase - (UIImage *)createOnePixelImage; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMClusterManagersControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMClusterManagersControllerTests.m index f9baaa10184b..94c2ca5369d0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMClusterManagersControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMClusterManagersControllerTests.m @@ -3,11 +3,12 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import #import + #import "PartiallyMockedMapView.h" @interface FGMClusterManagersControllerTests : XCTestCase diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMConversionsUtilsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMConversionsUtilsTests.m index ea39943cf571..3408305e80e3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMConversionsUtilsTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FGMConversionsUtilsTests.m @@ -3,10 +3,11 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" @interface FGMConversionUtilsTests : XCTestCase diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m index 2b0134d3ef9b..1cc2a2a1ed2e 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTGoogleMapHeatmapControllerTests.m @@ -3,9 +3,9 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; @import GoogleMapsUtils; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTTileProviderControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTTileProviderControllerTests.m index 3c7f43b3c206..8971708a23b1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTTileProviderControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/FLTTileProviderControllerTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -@import XCTest; -@import GoogleMaps; @import google_maps_flutter_ios; +@import GoogleMaps; +@import XCTest; #import diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m index 7514a70704f5..ea03ce5ca5d4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsCircleControllerTests.m @@ -3,8 +3,8 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m index 9169d6064956..b57035f84705 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -3,10 +3,11 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" /// A GMSGroundOverlay that ensures that property updates are made before the map is set. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m index bac3fb2cc84e..03110f1da242 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -3,8 +3,8 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m index 2cb386e0fc55..0db5e5364b6d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolygonControllerTests.m @@ -3,8 +3,8 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; /// A GMSPolygon that ensures that property updates are made before the map is set. @interface PropertyOrderValidatingPolygon : GMSPolygon { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m index 19ca6e84a266..dd31352492a6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsPolylineControllerTests.m @@ -3,10 +3,11 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import + #import "PartiallyMockedMapView.h" /// A GMSPolyline that ensures that property updates are made before the map is set. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.m index ecbef7b3924e..f43667e510ff 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTests.m @@ -3,11 +3,11 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import -#import "FGMCATransactionWrapper.h" + #import "PartiallyMockedMapView.h" @interface FLTGoogleMapFactory (Test) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m index e7b1118a8d56..32c2b1e6d6ba 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsTileOverlayControllerTests.m @@ -3,8 +3,8 @@ // found in the LICENSE file. @import google_maps_flutter_ios; -@import XCTest; @import GoogleMaps; +@import XCTest; #import "PartiallyMockedMapView.h" diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart index 1a423bba92e6..f2858929cea3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart @@ -140,6 +140,10 @@ void _syncFile( destinationPackageName, ); } + // Native unit tests need to import the Swift package. + if (source.absolute.path.contains('/RunnerTests/')) { + updatePackageNameInImports(File(destinationPath), destinationPackageName); + } } void _reportUnsharedFiles( diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart index d311e4f64891..21a6ec647250 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart @@ -53,3 +53,19 @@ void updatePackageNameInPathReferences(File file, String packageName) { ); file.writeAsStringSync(newContents); } + +/// Updates the contents of [file] to replace any occurrences of variants of the +/// package name in Obj-C or Swift import statements. +/// +/// This is necessary for native unit tests, which need to import the Swift +/// package by name. +void updatePackageNameInImports(File file, String packageName) { + final String newContents = file.readAsStringSync().replaceAllMapped( + RegExp( + r'^(@?)import google_maps_flutter_ios[_\w\d]*(;?)$', + multiLine: true, + ), + (match) => '${match.group(1)}import $packageName${match.group(2)}', + ); + file.writeAsStringSync(newContents); +} From 3dd739e562353fca70c17b38791ac809f676f283 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Tue, 3 Feb 2026 17:00:57 -0500 Subject: [PATCH 17/19] Add enforced checks for unshared files --- .../tool/run_tests.dart | 18 ++++++ .../tool/sync_shared_files.dart | 49 +++------------- .../tool/unshared_source_files.dart | 13 +++++ .../google_maps_flutter_ios/tool/utils.dart | 56 +++++++++++++++++++ .../tool/run_tests.dart | 18 ++++++ .../tool/sync_shared_files.dart | 49 +++------------- .../tool/unshared_source_files.dart | 15 +++++ .../tool/utils.dart | 56 +++++++++++++++++++ .../tool/run_tests.dart | 18 ++++++ .../tool/sync_shared_files.dart | 49 +++------------- .../tool/unshared_source_files.dart | 15 +++++ .../tool/utils.dart | 56 +++++++++++++++++++ .../tool/run_tests.dart | 18 ++++++ .../tool/sync_shared_files.dart | 49 +++------------- .../tool/utils.dart | 56 +++++++++++++++++++ 15 files changed, 375 insertions(+), 160 deletions(-) create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios/tool/unshared_source_files.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/unshared_source_files.dart create mode 100644 packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/unshared_source_files.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/run_tests.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/run_tests.dart index 114db5c7b00f..f86778c0c2a1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/tool/run_tests.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/run_tests.dart @@ -73,6 +73,24 @@ Future main(List args) async { } } + print( + '\nChecking for unshared source files that are not in ' + 'tool/unshared_source_files.dart...', + ); + final List unsharedFiles = unexpectedUnsharedSourceFiles( + packageRoot, + packageName, + sharedSourceRoot, + ); + if (unsharedFiles.isEmpty) { + print(' No unexpected unshared files.'); + } else { + failed = true; + for (final file in unsharedFiles) { + print(' $file is not shared'); + } + } + if (failed) { print(''' diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart index f2858929cea3..fbbd50d0a499 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/sync_shared_files.dart @@ -112,7 +112,8 @@ void _syncSharedFiles( print(' $file'); } print( - 'If these files should no longer be shared, remove them from the shared source.', + 'If these files should no longer be shared, remove them from the shared source.\n' + 'If they should no longer exist at all, remove them from all copies of the package.', ); } } @@ -151,32 +152,11 @@ void _reportUnsharedFiles( String packageName, Directory sharedSourceRoot, ) { - final List codeFiles = packageRoot - .listSync(recursive: true) - .whereType() - // Only report code files. - .where( - (file) => - ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), - ) - // Flutter-generated files aren't expected to be shared. - .where((file) => !file.path.contains('GeneratedPluginRegistrant')) - // Ignore intermediate file directories. - .where((file) => !_isInIntermediateDirectory(file.path)) - .toList(); - - final unsharedFiles = []; - for (final file in codeFiles) { - final String relativePath = p.relative(file.path, from: packageRoot.path); - final String sharedPath = p.join( - sharedSourceRoot.path, - sharedSourceRelativePathForPackagePath(relativePath), - ); - final sharedFile = File(sharedPath); - if (!sharedFile.existsSync()) { - unsharedFiles.add(relativePath); - } - } + final List unsharedFiles = unexpectedUnsharedSourceFiles( + packageRoot, + packageName, + sharedSourceRoot, + ); if (unsharedFiles.isNotEmpty) { print('\nThe following code files are not shared with other packages:'); @@ -184,19 +164,8 @@ void _reportUnsharedFiles( print(' $file'); } print( - 'If this is not intentional, copy the relevant files to ' - '$_sharedSourceRootName, then re-run this tool.', + 'If this is intentional, add the .\n' + 'Otherwise, copy the relevant files to $_sharedSourceRootName, then re-run this tool.', ); } } - -bool _isInIntermediateDirectory(String path) { - return [ - '.dart_tool', - '.symlinks', - '.build', - 'build', - 'ephemeral', - 'Pods', - ].any((dir) => path.contains('/$dir/')); -} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/unshared_source_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/unshared_source_files.dart new file mode 100644 index 000000000000..90d963c64dde --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/unshared_source_files.dart @@ -0,0 +1,13 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const intentionallyUnsharedSourceFiles = [ + // Intentionally unshared since it has almost no code, and would need + // special handling for the filename being different. + 'lib/google_maps_flutter_ios.dart', + // Intentionally unshared to isolate import name differences. + 'test/package_specific_test_import.dart', + // Each package will have its own list. + 'tool/unshared_source_files.dart', +]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart index 21a6ec647250..c4b2b9b83433 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios/tool/utils.dart @@ -4,6 +4,51 @@ import 'dart:io'; +import 'package:path/path.dart' as p; + +import 'unshared_source_files.dart'; + +bool isIntentionallyUnsharedSourceFile(String packageRelativePath) { + return intentionallyUnsharedSourceFiles.contains(packageRelativePath); +} + +List unexpectedUnsharedSourceFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List codeFiles = packageRoot + .listSync(recursive: true) + .whereType() + // Only report code files. + .where( + (file) => + ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), + ) + // Flutter-generated files aren't expected to be shared. + .where((file) => !file.path.contains('GeneratedPluginRegistrant')) + // Ignore intermediate file directories. + .where((file) => !_isInIntermediateDirectory(file.path)) + .toList(); + + final unsharedFiles = []; + for (final file in codeFiles) { + final String relativePath = p.relative(file.path, from: packageRoot.path); + if (isIntentionallyUnsharedSourceFile(relativePath)) { + continue; + } + final String sharedPath = p.join( + sharedSourceRoot.path, + sharedSourceRelativePathForPackagePath(relativePath), + ); + final sharedFile = File(sharedPath); + if (!sharedFile.existsSync()) { + unsharedFiles.add(relativePath); + } + } + return unsharedFiles; +} + /// Adjusts a package-relative path to account for the package name being part of /// the directory structure for Swift packages. String sharedSourceRelativePathForPackagePath(String packageRelativePath) { @@ -69,3 +114,14 @@ void updatePackageNameInImports(File file, String packageName) { ); file.writeAsStringSync(newContents); } + +bool _isInIntermediateDirectory(String path) { + return [ + '.dart_tool', + '.symlinks', + '.build', + 'build', + 'ephemeral', + 'Pods', + ].any((dir) => path.contains('/$dir/')); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/run_tests.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/run_tests.dart index 114db5c7b00f..f86778c0c2a1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/run_tests.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/run_tests.dart @@ -73,6 +73,24 @@ Future main(List args) async { } } + print( + '\nChecking for unshared source files that are not in ' + 'tool/unshared_source_files.dart...', + ); + final List unsharedFiles = unexpectedUnsharedSourceFiles( + packageRoot, + packageName, + sharedSourceRoot, + ); + if (unsharedFiles.isEmpty) { + print(' No unexpected unshared files.'); + } else { + failed = true; + for (final file in unsharedFiles) { + print(' $file is not shared'); + } + } + if (failed) { print(''' diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart index f2858929cea3..fbbd50d0a499 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/sync_shared_files.dart @@ -112,7 +112,8 @@ void _syncSharedFiles( print(' $file'); } print( - 'If these files should no longer be shared, remove them from the shared source.', + 'If these files should no longer be shared, remove them from the shared source.\n' + 'If they should no longer exist at all, remove them from all copies of the package.', ); } } @@ -151,32 +152,11 @@ void _reportUnsharedFiles( String packageName, Directory sharedSourceRoot, ) { - final List codeFiles = packageRoot - .listSync(recursive: true) - .whereType() - // Only report code files. - .where( - (file) => - ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), - ) - // Flutter-generated files aren't expected to be shared. - .where((file) => !file.path.contains('GeneratedPluginRegistrant')) - // Ignore intermediate file directories. - .where((file) => !_isInIntermediateDirectory(file.path)) - .toList(); - - final unsharedFiles = []; - for (final file in codeFiles) { - final String relativePath = p.relative(file.path, from: packageRoot.path); - final String sharedPath = p.join( - sharedSourceRoot.path, - sharedSourceRelativePathForPackagePath(relativePath), - ); - final sharedFile = File(sharedPath); - if (!sharedFile.existsSync()) { - unsharedFiles.add(relativePath); - } - } + final List unsharedFiles = unexpectedUnsharedSourceFiles( + packageRoot, + packageName, + sharedSourceRoot, + ); if (unsharedFiles.isNotEmpty) { print('\nThe following code files are not shared with other packages:'); @@ -184,19 +164,8 @@ void _reportUnsharedFiles( print(' $file'); } print( - 'If this is not intentional, copy the relevant files to ' - '$_sharedSourceRootName, then re-run this tool.', + 'If this is intentional, add the .\n' + 'Otherwise, copy the relevant files to $_sharedSourceRootName, then re-run this tool.', ); } } - -bool _isInIntermediateDirectory(String path) { - return [ - '.dart_tool', - '.symlinks', - '.build', - 'build', - 'ephemeral', - 'Pods', - ].any((dir) => path.contains('/$dir/')); -} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/unshared_source_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/unshared_source_files.dart new file mode 100644 index 000000000000..8660b7e6a17e --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/unshared_source_files.dart @@ -0,0 +1,15 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const intentionallyUnsharedSourceFiles = [ + // Package dependencies are platform-specific due to versioning. + 'ios/google_maps_flutter_ios_sdk10/Package.swift', + // Intentionally unshared since it has almost no code, and would need + // special handling for the filename being different. + 'lib/google_maps_flutter_ios_sdk10.dart', + // Intentionally unshared to isolate import name differences. + 'test/package_specific_test_import.dart', + // Each package will have its own list. + 'tool/unshared_source_files.dart', +]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart index 21a6ec647250..c4b2b9b83433 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/tool/utils.dart @@ -4,6 +4,51 @@ import 'dart:io'; +import 'package:path/path.dart' as p; + +import 'unshared_source_files.dart'; + +bool isIntentionallyUnsharedSourceFile(String packageRelativePath) { + return intentionallyUnsharedSourceFiles.contains(packageRelativePath); +} + +List unexpectedUnsharedSourceFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List codeFiles = packageRoot + .listSync(recursive: true) + .whereType() + // Only report code files. + .where( + (file) => + ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), + ) + // Flutter-generated files aren't expected to be shared. + .where((file) => !file.path.contains('GeneratedPluginRegistrant')) + // Ignore intermediate file directories. + .where((file) => !_isInIntermediateDirectory(file.path)) + .toList(); + + final unsharedFiles = []; + for (final file in codeFiles) { + final String relativePath = p.relative(file.path, from: packageRoot.path); + if (isIntentionallyUnsharedSourceFile(relativePath)) { + continue; + } + final String sharedPath = p.join( + sharedSourceRoot.path, + sharedSourceRelativePathForPackagePath(relativePath), + ); + final sharedFile = File(sharedPath); + if (!sharedFile.existsSync()) { + unsharedFiles.add(relativePath); + } + } + return unsharedFiles; +} + /// Adjusts a package-relative path to account for the package name being part of /// the directory structure for Swift packages. String sharedSourceRelativePathForPackagePath(String packageRelativePath) { @@ -69,3 +114,14 @@ void updatePackageNameInImports(File file, String packageName) { ); file.writeAsStringSync(newContents); } + +bool _isInIntermediateDirectory(String path) { + return [ + '.dart_tool', + '.symlinks', + '.build', + 'build', + 'ephemeral', + 'Pods', + ].any((dir) => path.contains('/$dir/')); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/run_tests.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/run_tests.dart index 114db5c7b00f..f86778c0c2a1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/run_tests.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/run_tests.dart @@ -73,6 +73,24 @@ Future main(List args) async { } } + print( + '\nChecking for unshared source files that are not in ' + 'tool/unshared_source_files.dart...', + ); + final List unsharedFiles = unexpectedUnsharedSourceFiles( + packageRoot, + packageName, + sharedSourceRoot, + ); + if (unsharedFiles.isEmpty) { + print(' No unexpected unshared files.'); + } else { + failed = true; + for (final file in unsharedFiles) { + print(' $file is not shared'); + } + } + if (failed) { print(''' diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart index f2858929cea3..fbbd50d0a499 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/sync_shared_files.dart @@ -112,7 +112,8 @@ void _syncSharedFiles( print(' $file'); } print( - 'If these files should no longer be shared, remove them from the shared source.', + 'If these files should no longer be shared, remove them from the shared source.\n' + 'If they should no longer exist at all, remove them from all copies of the package.', ); } } @@ -151,32 +152,11 @@ void _reportUnsharedFiles( String packageName, Directory sharedSourceRoot, ) { - final List codeFiles = packageRoot - .listSync(recursive: true) - .whereType() - // Only report code files. - .where( - (file) => - ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), - ) - // Flutter-generated files aren't expected to be shared. - .where((file) => !file.path.contains('GeneratedPluginRegistrant')) - // Ignore intermediate file directories. - .where((file) => !_isInIntermediateDirectory(file.path)) - .toList(); - - final unsharedFiles = []; - for (final file in codeFiles) { - final String relativePath = p.relative(file.path, from: packageRoot.path); - final String sharedPath = p.join( - sharedSourceRoot.path, - sharedSourceRelativePathForPackagePath(relativePath), - ); - final sharedFile = File(sharedPath); - if (!sharedFile.existsSync()) { - unsharedFiles.add(relativePath); - } - } + final List unsharedFiles = unexpectedUnsharedSourceFiles( + packageRoot, + packageName, + sharedSourceRoot, + ); if (unsharedFiles.isNotEmpty) { print('\nThe following code files are not shared with other packages:'); @@ -184,19 +164,8 @@ void _reportUnsharedFiles( print(' $file'); } print( - 'If this is not intentional, copy the relevant files to ' - '$_sharedSourceRootName, then re-run this tool.', + 'If this is intentional, add the .\n' + 'Otherwise, copy the relevant files to $_sharedSourceRootName, then re-run this tool.', ); } } - -bool _isInIntermediateDirectory(String path) { - return [ - '.dart_tool', - '.symlinks', - '.build', - 'build', - 'ephemeral', - 'Pods', - ].any((dir) => path.contains('/$dir/')); -} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/unshared_source_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/unshared_source_files.dart new file mode 100644 index 000000000000..1cfb85a852ac --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/unshared_source_files.dart @@ -0,0 +1,15 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const intentionallyUnsharedSourceFiles = [ + // Package dependencies are platform-specific due to versioning. + 'ios/google_maps_flutter_ios_sdk9/Package.swift', + // Intentionally unshared since it has almost no code, and would need + // special handling for the filename being different. + 'lib/google_maps_flutter_ios_sdk9.dart', + // Intentionally unshared to isolate import name differences. + 'test/package_specific_test_import.dart', + // Each package will have its own list. + 'tool/unshared_source_files.dart', +]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart index 21a6ec647250..c4b2b9b83433 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/tool/utils.dart @@ -4,6 +4,51 @@ import 'dart:io'; +import 'package:path/path.dart' as p; + +import 'unshared_source_files.dart'; + +bool isIntentionallyUnsharedSourceFile(String packageRelativePath) { + return intentionallyUnsharedSourceFiles.contains(packageRelativePath); +} + +List unexpectedUnsharedSourceFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List codeFiles = packageRoot + .listSync(recursive: true) + .whereType() + // Only report code files. + .where( + (file) => + ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), + ) + // Flutter-generated files aren't expected to be shared. + .where((file) => !file.path.contains('GeneratedPluginRegistrant')) + // Ignore intermediate file directories. + .where((file) => !_isInIntermediateDirectory(file.path)) + .toList(); + + final unsharedFiles = []; + for (final file in codeFiles) { + final String relativePath = p.relative(file.path, from: packageRoot.path); + if (isIntentionallyUnsharedSourceFile(relativePath)) { + continue; + } + final String sharedPath = p.join( + sharedSourceRoot.path, + sharedSourceRelativePathForPackagePath(relativePath), + ); + final sharedFile = File(sharedPath); + if (!sharedFile.existsSync()) { + unsharedFiles.add(relativePath); + } + } + return unsharedFiles; +} + /// Adjusts a package-relative path to account for the package name being part of /// the directory structure for Swift packages. String sharedSourceRelativePathForPackagePath(String packageRelativePath) { @@ -69,3 +114,14 @@ void updatePackageNameInImports(File file, String packageName) { ); file.writeAsStringSync(newContents); } + +bool _isInIntermediateDirectory(String path) { + return [ + '.dart_tool', + '.symlinks', + '.build', + 'build', + 'ephemeral', + 'Pods', + ].any((dir) => path.contains('/$dir/')); +} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/run_tests.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/run_tests.dart index 114db5c7b00f..f86778c0c2a1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/run_tests.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/run_tests.dart @@ -73,6 +73,24 @@ Future main(List args) async { } } + print( + '\nChecking for unshared source files that are not in ' + 'tool/unshared_source_files.dart...', + ); + final List unsharedFiles = unexpectedUnsharedSourceFiles( + packageRoot, + packageName, + sharedSourceRoot, + ); + if (unsharedFiles.isEmpty) { + print(' No unexpected unshared files.'); + } else { + failed = true; + for (final file in unsharedFiles) { + print(' $file is not shared'); + } + } + if (failed) { print(''' diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart index f2858929cea3..fbbd50d0a499 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/sync_shared_files.dart @@ -112,7 +112,8 @@ void _syncSharedFiles( print(' $file'); } print( - 'If these files should no longer be shared, remove them from the shared source.', + 'If these files should no longer be shared, remove them from the shared source.\n' + 'If they should no longer exist at all, remove them from all copies of the package.', ); } } @@ -151,32 +152,11 @@ void _reportUnsharedFiles( String packageName, Directory sharedSourceRoot, ) { - final List codeFiles = packageRoot - .listSync(recursive: true) - .whereType() - // Only report code files. - .where( - (file) => - ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), - ) - // Flutter-generated files aren't expected to be shared. - .where((file) => !file.path.contains('GeneratedPluginRegistrant')) - // Ignore intermediate file directories. - .where((file) => !_isInIntermediateDirectory(file.path)) - .toList(); - - final unsharedFiles = []; - for (final file in codeFiles) { - final String relativePath = p.relative(file.path, from: packageRoot.path); - final String sharedPath = p.join( - sharedSourceRoot.path, - sharedSourceRelativePathForPackagePath(relativePath), - ); - final sharedFile = File(sharedPath); - if (!sharedFile.existsSync()) { - unsharedFiles.add(relativePath); - } - } + final List unsharedFiles = unexpectedUnsharedSourceFiles( + packageRoot, + packageName, + sharedSourceRoot, + ); if (unsharedFiles.isNotEmpty) { print('\nThe following code files are not shared with other packages:'); @@ -184,19 +164,8 @@ void _reportUnsharedFiles( print(' $file'); } print( - 'If this is not intentional, copy the relevant files to ' - '$_sharedSourceRootName, then re-run this tool.', + 'If this is intentional, add the .\n' + 'Otherwise, copy the relevant files to $_sharedSourceRootName, then re-run this tool.', ); } } - -bool _isInIntermediateDirectory(String path) { - return [ - '.dart_tool', - '.symlinks', - '.build', - 'build', - 'ephemeral', - 'Pods', - ].any((dir) => path.contains('/$dir/')); -} diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart index 21a6ec647250..c4b2b9b83433 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/tool/utils.dart @@ -4,6 +4,51 @@ import 'dart:io'; +import 'package:path/path.dart' as p; + +import 'unshared_source_files.dart'; + +bool isIntentionallyUnsharedSourceFile(String packageRelativePath) { + return intentionallyUnsharedSourceFiles.contains(packageRelativePath); +} + +List unexpectedUnsharedSourceFiles( + Directory packageRoot, + String packageName, + Directory sharedSourceRoot, +) { + final List codeFiles = packageRoot + .listSync(recursive: true) + .whereType() + // Only report code files. + .where( + (file) => + ['.swift', '.m', '.h', '.dart'].any(file.path.endsWith), + ) + // Flutter-generated files aren't expected to be shared. + .where((file) => !file.path.contains('GeneratedPluginRegistrant')) + // Ignore intermediate file directories. + .where((file) => !_isInIntermediateDirectory(file.path)) + .toList(); + + final unsharedFiles = []; + for (final file in codeFiles) { + final String relativePath = p.relative(file.path, from: packageRoot.path); + if (isIntentionallyUnsharedSourceFile(relativePath)) { + continue; + } + final String sharedPath = p.join( + sharedSourceRoot.path, + sharedSourceRelativePathForPackagePath(relativePath), + ); + final sharedFile = File(sharedPath); + if (!sharedFile.existsSync()) { + unsharedFiles.add(relativePath); + } + } + return unsharedFiles; +} + /// Adjusts a package-relative path to account for the package name being part of /// the directory structure for Swift packages. String sharedSourceRelativePathForPackagePath(String packageRelativePath) { @@ -69,3 +114,14 @@ void updatePackageNameInImports(File file, String packageName) { ); file.writeAsStringSync(newContents); } + +bool _isInIntermediateDirectory(String path) { + return [ + '.dart_tool', + '.symlinks', + '.build', + 'build', + 'ephemeral', + 'Pods', + ].any((dir) => path.contains('/$dir/')); +} From b8f335efcbc1c7bc9fd9eae18a57c1549ec22848 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 4 Feb 2026 11:03:47 -0500 Subject: [PATCH 18/19] Copy project changes for OCMock PR resolution --- .../ios/Runner.xcodeproj/project.pbxproj | 20 ++++++++++++++++--- .../ios/Runner.xcodeproj/project.pbxproj | 20 ++++++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj index 0189321194f4..c2141f9f86c7 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ @@ -12,10 +12,12 @@ 2A6906C72D263DF4001F8426 /* GoogleMapsGroundOverlayControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */; }; 2BDE99378062AE3E60B40021 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */; }; 330909FF2D99B7A60077A751 /* GoogleMapsMarkerControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */; }; + 3378E6352F23F9300045E7DA /* TestMapEventHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 3378E6342F23F92E0045E7DA /* TestMapEventHandler.m */; }; 339355BA2EB3E50300EBF864 /* GoogleMapsCircleControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */; }; 339355BD2EB3E56300EBF864 /* GoogleMapsTileOverlayControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */; }; 339355BF2EB535A600EBF864 /* FLTGoogleMapHeatmapControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */; }; 339DF1F02F1FE49800748863 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339DF1EF2F1FE49300748863 /* AppDelegate.swift */; }; + 33BF9C6E2F2182DF0005FA15 /* TestAssetProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 33BF9C6D2F2182DB0005FA15 /* TestAssetProvider.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 478116522BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */; }; 528F16832C62941000148160 /* FGMClusterManagersControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 528F16822C62941000148160 /* FGMClusterManagersControllerTests.m */; }; @@ -68,12 +70,16 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsGroundOverlayControllerTests.m; sourceTree = ""; }; 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsMarkerControllerTests.m; sourceTree = ""; }; + 3378E6332F23F9220045E7DA /* TestMapEventHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestMapEventHandler.h; sourceTree = ""; }; + 3378E6342F23F92E0045E7DA /* TestMapEventHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestMapEventHandler.m; sourceTree = ""; }; 339355B82EB3E4D500EBF864 /* GoogleMapsPolygonControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsPolygonControllerTests.m; sourceTree = ""; }; 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsCircleControllerTests.m; sourceTree = ""; }; 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsTileOverlayControllerTests.m; sourceTree = ""; }; 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTGoogleMapHeatmapControllerTests.m; sourceTree = ""; }; 339DF1EF2F1FE49300748863 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 339DF1F12F1FE4AD00748863 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 33BF9C6C2F2182CB0005FA15 /* TestAssetProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestAssetProvider.h; sourceTree = ""; }; + 33BF9C6D2F2182DB0005FA15 /* TestAssetProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestAssetProvider.m; sourceTree = ""; }; 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsPolylineControllerTests.m; sourceTree = ""; }; @@ -82,6 +88,7 @@ 61A9A8623F5CA9BBC813DC6B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6851F3552835BC180032B7C8 /* FGMConversionsUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FGMConversionsUtilsTests.m; sourceTree = ""; }; 733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = Flutter/ephemeral/Packages/.packages/FlutterFramework; sourceTree = ""; }; 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; @@ -145,6 +152,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 784666492D4C4C64000A1A5F /* FlutterFramework */, 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, @@ -221,6 +229,10 @@ 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */, 982F2A6A27BADE17003C81F4 /* PartiallyMockedMapView.h */, 982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */, + 33BF9C6C2F2182CB0005FA15 /* TestAssetProvider.h */, + 33BF9C6D2F2182DB0005FA15 /* TestAssetProvider.m */, + 3378E6332F23F9220045E7DA /* TestMapEventHandler.h */, + 3378E6342F23F92E0045E7DA /* TestMapEventHandler.m */, F7151F14265D7ED70028CB91 /* Info.plist */, ); path = RunnerTests; @@ -336,7 +348,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -509,8 +521,10 @@ 339355BF2EB535A600EBF864 /* FLTGoogleMapHeatmapControllerTests.m in Sources */, 339355BD2EB3E56300EBF864 /* GoogleMapsTileOverlayControllerTests.m in Sources */, F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */, + 33BF9C6E2F2182DF0005FA15 /* TestAssetProvider.m in Sources */, 6851F3562835BC180032B7C8 /* FGMConversionsUtilsTests.m in Sources */, 982F2A6C27BADE17003C81F4 /* PartiallyMockedMapView.m in Sources */, + 3378E6352F23F9300045E7DA /* TestMapEventHandler.m in Sources */, 330909FF2D99B7A60077A751 /* GoogleMapsMarkerControllerTests.m in Sources */, 478116522BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m in Sources */, 2A6906C72D263DF4001F8426 /* GoogleMapsGroundOverlayControllerTests.m in Sources */, @@ -841,7 +855,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj index 27d1133df09f..f92721e69d4a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ @@ -12,10 +12,12 @@ 2A6906C72D263DF4001F8426 /* GoogleMapsGroundOverlayControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */; }; 2BDE99378062AE3E60B40021 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */; }; 330909FF2D99B7A60077A751 /* GoogleMapsMarkerControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */; }; + 3378E6352F23F9300045E7DA /* TestMapEventHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 3378E6342F23F92E0045E7DA /* TestMapEventHandler.m */; }; 339355BA2EB3E50300EBF864 /* GoogleMapsCircleControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */; }; 339355BD2EB3E56300EBF864 /* GoogleMapsTileOverlayControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */; }; 339355BF2EB535A600EBF864 /* FLTGoogleMapHeatmapControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */; }; 339DF1F02F1FE49800748863 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339DF1EF2F1FE49300748863 /* AppDelegate.swift */; }; + 33BF9C6E2F2182DF0005FA15 /* TestAssetProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 33BF9C6D2F2182DB0005FA15 /* TestAssetProvider.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 478116522BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */; }; 528F16832C62941000148160 /* FGMClusterManagersControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 528F16822C62941000148160 /* FGMClusterManagersControllerTests.m */; }; @@ -68,12 +70,16 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 2A6906C62D263DE7001F8426 /* GoogleMapsGroundOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsGroundOverlayControllerTests.m; sourceTree = ""; }; 330909FE2D99B79B0077A751 /* GoogleMapsMarkerControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsMarkerControllerTests.m; sourceTree = ""; }; + 3378E6332F23F9220045E7DA /* TestMapEventHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestMapEventHandler.h; sourceTree = ""; }; + 3378E6342F23F92E0045E7DA /* TestMapEventHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestMapEventHandler.m; sourceTree = ""; }; 339355B82EB3E4D500EBF864 /* GoogleMapsPolygonControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsPolygonControllerTests.m; sourceTree = ""; }; 339355B92EB3E4F900EBF864 /* GoogleMapsCircleControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsCircleControllerTests.m; sourceTree = ""; }; 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsTileOverlayControllerTests.m; sourceTree = ""; }; 339355BE2EB5359B00EBF864 /* FLTGoogleMapHeatmapControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLTGoogleMapHeatmapControllerTests.m; sourceTree = ""; }; 339DF1EF2F1FE49300748863 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 339DF1F12F1FE4AD00748863 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 33BF9C6C2F2182CB0005FA15 /* TestAssetProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestAssetProvider.h; sourceTree = ""; }; + 33BF9C6D2F2182DB0005FA15 /* TestAssetProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestAssetProvider.m; sourceTree = ""; }; 3ACE0AFE8D82CD5962486AFD /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 478116512BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GoogleMapsPolylineControllerTests.m; sourceTree = ""; }; @@ -82,6 +88,7 @@ 61A9A8623F5CA9BBC813DC6B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6851F3552835BC180032B7C8 /* FGMConversionsUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FGMConversionsUtilsTests.m; sourceTree = ""; }; 733AFAB37683A9DA7512F09C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 784666492D4C4C64000A1A5F /* FlutterFramework */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterFramework; path = Flutter/ephemeral/Packages/.packages/FlutterFramework; sourceTree = ""; }; 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; @@ -145,6 +152,7 @@ 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( + 784666492D4C4C64000A1A5F /* FlutterFramework */, 78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, @@ -221,6 +229,10 @@ 339355BC2EB3E55600EBF864 /* GoogleMapsTileOverlayControllerTests.m */, 982F2A6A27BADE17003C81F4 /* PartiallyMockedMapView.h */, 982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */, + 33BF9C6C2F2182CB0005FA15 /* TestAssetProvider.h */, + 33BF9C6D2F2182DB0005FA15 /* TestAssetProvider.m */, + 3378E6332F23F9220045E7DA /* TestMapEventHandler.h */, + 3378E6342F23F92E0045E7DA /* TestMapEventHandler.m */, F7151F14265D7ED70028CB91 /* Info.plist */, ); path = RunnerTests; @@ -336,7 +348,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -509,8 +521,10 @@ 339355BF2EB535A600EBF864 /* FLTGoogleMapHeatmapControllerTests.m in Sources */, 339355BD2EB3E56300EBF864 /* GoogleMapsTileOverlayControllerTests.m in Sources */, F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */, + 33BF9C6E2F2182DF0005FA15 /* TestAssetProvider.m in Sources */, 6851F3562835BC180032B7C8 /* FGMConversionsUtilsTests.m in Sources */, 982F2A6C27BADE17003C81F4 /* PartiallyMockedMapView.m in Sources */, + 3378E6352F23F9300045E7DA /* TestMapEventHandler.m in Sources */, 330909FF2D99B7A60077A751 /* GoogleMapsMarkerControllerTests.m in Sources */, 478116522BEF8F47002F593E /* GoogleMapsPolylineControllerTests.m in Sources */, 2A6906C72D263DF4001F8426 /* GoogleMapsGroundOverlayControllerTests.m in Sources */, @@ -841,7 +855,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; From a8881fa2276e9a5ab38f718fa946629613ba5a96 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 11 Feb 2026 16:50:40 -0500 Subject: [PATCH 19/19] Sync changes from merge with master to other copies --- .../GoogleMapsGroundOverlayControllerTests.m | 16 ++++++++++++++++ .../GoogleMapsMarkerControllerTests.m | 17 +++++++++++++++++ .../FGMGroundOverlayController.m | 2 +- .../GoogleMapMarkerController.m | 2 +- .../GoogleMapsGroundOverlayControllerTests.m | 16 ++++++++++++++++ .../GoogleMapsMarkerControllerTests.m | 17 +++++++++++++++++ .../FGMGroundOverlayController.m | 2 +- .../GoogleMapMarkerController.m | 2 +- .../GoogleMapsGroundOverlayControllerTests.m | 16 ++++++++++++++++ .../GoogleMapsMarkerControllerTests.m | 17 +++++++++++++++++ .../FGMGroundOverlayController.m | 2 +- .../GoogleMapMarkerController.m | 2 +- 12 files changed, 105 insertions(+), 6 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m index 5c3c6f309c04..0c598d5832c8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -8,6 +8,7 @@ #import "PartiallyMockedMapView.h" #import "TestAssetProvider.h" +#import "TestMapEventHandler.h" /// A GMSGroundOverlay that ensures that property updates are made before the map is set. @interface PropertyOrderValidatingGroundOverlay : GMSGroundOverlay { @@ -211,6 +212,21 @@ - (void)testUpdateGroundOverlaySetsVisibilityLast { XCTAssertTrue(groundOverlay.hasSetMap); } +- (void)testAssetProviderIsRetained { + FLTGroundOverlaysController *groundOverlayController; + __weak TestAssetProvider *weakAssetProvider; + @autoreleasepool { + TestAssetProvider *assetProvider = [[TestAssetProvider alloc] init]; + weakAssetProvider = assetProvider; + groundOverlayController = [[FLTGroundOverlaysController alloc] + initWithMapView:[GoogleMapsGroundOverlayControllerTests mapView] + eventDelegate:[[TestMapEventHandler alloc] init] + assetProvider:assetProvider]; + } + XCTAssertNotNil(groundOverlayController); + XCTAssertNotNil(weakAssetProvider); +} + /// Returns a simple map view to add map objects to. + (GMSMapView *)mapView { GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m index 8cc309b45174..b6c6a5652f64 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -268,6 +268,23 @@ - (void)testUpdateMarkerSetsVisibilityLast { XCTAssertTrue(marker.hasSetMap); } +- (void)testAssetProviderIsRetained { + FLTMarkersController *markerController; + __weak TestAssetProvider *weakAssetProvider; + @autoreleasepool { + TestAssetProvider *assetProvider = [[TestAssetProvider alloc] init]; + weakAssetProvider = assetProvider; + + markerController = + [[FLTMarkersController alloc] initWithMapView:[GoogleMapsMarkerControllerTests mapView] + eventDelegate:[[TestMapEventHandler alloc] init] + clusterManagersController:nil + assetProvider:assetProvider]; + } + XCTAssertNotNil(markerController); + XCTAssertNotNil(weakAssetProvider, @"AssetProvider should be retained by the marker controller"); +} + @end @implementation PropertyOrderValidatingMarker diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMGroundOverlayController.m index f1fe7281dc09..c5e45188510a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMGroundOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/FGMGroundOverlayController.m @@ -89,7 +89,7 @@ @interface FLTGroundOverlaysController () @property(weak, nonatomic) NSObject *eventDelegate; /// Asset provider used to load images. -@property(weak, nonatomic) NSObject *assetProvider; +@property(strong, nonatomic) NSObject *assetProvider; /// The map view used to generate the controllers. @property(weak, nonatomic) GMSMapView *mapView; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapMarkerController.m index 9d061eec8b09..09a05db2840d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapMarkerController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk10/ios/google_maps_flutter_ios_sdk10/Sources/google_maps_flutter_ios_sdk10/GoogleMapMarkerController.m @@ -113,7 +113,7 @@ @interface FLTMarkersController () @property(weak, nonatomic) NSObject *eventDelegate; /// Controller for adding/removing/fetching cluster managers @property(weak, nonatomic, nullable) FGMClusterManagersController *clusterManagersController; -@property(weak, nonatomic) NSObject *assetProvider; +@property(strong, nonatomic) NSObject *assetProvider; @property(weak, nonatomic) GMSMapView *mapView; @end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m index 404b07e7d139..dc4cdf4c1a88 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -8,6 +8,7 @@ #import "PartiallyMockedMapView.h" #import "TestAssetProvider.h" +#import "TestMapEventHandler.h" /// A GMSGroundOverlay that ensures that property updates are made before the map is set. @interface PropertyOrderValidatingGroundOverlay : GMSGroundOverlay { @@ -211,6 +212,21 @@ - (void)testUpdateGroundOverlaySetsVisibilityLast { XCTAssertTrue(groundOverlay.hasSetMap); } +- (void)testAssetProviderIsRetained { + FLTGroundOverlaysController *groundOverlayController; + __weak TestAssetProvider *weakAssetProvider; + @autoreleasepool { + TestAssetProvider *assetProvider = [[TestAssetProvider alloc] init]; + weakAssetProvider = assetProvider; + groundOverlayController = [[FLTGroundOverlaysController alloc] + initWithMapView:[GoogleMapsGroundOverlayControllerTests mapView] + eventDelegate:[[TestMapEventHandler alloc] init] + assetProvider:assetProvider]; + } + XCTAssertNotNil(groundOverlayController); + XCTAssertNotNil(weakAssetProvider); +} + /// Returns a simple map view to add map objects to. + (GMSMapView *)mapView { GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m index ac380a85d479..cec2ccfb2995 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -268,6 +268,23 @@ - (void)testUpdateMarkerSetsVisibilityLast { XCTAssertTrue(marker.hasSetMap); } +- (void)testAssetProviderIsRetained { + FLTMarkersController *markerController; + __weak TestAssetProvider *weakAssetProvider; + @autoreleasepool { + TestAssetProvider *assetProvider = [[TestAssetProvider alloc] init]; + weakAssetProvider = assetProvider; + + markerController = + [[FLTMarkersController alloc] initWithMapView:[GoogleMapsMarkerControllerTests mapView] + eventDelegate:[[TestMapEventHandler alloc] init] + clusterManagersController:nil + assetProvider:assetProvider]; + } + XCTAssertNotNil(markerController); + XCTAssertNotNil(weakAssetProvider, @"AssetProvider should be retained by the marker controller"); +} + @end @implementation PropertyOrderValidatingMarker diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m index f1fe7281dc09..c5e45188510a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/FGMGroundOverlayController.m @@ -89,7 +89,7 @@ @interface FLTGroundOverlaysController () @property(weak, nonatomic) NSObject *eventDelegate; /// Asset provider used to load images. -@property(weak, nonatomic) NSObject *assetProvider; +@property(strong, nonatomic) NSObject *assetProvider; /// The map view used to generate the controllers. @property(weak, nonatomic) GMSMapView *mapView; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m index 9d061eec8b09..09a05db2840d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_sdk9/ios/google_maps_flutter_ios_sdk9/Sources/google_maps_flutter_ios_sdk9/GoogleMapMarkerController.m @@ -113,7 +113,7 @@ @interface FLTMarkersController () @property(weak, nonatomic) NSObject *eventDelegate; /// Controller for adding/removing/fetching cluster managers @property(weak, nonatomic, nullable) FGMClusterManagersController *clusterManagersController; -@property(weak, nonatomic) NSObject *assetProvider; +@property(strong, nonatomic) NSObject *assetProvider; @property(weak, nonatomic) GMSMapView *mapView; @end diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m index 0486043eec8b..9bace1c1d763 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsGroundOverlayControllerTests.m @@ -8,6 +8,7 @@ #import "PartiallyMockedMapView.h" #import "TestAssetProvider.h" +#import "TestMapEventHandler.h" /// A GMSGroundOverlay that ensures that property updates are made before the map is set. @interface PropertyOrderValidatingGroundOverlay : GMSGroundOverlay { @@ -211,6 +212,21 @@ - (void)testUpdateGroundOverlaySetsVisibilityLast { XCTAssertTrue(groundOverlay.hasSetMap); } +- (void)testAssetProviderIsRetained { + FLTGroundOverlaysController *groundOverlayController; + __weak TestAssetProvider *weakAssetProvider; + @autoreleasepool { + TestAssetProvider *assetProvider = [[TestAssetProvider alloc] init]; + weakAssetProvider = assetProvider; + groundOverlayController = [[FLTGroundOverlaysController alloc] + initWithMapView:[GoogleMapsGroundOverlayControllerTests mapView] + eventDelegate:[[TestMapEventHandler alloc] init] + assetProvider:assetProvider]; + } + XCTAssertNotNil(groundOverlayController); + XCTAssertNotNil(weakAssetProvider); +} + /// Returns a simple map view to add map objects to. + (GMSMapView *)mapView { GMSMapViewOptions *mapViewOptions = [[GMSMapViewOptions alloc] init]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m index f91a812642ae..05afc39c1ce1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/example/ios/RunnerTests/GoogleMapsMarkerControllerTests.m @@ -268,6 +268,23 @@ - (void)testUpdateMarkerSetsVisibilityLast { XCTAssertTrue(marker.hasSetMap); } +- (void)testAssetProviderIsRetained { + FLTMarkersController *markerController; + __weak TestAssetProvider *weakAssetProvider; + @autoreleasepool { + TestAssetProvider *assetProvider = [[TestAssetProvider alloc] init]; + weakAssetProvider = assetProvider; + + markerController = + [[FLTMarkersController alloc] initWithMapView:[GoogleMapsMarkerControllerTests mapView] + eventDelegate:[[TestMapEventHandler alloc] init] + clusterManagersController:nil + assetProvider:assetProvider]; + } + XCTAssertNotNil(markerController); + XCTAssertNotNil(weakAssetProvider, @"AssetProvider should be retained by the marker controller"); +} + @end @implementation PropertyOrderValidatingMarker diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMGroundOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMGroundOverlayController.m index f1fe7281dc09..c5e45188510a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMGroundOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/FGMGroundOverlayController.m @@ -89,7 +89,7 @@ @interface FLTGroundOverlaysController () @property(weak, nonatomic) NSObject *eventDelegate; /// Asset provider used to load images. -@property(weak, nonatomic) NSObject *assetProvider; +@property(strong, nonatomic) NSObject *assetProvider; /// The map view used to generate the controllers. @property(weak, nonatomic) GMSMapView *mapView; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapMarkerController.m index 9d061eec8b09..09a05db2840d 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapMarkerController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios_shared_code/ios/google_maps_flutter_ios/Sources/google_maps_flutter_ios/GoogleMapMarkerController.m @@ -113,7 +113,7 @@ @interface FLTMarkersController () @property(weak, nonatomic) NSObject *eventDelegate; /// Controller for adding/removing/fetching cluster managers @property(weak, nonatomic, nullable) FGMClusterManagersController *clusterManagersController; -@property(weak, nonatomic) NSObject *assetProvider; +@property(strong, nonatomic) NSObject *assetProvider; @property(weak, nonatomic) GMSMapView *mapView; @end