diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index b4fb6622edc2..8d78ec38b057 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.1.7 + +* Objective-C code cleanup. + ## 2.1.6 * Fixes issue in Flutter v3.0.0 where some updates to the map don't take effect on Android. diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj index a8d37106bb83..b37246b98a47 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -10,6 +10,8 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 4510D964F3B1259FEDD3ABA6 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7755F8F4BABC3D6A0BD4048B /* libPods-Runner.a */; }; + 6851F3562835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6851F3552835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m */; }; + 68E4726A2836FF0C00BDDDAC /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 68E472692836FF0C00BDDDAC /* MapKit.framework */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -55,6 +57,8 @@ 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 = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 6851F3552835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FLTGoogleMapJSONConversionsConversionTests.m; sourceTree = ""; }; + 68E472692836FF0C00BDDDAC /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.0.sdk/System/iOSSupport/System/Library/Frameworks/MapKit.framework; sourceTree = DEVELOPER_DIR; }; 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 = ""; }; 7755F8F4BABC3D6A0BD4048B /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -95,6 +99,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 68E4726A2836FF0C00BDDDAC /* MapKit.framework in Frameworks */, FC8F35FC8CD533B128950487 /* libPods-RunnerTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -112,6 +117,7 @@ 1E7CF0857EFC88FC263CF3B2 /* Frameworks */ = { isa = PBXGroup; children = ( + 68E472692836FF0C00BDDDAC /* MapKit.framework */, 7755F8F4BABC3D6A0BD4048B /* libPods-Runner.a */, F267F68029D1A4E2E4C572A7 /* libPods-RunnerTests.a */, ); @@ -190,6 +196,7 @@ F7151F11265D7ED70028CB91 /* RunnerTests */ = { isa = PBXGroup; children = ( + 6851F3552835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m */, F7151F12265D7ED70028CB91 /* GoogleMapsTests.m */, 982F2A6A27BADE17003C81F4 /* PartiallyMockedMapView.h */, 982F2A6B27BADE17003C81F4 /* PartiallyMockedMapView.m */, @@ -446,6 +453,7 @@ buildActionMask = 2147483647; files = ( F7151F13265D7ED70028CB91 /* GoogleMapsTests.m in Sources */, + 6851F3562835BC180032B7C8 /* FLTGoogleMapJSONConversionsConversionTests.m in Sources */, 982F2A6C27BADE17003C81F4 /* PartiallyMockedMapView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/ios/RunnerTests/FLTGoogleMapJSONConversionsConversionTests.m b/packages/google_maps_flutter/google_maps_flutter/example/ios/RunnerTests/FLTGoogleMapJSONConversionsConversionTests.m new file mode 100644 index 000000000000..bf226feb2341 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/example/ios/RunnerTests/FLTGoogleMapJSONConversionsConversionTests.m @@ -0,0 +1,290 @@ +// 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 google_maps_flutter; +@import google_maps_flutter.Test; +@import XCTest; +@import MapKit; +@import GoogleMaps; + +#import +#import "PartiallyMockedMapView.h" + +@interface FLTGoogleMapJSONConversionsTests : XCTestCase +@end + +@implementation FLTGoogleMapJSONConversionsTests + +- (void)testLocationFromLatLong { + NSArray *latlong = @[ @1, @2 ]; + CLLocationCoordinate2D location = [FLTGoogleMapJSONConversions locationFromLatLong:latlong]; + XCTAssertEqual(location.latitude, 1); + XCTAssertEqual(location.longitude, 2); +} + +- (void)testPointFromArray { + NSArray *array = @[ @1, @2 ]; + CGPoint point = [FLTGoogleMapJSONConversions pointFromArray:array]; + XCTAssertEqual(point.x, 1); + XCTAssertEqual(point.y, 2); +} + +- (void)testArrayFromLocation { + CLLocationCoordinate2D location = CLLocationCoordinate2DMake(1, 2); + NSArray *array = [FLTGoogleMapJSONConversions arrayFromLocation:location]; + XCTAssertEqual([array[0] integerValue], 1); + XCTAssertEqual([array[1] integerValue], 2); +} + +- (void)testColorFromRGBA { + NSNumber *rgba = @(0x01020304); + UIColor *color = [FLTGoogleMapJSONConversions colorFromRGBA:rgba]; + 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, 2 / 255.0, accuracy); + XCTAssertEqualWithAccuracy(green, 3 / 255.0, accuracy); + XCTAssertEqualWithAccuracy(blue, 4 / 255.0, accuracy); + XCTAssertEqualWithAccuracy(alpha, 1 / 255.0, accuracy); +} + +- (void)testPointsFromLatLongs { + NSArray *latlongs = @[ @[ @1, @2 ], @[ @(3), @(4) ] ]; + NSArray *locations = [FLTGoogleMapJSONConversions pointsFromLatLongs: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 = + @[ @[ @[ @1, @2 ], @[ @(3), @(4) ] ], @[ @[ @(5), @(6) ], @[ @(7), @(8) ] ] ]; + NSArray *> *holes = + [FLTGoogleMapJSONConversions holesFromPointsArray: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)testDictionaryFromPosition { + id mockPosition = OCMClassMock([GMSCameraPosition class]); + NSValue *locationValue = [NSValue valueWithMKCoordinate:CLLocationCoordinate2DMake(1, 2)]; + [(GMSCameraPosition *)[[mockPosition stub] andReturnValue:locationValue] target]; + [[[mockPosition stub] andReturnValue:@(2.0)] zoom]; + [[[mockPosition stub] andReturnValue:@(3.0)] bearing]; + [[[mockPosition stub] andReturnValue:@(75.0)] viewingAngle]; + NSDictionary *dictionary = [FLTGoogleMapJSONConversions dictionaryFromPosition:mockPosition]; + NSArray *targetArray = @[ @1, @2 ]; + XCTAssertEqualObjects(dictionary[@"target"], targetArray); + XCTAssertEqualObjects(dictionary[@"zoom"], @2.0); + XCTAssertEqualObjects(dictionary[@"bearing"], @3.0); + XCTAssertEqualObjects(dictionary[@"tilt"], @75.0); +} + +- (void)testDictionaryFromPoint { + CGPoint point = CGPointMake(10, 20); + NSDictionary *dictionary = [FLTGoogleMapJSONConversions dictionaryFromPoint:point]; + const CGFloat accuracy = 0.0001; + XCTAssertEqualWithAccuracy([dictionary[@"x"] floatValue], point.x, accuracy); + XCTAssertEqualWithAccuracy([dictionary[@"y"] floatValue], point.y, accuracy); +} + +- (void)testDictionaryFromCoordinateBounds { + XCTAssertNil([FLTGoogleMapJSONConversions dictionaryFromCoordinateBounds:nil]); + + GMSCoordinateBounds *bounds = + [[GMSCoordinateBounds alloc] initWithCoordinate:CLLocationCoordinate2DMake(10, 20) + coordinate:CLLocationCoordinate2DMake(30, 40)]; + NSDictionary *dictionary = [FLTGoogleMapJSONConversions dictionaryFromCoordinateBounds:bounds]; + NSArray *southwest = @[ @10, @20 ]; + NSArray *northeast = @[ @30, @40 ]; + XCTAssertEqualObjects(dictionary[@"southwest"], southwest); + XCTAssertEqualObjects(dictionary[@"northeast"], northeast); +} + +- (void)testCameraPostionFromDictionary { + XCTAssertNil([FLTGoogleMapJSONConversions cameraPostionFromDictionary:nil]); + + NSDictionary *channelValue = + @{@"target" : @[ @1, @2 ], @"zoom" : @3, @"bearing" : @4, @"tilt" : @5}; + + GMSCameraPosition *cameraPosition = + [FLTGoogleMapJSONConversions cameraPostionFromDictionary:channelValue]; + + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(cameraPosition.target.latitude, 1, accuracy); + XCTAssertEqualWithAccuracy(cameraPosition.target.longitude, 2, accuracy); + XCTAssertEqualWithAccuracy(cameraPosition.zoom, 3, accuracy); + XCTAssertEqualWithAccuracy(cameraPosition.bearing, 4, accuracy); + XCTAssertEqualWithAccuracy(cameraPosition.viewingAngle, 5, accuracy); +} + +- (void)testPointFromDictionary { + XCTAssertNil([FLTGoogleMapJSONConversions cameraPostionFromDictionary:nil]); + + NSDictionary *dictionary = @{ + @"x" : @1, + @"y" : @2, + }; + + CGPoint point = [FLTGoogleMapJSONConversions pointFromDictionary:dictionary]; + + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(point.x, 1, accuracy); + XCTAssertEqualWithAccuracy(point.y, 2, accuracy); +} + +- (void)testCoordinateBoundsFromLatLongs { + NSArray *latlong1 = @[ @1, @2 ]; + NSArray *latlong2 = @[ @(3), @(4) ]; + + GMSCoordinateBounds *bounds = + [FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:@[ latlong1, latlong2 ]]; + + 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)testMapViewTypeFromTypeValue { + XCTAssertEqual(kGMSTypeNormal, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@1]); + XCTAssertEqual(kGMSTypeSatellite, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@2]); + XCTAssertEqual(kGMSTypeTerrain, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@3]); + XCTAssertEqual(kGMSTypeHybrid, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@4]); + XCTAssertEqual(kGMSTypeNone, [FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:@5]); +} + +- (void)testCameraUpdateFromChannelValueNewCameraPosition { + NSArray *channelValue = @[ + @"newCameraPosition", @{@"target" : @[ @1, @2 ], @"zoom" : @3, @"bearing" : @4, @"tilt" : @5} + ]; + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue]; + [[classMockCameraUpdate expect] + setCamera:[FLTGoogleMapJSONConversions cameraPostionFromDictionary:channelValue[1]]]; + [classMockCameraUpdate stopMocking]; +} + +// TODO(cyanglaz): Fix the test for CameraUpdateFromChannelValue 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_testCameraUpdateFromChannelValueNewLatLong { + NSArray *channelValue = @[ @"newLatLng", @[ @1, @2 ] ]; + + GMSCameraUpdate *update = [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue]; + + GMSMapView *mapView = [[GMSMapView alloc] + initWithFrame:CGRectZero + camera:[GMSCameraPosition cameraWithTarget:CLLocationCoordinate2DMake(5, 6) zoom:1]]; + [mapView moveCamera:update]; + const CGFloat accuracy = 0.001; + XCTAssertEqualWithAccuracy(mapView.camera.target.latitude, 1, + accuracy); // mapView.camera.target.latitude is still 5. + XCTAssertEqualWithAccuracy(mapView.camera.target.longitude, 2, + accuracy); // mapView.camera.target.longitude is still 6. +} + +- (void)testCameraUpdateFromChannelValueNewLatLngBounds { + NSArray *latlong1 = @[ @1, @2 ]; + NSArray *latlong2 = @[ @(3), @(4) ]; + GMSCoordinateBounds *bounds = + [FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:@[ latlong1, latlong2 ]]; + + NSArray *channelValue = @[ @"newLatLngBounds", @[ latlong1, latlong2 ], @20 ]; + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue]; + + [[classMockCameraUpdate expect] fitBounds:bounds withPadding:20]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromChannelValueNewLatLngZoom { + NSArray *channelValue = @[ @"newLatLngZoom", @[ @1, @2 ], @3 ]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue]; + + [[classMockCameraUpdate expect] setTarget:CLLocationCoordinate2DMake(1, 2) zoom:3]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromChannelValueScrollBy { + NSArray *channelValue = @[ @"scrollBy", @1, @2 ]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValue]; + + [[classMockCameraUpdate expect] scrollByX:1 Y:2]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromChannelValueZoomBy { + NSArray *channelValueNoPoint = @[ @"zoomBy", @1 ]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueNoPoint]; + + [[classMockCameraUpdate expect] zoomBy:1]; + + NSArray *channelValueWithPoint = @[ @"zoomBy", @1, @[ @2, @3 ] ]; + + [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueWithPoint]; + + [[classMockCameraUpdate expect] zoomBy:1 atPoint:CGPointMake(2, 3)]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromChannelValueZoomIn { + NSArray *channelValueNoPoint = @[ @"zoomIn" ]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueNoPoint]; + + [[classMockCameraUpdate expect] zoomIn]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromChannelValueZoomOut { + NSArray *channelValueNoPoint = @[ @"zoomOut" ]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueNoPoint]; + + [[classMockCameraUpdate expect] zoomOut]; + [classMockCameraUpdate stopMocking]; +} + +- (void)testCameraUpdateFromChannelValueZoomTo { + NSArray *channelValueNoPoint = @[ @"zoomTo", @1 ]; + + id classMockCameraUpdate = OCMClassMock([GMSCameraUpdate class]); + [FLTGoogleMapJSONConversions cameraUpdateFromChannelValue:channelValueNoPoint]; + + [[classMockCameraUpdate expect] zoomTo:1]; + [classMockCameraUpdate stopMocking]; +} + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapJSONConversions.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapJSONConversions.h new file mode 100644 index 000000000000..cfccb7b0b5f9 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapJSONConversions.h @@ -0,0 +1,30 @@ +// 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 +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FLTGoogleMapJSONConversions : NSObject + ++ (CLLocationCoordinate2D)locationFromLatLong:(NSArray *)latlong; ++ (CGPoint)pointFromArray:(NSArray *)array; ++ (NSArray *)arrayFromLocation:(CLLocationCoordinate2D)location; ++ (UIColor *)colorFromRGBA:(NSNumber *)data; ++ (NSArray *)pointsFromLatLongs:(NSArray *)data; ++ (NSArray *> *)holesFromPointsArray:(NSArray *)data; ++ (nullable NSDictionary *)dictionaryFromPosition: + (nullable GMSCameraPosition *)position; ++ (NSDictionary *)dictionaryFromPoint:(CGPoint)point; ++ (nullable NSDictionary *)dictionaryFromCoordinateBounds:(nullable GMSCoordinateBounds *)bounds; ++ (nullable GMSCameraPosition *)cameraPostionFromDictionary:(nullable NSDictionary *)channelValue; ++ (CGPoint)pointFromDictionary:(NSDictionary *)dictionary; ++ (GMSCoordinateBounds *)coordinateBoundsFromLatLongs:(NSArray *)latlongs; ++ (GMSMapViewType)mapViewTypeFromTypeValue:(NSNumber *)value; ++ (nullable GMSCameraUpdate *)cameraUpdateFromChannelValue:(NSArray *)channelValue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapJSONConversions.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapJSONConversions.m new file mode 100644 index 000000000000..d554c501b1e2 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapJSONConversions.m @@ -0,0 +1,144 @@ +// 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 "FLTGoogleMapJSONConversions.h" + +@implementation FLTGoogleMapJSONConversions + ++ (CLLocationCoordinate2D)locationFromLatLong:(NSArray *)latlong { + return CLLocationCoordinate2DMake([latlong[0] doubleValue], [latlong[1] doubleValue]); +} + ++ (CGPoint)pointFromArray:(NSArray *)array { + return CGPointMake([array[0] doubleValue], [array[1] doubleValue]); +} + ++ (NSArray *)arrayFromLocation:(CLLocationCoordinate2D)location { + return @[ @(location.latitude), @(location.longitude) ]; +} + ++ (UIColor *)colorFromRGBA:(NSNumber *)numberColor { + unsigned long value = [numberColor unsignedLongValue]; + return [UIColor colorWithRed:((float)((value & 0xFF0000) >> 16)) / 255.0 + green:((float)((value & 0xFF00) >> 8)) / 255.0 + blue:((float)(value & 0xFF)) / 255.0 + alpha:((float)((value & 0xFF000000) >> 24)) / 255.0]; +} + ++ (NSArray *)pointsFromLatLongs:(NSArray *)data { + NSMutableArray *points = [[NSMutableArray alloc] init]; + for (unsigned i = 0; i < [data count]; i++) { + NSNumber *latitude = data[i][0]; + NSNumber *longitude = data[i][1]; + CLLocation *point = [[CLLocation alloc] initWithLatitude:[latitude doubleValue] + longitude:[longitude doubleValue]]; + [points addObject:point]; + } + + return points; +} + ++ (NSArray *> *)holesFromPointsArray:(NSArray *)data { + NSMutableArray *> *holes = [[[NSMutableArray alloc] init] init]; + for (unsigned i = 0; i < [data count]; i++) { + NSArray *points = [FLTGoogleMapJSONConversions pointsFromLatLongs:data[i]]; + [holes addObject:points]; + } + + return holes; +} + ++ (nullable NSDictionary *)dictionaryFromPosition:(GMSCameraPosition *)position { + if (!position) { + return nil; + } + return @{ + @"target" : [FLTGoogleMapJSONConversions arrayFromLocation:[position target]], + @"zoom" : @([position zoom]), + @"bearing" : @([position bearing]), + @"tilt" : @([position viewingAngle]), + }; +} + ++ (NSDictionary *)dictionaryFromPoint:(CGPoint)point { + return @{ + @"x" : @(lroundf(point.x)), + @"y" : @(lroundf(point.y)), + }; +} + ++ (nullable NSDictionary *)dictionaryFromCoordinateBounds:(GMSCoordinateBounds *)bounds { + if (!bounds) { + return nil; + } + return @{ + @"southwest" : [FLTGoogleMapJSONConversions arrayFromLocation:[bounds southWest]], + @"northeast" : [FLTGoogleMapJSONConversions arrayFromLocation:[bounds northEast]], + }; +} + ++ (nullable GMSCameraPosition *)cameraPostionFromDictionary:(nullable NSDictionary *)data { + if (!data) { + return nil; + } + return [GMSCameraPosition + cameraWithTarget:[FLTGoogleMapJSONConversions locationFromLatLong:data[@"target"]] + zoom:[data[@"zoom"] floatValue] + bearing:[data[@"bearing"] doubleValue] + viewingAngle:[data[@"tilt"] doubleValue]]; +} + ++ (CGPoint)pointFromDictionary:(NSDictionary *)dictionary { + double x = [dictionary[@"x"] doubleValue]; + double y = [dictionary[@"y"] doubleValue]; + return CGPointMake(x, y); +} + ++ (GMSCoordinateBounds *)coordinateBoundsFromLatLongs:(NSArray *)latlongs { + return [[GMSCoordinateBounds alloc] + initWithCoordinate:[FLTGoogleMapJSONConversions locationFromLatLong:latlongs[0]] + coordinate:[FLTGoogleMapJSONConversions locationFromLatLong:latlongs[1]]]; +} + ++ (GMSMapViewType)mapViewTypeFromTypeValue:(NSNumber *)typeValue { + int value = [typeValue intValue]; + return (GMSMapViewType)(value == 0 ? 5 : value); +} + ++ (nullable GMSCameraUpdate *)cameraUpdateFromChannelValue:(NSArray *)channelValue { + NSString *update = channelValue[0]; + if ([update isEqualToString:@"newCameraPosition"]) { + return [GMSCameraUpdate + setCamera:[FLTGoogleMapJSONConversions cameraPostionFromDictionary:channelValue[1]]]; + } else if ([update isEqualToString:@"newLatLng"]) { + return [GMSCameraUpdate + setTarget:[FLTGoogleMapJSONConversions locationFromLatLong:channelValue[1]]]; + } else if ([update isEqualToString:@"newLatLngBounds"]) { + return [GMSCameraUpdate + fitBounds:[FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:channelValue[1]] + withPadding:[channelValue[2] doubleValue]]; + } else if ([update isEqualToString:@"newLatLngZoom"]) { + return + [GMSCameraUpdate setTarget:[FLTGoogleMapJSONConversions locationFromLatLong:channelValue[1]] + zoom:[channelValue[2] floatValue]]; + } else if ([update isEqualToString:@"scrollBy"]) { + return [GMSCameraUpdate scrollByX:[channelValue[1] doubleValue] + Y:[channelValue[2] doubleValue]]; + } else if ([update isEqualToString:@"zoomBy"]) { + if (channelValue.count == 2) { + return [GMSCameraUpdate zoomBy:[channelValue[1] floatValue]]; + } else { + return [GMSCameraUpdate zoomBy:[channelValue[1] floatValue] + atPoint:[FLTGoogleMapJSONConversions pointFromArray:channelValue[2]]]; + } + } else if ([update isEqualToString:@"zoomIn"]) { + return [GMSCameraUpdate zoomIn]; + } else if ([update isEqualToString:@"zoomOut"]) { + return [GMSCameraUpdate zoomOut]; + } else if ([update isEqualToString:@"zoomTo"]) { + return [GMSCameraUpdate zoomTo:[channelValue[1] floatValue]]; + } + return nil; +} +@end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h index 356a13faba62..5dcc66594f18 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.h @@ -7,25 +7,19 @@ NS_ASSUME_NONNULL_BEGIN -// Defines map UI options writable from Flutter. -@protocol FLTGoogleMapTileOverlayOptionsSink -- (void)setFadeIn:(BOOL)fadeIn; -- (void)setTransparency:(float)transparency; -- (void)setZIndex:(int)zIndex; -- (void)setVisible:(BOOL)visible; -- (void)setTileSize:(NSInteger)tileSize; -@end - -@interface FLTGoogleMapTileOverlayController : NSObject -- (instancetype)initWithTileLayer:(GMSTileLayer *)tileLayer mapView:(GMSMapView *)mapView; +@interface FLTGoogleMapTileOverlayController : NSObject +- (instancetype)initWithTileLayer:(GMSTileLayer *)tileLayer + mapView:(GMSMapView *)mapView + options:(NSDictionary *)optionsData; - (void)removeTileOverlay; - (void)clearTileCache; - (NSDictionary *)getTileOverlayInfo; @end @interface FLTTileProviderController : GMSTileLayer -@property(copy, nonatomic, readonly) NSString *tileOverlayId; -- (instancetype)init:(FlutterMethodChannel *)methodChannel tileOverlayId:(NSString *)tileOverlayId; +@property(copy, nonatomic, readonly) NSString *tileOverlayIdentifier; +- (instancetype)init:(FlutterMethodChannel *)methodChannel + withTileOverlayIdentifier:(NSString *)identifier; @end @interface FLTTileOverlaysController : NSObject @@ -34,9 +28,9 @@ NS_ASSUME_NONNULL_BEGIN registrar:(NSObject *)registrar; - (void)addTileOverlays:(NSArray *)tileOverlaysToAdd; - (void)changeTileOverlays:(NSArray *)tileOverlaysToChange; -- (void)removeTileOverlayIds:(NSArray *)tileOverlayIdsToRemove; -- (void)clearTileCache:(NSString *)tileOverlayId; -- (nullable NSDictionary *)getTileOverlayInfo:(NSString *)tileverlayId; +- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers; +- (void)clearTileCacheWithIdentifier:(NSString *)identifier; +- (nullable NSDictionary *)tileOverlayInfoWithIdentifier:(NSString *)identifier; @end NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m index 6baa753ef999..5863697d7b9b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapTileOverlayController.m @@ -3,36 +3,7 @@ // found in the LICENSE file. #import "FLTGoogleMapTileOverlayController.h" -#import "JsonConversions.h" - -static void InterpretTileOverlayOptions(NSDictionary *data, - id sink, - NSObject *registrar) { - NSNumber *visible = data[@"visible"]; - if (visible != nil) { - [sink setVisible:visible.boolValue]; - } - - NSNumber *transparency = data[@"transparency"]; - if (transparency != nil) { - [sink setTransparency:transparency.floatValue]; - } - - NSNumber *zIndex = data[@"zIndex"]; - if (zIndex != nil) { - [sink setZIndex:zIndex.intValue]; - } - - NSNumber *fadeIn = data[@"fadeIn"]; - if (fadeIn != nil) { - [sink setFadeIn:fadeIn.boolValue]; - } - - NSNumber *tileSize = data[@"tileSize"]; - if (tileSize != nil) { - [sink setTileSize:tileSize.integerValue]; - } -} +#import "FLTGoogleMapJSONConversions.h" @interface FLTGoogleMapTileOverlayController () @@ -43,11 +14,14 @@ @interface FLTGoogleMapTileOverlayController () @implementation FLTGoogleMapTileOverlayController -- (instancetype)initWithTileLayer:(GMSTileLayer *)tileLayer mapView:(GMSMapView *)mapView { +- (instancetype)initWithTileLayer:(GMSTileLayer *)tileLayer + mapView:(GMSMapView *)mapView + options:(NSDictionary *)optionsData { self = [super init]; if (self) { - self.layer = tileLayer; - self.mapView = mapView; + _layer = tileLayer; + _mapView = mapView; + [self interpretTileOverlayOptions:optionsData]; } return self; } @@ -71,8 +45,6 @@ - (NSDictionary *)getTileOverlayInfo { return info; } -#pragma mark - FLTGoogleMapTileOverlayOptionsSink methods - - (void)setFadeIn:(BOOL)fadeIn { self.layer.fadeIn = fadeIn; } @@ -93,22 +65,53 @@ - (void)setZIndex:(int)zIndex { - (void)setTileSize:(NSInteger)tileSize { self.layer.tileSize = tileSize; } + +- (void)interpretTileOverlayOptions:(NSDictionary *)data { + if (!data) { + return; + } + NSNumber *visible = data[@"visible"]; + if (visible != nil && visible != (id)[NSNull null]) { + [self setVisible:visible.boolValue]; + } + + NSNumber *transparency = data[@"transparency"]; + if (transparency != nil && transparency != (id)[NSNull null]) { + [self setTransparency:transparency.floatValue]; + } + + NSNumber *zIndex = data[@"zIndex"]; + if (zIndex != nil && zIndex != (id)[NSNull null]) { + [self setZIndex:zIndex.intValue]; + } + + NSNumber *fadeIn = data[@"fadeIn"]; + if (fadeIn != nil && fadeIn != (id)[NSNull null]) { + [self setFadeIn:fadeIn.boolValue]; + } + + NSNumber *tileSize = data[@"tileSize"]; + if (tileSize != nil && tileSize != (id)[NSNull null]) { + [self setTileSize:tileSize.integerValue]; + } +} + @end @interface FLTTileProviderController () -@property(weak, nonatomic) FlutterMethodChannel *methodChannel; -@property(copy, nonatomic, readwrite) NSString *tileOverlayId; +@property(strong, nonatomic) FlutterMethodChannel *methodChannel; @end @implementation FLTTileProviderController -- (instancetype)init:(FlutterMethodChannel *)methodChannel tileOverlayId:(NSString *)tileOverlayId { +- (instancetype)init:(FlutterMethodChannel *)methodChannel + withTileOverlayIdentifier:(NSString *)identifier { self = [super init]; if (self) { - self.methodChannel = methodChannel; - self.tileOverlayId = tileOverlayId; + _methodChannel = methodChannel; + _tileOverlayIdentifier = identifier; } return self; } @@ -122,7 +125,7 @@ - (void)requestTileForX:(NSUInteger)x [self.methodChannel invokeMethod:@"tileOverlay#getTile" arguments:@{ - @"tileOverlayId" : self.tileOverlayId, + @"tileOverlayId" : self.tileOverlayIdentifier, @"x" : @(x), @"y" : @(y), @"zoom" : @(zoom) @@ -156,9 +159,8 @@ - (void)requestTileForX:(NSUInteger)x @interface FLTTileOverlaysController () -@property(strong, nonatomic) NSMutableDictionary *tileOverlayIdToController; -@property(weak, nonatomic) FlutterMethodChannel *methodChannel; -@property(weak, nonatomic) NSObject *registrar; +@property(strong, nonatomic) NSMutableDictionary *tileOverlayIdentifierToController; +@property(strong, nonatomic) FlutterMethodChannel *methodChannel; @property(weak, nonatomic) GMSMapView *mapView; @end @@ -170,64 +172,67 @@ - (instancetype)init:(FlutterMethodChannel *)methodChannel registrar:(NSObject *)registrar { self = [super init]; if (self) { - self.methodChannel = methodChannel; - self.mapView = mapView; - self.tileOverlayIdToController = [[NSMutableDictionary alloc] init]; - self.registrar = registrar; + _methodChannel = methodChannel; + _mapView = mapView; + _tileOverlayIdentifierToController = [[NSMutableDictionary alloc] init]; } return self; } - (void)addTileOverlays:(NSArray *)tileOverlaysToAdd { for (NSDictionary *tileOverlay in tileOverlaysToAdd) { - NSString *tileOverlayId = [FLTTileOverlaysController getTileOverlayId:tileOverlay]; + NSString *identifier = [FLTTileOverlaysController identifierForTileOverlay:tileOverlay]; FLTTileProviderController *tileProvider = - [[FLTTileProviderController alloc] init:self.methodChannel tileOverlayId:tileOverlayId]; + [[FLTTileProviderController alloc] init:self.methodChannel + withTileOverlayIdentifier:identifier]; FLTGoogleMapTileOverlayController *controller = [[FLTGoogleMapTileOverlayController alloc] initWithTileLayer:tileProvider - mapView:self.mapView]; - InterpretTileOverlayOptions(tileOverlay, controller, self.registrar); - self.tileOverlayIdToController[tileOverlayId] = controller; + mapView:self.mapView + options:tileOverlay]; + self.tileOverlayIdentifierToController[identifier] = controller; } } - (void)changeTileOverlays:(NSArray *)tileOverlaysToChange { for (NSDictionary *tileOverlay in tileOverlaysToChange) { - NSString *tileOverlayId = [FLTTileOverlaysController getTileOverlayId:tileOverlay]; - FLTGoogleMapTileOverlayController *controller = self.tileOverlayIdToController[tileOverlayId]; + NSString *identifier = [FLTTileOverlaysController identifierForTileOverlay:tileOverlay]; + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; if (!controller) { continue; } - InterpretTileOverlayOptions(tileOverlay, controller, self.registrar); + [controller interpretTileOverlayOptions:tileOverlay]; } } -- (void)removeTileOverlayIds:(NSArray *)tileOverlayIdsToRemove { - for (NSString *tileOverlayId in tileOverlayIdsToRemove) { - FLTGoogleMapTileOverlayController *controller = self.tileOverlayIdToController[tileOverlayId]; +- (void)removeTileOverlayWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; if (!controller) { continue; } [controller removeTileOverlay]; - [self.tileOverlayIdToController removeObjectForKey:tileOverlayId]; + [self.tileOverlayIdentifierToController removeObjectForKey:identifier]; } } -- (void)clearTileCache:(NSString *)tileOverlayId { - FLTGoogleMapTileOverlayController *controller = self.tileOverlayIdToController[tileOverlayId]; +- (void)clearTileCacheWithIdentifier:(NSString *)identifier { + FLTGoogleMapTileOverlayController *controller = + self.tileOverlayIdentifierToController[identifier]; if (!controller) { return; } [controller clearTileCache]; } -- (nullable NSDictionary *)getTileOverlayInfo:(NSString *)tileverlayId { - if (self.tileOverlayIdToController[tileverlayId] == nil) { +- (nullable NSDictionary *)tileOverlayInfoWithIdentifier:(NSString *)identifier { + if (self.tileOverlayIdentifierToController[identifier] == nil) { return nil; } - return [self.tileOverlayIdToController[tileverlayId] getTileOverlayInfo]; + return [self.tileOverlayIdentifierToController[identifier] getTileOverlayInfo]; } -+ (NSString *)getTileOverlayId:(NSDictionary *)tileOverlay { ++ (NSString *)identifierForTileOverlay:(NSDictionary *)tileOverlay { return tileOverlay[@"tileOverlayId"]; } diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h index 953c0557ff20..26f69eaf3882 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.h @@ -10,5 +10,9 @@ #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/Classes/FLTGoogleMapsPlugin.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m index e78a505ecfb0..d62f19ced4f3 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/FLTGoogleMapsPlugin.m @@ -6,11 +6,7 @@ #pragma mark - GoogleMaps plugin implementation -@implementation FLTGoogleMapsPlugin { - NSObject *_registrar; - FlutterMethodChannel *_channel; - NSMutableDictionary *_mapControllers; -} +@implementation FLTGoogleMapsPlugin + (void)registerWithRegistrar:(NSObject *)registrar { FLTGoogleMapFactory *googleMapFactory = [[FLTGoogleMapFactory alloc] initWithRegistrar:registrar]; @@ -20,12 +16,4 @@ + (void)registerWithRegistrar:(NSObject *)registrar { FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded]; } -- (FLTGoogleMapController *)mapFromCall:(FlutterMethodCall *)call error:(FlutterError **)error { - id mapId = call.arguments[@"map"]; - FLTGoogleMapController *controller = _mapControllers[mapId]; - if (!controller && error) { - *error = [FlutterError errorWithCode:@"unknown_map" message:nil details:mapId]; - } - return controller; -} @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h index 26b7ce573bdf..6b67760fdaff 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.h @@ -5,25 +5,13 @@ #import #import -// Defines circle UI options writable from Flutter. -@protocol FLTGoogleMapCircleOptionsSink -- (void)setConsumeTapEvents:(BOOL)consume; -- (void)setVisible:(BOOL)visible; -- (void)setStrokeColor:(UIColor *)color; -- (void)setStrokeWidth:(CGFloat)width; -- (void)setFillColor:(UIColor *)color; -- (void)setCenter:(CLLocationCoordinate2D)center; -- (void)setRadius:(CLLocationDistance)radius; -- (void)setZIndex:(int)zIndex; -@end - // Defines circle controllable by Flutter. -@interface FLTGoogleMapCircleController : NSObject -@property(atomic, readonly) NSString *circleId; +@interface FLTGoogleMapCircleController : NSObject - (instancetype)initCircleWithPosition:(CLLocationCoordinate2D)position radius:(CLLocationDistance)radius - circleId:(NSString *)circleId - mapView:(GMSMapView *)mapView; + circleId:(NSString *)circleIdentifier + mapView:(GMSMapView *)mapView + options:(NSDictionary *)options; - (void)removeCircle; @end @@ -33,7 +21,7 @@ registrar:(NSObject *)registrar; - (void)addCircles:(NSArray *)circlesToAdd; - (void)changeCircles:(NSArray *)circlesToChange; -- (void)removeCircleIds:(NSArray *)circleIdsToRemove; -- (void)onCircleTap:(NSString *)circleId; -- (bool)hasCircleWithId:(NSString *)circleId; +- (void)removeCircleWithIdentifiers:(NSArray *)identifiers; +- (void)didTapCircleWithIdentifier:(NSString *)identifier; +- (bool)hasCircleWithIdentifier:(NSString *)identifier; @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m index d97de587fb17..53bf69075c95 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapCircleController.m @@ -3,122 +3,116 @@ // found in the LICENSE file. #import "GoogleMapCircleController.h" -#import "JsonConversions.h" +#import "FLTGoogleMapJSONConversions.h" + +@interface FLTGoogleMapCircleController () + +@property(nonatomic, strong) GMSCircle *circle; +@property(nonatomic, weak) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapCircleController -@implementation FLTGoogleMapCircleController { - GMSCircle *_circle; - GMSMapView *_mapView; -} - (instancetype)initCircleWithPosition:(CLLocationCoordinate2D)position radius:(CLLocationDistance)radius - circleId:(NSString *)circleId - mapView:(GMSMapView *)mapView { + circleId:(NSString *)circleIdentifier + mapView:(GMSMapView *)mapView + options:(NSDictionary *)options { self = [super init]; if (self) { _circle = [GMSCircle circleWithPosition:position radius:radius]; _mapView = mapView; - _circleId = circleId; - _circle.userData = @[ circleId ]; + _circle.userData = @[ circleIdentifier ]; + [self interpretCircleOptions:options]; } return self; } - (void)removeCircle { - _circle.map = nil; + self.circle.map = nil; } -#pragma mark - FLTGoogleMapCircleOptionsSink methods - - (void)setConsumeTapEvents:(BOOL)consumes { - _circle.tappable = consumes; + self.circle.tappable = consumes; } - (void)setVisible:(BOOL)visible { - _circle.map = visible ? _mapView : nil; + self.circle.map = visible ? self.mapView : nil; } - (void)setZIndex:(int)zIndex { - _circle.zIndex = zIndex; + self.circle.zIndex = zIndex; } - (void)setCenter:(CLLocationCoordinate2D)center { - _circle.position = center; + self.circle.position = center; } - (void)setRadius:(CLLocationDistance)radius { - _circle.radius = radius; + self.circle.radius = radius; } - (void)setStrokeColor:(UIColor *)color { - _circle.strokeColor = color; + self.circle.strokeColor = color; } - (void)setStrokeWidth:(CGFloat)width { - _circle.strokeWidth = width; + self.circle.strokeWidth = width; } - (void)setFillColor:(UIColor *)color { - _circle.fillColor = color; + self.circle.fillColor = color; } -@end - -static int ToInt(NSNumber *data) { return [FLTGoogleMapJsonConversions toInt:data]; } -static BOOL ToBool(NSNumber *data) { return [FLTGoogleMapJsonConversions toBool:data]; } - -static CLLocationCoordinate2D ToLocation(NSArray *data) { - return [FLTGoogleMapJsonConversions toLocation:data]; -} - -static CLLocationDistance ToDistance(NSNumber *data) { - return [FLTGoogleMapJsonConversions toFloat:data]; -} - -static UIColor *ToColor(NSNumber *data) { return [FLTGoogleMapJsonConversions toColor:data]; } - -static void InterpretCircleOptions(NSDictionary *data, id sink, - NSObject *registrar) { +- (void)interpretCircleOptions:(NSDictionary *)data { NSNumber *consumeTapEvents = data[@"consumeTapEvents"]; - if (consumeTapEvents != nil) { - [sink setConsumeTapEvents:ToBool(consumeTapEvents)]; + if (consumeTapEvents && consumeTapEvents != (id)[NSNull null]) { + [self setConsumeTapEvents:consumeTapEvents.boolValue]; } NSNumber *visible = data[@"visible"]; - if (visible != nil) { - [sink setVisible:ToBool(visible)]; + if (visible && visible != (id)[NSNull null]) { + [self setVisible:[visible boolValue]]; } NSNumber *zIndex = data[@"zIndex"]; - if (zIndex != nil) { - [sink setZIndex:ToInt(zIndex)]; + if (zIndex && zIndex != (id)[NSNull null]) { + [self setZIndex:[zIndex intValue]]; } NSArray *center = data[@"center"]; - if (center) { - [sink setCenter:ToLocation(center)]; + if (center && center != (id)[NSNull null]) { + [self setCenter:[FLTGoogleMapJSONConversions locationFromLatLong:center]]; } NSNumber *radius = data[@"radius"]; - if (radius != nil) { - [sink setRadius:ToDistance(radius)]; + if (radius && radius != (id)[NSNull null]) { + [self setRadius:[radius floatValue]]; } NSNumber *strokeColor = data[@"strokeColor"]; - if (strokeColor != nil) { - [sink setStrokeColor:ToColor(strokeColor)]; + if (strokeColor && strokeColor != (id)[NSNull null]) { + [self setStrokeColor:[FLTGoogleMapJSONConversions colorFromRGBA:strokeColor]]; } NSNumber *strokeWidth = data[@"strokeWidth"]; - if (strokeWidth != nil) { - [sink setStrokeWidth:ToInt(strokeWidth)]; + if (strokeWidth && strokeWidth != (id)[NSNull null]) { + [self setStrokeWidth:[strokeWidth intValue]]; } NSNumber *fillColor = data[@"fillColor"]; - if (fillColor != nil) { - [sink setFillColor:ToColor(fillColor)]; + if (fillColor && fillColor != (id)[NSNull null]) { + [self setFillColor:[FLTGoogleMapJSONConversions colorFromRGBA:fillColor]]; } } -@implementation FLTCirclesController { - NSMutableDictionary *_circleIdToController; - FlutterMethodChannel *_methodChannel; - NSObject *_registrar; - GMSMapView *_mapView; -} +@end + +@interface FLTCirclesController () + +@property(strong, nonatomic) FlutterMethodChannel *methodChannel; +@property(weak, nonatomic) GMSMapView *mapView; +@property(strong, nonatomic) NSMutableDictionary *circleIdToController; + +@end + +@implementation FLTCirclesController + - (instancetype)init:(FlutterMethodChannel *)methodChannel mapView:(GMSMapView *)mapView registrar:(NSObject *)registrar { @@ -127,10 +121,10 @@ - (instancetype)init:(FlutterMethodChannel *)methodChannel _methodChannel = methodChannel; _mapView = mapView; _circleIdToController = [NSMutableDictionary dictionaryWithCapacity:1]; - _registrar = registrar; } return self; } + - (void)addCircles:(NSArray *)circlesToAdd { for (NSDictionary *circle in circlesToAdd) { CLLocationCoordinate2D position = [FLTCirclesController getPosition:circle]; @@ -140,59 +134,64 @@ - (void)addCircles:(NSArray *)circlesToAdd { [[FLTGoogleMapCircleController alloc] initCircleWithPosition:position radius:radius circleId:circleId - mapView:_mapView]; - InterpretCircleOptions(circle, controller, _registrar); - _circleIdToController[circleId] = controller; + mapView:self.mapView + options:circle]; + self.circleIdToController[circleId] = controller; } } + - (void)changeCircles:(NSArray *)circlesToChange { for (NSDictionary *circle in circlesToChange) { NSString *circleId = [FLTCirclesController getCircleId:circle]; - FLTGoogleMapCircleController *controller = _circleIdToController[circleId]; + FLTGoogleMapCircleController *controller = self.circleIdToController[circleId]; if (!controller) { continue; } - InterpretCircleOptions(circle, controller, _registrar); + [controller interpretCircleOptions:circle]; } } -- (void)removeCircleIds:(NSArray *)circleIdsToRemove { - for (NSString *circleId in circleIdsToRemove) { - if (!circleId) { - continue; - } - FLTGoogleMapCircleController *controller = _circleIdToController[circleId]; + +- (void)removeCircleWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapCircleController *controller = self.circleIdToController[identifier]; if (!controller) { continue; } [controller removeCircle]; - [_circleIdToController removeObjectForKey:circleId]; + [self.circleIdToController removeObjectForKey:identifier]; } } -- (bool)hasCircleWithId:(NSString *)circleId { - if (!circleId) { + +- (bool)hasCircleWithIdentifier:(NSString *)identifier { + if (!identifier) { return false; } - return _circleIdToController[circleId] != nil; + return self.circleIdToController[identifier] != nil; } -- (void)onCircleTap:(NSString *)circleId { - if (!circleId) { + +- (void)didTapCircleWithIdentifier:(NSString *)identifier { + if (!identifier) { return; } - FLTGoogleMapCircleController *controller = _circleIdToController[circleId]; + FLTGoogleMapCircleController *controller = self.circleIdToController[identifier]; if (!controller) { return; } - [_methodChannel invokeMethod:@"circle#onTap" arguments:@{@"circleId" : circleId}]; + [self.methodChannel invokeMethod:@"circle#onTap" arguments:@{@"circleId" : identifier}]; } + + (CLLocationCoordinate2D)getPosition:(NSDictionary *)circle { NSArray *center = circle[@"center"]; - return ToLocation(center); + return [FLTGoogleMapJSONConversions locationFromLatLong:center]; } + + (CLLocationDistance)getRadius:(NSDictionary *)circle { NSNumber *radius = circle[@"radius"]; - return ToDistance(radius); + return [radius floatValue]; } + + (NSString *)getCircleId:(NSDictionary *)circle { return circle[@"circleId"]; } + @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h index a8cebb983347..d1069ac16b39 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h @@ -11,34 +11,13 @@ NS_ASSUME_NONNULL_BEGIN -// Defines map UI options writable from Flutter. -@protocol FLTGoogleMapOptionsSink -- (void)setCameraTargetBounds:(nullable GMSCoordinateBounds *)bounds; -- (void)setCompassEnabled:(BOOL)enabled; -- (void)setIndoorEnabled:(BOOL)enabled; -- (void)setTrafficEnabled:(BOOL)enabled; -- (void)setBuildingsEnabled:(BOOL)enabled; -- (void)setMapType:(GMSMapViewType)type; -- (void)setMinZoom:(float)minZoom maxZoom:(float)maxZoom; -- (void)setPaddingTop:(float)top left:(float)left bottom:(float)bottom right:(float)right; -- (void)setRotateGesturesEnabled:(BOOL)enabled; -- (void)setScrollGesturesEnabled:(BOOL)enabled; -- (void)setTiltGesturesEnabled:(BOOL)enabled; -- (void)setTrackCameraPosition:(BOOL)enabled; -- (void)setZoomGesturesEnabled:(BOOL)enabled; -- (void)setMyLocationEnabled:(BOOL)enabled; -- (void)setMyLocationButtonEnabled:(BOOL)enabled; -- (nullable NSString *)setMapStyle:(NSString *)mapStyle; -@end - // Defines map overlay controllable from Flutter. -@interface FLTGoogleMapController - : NSObject +@interface FLTGoogleMapController : NSObject - (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(nullable id)args registrar:(NSObject *)registrar; -- (void)showAtX:(CGFloat)x Y:(CGFloat)y; +- (void)showAtOrigin:(CGPoint)origin; - (void)hide; - (void)animateWithCameraUpdate:(GMSCameraUpdate *)cameraUpdate; - (void)moveWithCameraUpdate:(GMSCameraUpdate *)cameraUpdate; diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m index ca8068129566..6378994819dd 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m @@ -3,25 +3,18 @@ // found in the LICENSE file. #import "GoogleMapController.h" +#import "FLTGoogleMapJSONConversions.h" #import "FLTGoogleMapTileOverlayController.h" -#import "JsonConversions.h" #pragma mark - Conversion of JSON-like values sent via platform channels. Forward declarations. -static NSDictionary *PositionToJson(GMSCameraPosition *position); -static NSDictionary *PointToJson(CGPoint point); -static NSArray *LocationToJson(CLLocationCoordinate2D position); -static CGPoint ToCGPoint(NSDictionary *json); -static GMSCameraPosition *ToOptionalCameraPosition(NSDictionary *json); -static GMSCoordinateBounds *ToOptionalBounds(NSArray *json); -static GMSCameraUpdate *ToCameraUpdate(NSArray *data); -static NSDictionary *GMSCoordinateBoundsToJson(GMSCoordinateBounds *bounds); -static void InterpretMapOptions(NSDictionary *data, id sink); -static double ToDouble(NSNumber *data) { return [FLTGoogleMapJsonConversions toDouble:data]; } +@interface FLTGoogleMapFactory () -@implementation FLTGoogleMapFactory { - NSObject *_registrar; -} +@property(weak, nonatomic) NSObject *registrar; + +@end + +@implementation FLTGoogleMapFactory - (instancetype)initWithRegistrar:(NSObject *)registrar { self = [super init]; @@ -41,28 +34,32 @@ - (instancetype)initWithRegistrar:(NSObject *)registrar return [[FLTGoogleMapController alloc] initWithFrame:frame viewIdentifier:viewId arguments:args - registrar:_registrar]; + registrar:self.registrar]; } @end -@implementation FLTGoogleMapController { - GMSMapView *_mapView; - int64_t _viewId; - FlutterMethodChannel *_channel; - BOOL _trackCameraPosition; - NSObject *_registrar; - FLTMarkersController *_markersController; - FLTPolygonsController *_polygonsController; - FLTPolylinesController *_polylinesController; - FLTCirclesController *_circlesController; - FLTTileOverlaysController *_tileOverlaysController; -} +@interface FLTGoogleMapController () + +@property(nonatomic, strong) GMSMapView *mapView; +@property(nonatomic, strong) FlutterMethodChannel *channel; +@property(nonatomic, assign) BOOL trackCameraPosition; +@property(nonatomic, weak) NSObject *registrar; +@property(nonatomic, strong) FLTMarkersController *markersController; +@property(nonatomic, strong) FLTPolygonsController *polygonsController; +@property(nonatomic, strong) FLTPolylinesController *polylinesController; +@property(nonatomic, strong) FLTCirclesController *circlesController; +@property(nonatomic, strong) FLTTileOverlaysController *tileOverlaysController; + +@end + +@implementation FLTGoogleMapController - (instancetype)initWithFrame:(CGRect)frame viewIdentifier:(int64_t)viewId arguments:(id _Nullable)args registrar:(NSObject *)registrar { - GMSCameraPosition *camera = ToOptionalCameraPosition(args[@"initialCameraPosition"]); + GMSCameraPosition *camera = + [FLTGoogleMapJSONConversions cameraPostionFromDictionary:args[@"initialCameraPosition"]]; GMSMapView *mapView = [GMSMapView mapWithFrame:frame camera:camera]; return [self initWithMapView:mapView viewIdentifier:viewId arguments:args registrar:registrar]; } @@ -73,11 +70,11 @@ - (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView registrar:(NSObject *_Nonnull)registrar { if (self = [super init]) { _mapView = mapView; - _viewId = viewId; _mapView.accessibilityElementsHidden = NO; - _trackCameraPosition = NO; - InterpretMapOptions(args[@"options"], self); + // TODO(cyanglaz): avoid sending message to self in the middle of the init method. + // https://github.com/flutter/flutter/issues/104121 + [self interpretMapOptions:args[@"options"]]; NSString *channelName = [NSString stringWithFormat:@"plugins.flutter.io/google_maps_%lld", viewId]; _channel = [FlutterMethodChannel methodChannelWithName:channelName @@ -90,9 +87,9 @@ - (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView }]; _mapView.delegate = weakSelf; _registrar = registrar; - _markersController = [[FLTMarkersController alloc] init:_channel - mapView:_mapView - registrar:registrar]; + _markersController = [[FLTMarkersController alloc] initWithMethodChannel:_channel + mapView:_mapView + registrar:registrar]; _polygonsController = [[FLTPolygonsController alloc] init:_channel mapView:_mapView registrar:registrar]; @@ -132,25 +129,25 @@ - (instancetype)initWithMapView:(GMSMapView *_Nonnull)mapView } - (UIView *)view { - return _mapView; + return self.mapView; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if (object == _mapView && [keyPath isEqualToString:@"frame"]) { - CGRect bounds = _mapView.bounds; + 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 `_mapView`, ignore the frame changes when the size is - // zero. + // 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. - [_mapView removeObserver:self forKeyPath:@"frame"]; - [_mapView moveCamera:[GMSCameraUpdate setCamera:_mapView.camera]]; + [self.mapView removeObserver:self forKeyPath:@"frame"]; + [self.mapView moveCamera:[GMSCameraUpdate setCamera:self.mapView.camera]]; } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } @@ -158,46 +155,50 @@ - (void)observeValueForKeyPath:(NSString *)keyPath - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { if ([call.method isEqualToString:@"map#show"]) { - [self showAtX:ToDouble(call.arguments[@"x"]) Y:ToDouble(call.arguments[@"y"])]; + [self showAtOrigin:CGPointMake([call.arguments[@"x"] doubleValue], + [call.arguments[@"y"] doubleValue])]; result(nil); } else if ([call.method isEqualToString:@"map#hide"]) { [self hide]; result(nil); } else if ([call.method isEqualToString:@"camera#animate"]) { - [self animateWithCameraUpdate:ToCameraUpdate(call.arguments[@"cameraUpdate"])]; + [self + animateWithCameraUpdate:[FLTGoogleMapJSONConversions + cameraUpdateFromChannelValue:call.arguments[@"cameraUpdate"]]]; result(nil); } else if ([call.method isEqualToString:@"camera#move"]) { - [self moveWithCameraUpdate:ToCameraUpdate(call.arguments[@"cameraUpdate"])]; + [self moveWithCameraUpdate:[FLTGoogleMapJSONConversions + cameraUpdateFromChannelValue:call.arguments[@"cameraUpdate"]]]; result(nil); } else if ([call.method isEqualToString:@"map#update"]) { - InterpretMapOptions(call.arguments[@"options"], self); - result(PositionToJson([self cameraPosition])); + [self interpretMapOptions:call.arguments[@"options"]]; + result([FLTGoogleMapJSONConversions dictionaryFromPosition:[self cameraPosition]]); } else if ([call.method isEqualToString:@"map#getVisibleRegion"]) { - if (_mapView != nil) { - GMSVisibleRegion visibleRegion = _mapView.projection.visibleRegion; + if (self.mapView != nil) { + GMSVisibleRegion visibleRegion = self.mapView.projection.visibleRegion; GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithRegion:visibleRegion]; - - result(GMSCoordinateBoundsToJson(bounds)); + result([FLTGoogleMapJSONConversions dictionaryFromCoordinateBounds:bounds]); } else { result([FlutterError errorWithCode:@"GoogleMap uninitialized" message:@"getVisibleRegion called prior to map initialization" details:nil]); } } else if ([call.method isEqualToString:@"map#getScreenCoordinate"]) { - if (_mapView != nil) { - CLLocationCoordinate2D location = [FLTGoogleMapJsonConversions toLocation:call.arguments]; - CGPoint point = [_mapView.projection pointForCoordinate:location]; - result(PointToJson(point)); + if (self.mapView != nil) { + CLLocationCoordinate2D location = + [FLTGoogleMapJSONConversions locationFromLatLong:call.arguments]; + CGPoint point = [self.mapView.projection pointForCoordinate:location]; + result([FLTGoogleMapJSONConversions dictionaryFromPoint:point]); } else { result([FlutterError errorWithCode:@"GoogleMap uninitialized" message:@"getScreenCoordinate called prior to map initialization" details:nil]); } } else if ([call.method isEqualToString:@"map#getLatLng"]) { - if (_mapView != nil && call.arguments) { - CGPoint point = ToCGPoint(call.arguments); - CLLocationCoordinate2D latlng = [_mapView.projection coordinateForPoint:point]; - result(LocationToJson(latlng)); + if (self.mapView != nil && call.arguments) { + CGPoint point = [FLTGoogleMapJSONConversions pointFromDictionary:call.arguments]; + CLLocationCoordinate2D latlng = [self.mapView.projection coordinateForPoint:point]; + result([FLTGoogleMapJSONConversions arrayFromLocation:latlng]); } else { result([FlutterError errorWithCode:@"GoogleMap uninitialized" message:@"getLatLng called prior to map initialization" @@ -207,14 +208,14 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { result(nil); } else if ([call.method isEqualToString:@"map#takeSnapshot"]) { if (@available(iOS 10.0, *)) { - if (_mapView != nil) { + if (self.mapView != nil) { UIGraphicsImageRendererFormat *format = [UIGraphicsImageRendererFormat defaultFormat]; format.scale = [[UIScreen mainScreen] scale]; UIGraphicsImageRenderer *renderer = - [[UIGraphicsImageRenderer alloc] initWithSize:_mapView.frame.size format:format]; + [[UIGraphicsImageRenderer alloc] initWithSize:self.mapView.frame.size format:format]; UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *context) { - [_mapView.layer renderInContext:context.CGContext]; + [self.mapView.layer renderInContext:context.CGContext]; }]; result([FlutterStandardTypedData typedDataWithBytes:UIImagePNGRepresentation(image)]); } else { @@ -229,21 +230,21 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { } else if ([call.method isEqualToString:@"markers#update"]) { id markersToAdd = call.arguments[@"markersToAdd"]; if ([markersToAdd isKindOfClass:[NSArray class]]) { - [_markersController addMarkers:markersToAdd]; + [self.markersController addMarkers:markersToAdd]; } id markersToChange = call.arguments[@"markersToChange"]; if ([markersToChange isKindOfClass:[NSArray class]]) { - [_markersController changeMarkers:markersToChange]; + [self.markersController changeMarkers:markersToChange]; } id markerIdsToRemove = call.arguments[@"markerIdsToRemove"]; if ([markerIdsToRemove isKindOfClass:[NSArray class]]) { - [_markersController removeMarkerIds:markerIdsToRemove]; + [self.markersController removeMarkersWithIdentifiers:markerIdsToRemove]; } result(nil); } else if ([call.method isEqualToString:@"markers#showInfoWindow"]) { id markerId = call.arguments[@"markerId"]; if ([markerId isKindOfClass:[NSString class]]) { - [_markersController showMarkerInfoWindow:markerId result:result]; + [self.markersController showMarkerInfoWindowWithIdentifier:markerId result:result]; } else { result([FlutterError errorWithCode:@"Invalid markerId" message:@"showInfoWindow called with invalid markerId" @@ -252,7 +253,7 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { } else if ([call.method isEqualToString:@"markers#hideInfoWindow"]) { id markerId = call.arguments[@"markerId"]; if ([markerId isKindOfClass:[NSString class]]) { - [_markersController hideMarkerInfoWindow:markerId result:result]; + [self.markersController hideMarkerInfoWindowWithIdentifier:markerId result:result]; } else { result([FlutterError errorWithCode:@"Invalid markerId" message:@"hideInfoWindow called with invalid markerId" @@ -261,7 +262,7 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { } else if ([call.method isEqualToString:@"markers#isInfoWindowShown"]) { id markerId = call.arguments[@"markerId"]; if ([markerId isKindOfClass:[NSString class]]) { - [_markersController isMarkerInfoWindowShown:markerId result:result]; + [self.markersController isInfoWindowShownForMarkerWithIdentifier:markerId result:result]; } else { result([FlutterError errorWithCode:@"Invalid markerId" message:@"isInfoWindowShown called with invalid markerId" @@ -270,97 +271,97 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { } else if ([call.method isEqualToString:@"polygons#update"]) { id polygonsToAdd = call.arguments[@"polygonsToAdd"]; if ([polygonsToAdd isKindOfClass:[NSArray class]]) { - [_polygonsController addPolygons:polygonsToAdd]; + [self.polygonsController addPolygons:polygonsToAdd]; } id polygonsToChange = call.arguments[@"polygonsToChange"]; if ([polygonsToChange isKindOfClass:[NSArray class]]) { - [_polygonsController changePolygons:polygonsToChange]; + [self.polygonsController changePolygons:polygonsToChange]; } id polygonIdsToRemove = call.arguments[@"polygonIdsToRemove"]; if ([polygonIdsToRemove isKindOfClass:[NSArray class]]) { - [_polygonsController removePolygonIds:polygonIdsToRemove]; + [self.polygonsController removePolygonWithIdentifiers:polygonIdsToRemove]; } result(nil); } else if ([call.method isEqualToString:@"polylines#update"]) { id polylinesToAdd = call.arguments[@"polylinesToAdd"]; if ([polylinesToAdd isKindOfClass:[NSArray class]]) { - [_polylinesController addPolylines:polylinesToAdd]; + [self.polylinesController addPolylines:polylinesToAdd]; } id polylinesToChange = call.arguments[@"polylinesToChange"]; if ([polylinesToChange isKindOfClass:[NSArray class]]) { - [_polylinesController changePolylines:polylinesToChange]; + [self.polylinesController changePolylines:polylinesToChange]; } id polylineIdsToRemove = call.arguments[@"polylineIdsToRemove"]; if ([polylineIdsToRemove isKindOfClass:[NSArray class]]) { - [_polylinesController removePolylineIds:polylineIdsToRemove]; + [self.polylinesController removePolylineWithIdentifiers:polylineIdsToRemove]; } result(nil); } else if ([call.method isEqualToString:@"circles#update"]) { id circlesToAdd = call.arguments[@"circlesToAdd"]; if ([circlesToAdd isKindOfClass:[NSArray class]]) { - [_circlesController addCircles:circlesToAdd]; + [self.circlesController addCircles:circlesToAdd]; } id circlesToChange = call.arguments[@"circlesToChange"]; if ([circlesToChange isKindOfClass:[NSArray class]]) { - [_circlesController changeCircles:circlesToChange]; + [self.circlesController changeCircles:circlesToChange]; } id circleIdsToRemove = call.arguments[@"circleIdsToRemove"]; if ([circleIdsToRemove isKindOfClass:[NSArray class]]) { - [_circlesController removeCircleIds:circleIdsToRemove]; + [self.circlesController removeCircleWithIdentifiers:circleIdsToRemove]; } result(nil); } else if ([call.method isEqualToString:@"tileOverlays#update"]) { id tileOverlaysToAdd = call.arguments[@"tileOverlaysToAdd"]; if ([tileOverlaysToAdd isKindOfClass:[NSArray class]]) { - [_tileOverlaysController addTileOverlays:tileOverlaysToAdd]; + [self.tileOverlaysController addTileOverlays:tileOverlaysToAdd]; } id tileOverlaysToChange = call.arguments[@"tileOverlaysToChange"]; if ([tileOverlaysToChange isKindOfClass:[NSArray class]]) { - [_tileOverlaysController changeTileOverlays:tileOverlaysToChange]; + [self.tileOverlaysController changeTileOverlays:tileOverlaysToChange]; } id tileOverlayIdsToRemove = call.arguments[@"tileOverlayIdsToRemove"]; if ([tileOverlayIdsToRemove isKindOfClass:[NSArray class]]) { - [_tileOverlaysController removeTileOverlayIds:tileOverlayIdsToRemove]; + [self.tileOverlaysController removeTileOverlayWithIdentifiers:tileOverlayIdsToRemove]; } result(nil); } else if ([call.method isEqualToString:@"tileOverlays#clearTileCache"]) { id rawTileOverlayId = call.arguments[@"tileOverlayId"]; - [_tileOverlaysController clearTileCache:rawTileOverlayId]; + [self.tileOverlaysController clearTileCacheWithIdentifier:rawTileOverlayId]; result(nil); } else if ([call.method isEqualToString:@"map#isCompassEnabled"]) { - NSNumber *isCompassEnabled = @(_mapView.settings.compassButton); + NSNumber *isCompassEnabled = @(self.mapView.settings.compassButton); result(isCompassEnabled); } else if ([call.method isEqualToString:@"map#isMapToolbarEnabled"]) { NSNumber *isMapToolbarEnabled = @NO; result(isMapToolbarEnabled); } else if ([call.method isEqualToString:@"map#getMinMaxZoomLevels"]) { - NSArray *zoomLevels = @[ @(_mapView.minZoom), @(_mapView.maxZoom) ]; + NSArray *zoomLevels = @[ @(self.mapView.minZoom), @(self.mapView.maxZoom) ]; result(zoomLevels); } else if ([call.method isEqualToString:@"map#getZoomLevel"]) { - result(@(_mapView.camera.zoom)); + result(@(self.mapView.camera.zoom)); } else if ([call.method isEqualToString:@"map#isZoomGesturesEnabled"]) { - NSNumber *isZoomGesturesEnabled = @(_mapView.settings.zoomGestures); + NSNumber *isZoomGesturesEnabled = @(self.mapView.settings.zoomGestures); result(isZoomGesturesEnabled); } else if ([call.method isEqualToString:@"map#isZoomControlsEnabled"]) { NSNumber *isZoomControlsEnabled = @NO; result(isZoomControlsEnabled); } else if ([call.method isEqualToString:@"map#isTiltGesturesEnabled"]) { - NSNumber *isTiltGesturesEnabled = @(_mapView.settings.tiltGestures); + NSNumber *isTiltGesturesEnabled = @(self.mapView.settings.tiltGestures); result(isTiltGesturesEnabled); } else if ([call.method isEqualToString:@"map#isRotateGesturesEnabled"]) { - NSNumber *isRotateGesturesEnabled = @(_mapView.settings.rotateGestures); + NSNumber *isRotateGesturesEnabled = @(self.mapView.settings.rotateGestures); result(isRotateGesturesEnabled); } else if ([call.method isEqualToString:@"map#isScrollGesturesEnabled"]) { - NSNumber *isScrollGesturesEnabled = @(_mapView.settings.scrollGestures); + NSNumber *isScrollGesturesEnabled = @(self.mapView.settings.scrollGestures); result(isScrollGesturesEnabled); } else if ([call.method isEqualToString:@"map#isMyLocationButtonEnabled"]) { - NSNumber *isMyLocationButtonEnabled = @(_mapView.settings.myLocationButton); + NSNumber *isMyLocationButtonEnabled = @(self.mapView.settings.myLocationButton); result(isMyLocationButtonEnabled); } else if ([call.method isEqualToString:@"map#isTrafficEnabled"]) { - NSNumber *isTrafficEnabled = @(_mapView.trafficEnabled); + NSNumber *isTrafficEnabled = @(self.mapView.trafficEnabled); result(isTrafficEnabled); } else if ([call.method isEqualToString:@"map#isBuildingsEnabled"]) { - NSNumber *isBuildingsEnabled = @(_mapView.buildingsEnabled); + NSNumber *isBuildingsEnabled = @(self.mapView.buildingsEnabled); result(isBuildingsEnabled); } else if ([call.method isEqualToString:@"map#setStyle"]) { NSString *mapStyle = [call arguments]; @@ -372,86 +373,84 @@ - (void)onMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { } } else if ([call.method isEqualToString:@"map#getTileOverlayInfo"]) { NSString *rawTileOverlayId = call.arguments[@"tileOverlayId"]; - result([_tileOverlaysController getTileOverlayInfo:rawTileOverlayId]); + result([self.tileOverlaysController tileOverlayInfoWithIdentifier:rawTileOverlayId]); } else { result(FlutterMethodNotImplemented); } } -- (void)showAtX:(CGFloat)x Y:(CGFloat)y { - _mapView.frame = - CGRectMake(x, y, CGRectGetWidth(_mapView.frame), CGRectGetHeight(_mapView.frame)); - _mapView.hidden = NO; +- (void)showAtOrigin:(CGPoint)origin { + CGRect frame = {origin, self.mapView.frame.size}; + self.mapView.frame = frame; + self.mapView.hidden = NO; } - (void)hide { - _mapView.hidden = YES; + self.mapView.hidden = YES; } - (void)animateWithCameraUpdate:(GMSCameraUpdate *)cameraUpdate { - [_mapView animateWithCameraUpdate:cameraUpdate]; + [self.mapView animateWithCameraUpdate:cameraUpdate]; } - (void)moveWithCameraUpdate:(GMSCameraUpdate *)cameraUpdate { - [_mapView moveCamera:cameraUpdate]; + [self.mapView moveCamera:cameraUpdate]; } - (GMSCameraPosition *)cameraPosition { - if (_trackCameraPosition) { - return _mapView.camera; + if (self.trackCameraPosition) { + return self.mapView.camera; } else { return nil; } } -#pragma mark - FLTGoogleMapOptionsSink methods - - (void)setCamera:(GMSCameraPosition *)camera { - _mapView.camera = camera; + self.mapView.camera = camera; } - (void)setCameraTargetBounds:(GMSCoordinateBounds *)bounds { - _mapView.cameraTargetBounds = bounds; + self.mapView.cameraTargetBounds = bounds; } - (void)setCompassEnabled:(BOOL)enabled { - _mapView.settings.compassButton = enabled; + self.mapView.settings.compassButton = enabled; } - (void)setIndoorEnabled:(BOOL)enabled { - _mapView.indoorEnabled = enabled; + self.mapView.indoorEnabled = enabled; } - (void)setTrafficEnabled:(BOOL)enabled { - _mapView.trafficEnabled = enabled; + self.mapView.trafficEnabled = enabled; } - (void)setBuildingsEnabled:(BOOL)enabled { - _mapView.buildingsEnabled = enabled; + self.mapView.buildingsEnabled = enabled; } - (void)setMapType:(GMSMapViewType)mapType { - _mapView.mapType = mapType; + self.mapView.mapType = mapType; } - (void)setMinZoom:(float)minZoom maxZoom:(float)maxZoom { - [_mapView setMinZoom:minZoom maxZoom:maxZoom]; + [self.mapView setMinZoom:minZoom maxZoom:maxZoom]; } - (void)setPaddingTop:(float)top left:(float)left bottom:(float)bottom right:(float)right { - _mapView.padding = UIEdgeInsetsMake(top, left, bottom, right); + self.mapView.padding = UIEdgeInsetsMake(top, left, bottom, right); } - (void)setRotateGesturesEnabled:(BOOL)enabled { - _mapView.settings.rotateGestures = enabled; + self.mapView.settings.rotateGestures = enabled; } - (void)setScrollGesturesEnabled:(BOOL)enabled { - _mapView.settings.scrollGestures = enabled; + self.mapView.settings.scrollGestures = enabled; } - (void)setTiltGesturesEnabled:(BOOL)enabled { - _mapView.settings.tiltGestures = enabled; + self.mapView.settings.tiltGestures = enabled; } - (void)setTrackCameraPosition:(BOOL)enabled { @@ -459,20 +458,20 @@ - (void)setTrackCameraPosition:(BOOL)enabled { } - (void)setZoomGesturesEnabled:(BOOL)enabled { - _mapView.settings.zoomGestures = enabled; + self.mapView.settings.zoomGestures = enabled; } - (void)setMyLocationEnabled:(BOOL)enabled { - _mapView.myLocationEnabled = enabled; + self.mapView.myLocationEnabled = enabled; } - (void)setMyLocationButtonEnabled:(BOOL)enabled { - _mapView.settings.myLocationButton = enabled; + self.mapView.settings.myLocationButton = enabled; } - (NSString *)setMapStyle:(NSString *)mapStyle { if (mapStyle == (id)[NSNull null] || mapStyle.length == 0) { - _mapView.mapStyle = nil; + self.mapView.mapStyle = nil; return nil; } NSError *error; @@ -480,7 +479,7 @@ - (NSString *)setMapStyle:(NSString *)mapStyle { if (!style) { return [error localizedDescription]; } else { - _mapView.mapStyle = style; + self.mapView.mapStyle = style; return nil; } } @@ -488,236 +487,141 @@ - (NSString *)setMapStyle:(NSString *)mapStyle { #pragma mark - GMSMapViewDelegate methods - (void)mapView:(GMSMapView *)mapView willMove:(BOOL)gesture { - [_channel invokeMethod:@"camera#onMoveStarted" arguments:@{@"isGesture" : @(gesture)}]; + [self.channel invokeMethod:@"camera#onMoveStarted" arguments:@{@"isGesture" : @(gesture)}]; } - (void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position { - if (_trackCameraPosition) { - [_channel invokeMethod:@"camera#onMove" arguments:@{@"position" : PositionToJson(position)}]; + if (self.trackCameraPosition) { + [self.channel invokeMethod:@"camera#onMove" + arguments:@{ + @"position" : [FLTGoogleMapJSONConversions dictionaryFromPosition:position] + }]; } } - (void)mapView:(GMSMapView *)mapView idleAtCameraPosition:(GMSCameraPosition *)position { - [_channel invokeMethod:@"camera#onIdle" arguments:@{}]; + [self.channel invokeMethod:@"camera#onIdle" arguments:@{}]; } - (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker { NSString *markerId = marker.userData[0]; - return [_markersController onMarkerTap:markerId]; + return [self.markersController didTapMarkerWithIdentifier:markerId]; } - (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker { NSString *markerId = marker.userData[0]; - [_markersController onMarkerDragEnd:markerId coordinate:marker.position]; + [self.markersController didEndDraggingMarkerWithIdentifier:markerId location:marker.position]; } - (void)mapView:(GMSMapView *)mapView didStartDraggingMarker:(GMSMarker *)marker { NSString *markerId = marker.userData[0]; - [_markersController onMarkerDragStart:markerId coordinate:marker.position]; + [self.markersController didStartDraggingMarkerWithIdentifier:markerId location:marker.position]; } - (void)mapView:(GMSMapView *)mapView didDragMarker:(GMSMarker *)marker { NSString *markerId = marker.userData[0]; - [_markersController onMarkerDrag:markerId coordinate:marker.position]; + [self.markersController didDragMarkerWithIdentifier:markerId location:marker.position]; } - (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker { NSString *markerId = marker.userData[0]; - [_markersController onInfoWindowTap:markerId]; + [self.markersController didTapInfoWindowOfMarkerWithIdentifier:markerId]; } - (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSOverlay *)overlay { NSString *overlayId = overlay.userData[0]; - if ([_polylinesController hasPolylineWithId:overlayId]) { - [_polylinesController onPolylineTap:overlayId]; - } else if ([_polygonsController hasPolygonWithId:overlayId]) { - [_polygonsController onPolygonTap:overlayId]; - } else if ([_circlesController hasCircleWithId:overlayId]) { - [_circlesController onCircleTap:overlayId]; + 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]; } } - (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { - [_channel invokeMethod:@"map#onTap" arguments:@{@"position" : LocationToJson(coordinate)}]; + [self.channel + invokeMethod:@"map#onTap" + arguments:@{@"position" : [FLTGoogleMapJSONConversions arrayFromLocation:coordinate]}]; } - (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate { - [_channel invokeMethod:@"map#onLongPress" arguments:@{@"position" : LocationToJson(coordinate)}]; -} - -@end - -#pragma mark - Implementations of JSON conversion functions. - -static NSArray *LocationToJson(CLLocationCoordinate2D position) { - return @[ @(position.latitude), @(position.longitude) ]; -} - -static NSDictionary *PositionToJson(GMSCameraPosition *position) { - if (!position) { - return nil; - } - return @{ - @"target" : LocationToJson([position target]), - @"zoom" : @([position zoom]), - @"bearing" : @([position bearing]), - @"tilt" : @([position viewingAngle]), - }; -} - -static NSDictionary *PointToJson(CGPoint point) { - return @{ - @"x" : @(lroundf(point.x)), - @"y" : @(lroundf(point.y)), - }; + [self.channel + invokeMethod:@"map#onLongPress" + arguments:@{@"position" : [FLTGoogleMapJSONConversions arrayFromLocation:coordinate]}]; } -static NSDictionary *GMSCoordinateBoundsToJson(GMSCoordinateBounds *bounds) { - if (!bounds) { - return nil; - } - return @{ - @"southwest" : LocationToJson([bounds southWest]), - @"northeast" : LocationToJson([bounds northEast]), - }; -} - -static float ToFloat(NSNumber *data) { return [FLTGoogleMapJsonConversions toFloat:data]; } - -static CLLocationCoordinate2D ToLocation(NSArray *data) { - return [FLTGoogleMapJsonConversions toLocation:data]; -} - -static int ToInt(NSNumber *data) { return [FLTGoogleMapJsonConversions toInt:data]; } - -static BOOL ToBool(NSNumber *data) { return [FLTGoogleMapJsonConversions toBool:data]; } - -static CGPoint ToPoint(NSArray *data) { return [FLTGoogleMapJsonConversions toPoint:data]; } - -static GMSCameraPosition *ToCameraPosition(NSDictionary *data) { - return [GMSCameraPosition cameraWithTarget:ToLocation(data[@"target"]) - zoom:ToFloat(data[@"zoom"]) - bearing:ToDouble(data[@"bearing"]) - viewingAngle:ToDouble(data[@"tilt"])]; -} - -static GMSCameraPosition *ToOptionalCameraPosition(NSDictionary *json) { - return json ? ToCameraPosition(json) : nil; -} - -static CGPoint ToCGPoint(NSDictionary *json) { - double x = ToDouble(json[@"x"]); - double y = ToDouble(json[@"y"]); - return CGPointMake(x, y); -} - -static GMSCoordinateBounds *ToBounds(NSArray *data) { - return [[GMSCoordinateBounds alloc] initWithCoordinate:ToLocation(data[0]) - coordinate:ToLocation(data[1])]; -} - -static GMSCoordinateBounds *ToOptionalBounds(NSArray *data) { - return (data[0] == [NSNull null]) ? nil : ToBounds(data[0]); -} - -static GMSMapViewType ToMapViewType(NSNumber *json) { - int value = ToInt(json); - return (GMSMapViewType)(value == 0 ? 5 : value); -} - -static GMSCameraUpdate *ToCameraUpdate(NSArray *data) { - NSString *update = data[0]; - if ([update isEqualToString:@"newCameraPosition"]) { - return [GMSCameraUpdate setCamera:ToCameraPosition(data[1])]; - } else if ([update isEqualToString:@"newLatLng"]) { - return [GMSCameraUpdate setTarget:ToLocation(data[1])]; - } else if ([update isEqualToString:@"newLatLngBounds"]) { - return [GMSCameraUpdate fitBounds:ToBounds(data[1]) withPadding:ToDouble(data[2])]; - } else if ([update isEqualToString:@"newLatLngZoom"]) { - return [GMSCameraUpdate setTarget:ToLocation(data[1]) zoom:ToFloat(data[2])]; - } else if ([update isEqualToString:@"scrollBy"]) { - return [GMSCameraUpdate scrollByX:ToDouble(data[1]) Y:ToDouble(data[2])]; - } else if ([update isEqualToString:@"zoomBy"]) { - if (data.count == 2) { - return [GMSCameraUpdate zoomBy:ToFloat(data[1])]; - } else { - return [GMSCameraUpdate zoomBy:ToFloat(data[1]) atPoint:ToPoint(data[2])]; - } - } else if ([update isEqualToString:@"zoomIn"]) { - return [GMSCameraUpdate zoomIn]; - } else if ([update isEqualToString:@"zoomOut"]) { - return [GMSCameraUpdate zoomOut]; - } else if ([update isEqualToString:@"zoomTo"]) { - return [GMSCameraUpdate zoomTo:ToFloat(data[1])]; - } - return nil; -} - -static void InterpretMapOptions(NSDictionary *data, id sink) { +- (void)interpretMapOptions:(NSDictionary *)data { NSArray *cameraTargetBounds = data[@"cameraTargetBounds"]; - if (cameraTargetBounds) { - [sink setCameraTargetBounds:ToOptionalBounds(cameraTargetBounds)]; + if (cameraTargetBounds && cameraTargetBounds != (id)[NSNull null]) { + [self + setCameraTargetBounds:cameraTargetBounds.count > 0 && cameraTargetBounds[0] != [NSNull null] + ? [FLTGoogleMapJSONConversions + coordinateBoundsFromLatLongs:cameraTargetBounds.firstObject] + : nil]; } NSNumber *compassEnabled = data[@"compassEnabled"]; - if (compassEnabled != nil) { - [sink setCompassEnabled:ToBool(compassEnabled)]; + if (compassEnabled && compassEnabled != (id)[NSNull null]) { + [self setCompassEnabled:[compassEnabled boolValue]]; } id indoorEnabled = data[@"indoorEnabled"]; - if (indoorEnabled) { - [sink setIndoorEnabled:ToBool(indoorEnabled)]; + if (indoorEnabled && indoorEnabled != [NSNull null]) { + [self setIndoorEnabled:[indoorEnabled boolValue]]; } id trafficEnabled = data[@"trafficEnabled"]; - if (trafficEnabled) { - [sink setTrafficEnabled:ToBool(trafficEnabled)]; + if (trafficEnabled && trafficEnabled != [NSNull null]) { + [self setTrafficEnabled:[trafficEnabled boolValue]]; } id buildingsEnabled = data[@"buildingsEnabled"]; - if (buildingsEnabled) { - [sink setBuildingsEnabled:ToBool(buildingsEnabled)]; + if (buildingsEnabled && buildingsEnabled != [NSNull null]) { + [self setBuildingsEnabled:[buildingsEnabled boolValue]]; } id mapType = data[@"mapType"]; - if (mapType) { - [sink setMapType:ToMapViewType(mapType)]; + if (mapType && mapType != [NSNull null]) { + [self setMapType:[FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:mapType]]; } NSArray *zoomData = data[@"minMaxZoomPreference"]; - if (zoomData) { - float minZoom = (zoomData[0] == [NSNull null]) ? kGMSMinZoomLevel : ToFloat(zoomData[0]); - float maxZoom = (zoomData[1] == [NSNull null]) ? kGMSMaxZoomLevel : ToFloat(zoomData[1]); - [sink setMinZoom:minZoom maxZoom:maxZoom]; + if (zoomData && zoomData != (id)[NSNull null]) { + float minZoom = (zoomData[0] == [NSNull null]) ? kGMSMinZoomLevel : [zoomData[0] floatValue]; + float maxZoom = (zoomData[1] == [NSNull null]) ? kGMSMaxZoomLevel : [zoomData[1] floatValue]; + [self setMinZoom:minZoom maxZoom:maxZoom]; } NSArray *paddingData = data[@"padding"]; if (paddingData) { - float top = (paddingData[0] == [NSNull null]) ? 0 : ToFloat(paddingData[0]); - float left = (paddingData[1] == [NSNull null]) ? 0 : ToFloat(paddingData[1]); - float bottom = (paddingData[2] == [NSNull null]) ? 0 : ToFloat(paddingData[2]); - float right = (paddingData[3] == [NSNull null]) ? 0 : ToFloat(paddingData[3]); - [sink setPaddingTop:top left:left bottom:bottom right:right]; + float top = (paddingData[0] == [NSNull null]) ? 0 : [paddingData[0] floatValue]; + float left = (paddingData[1] == [NSNull null]) ? 0 : [paddingData[1] floatValue]; + float bottom = (paddingData[2] == [NSNull null]) ? 0 : [paddingData[2] floatValue]; + float right = (paddingData[3] == [NSNull null]) ? 0 : [paddingData[3] floatValue]; + [self setPaddingTop:top left:left bottom:bottom right:right]; } NSNumber *rotateGesturesEnabled = data[@"rotateGesturesEnabled"]; - if (rotateGesturesEnabled != nil) { - [sink setRotateGesturesEnabled:ToBool(rotateGesturesEnabled)]; + if (rotateGesturesEnabled && rotateGesturesEnabled != (id)[NSNull null]) { + [self setRotateGesturesEnabled:[rotateGesturesEnabled boolValue]]; } NSNumber *scrollGesturesEnabled = data[@"scrollGesturesEnabled"]; - if (scrollGesturesEnabled != nil) { - [sink setScrollGesturesEnabled:ToBool(scrollGesturesEnabled)]; + if (scrollGesturesEnabled && scrollGesturesEnabled != (id)[NSNull null]) { + [self setScrollGesturesEnabled:[scrollGesturesEnabled boolValue]]; } NSNumber *tiltGesturesEnabled = data[@"tiltGesturesEnabled"]; - if (tiltGesturesEnabled != nil) { - [sink setTiltGesturesEnabled:ToBool(tiltGesturesEnabled)]; + if (tiltGesturesEnabled && tiltGesturesEnabled != (id)[NSNull null]) { + [self setTiltGesturesEnabled:[tiltGesturesEnabled boolValue]]; } NSNumber *trackCameraPosition = data[@"trackCameraPosition"]; - if (trackCameraPosition != nil) { - [sink setTrackCameraPosition:ToBool(trackCameraPosition)]; + if (trackCameraPosition && trackCameraPosition != (id)[NSNull null]) { + [self setTrackCameraPosition:[trackCameraPosition boolValue]]; } NSNumber *zoomGesturesEnabled = data[@"zoomGesturesEnabled"]; - if (zoomGesturesEnabled != nil) { - [sink setZoomGesturesEnabled:ToBool(zoomGesturesEnabled)]; + if (zoomGesturesEnabled && zoomGesturesEnabled != (id)[NSNull null]) { + [self setZoomGesturesEnabled:[zoomGesturesEnabled boolValue]]; } NSNumber *myLocationEnabled = data[@"myLocationEnabled"]; - if (myLocationEnabled != nil) { - [sink setMyLocationEnabled:ToBool(myLocationEnabled)]; + if (myLocationEnabled && myLocationEnabled != (id)[NSNull null]) { + [self setMyLocationEnabled:[myLocationEnabled boolValue]]; } NSNumber *myLocationButtonEnabled = data[@"myLocationButtonEnabled"]; - if (myLocationButtonEnabled != nil) { - [sink setMyLocationButtonEnabled:ToBool(myLocationButtonEnabled)]; + if (myLocationButtonEnabled && myLocationButtonEnabled != (id)[NSNull null]) { + [self setMyLocationButtonEnabled:[myLocationButtonEnabled boolValue]]; } } + +@end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h index 8734c06fe929..a33d48073dd2 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.h @@ -8,50 +8,37 @@ NS_ASSUME_NONNULL_BEGIN -// Defines marker UI options writable from Flutter. -@protocol FLTGoogleMapMarkerOptionsSink -- (void)setAlpha:(float)alpha; -- (void)setAnchor:(CGPoint)anchor; -- (void)setConsumeTapEvents:(BOOL)consume; -- (void)setDraggable:(BOOL)draggable; -- (void)setFlat:(BOOL)flat; -- (void)setIcon:(UIImage *)icon; -- (void)setInfoWindowAnchor:(CGPoint)anchor; -- (void)setInfoWindowTitle:(NSString *)title snippet:(NSString *)snippet; -- (void)setPosition:(CLLocationCoordinate2D)position; -- (void)setRotation:(CLLocationDegrees)rotation; -- (void)setVisible:(BOOL)visible; -- (void)setZIndex:(int)zIndex; -@end - // Defines marker controllable by Flutter. -@interface FLTGoogleMapMarkerController : NSObject -@property(atomic, readonly) NSString *markerId; +@interface FLTGoogleMapMarkerController : NSObject +@property(assign, nonatomic, readonly) BOOL consumeTapEvents; - (instancetype)initMarkerWithPosition:(CLLocationCoordinate2D)position - markerId:(NSString *)markerId + identifier:(NSString *)identifier mapView:(GMSMapView *)mapView; - (void)showInfoWindow; - (void)hideInfoWindow; - (BOOL)isInfoWindowShown; -- (BOOL)consumeTapEvents; - (void)removeMarker; @end @interface FLTMarkersController : NSObject -- (instancetype)init:(FlutterMethodChannel *)methodChannel - mapView:(GMSMapView *)mapView - registrar:(NSObject *)registrar; +- (instancetype)initWithMethodChannel:(FlutterMethodChannel *)methodChannel + mapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar; - (void)addMarkers:(NSArray *)markersToAdd; - (void)changeMarkers:(NSArray *)markersToChange; -- (void)removeMarkerIds:(NSArray *)markerIdsToRemove; -- (BOOL)onMarkerTap:(NSString *)markerId; -- (void)onMarkerDragStart:(NSString *)markerId coordinate:(CLLocationCoordinate2D)coordinate; -- (void)onMarkerDragEnd:(NSString *)markerId coordinate:(CLLocationCoordinate2D)coordinate; -- (void)onMarkerDrag:(NSString *)markerId coordinate:(CLLocationCoordinate2D)coordinate; -- (void)onInfoWindowTap:(NSString *)markerId; -- (void)showMarkerInfoWindow:(NSString *)markerId result:(FlutterResult)result; -- (void)hideMarkerInfoWindow:(NSString *)markerId result:(FlutterResult)result; -- (void)isMarkerInfoWindowShown:(NSString *)markerId result:(FlutterResult)result; +- (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 result:(FlutterResult)result; +- (void)hideMarkerInfoWindowWithIdentifier:(NSString *)identifier result:(FlutterResult)result; +- (void)isInfoWindowShownForMarkerWithIdentifier:(NSString *)identifier + result:(FlutterResult)result; @end NS_ASSUME_NONNULL_END diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m index c2877e2bd78f..dd07e791a888 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapMarkerController.m @@ -3,184 +3,159 @@ // found in the LICENSE file. #import "GoogleMapMarkerController.h" -#import "JsonConversions.h" +#import "FLTGoogleMapJSONConversions.h" -static UIImage *ExtractIcon(NSObject *registrar, NSArray *icon); -static void InterpretInfoWindow(id sink, NSDictionary *data); +@interface FLTGoogleMapMarkerController () + +@property(strong, nonatomic) GMSMarker *marker; +@property(weak, nonatomic) GMSMapView *mapView; +@property(assign, nonatomic, readwrite) BOOL consumeTapEvents; + +@end + +@implementation FLTGoogleMapMarkerController -@implementation FLTGoogleMapMarkerController { - GMSMarker *_marker; - GMSMapView *_mapView; - BOOL _consumeTapEvents; -} - (instancetype)initMarkerWithPosition:(CLLocationCoordinate2D)position - markerId:(NSString *)markerId + identifier:(NSString *)identifier mapView:(GMSMapView *)mapView { self = [super init]; if (self) { _marker = [GMSMarker markerWithPosition:position]; _mapView = mapView; - _markerId = markerId; - _marker.userData = @[ _markerId ]; - _consumeTapEvents = NO; + _marker.userData = @[ identifier ]; } return self; } + - (void)showInfoWindow { - _mapView.selectedMarker = _marker; + self.mapView.selectedMarker = self.marker; } + - (void)hideInfoWindow { - if (_mapView.selectedMarker == _marker) { - _mapView.selectedMarker = nil; + if (self.mapView.selectedMarker == self.marker) { + self.mapView.selectedMarker = nil; } } + - (BOOL)isInfoWindowShown { - return _mapView.selectedMarker == _marker; -} -- (BOOL)consumeTapEvents { - return _consumeTapEvents; + return self.mapView.selectedMarker == self.marker; } + - (void)removeMarker { - _marker.map = nil; + self.marker.map = nil; } -#pragma mark - FLTGoogleMapMarkerOptionsSink methods - - (void)setAlpha:(float)alpha { - _marker.opacity = alpha; + self.marker.opacity = alpha; } + - (void)setAnchor:(CGPoint)anchor { - _marker.groundAnchor = anchor; -} -- (void)setConsumeTapEvents:(BOOL)consumes { - _consumeTapEvents = consumes; + self.marker.groundAnchor = anchor; } + - (void)setDraggable:(BOOL)draggable { - _marker.draggable = draggable; + self.marker.draggable = draggable; } + - (void)setFlat:(BOOL)flat { - _marker.flat = flat; + self.marker.flat = flat; } + - (void)setIcon:(UIImage *)icon { - _marker.icon = icon; + self.marker.icon = icon; } + - (void)setInfoWindowAnchor:(CGPoint)anchor { - _marker.infoWindowAnchor = anchor; + self.marker.infoWindowAnchor = anchor; } + - (void)setInfoWindowTitle:(NSString *)title snippet:(NSString *)snippet { - _marker.title = title; - _marker.snippet = snippet; + self.marker.title = title; + self.marker.snippet = snippet; } + - (void)setPosition:(CLLocationCoordinate2D)position { - _marker.position = position; + self.marker.position = position; } + - (void)setRotation:(CLLocationDegrees)rotation { - _marker.rotation = rotation; + self.marker.rotation = rotation; } -- (void)setVisible:(BOOL)visible { - _marker.map = visible ? _mapView : nil; -} -- (void)setZIndex:(int)zIndex { - _marker.zIndex = zIndex; -} -@end -static double ToDouble(NSNumber *data) { return [FLTGoogleMapJsonConversions toDouble:data]; } - -static float ToFloat(NSNumber *data) { return [FLTGoogleMapJsonConversions toFloat:data]; } - -static CLLocationCoordinate2D ToLocation(NSArray *data) { - return [FLTGoogleMapJsonConversions toLocation:data]; +- (void)setVisible:(BOOL)visible { + self.marker.map = visible ? self.mapView : nil; } -static int ToInt(NSNumber *data) { return [FLTGoogleMapJsonConversions toInt:data]; } - -static BOOL ToBool(NSNumber *data) { return [FLTGoogleMapJsonConversions toBool:data]; } - -static CGPoint ToPoint(NSArray *data) { return [FLTGoogleMapJsonConversions toPoint:data]; } - -static NSArray *PositionToJson(CLLocationCoordinate2D data) { - return [FLTGoogleMapJsonConversions positionToJson:data]; +- (void)setZIndex:(int)zIndex { + self.marker.zIndex = zIndex; } -static void InterpretMarkerOptions(NSDictionary *data, id sink, - NSObject *registrar) { +- (void)interpretMarkerOptions:(NSDictionary *)data + registrar:(NSObject *)registrar { NSNumber *alpha = data[@"alpha"]; - if (alpha != nil) { - [sink setAlpha:ToFloat(alpha)]; + if (alpha && alpha != (id)[NSNull null]) { + [self setAlpha:[alpha floatValue]]; } NSArray *anchor = data[@"anchor"]; - if (anchor) { - [sink setAnchor:ToPoint(anchor)]; + if (anchor && anchor != (id)[NSNull null]) { + [self setAnchor:[FLTGoogleMapJSONConversions pointFromArray:anchor]]; } NSNumber *draggable = data[@"draggable"]; - if (draggable != nil) { - [sink setDraggable:ToBool(draggable)]; + if (draggable && draggable != (id)[NSNull null]) { + [self setDraggable:[draggable boolValue]]; } NSArray *icon = data[@"icon"]; - if (icon) { - UIImage *image = ExtractIcon(registrar, icon); - [sink setIcon:image]; + if (icon && icon != (id)[NSNull null]) { + UIImage *image = [self extractIconFromData:icon registrar:registrar]; + [self setIcon:image]; } NSNumber *flat = data[@"flat"]; - if (flat != nil) { - [sink setFlat:ToBool(flat)]; + if (flat && flat != (id)[NSNull null]) { + [self setFlat:[flat boolValue]]; } NSNumber *consumeTapEvents = data[@"consumeTapEvents"]; - if (consumeTapEvents != nil) { - [sink setConsumeTapEvents:ToBool(consumeTapEvents)]; + if (consumeTapEvents && consumeTapEvents != (id)[NSNull null]) { + [self setConsumeTapEvents:[consumeTapEvents boolValue]]; } - InterpretInfoWindow(sink, data); + [self interpretInfoWindow:data]; NSArray *position = data[@"position"]; - if (position) { - [sink setPosition:ToLocation(position)]; + if (position && position != (id)[NSNull null]) { + [self setPosition:[FLTGoogleMapJSONConversions locationFromLatLong:position]]; } NSNumber *rotation = data[@"rotation"]; - if (rotation != nil) { - [sink setRotation:ToDouble(rotation)]; + if (rotation && rotation != (id)[NSNull null]) { + [self setRotation:[rotation doubleValue]]; } NSNumber *visible = data[@"visible"]; - if (visible != nil) { - [sink setVisible:ToBool(visible)]; + if (visible && visible != (id)[NSNull null]) { + [self setVisible:[visible boolValue]]; } NSNumber *zIndex = data[@"zIndex"]; - if (zIndex != nil) { - [sink setZIndex:ToInt(zIndex)]; + if (zIndex && zIndex != (id)[NSNull null]) { + [self setZIndex:[zIndex intValue]]; } } -static void InterpretInfoWindow(id sink, NSDictionary *data) { +- (void)interpretInfoWindow:(NSDictionary *)data { NSDictionary *infoWindow = data[@"infoWindow"]; - if (infoWindow) { + if (infoWindow && infoWindow != (id)[NSNull null]) { NSString *title = infoWindow[@"title"]; NSString *snippet = infoWindow[@"snippet"]; - if (title) { - [sink setInfoWindowTitle:title snippet:snippet]; + if (title && title != (id)[NSNull null]) { + [self setInfoWindowTitle:title snippet:snippet]; } NSArray *infoWindowAnchor = infoWindow[@"infoWindowAnchor"]; - if (infoWindowAnchor) { - [sink setInfoWindowAnchor:ToPoint(infoWindowAnchor)]; + if (infoWindowAnchor && infoWindowAnchor != (id)[NSNull null]) { + [self setInfoWindowAnchor:[FLTGoogleMapJSONConversions pointFromArray:infoWindowAnchor]]; } } } -static UIImage *scaleImage(UIImage *image, NSNumber *scaleParam) { - double scale = 1.0; - if ([scaleParam isKindOfClass:[NSNumber class]]) { - scale = scaleParam.doubleValue; - } - if (fabs(scale - 1) > 1e-3) { - return [UIImage imageWithCGImage:[image CGImage] - scale:(image.scale * scale) - orientation:(image.imageOrientation)]; - } - return image; -} - -static UIImage *ExtractIcon(NSObject *registrar, NSArray *iconData) { +- (UIImage *)extractIconFromData:(NSArray *)iconData + registrar:(NSObject *)registrar { UIImage *image; if ([iconData.firstObject isEqualToString:@"defaultMarker"]) { - CGFloat hue = (iconData.count == 1) ? 0.0f : ToDouble(iconData[1]); + CGFloat hue = (iconData.count == 1) ? 0.0f : [iconData[1] doubleValue]; image = [GMSMarker markerImageWithColor:[UIColor colorWithHue:hue / 360.0 saturation:1.0 brightness:0.7 @@ -195,8 +170,8 @@ static void InterpretInfoWindow(id sink, NSDictio } else if ([iconData.firstObject isEqualToString:@"fromAssetImage"]) { if (iconData.count == 3) { image = [UIImage imageNamed:[registrar lookupKeyForAsset:iconData[1]]]; - NSNumber *scaleParam = iconData[2]; - image = scaleImage(image, scaleParam); + id scaleParam = iconData[2]; + image = [self scaleImage:image by:scaleParam]; } else { NSString *error = [NSString stringWithFormat:@"'fromAssetImage' should have exactly 3 arguments. Got: %lu", @@ -231,110 +206,145 @@ static void InterpretInfoWindow(id sink, NSDictio return image; } -@implementation FLTMarkersController { - NSMutableDictionary *_markerIdToController; - FlutterMethodChannel *_methodChannel; - NSObject *_registrar; - GMSMapView *_mapView; +- (UIImage *)scaleImage:(UIImage *)image by:(id)scaleParam { + double scale = 1.0; + if ([scaleParam isKindOfClass:[NSNumber class]]) { + scale = [scaleParam doubleValue]; + } + if (fabs(scale - 1) > 1e-3) { + return [UIImage imageWithCGImage:[image CGImage] + scale:(image.scale * scale) + orientation:(image.imageOrientation)]; + } + return image; } -- (instancetype)init:(FlutterMethodChannel *)methodChannel - mapView:(GMSMapView *)mapView - registrar:(NSObject *)registrar { + +@end + +@interface FLTMarkersController () + +@property(strong, nonatomic) NSMutableDictionary *markerIdentifierToController; +@property(strong, nonatomic) FlutterMethodChannel *methodChannel; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTMarkersController + +- (instancetype)initWithMethodChannel:(FlutterMethodChannel *)methodChannel + mapView:(GMSMapView *)mapView + registrar:(NSObject *)registrar { self = [super init]; if (self) { _methodChannel = methodChannel; _mapView = mapView; - _markerIdToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _markerIdentifierToController = [[NSMutableDictionary alloc] init]; _registrar = registrar; } return self; } + - (void)addMarkers:(NSArray *)markersToAdd { for (NSDictionary *marker in markersToAdd) { CLLocationCoordinate2D position = [FLTMarkersController getPosition:marker]; - NSString *markerId = [FLTMarkersController getMarkerId:marker]; + NSString *identifier = marker[@"markerId"]; FLTGoogleMapMarkerController *controller = [[FLTGoogleMapMarkerController alloc] initMarkerWithPosition:position - markerId:markerId - mapView:_mapView]; - InterpretMarkerOptions(marker, controller, _registrar); - _markerIdToController[markerId] = controller; + identifier:identifier + mapView:self.mapView]; + [controller interpretMarkerOptions:marker registrar:self.registrar]; + self.markerIdentifierToController[identifier] = controller; } } + - (void)changeMarkers:(NSArray *)markersToChange { for (NSDictionary *marker in markersToChange) { - NSString *markerId = [FLTMarkersController getMarkerId:marker]; - FLTGoogleMapMarkerController *controller = _markerIdToController[markerId]; + NSString *identifier = marker[@"markerId"]; + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; if (!controller) { continue; } - InterpretMarkerOptions(marker, controller, _registrar); + [controller interpretMarkerOptions:marker registrar:self.registrar]; } } -- (void)removeMarkerIds:(NSArray *)markerIdsToRemove { - for (NSString *markerId in markerIdsToRemove) { - if (!markerId) { - continue; - } - FLTGoogleMapMarkerController *controller = _markerIdToController[markerId]; + +- (void)removeMarkersWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; if (!controller) { continue; } [controller removeMarker]; - [_markerIdToController removeObjectForKey:markerId]; + [self.markerIdentifierToController removeObjectForKey:identifier]; } } -- (BOOL)onMarkerTap:(NSString *)markerId { - if (!markerId) { + +- (BOOL)didTapMarkerWithIdentifier:(NSString *)identifier { + if (!identifier) { return NO; } - FLTGoogleMapMarkerController *controller = _markerIdToController[markerId]; + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; if (!controller) { return NO; } - [_methodChannel invokeMethod:@"marker#onTap" arguments:@{@"markerId" : markerId}]; + [self.methodChannel invokeMethod:@"marker#onTap" arguments:@{@"markerId" : identifier}]; return controller.consumeTapEvents; } -- (void)onMarkerDragStart:(NSString *)markerId coordinate:(CLLocationCoordinate2D)coordinate { - if (!markerId) { + +- (void)didStartDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + if (!identifier) { return; } - FLTGoogleMapMarkerController *controller = _markerIdToController[markerId]; + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; if (!controller) { return; } - [_methodChannel invokeMethod:@"marker#onDragStart" - arguments:@{@"markerId" : markerId, @"position" : PositionToJson(coordinate)}]; + [self.methodChannel invokeMethod:@"marker#onDragStart" + arguments:@{ + @"markerId" : identifier, + @"position" : [FLTGoogleMapJSONConversions arrayFromLocation:location] + }]; } -- (void)onMarkerDrag:(NSString *)markerId coordinate:(CLLocationCoordinate2D)coordinate { - if (!markerId) { + +- (void)didDragMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + if (!identifier) { return; } - FLTGoogleMapMarkerController *controller = _markerIdToController[markerId]; + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; if (!controller) { return; } - [_methodChannel invokeMethod:@"marker#onDrag" - arguments:@{@"markerId" : markerId, @"position" : PositionToJson(coordinate)}]; + [self.methodChannel invokeMethod:@"marker#onDrag" + arguments:@{ + @"markerId" : identifier, + @"position" : [FLTGoogleMapJSONConversions arrayFromLocation:location] + }]; } -- (void)onMarkerDragEnd:(NSString *)markerId coordinate:(CLLocationCoordinate2D)coordinate { - if (!markerId) { - return; - } - FLTGoogleMapMarkerController *controller = _markerIdToController[markerId]; + +- (void)didEndDraggingMarkerWithIdentifier:(NSString *)identifier + location:(CLLocationCoordinate2D)location { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; if (!controller) { return; } - [_methodChannel invokeMethod:@"marker#onDragEnd" - arguments:@{@"markerId" : markerId, @"position" : PositionToJson(coordinate)}]; + [self.methodChannel invokeMethod:@"marker#onDragEnd" + arguments:@{ + @"markerId" : identifier, + @"position" : [FLTGoogleMapJSONConversions arrayFromLocation:location] + }]; } -- (void)onInfoWindowTap:(NSString *)markerId { - if (markerId && _markerIdToController[markerId]) { - [_methodChannel invokeMethod:@"infoWindow#onTap" arguments:@{@"markerId" : markerId}]; + +- (void)didTapInfoWindowOfMarkerWithIdentifier:(NSString *)identifier { + if (identifier && self.markerIdentifierToController[identifier]) { + [self.methodChannel invokeMethod:@"infoWindow#onTap" arguments:@{@"markerId" : identifier}]; } } -- (void)showMarkerInfoWindow:(NSString *)markerId result:(FlutterResult)result { - FLTGoogleMapMarkerController *controller = _markerIdToController[markerId]; + +- (void)showMarkerInfoWindowWithIdentifier:(NSString *)identifier result:(FlutterResult)result { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; if (controller) { [controller showInfoWindow]; result(nil); @@ -344,8 +354,9 @@ - (void)showMarkerInfoWindow:(NSString *)markerId result:(FlutterResult)result { details:nil]); } } -- (void)hideMarkerInfoWindow:(NSString *)markerId result:(FlutterResult)result { - FLTGoogleMapMarkerController *controller = _markerIdToController[markerId]; + +- (void)hideMarkerInfoWindowWithIdentifier:(NSString *)identifier result:(FlutterResult)result { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; if (controller) { [controller hideInfoWindow]; result(nil); @@ -355,8 +366,10 @@ - (void)hideMarkerInfoWindow:(NSString *)markerId result:(FlutterResult)result { details:nil]); } } -- (void)isMarkerInfoWindowShown:(NSString *)markerId result:(FlutterResult)result { - FLTGoogleMapMarkerController *controller = _markerIdToController[markerId]; + +- (void)isInfoWindowShownForMarkerWithIdentifier:(NSString *)identifier + result:(FlutterResult)result { + FLTGoogleMapMarkerController *controller = self.markerIdentifierToController[identifier]; if (controller) { result(@([controller isInfoWindowShown])); } else { @@ -368,9 +381,7 @@ - (void)isMarkerInfoWindowShown:(NSString *)markerId result:(FlutterResult)resul + (CLLocationCoordinate2D)getPosition:(NSDictionary *)marker { NSArray *position = marker[@"position"]; - return ToLocation(position); -} -+ (NSString *)getMarkerId:(NSDictionary *)marker { - return marker[@"markerId"]; + return [FLTGoogleMapJSONConversions locationFromLatLong:position]; } + @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h index bdc5dd4bf850..bd0c9110200e 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.h @@ -5,23 +5,10 @@ #import #import -// Defines polygon UI options writable from Flutter. -@protocol FLTGoogleMapPolygonOptionsSink -- (void)setConsumeTapEvents:(BOOL)consume; -- (void)setVisible:(BOOL)visible; -- (void)setFillColor:(UIColor *)color; -- (void)setStrokeColor:(UIColor *)color; -- (void)setStrokeWidth:(CGFloat)width; -- (void)setPoints:(NSArray *)points; -- (void)setHoles:(NSArray *> *)holes; -- (void)setZIndex:(int)zIndex; -@end - // Defines polygon controllable by Flutter. -@interface FLTGoogleMapPolygonController : NSObject -@property(atomic, readonly) NSString *polygonId; +@interface FLTGoogleMapPolygonController : NSObject - (instancetype)initPolygonWithPath:(GMSMutablePath *)path - polygonId:(NSString *)polygonId + identifier:(NSString *)identifier mapView:(GMSMapView *)mapView; - (void)removePolygon; @end @@ -32,7 +19,7 @@ registrar:(NSObject *)registrar; - (void)addPolygons:(NSArray *)polygonsToAdd; - (void)changePolygons:(NSArray *)polygonsToChange; -- (void)removePolygonIds:(NSArray *)polygonIdsToRemove; -- (void)onPolygonTap:(NSString *)polygonId; -- (bool)hasPolygonWithId:(NSString *)polygonId; +- (void)removePolygonWithIdentifiers:(NSArray *)identifiers; +- (void)didTapPolygonWithIdentifier:(NSString *)identifier; +- (bool)hasPolygonWithIdentifier:(NSString *)identifier; @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m index 649ba98bca13..398adfcacecb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolygonController.m @@ -3,39 +3,41 @@ // found in the LICENSE file. #import "GoogleMapPolygonController.h" -#import "JsonConversions.h" +#import "FLTGoogleMapJSONConversions.h" + +@interface FLTGoogleMapPolygonController () + +@property(strong, nonatomic) GMSPolygon *polygon; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapPolygonController -@implementation FLTGoogleMapPolygonController { - GMSPolygon *_polygon; - GMSMapView *_mapView; -} - (instancetype)initPolygonWithPath:(GMSMutablePath *)path - polygonId:(NSString *)polygonId + identifier:(NSString *)identifier mapView:(GMSMapView *)mapView { self = [super init]; if (self) { _polygon = [GMSPolygon polygonWithPath:path]; _mapView = mapView; - _polygonId = polygonId; - _polygon.userData = @[ polygonId ]; + _polygon.userData = @[ identifier ]; } return self; } - (void)removePolygon { - _polygon.map = nil; + self.polygon.map = nil; } -#pragma mark - FLTGoogleMapPolygonOptionsSink methods - - (void)setConsumeTapEvents:(BOOL)consumes { - _polygon.tappable = consumes; + self.polygon.tappable = consumes; } - (void)setVisible:(BOOL)visible { - _polygon.map = visible ? _mapView : nil; + self.polygon.map = visible ? self.mapView : nil; } - (void)setZIndex:(int)zIndex { - _polygon.zIndex = zIndex; + self.polygon.zIndex = zIndex; } - (void)setPoints:(NSArray *)points { GMSMutablePath *path = [GMSMutablePath path]; @@ -43,7 +45,7 @@ - (void)setPoints:(NSArray *)points { for (CLLocation *location in points) { [path addCoordinate:location.coordinate]; } - _polygon.path = path; + self.polygon.path = path; } - (void)setHoles:(NSArray *> *)rawHoles { NSMutableArray *holes = [[NSMutableArray alloc] init]; @@ -56,83 +58,75 @@ - (void)setHoles:(NSArray *> *)rawHoles { [holes addObject:path]; } - _polygon.holes = holes; + self.polygon.holes = holes; } - (void)setFillColor:(UIColor *)color { - _polygon.fillColor = color; + self.polygon.fillColor = color; } - (void)setStrokeColor:(UIColor *)color { - _polygon.strokeColor = color; + self.polygon.strokeColor = color; } - (void)setStrokeWidth:(CGFloat)width { - _polygon.strokeWidth = width; + self.polygon.strokeWidth = width; } -@end - -static int ToInt(NSNumber *data) { return [FLTGoogleMapJsonConversions toInt:data]; } -static BOOL ToBool(NSNumber *data) { return [FLTGoogleMapJsonConversions toBool:data]; } - -static NSArray *ToPoints(NSArray *data) { - return [FLTGoogleMapJsonConversions toPoints:data]; -} - -static NSArray *> *ToHoles(NSArray *data) { - return [FLTGoogleMapJsonConversions toHoles:data]; -} - -static UIColor *ToColor(NSNumber *data) { return [FLTGoogleMapJsonConversions toColor:data]; } - -static void InterpretPolygonOptions(NSDictionary *data, id sink, - NSObject *registrar) { +- (void)interpretPolygonOptions:(NSDictionary *)data + registrar:(NSObject *)registrar { NSNumber *consumeTapEvents = data[@"consumeTapEvents"]; - if (consumeTapEvents != nil) { - [sink setConsumeTapEvents:ToBool(consumeTapEvents)]; + if (consumeTapEvents && consumeTapEvents != (id)[NSNull null]) { + [self setConsumeTapEvents:[consumeTapEvents boolValue]]; } NSNumber *visible = data[@"visible"]; - if (visible != nil) { - [sink setVisible:ToBool(visible)]; + if (visible && visible != (id)[NSNull null]) { + [self setVisible:[visible boolValue]]; } NSNumber *zIndex = data[@"zIndex"]; - if (zIndex != nil) { - [sink setZIndex:ToInt(zIndex)]; + if (zIndex && zIndex != (id)[NSNull null]) { + [self setZIndex:[zIndex intValue]]; } NSArray *points = data[@"points"]; - if (points) { - [sink setPoints:ToPoints(points)]; + if (points && points != (id)[NSNull null]) { + [self setPoints:[FLTGoogleMapJSONConversions pointsFromLatLongs:points]]; } NSArray *holes = data[@"holes"]; - if (holes) { - [sink setHoles:ToHoles(holes)]; + if (holes && holes != (id)[NSNull null]) { + [self setHoles:[FLTGoogleMapJSONConversions holesFromPointsArray:holes]]; } NSNumber *fillColor = data[@"fillColor"]; - if (fillColor != nil) { - [sink setFillColor:ToColor(fillColor)]; + if (fillColor && fillColor != (id)[NSNull null]) { + [self setFillColor:[FLTGoogleMapJSONConversions colorFromRGBA:fillColor]]; } NSNumber *strokeColor = data[@"strokeColor"]; - if (strokeColor != nil) { - [sink setStrokeColor:ToColor(strokeColor)]; + if (strokeColor && strokeColor != (id)[NSNull null]) { + [self setStrokeColor:[FLTGoogleMapJSONConversions colorFromRGBA:strokeColor]]; } NSNumber *strokeWidth = data[@"strokeWidth"]; - if (strokeWidth != nil) { - [sink setStrokeWidth:ToInt(strokeWidth)]; + if (strokeWidth && strokeWidth != (id)[NSNull null]) { + [self setStrokeWidth:[strokeWidth intValue]]; } } -@implementation FLTPolygonsController { - NSMutableDictionary *_polygonIdToController; - FlutterMethodChannel *_methodChannel; - NSObject *_registrar; - GMSMapView *_mapView; -} +@end + +@interface FLTPolygonsController () + +@property(strong, nonatomic) NSMutableDictionary *polygonIdentifierToController; +@property(strong, nonatomic) FlutterMethodChannel *methodChannel; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTPolygonsController + - (instancetype)init:(FlutterMethodChannel *)methodChannel mapView:(GMSMapView *)mapView registrar:(NSObject *)registrar { @@ -140,72 +134,73 @@ - (instancetype)init:(FlutterMethodChannel *)methodChannel if (self) { _methodChannel = methodChannel; _mapView = mapView; - _polygonIdToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _polygonIdentifierToController = [NSMutableDictionary dictionaryWithCapacity:1]; _registrar = registrar; } return self; } + - (void)addPolygons:(NSArray *)polygonsToAdd { for (NSDictionary *polygon in polygonsToAdd) { GMSMutablePath *path = [FLTPolygonsController getPath:polygon]; - NSString *polygonId = [FLTPolygonsController getPolygonId:polygon]; + NSString *identifier = polygon[@"polygonId"]; FLTGoogleMapPolygonController *controller = [[FLTGoogleMapPolygonController alloc] initPolygonWithPath:path - polygonId:polygonId - mapView:_mapView]; - InterpretPolygonOptions(polygon, controller, _registrar); - _polygonIdToController[polygonId] = controller; + identifier:identifier + mapView:self.mapView]; + [controller interpretPolygonOptions:polygon registrar:self.registrar]; + self.polygonIdentifierToController[identifier] = controller; } } + - (void)changePolygons:(NSArray *)polygonsToChange { for (NSDictionary *polygon in polygonsToChange) { - NSString *polygonId = [FLTPolygonsController getPolygonId:polygon]; - FLTGoogleMapPolygonController *controller = _polygonIdToController[polygonId]; + NSString *identifier = polygon[@"polygonId"]; + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; if (!controller) { continue; } - InterpretPolygonOptions(polygon, controller, _registrar); + [controller interpretPolygonOptions:polygon registrar:self.registrar]; } } -- (void)removePolygonIds:(NSArray *)polygonIdsToRemove { - for (NSString *polygonId in polygonIdsToRemove) { - if (!polygonId) { - continue; - } - FLTGoogleMapPolygonController *controller = _polygonIdToController[polygonId]; + +- (void)removePolygonWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; if (!controller) { continue; } [controller removePolygon]; - [_polygonIdToController removeObjectForKey:polygonId]; + [self.polygonIdentifierToController removeObjectForKey:identifier]; } } -- (void)onPolygonTap:(NSString *)polygonId { - if (!polygonId) { + +- (void)didTapPolygonWithIdentifier:(NSString *)identifier { + if (!identifier) { return; } - FLTGoogleMapPolygonController *controller = _polygonIdToController[polygonId]; + FLTGoogleMapPolygonController *controller = self.polygonIdentifierToController[identifier]; if (!controller) { return; } - [_methodChannel invokeMethod:@"polygon#onTap" arguments:@{@"polygonId" : polygonId}]; + [self.methodChannel invokeMethod:@"polygon#onTap" arguments:@{@"polygonId" : identifier}]; } -- (bool)hasPolygonWithId:(NSString *)polygonId { - if (!polygonId) { + +- (bool)hasPolygonWithIdentifier:(NSString *)identifier { + if (!identifier) { return false; } - return _polygonIdToController[polygonId] != nil; + return self.polygonIdentifierToController[identifier] != nil; } + + (GMSMutablePath *)getPath:(NSDictionary *)polygon { NSArray *pointArray = polygon[@"points"]; - NSArray *points = ToPoints(pointArray); + NSArray *points = [FLTGoogleMapJSONConversions pointsFromLatLongs:pointArray]; GMSMutablePath *path = [GMSMutablePath path]; for (CLLocation *location in points) { [path addCoordinate:location.coordinate]; } return path; } -+ (NSString *)getPolygonId:(NSDictionary *)polygon { - return polygon[@"polygonId"]; -} + @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h index 0e614eeb62ab..f85d1a3896fa 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.h @@ -5,22 +5,10 @@ #import #import -// Defines polyline UI options writable from Flutter. -@protocol FLTGoogleMapPolylineOptionsSink -- (void)setConsumeTapEvents:(BOOL)consume; -- (void)setVisible:(BOOL)visible; -- (void)setColor:(UIColor *)color; -- (void)setStrokeWidth:(CGFloat)width; -- (void)setPoints:(NSArray *)points; -- (void)setZIndex:(int)zIndex; -- (void)setGeodesic:(BOOL)isGeodesic; -@end - // Defines polyline controllable by Flutter. -@interface FLTGoogleMapPolylineController : NSObject -@property(atomic, readonly) NSString *polylineId; +@interface FLTGoogleMapPolylineController : NSObject - (instancetype)initPolylineWithPath:(GMSMutablePath *)path - polylineId:(NSString *)polylineId + identifier:(NSString *)identifier mapView:(GMSMapView *)mapView; - (void)removePolyline; @end @@ -31,7 +19,7 @@ registrar:(NSObject *)registrar; - (void)addPolylines:(NSArray *)polylinesToAdd; - (void)changePolylines:(NSArray *)polylinesToChange; -- (void)removePolylineIds:(NSArray *)polylineIdsToRemove; -- (void)onPolylineTap:(NSString *)polylineId; -- (bool)hasPolylineWithId:(NSString *)polylineId; +- (void)removePolylineWithIdentifiers:(NSArray *)identifiers; +- (void)didTapPolylineWithIdentifier:(NSString *)identifier; +- (bool)hasPolylineWithIdentifier:(NSString *)identifier; @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m index f366051b4af2..77601d4a1bb5 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapPolylineController.m @@ -3,39 +3,41 @@ // found in the LICENSE file. #import "GoogleMapPolylineController.h" -#import "JsonConversions.h" +#import "FLTGoogleMapJSONConversions.h" + +@interface FLTGoogleMapPolylineController () + +@property(strong, nonatomic) GMSPolyline *polyline; +@property(weak, nonatomic) GMSMapView *mapView; + +@end + +@implementation FLTGoogleMapPolylineController -@implementation FLTGoogleMapPolylineController { - GMSPolyline *_polyline; - GMSMapView *_mapView; -} - (instancetype)initPolylineWithPath:(GMSMutablePath *)path - polylineId:(NSString *)polylineId + identifier:(NSString *)identifier mapView:(GMSMapView *)mapView { self = [super init]; if (self) { _polyline = [GMSPolyline polylineWithPath:path]; _mapView = mapView; - _polylineId = polylineId; - _polyline.userData = @[ polylineId ]; + _polyline.userData = @[ identifier ]; } return self; } - (void)removePolyline { - _polyline.map = nil; + self.polyline.map = nil; } -#pragma mark - FLTGoogleMapPolylineOptionsSink methods - - (void)setConsumeTapEvents:(BOOL)consumes { - _polyline.tappable = consumes; + self.polyline.tappable = consumes; } - (void)setVisible:(BOOL)visible { - _polyline.map = visible ? _mapView : nil; + self.polyline.map = visible ? self.mapView : nil; } - (void)setZIndex:(int)zIndex { - _polyline.zIndex = zIndex; + self.polyline.zIndex = zIndex; } - (void)setPoints:(NSArray *)points { GMSMutablePath *path = [GMSMutablePath path]; @@ -43,75 +45,72 @@ - (void)setPoints:(NSArray *)points { for (CLLocation *location in points) { [path addCoordinate:location.coordinate]; } - _polyline.path = path; + self.polyline.path = path; } - (void)setColor:(UIColor *)color { - _polyline.strokeColor = color; + self.polyline.strokeColor = color; } - (void)setStrokeWidth:(CGFloat)width { - _polyline.strokeWidth = width; + self.polyline.strokeWidth = width; } - (void)setGeodesic:(BOOL)isGeodesic { - _polyline.geodesic = isGeodesic; + self.polyline.geodesic = isGeodesic; } -@end - -static int ToInt(NSNumber *data) { return [FLTGoogleMapJsonConversions toInt:data]; } - -static BOOL ToBool(NSNumber *data) { return [FLTGoogleMapJsonConversions toBool:data]; } - -static NSArray *ToPoints(NSArray *data) { - return [FLTGoogleMapJsonConversions toPoints:data]; -} - -static UIColor *ToColor(NSNumber *data) { return [FLTGoogleMapJsonConversions toColor:data]; } -static void InterpretPolylineOptions(NSDictionary *data, id sink, - NSObject *registrar) { +- (void)interpretPolylineOptions:(NSDictionary *)data + registrar:(NSObject *)registrar { NSNumber *consumeTapEvents = data[@"consumeTapEvents"]; - if (consumeTapEvents != nil) { - [sink setConsumeTapEvents:ToBool(consumeTapEvents)]; + if (consumeTapEvents && consumeTapEvents != (id)[NSNull null]) { + [self setConsumeTapEvents:[consumeTapEvents boolValue]]; } NSNumber *visible = data[@"visible"]; - if (visible != nil) { - [sink setVisible:ToBool(visible)]; + if (visible && visible != (id)[NSNull null]) { + [self setVisible:[visible boolValue]]; } NSNumber *zIndex = data[@"zIndex"]; - if (zIndex != nil) { - [sink setZIndex:ToInt(zIndex)]; + if (zIndex && zIndex != (id)[NSNull null]) { + [self setZIndex:[zIndex intValue]]; } NSArray *points = data[@"points"]; - if (points) { - [sink setPoints:ToPoints(points)]; + if (points && points != (id)[NSNull null]) { + [self setPoints:[FLTGoogleMapJSONConversions pointsFromLatLongs:points]]; } NSNumber *strokeColor = data[@"color"]; - if (strokeColor != nil) { - [sink setColor:ToColor(strokeColor)]; + if (strokeColor && strokeColor != (id)[NSNull null]) { + [self setColor:[FLTGoogleMapJSONConversions colorFromRGBA:strokeColor]]; } NSNumber *strokeWidth = data[@"width"]; - if (strokeWidth != nil) { - [sink setStrokeWidth:ToInt(strokeWidth)]; + if (strokeWidth && strokeWidth != (id)[NSNull null]) { + [self setStrokeWidth:[strokeWidth intValue]]; } NSNumber *geodesic = data[@"geodesic"]; - if (geodesic != nil) { - [sink setGeodesic:geodesic.boolValue]; + if (geodesic && geodesic != (id)[NSNull null]) { + [self setGeodesic:geodesic.boolValue]; } } -@implementation FLTPolylinesController { - NSMutableDictionary *_polylineIdToController; - FlutterMethodChannel *_methodChannel; - NSObject *_registrar; - GMSMapView *_mapView; -} +@end + +@interface FLTPolylinesController () + +@property(strong, nonatomic) NSMutableDictionary *polylineIdentifierToController; +@property(strong, nonatomic) FlutterMethodChannel *methodChannel; +@property(weak, nonatomic) NSObject *registrar; +@property(weak, nonatomic) GMSMapView *mapView; + +@end +; + +@implementation FLTPolylinesController + - (instancetype)init:(FlutterMethodChannel *)methodChannel mapView:(GMSMapView *)mapView registrar:(NSObject *)registrar { @@ -119,7 +118,7 @@ - (instancetype)init:(FlutterMethodChannel *)methodChannel if (self) { _methodChannel = methodChannel; _mapView = mapView; - _polylineIdToController = [NSMutableDictionary dictionaryWithCapacity:1]; + _polylineIdentifierToController = [NSMutableDictionary dictionaryWithCapacity:1]; _registrar = registrar; } return self; @@ -127,64 +126,59 @@ - (instancetype)init:(FlutterMethodChannel *)methodChannel - (void)addPolylines:(NSArray *)polylinesToAdd { for (NSDictionary *polyline in polylinesToAdd) { GMSMutablePath *path = [FLTPolylinesController getPath:polyline]; - NSString *polylineId = [FLTPolylinesController getPolylineId:polyline]; + NSString *identifier = polyline[@"polylineId"]; FLTGoogleMapPolylineController *controller = [[FLTGoogleMapPolylineController alloc] initPolylineWithPath:path - polylineId:polylineId - mapView:_mapView]; - InterpretPolylineOptions(polyline, controller, _registrar); - _polylineIdToController[polylineId] = controller; + identifier:identifier + mapView:self.mapView]; + [controller interpretPolylineOptions:polyline registrar:self.registrar]; + self.polylineIdentifierToController[identifier] = controller; } } - (void)changePolylines:(NSArray *)polylinesToChange { for (NSDictionary *polyline in polylinesToChange) { - NSString *polylineId = [FLTPolylinesController getPolylineId:polyline]; - FLTGoogleMapPolylineController *controller = _polylineIdToController[polylineId]; + NSString *identifier = polyline[@"polylineId"]; + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; if (!controller) { continue; } - InterpretPolylineOptions(polyline, controller, _registrar); + [controller interpretPolylineOptions:polyline registrar:self.registrar]; } } -- (void)removePolylineIds:(NSArray *)polylineIdsToRemove { - for (NSString *polylineId in polylineIdsToRemove) { - if (!polylineId) { - continue; - } - FLTGoogleMapPolylineController *controller = _polylineIdToController[polylineId]; +- (void)removePolylineWithIdentifiers:(NSArray *)identifiers { + for (NSString *identifier in identifiers) { + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; if (!controller) { continue; } [controller removePolyline]; - [_polylineIdToController removeObjectForKey:polylineId]; + [self.polylineIdentifierToController removeObjectForKey:identifier]; } } -- (void)onPolylineTap:(NSString *)polylineId { - if (!polylineId) { +- (void)didTapPolylineWithIdentifier:(NSString *)identifier { + if (!identifier) { return; } - FLTGoogleMapPolylineController *controller = _polylineIdToController[polylineId]; + FLTGoogleMapPolylineController *controller = self.polylineIdentifierToController[identifier]; if (!controller) { return; } - [_methodChannel invokeMethod:@"polyline#onTap" arguments:@{@"polylineId" : polylineId}]; + [self.methodChannel invokeMethod:@"polyline#onTap" arguments:@{@"polylineId" : identifier}]; } -- (bool)hasPolylineWithId:(NSString *)polylineId { - if (!polylineId) { +- (bool)hasPolylineWithIdentifier:(NSString *)identifier { + if (!identifier) { return false; } - return _polylineIdToController[polylineId] != nil; + return self.polylineIdentifierToController[identifier] != nil; } + (GMSMutablePath *)getPath:(NSDictionary *)polyline { NSArray *pointArray = polyline[@"points"]; - NSArray *points = ToPoints(pointArray); + NSArray *points = [FLTGoogleMapJSONConversions pointsFromLatLongs:pointArray]; GMSMutablePath *path = [GMSMutablePath path]; for (CLLocation *location in points) { [path addCoordinate:location.coordinate]; } return path; } -+ (NSString *)getPolylineId:(NSDictionary *)polyline { - return polyline[@"polylineId"]; -} + @end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h deleted file mode 100644 index c0f673ecd025..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.h +++ /dev/null @@ -1,19 +0,0 @@ -// 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 -#import - -@interface FLTGoogleMapJsonConversions : NSObject -+ (bool)toBool:(NSNumber *)data; -+ (int)toInt:(NSNumber *)data; -+ (double)toDouble:(NSNumber *)data; -+ (float)toFloat:(NSNumber *)data; -+ (CLLocationCoordinate2D)toLocation:(NSArray *)data; -+ (CGPoint)toPoint:(NSArray *)data; -+ (NSArray *)positionToJson:(CLLocationCoordinate2D)position; -+ (UIColor *)toColor:(NSNumber *)data; -+ (NSArray *)toPoints:(NSArray *)data; -+ (NSArray *> *)toHoles:(NSArray *)data; -@end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m deleted file mode 100644 index 0e88d4707489..000000000000 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/JsonConversions.m +++ /dev/null @@ -1,71 +0,0 @@ -// 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 "JsonConversions.h" - -@implementation FLTGoogleMapJsonConversions - -+ (bool)toBool:(NSNumber *)data { - return data.boolValue; -} - -+ (int)toInt:(NSNumber *)data { - return data.intValue; -} - -+ (double)toDouble:(NSNumber *)data { - return data.doubleValue; -} - -+ (float)toFloat:(NSNumber *)data { - return data.floatValue; -} - -+ (CLLocationCoordinate2D)toLocation:(NSArray *)data { - return CLLocationCoordinate2DMake([FLTGoogleMapJsonConversions toDouble:data[0]], - [FLTGoogleMapJsonConversions toDouble:data[1]]); -} - -+ (CGPoint)toPoint:(NSArray *)data { - return CGPointMake([FLTGoogleMapJsonConversions toDouble:data[0]], - [FLTGoogleMapJsonConversions toDouble:data[1]]); -} - -+ (NSArray *)positionToJson:(CLLocationCoordinate2D)position { - return @[ @(position.latitude), @(position.longitude) ]; -} - -+ (UIColor *)toColor:(NSNumber *)numberColor { - unsigned long value = [numberColor unsignedLongValue]; - return [UIColor colorWithRed:((float)((value & 0xFF0000) >> 16)) / 255.0 - green:((float)((value & 0xFF00) >> 8)) / 255.0 - blue:((float)(value & 0xFF)) / 255.0 - alpha:((float)((value & 0xFF000000) >> 24)) / 255.0]; -} - -+ (NSArray *)toPoints:(NSArray *)data { - NSMutableArray *points = [[NSMutableArray alloc] init]; - for (unsigned i = 0; i < [data count]; i++) { - NSNumber *latitude = data[i][0]; - NSNumber *longitude = data[i][1]; - CLLocation *point = - [[CLLocation alloc] initWithLatitude:[FLTGoogleMapJsonConversions toDouble:latitude] - longitude:[FLTGoogleMapJsonConversions toDouble:longitude]]; - [points addObject:point]; - } - - return points; -} - -+ (NSArray *> *)toHoles:(NSArray *)data { - NSMutableArray *> *holes = [[[NSMutableArray alloc] init] init]; - for (unsigned i = 0; i < [data count]; i++) { - NSArray *points = [FLTGoogleMapJsonConversions toPoints:data[i]]; - [holes addObject:points]; - } - - return holes; -} - -@end diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/google_maps_flutter-umbrella.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/google_maps_flutter-umbrella.h index 50880a2b9e9d..9969e716c26b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/google_maps_flutter-umbrella.h +++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/google_maps_flutter-umbrella.h @@ -3,9 +3,9 @@ // found in the LICENSE file. #import +#import #import #import -#import FOUNDATION_EXPORT double google_maps_flutterVersionNumber; FOUNDATION_EXPORT const unsigned char google_maps_flutterVersionString[]; diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 59ee23d0b260..215a930c91b9 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. repository: https://github.com/flutter/plugins/tree/main/packages/google_maps_flutter/google_maps_flutter issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.1.6 +version: 2.1.7 environment: sdk: ">=2.14.0 <3.0.0"