summaryrefslogtreecommitdiff
path: root/platform/ios/src/MGLMapView.mm
diff options
context:
space:
mode:
Diffstat (limited to 'platform/ios/src/MGLMapView.mm')
-rw-r--r--platform/ios/src/MGLMapView.mm258
1 files changed, 148 insertions, 110 deletions
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index fe3f12b152..2476ec3e97 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -221,10 +221,8 @@ public:
@interface MGLMapView () <UIGestureRecognizerDelegate,
GLKViewDelegate,
CLLocationManagerDelegate,
- UIActionSheetDelegate,
SMCalloutViewDelegate,
MGLCalloutViewDelegate,
- UIAlertViewDelegate,
MGLMultiPointDelegate,
MGLAnnotationImageDelegate>
@@ -237,7 +235,6 @@ public:
@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *logoViewConstraints;
@property (nonatomic, readwrite) UIButton *attributionButton;
@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints;
-@property (nonatomic) UIActionSheet *attributionSheet;
@property (nonatomic, readwrite) MGLStyle *style;
@property (nonatomic) UITapGestureRecognizer *singleTapGestureRecognizer;
@property (nonatomic) UITapGestureRecognizer *doubleTap;
@@ -315,8 +312,6 @@ public:
MGLCompassDirectionFormatter *_accessibilityCompassFormatter;
- NS_ARRAY_OF(MGLAttributionInfo *) *_attributionInfos;
-
MGLReachability *_reachability;
}
@@ -890,11 +885,6 @@ public:
_mbglMap->setSize([self size]);
}
- if (self.attributionSheet.visible)
- {
- [self.attributionSheet dismissWithClickedButtonIndex:self.attributionSheet.cancelButtonIndex animated:YES];
- }
-
if (self.compassView.alpha)
{
[self updateHeadingForDeviceOrientation];
@@ -1456,7 +1446,9 @@ public:
}
else
{
- nextElement = _annotationContextsByAnnotationTag[_selectedAnnotationTag].accessibilityElement;
+ if (_selectedAnnotationTag != MGLAnnotationTagNotFound) {
+ nextElement = _annotationContextsByAnnotationTag.at(_selectedAnnotationTag).accessibilityElement;
+ }
}
[self deselectAnnotation:self.selectedAnnotation animated:YES];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nextElement);
@@ -1875,82 +1867,108 @@ public:
- (void)showAttribution
{
- self.attributionSheet = [[UIActionSheet alloc] initWithTitle:NSLocalizedStringWithDefaultValue(@"SDK_NAME", nil, nil, @"Mapbox iOS SDK", @"Action sheet title")
- delegate:self
- cancelButtonTitle:NSLocalizedStringWithDefaultValue(@"CANCEL", nil, nil, @"Cancel", @"")
- destructiveButtonTitle:nil
- otherButtonTitles:nil];
-
- _attributionInfos = [self.style attributionInfosWithFontSize:[UIFont buttonFontSize] linkColor:nil];
- for (MGLAttributionInfo *info in _attributionInfos)
+ NSString *title = NSLocalizedStringWithDefaultValue(@"SDK_NAME", nil, nil, @"Mapbox iOS SDK", @"Action sheet title");
+ UIAlertController *attributionController = [UIAlertController alertControllerWithTitle:title
+ message:nil
+ preferredStyle:UIAlertControllerStyleActionSheet];
+
+ NSArray *attributionInfos = [self.style attributionInfosWithFontSize:[UIFont buttonFontSize]
+ linkColor:nil];
+ for (MGLAttributionInfo *info in attributionInfos)
{
NSString *title = [info.title.string mgl_titleCasedStringWithLocale:[NSLocale currentLocale]];
- [self.attributionSheet addButtonWithTitle:title];
- }
-
- [self.attributionSheet addButtonWithTitle:NSLocalizedStringWithDefaultValue(@"TELEMETRY_NAME", nil, nil, @"Mapbox Telemetry", @"Action in attribution sheet")];
-
- [self.attributionSheet showFromRect:self.attributionButton.frame inView:self animated:YES];
-}
-
-- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
-{
- if (buttonIndex == actionSheet.numberOfButtons - 1)
- {
- NSString *message;
- NSString *participate;
- NSString *optOut;
-
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsEnabled"])
- {
- message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_MSG", nil, nil, @"You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message");
- participate = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_ON", nil, nil, @"Keep Participating", @"Telemetry prompt button");
- optOut = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_OFF", nil, nil, @"Stop Participating", @"Telemetry prompt button");
- }
- else
- {
- message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_MSG", nil, nil, @"You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message");
- participate = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_ON", nil, nil, @"Participate", @"Telemetry prompt button");
- optOut = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_OFF", nil, nil, @"Don’t Participate", @"Telemetry prompt button");
- }
-
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedStringWithDefaultValue(@"TELEMETRY_TITLE", nil, nil, @"Make Mapbox Maps Better", @"Telemetry prompt title")
- message:message
- delegate:self
- cancelButtonTitle:participate
- otherButtonTitles:NSLocalizedStringWithDefaultValue(@"TELEMETRY_MORE", nil, nil, @"Tell Me More", @"Telemetry prompt button"), optOut, nil];
- [alert show];
- }
- else if (buttonIndex > 0)
- {
- MGLAttributionInfo *info = _attributionInfos[buttonIndex + actionSheet.firstOtherButtonIndex];
- NSURL *url = info.URL;
- if (url)
- {
- if (info.feedbackLink)
+ UIAlertAction *action = [UIAlertAction actionWithTitle:title
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction * _Nonnull action) {
+ NSURL *url = info.URL;
+ if (url)
{
- url = [info feedbackURLAtCenterCoordinate:self.centerCoordinate zoomLevel:self.zoomLevel];
+ if (info.feedbackLink)
+ {
+ url = [info feedbackURLAtCenterCoordinate:self.centerCoordinate
+ zoomLevel:self.zoomLevel];
+ }
+ [[UIApplication sharedApplication] openURL:url];
}
- [[UIApplication sharedApplication] openURL:url];
- }
+ }];
+ [attributionController addAction:action];
}
+
+ NSString *telemetryTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_NAME", nil, nil, @"Mapbox Telemetry", @"Action in attribution sheet");
+ UIAlertAction *telemetryAction = [UIAlertAction actionWithTitle:telemetryTitle
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction * _Nonnull action) {
+ [self presentTelemetryAlertController];
+ }];
+ [attributionController addAction:telemetryAction];
+
+ NSString *cancelTitle = NSLocalizedStringWithDefaultValue(@"CANCEL", nil, nil, @"Cancel", @"");
+ UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelTitle
+ style:UIAlertActionStyleCancel
+ handler:NULL];
+ [attributionController addAction:cancelAction];
+
+ attributionController.popoverPresentationController.sourceView = self;
+ attributionController.popoverPresentationController.sourceRect = self.attributionButton.frame;
+
+ UIViewController *viewController = self.window.rootViewController;
+ if ([viewController isKindOfClass:[UINavigationController class]]) {
+ viewController = [(UINavigationController *)viewController viewControllers].firstObject;
+ }
+ [viewController presentViewController:attributionController
+ animated:YES
+ completion:NULL];
}
-- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
+- (void)presentTelemetryAlertController
{
- if (buttonIndex == alertView.cancelButtonIndex)
+ NSString *title = NSLocalizedStringWithDefaultValue(@"TELEMETRY_TITLE", nil, nil, @"Make Mapbox Maps Better", @"Telemetry prompt title");
+ NSString *message;
+ NSString *participateTitle;
+ NSString *declineTitle;
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsEnabled"])
{
- [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"MGLMapboxMetricsEnabled"];
+ message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_MSG", nil, nil, @"You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message");
+ participateTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_ON", nil, nil, @"Keep Participating", @"Telemetry prompt button");
+ declineTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_OFF", nil, nil, @"Stop Participating", @"Telemetry prompt button");
}
- else if (buttonIndex == alertView.firstOtherButtonIndex)
+ else
{
+ message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_MSG", nil, nil, @"You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message");
+ participateTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_ON", nil, nil, @"Participate", @"Telemetry prompt button");
+ declineTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_OFF", nil, nil, @"Don’t Participate", @"Telemetry prompt button");
+ }
+
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title
+ message:message
+ preferredStyle:UIAlertControllerStyleAlert];
+
+ NSString *moreTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_MORE", nil, nil, @"Tell Me More", @"Telemetry prompt button");
+ UIAlertAction *moreAction = [UIAlertAction actionWithTitle:moreTitle
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction * _Nonnull action) {
[[UIApplication sharedApplication] openURL:
[NSURL URLWithString:@"https://www.mapbox.com/telemetry/"]];
- }
- else if (buttonIndex == alertView.firstOtherButtonIndex + 1)
- {
+ }];
+ [alertController addAction:moreAction];
+
+ UIAlertAction *declineAction = [UIAlertAction actionWithTitle:declineTitle
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction * _Nonnull action) {
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"MGLMapboxMetricsEnabled"];
- }
+ }];
+ [alertController addAction:declineAction];
+
+ UIAlertAction *participateAction = [UIAlertAction actionWithTitle:participateTitle
+ style:UIAlertActionStyleCancel
+ handler:^(UIAlertAction * _Nonnull action) {
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"MGLMapboxMetricsEnabled"];
+ }];
+ [alertController addAction:participateAction];
+
+ [self.window.rootViewController presentViewController:alertController
+ animated:YES
+ completion:NULL];
}
#pragma mark - Properties -
@@ -1980,19 +1998,21 @@ public:
{
const mbgl::Point<double> point = MGLPointFromLocationCoordinate2D(annotation.coordinate);
- MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
- if (annotationContext.annotationView)
- {
- // Redundantly move the associated annotation view outside the scope of the animation-less transaction block in -updateAnnotationViews.
- annotationContext.annotationView.center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self];
- }
+ if (annotationTag != MGLAnnotationTagNotFound) {
+ MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
+ if (annotationContext.annotationView)
+ {
+ // Redundantly move the associated annotation view outside the scope of the animation-less transaction block in -updateAnnotationViews.
+ annotationContext.annotationView.center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self];
+ }
- MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
- NSString *symbolName = annotationImage.styleIconIdentifier;
+ MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
+ NSString *symbolName = annotationImage.styleIconIdentifier;
- // Update the annotation’s backing geometry to match the annotation model object. Any associated annotation view is also moved by side effect. However, -updateAnnotationViews disables the view’s animation actions, because it can’t distinguish between moves due to the viewport changing and moves due to the annotation’s coordinate changing.
- _mbglMap->updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, symbolName.UTF8String });
- [self updateCalloutView];
+ // Update the annotation’s backing geometry to match the annotation model object. Any associated annotation view is also moved by side effect. However, -updateAnnotationViews disables the view’s animation actions, because it can’t distinguish between moves due to the viewport changing and moves due to the annotation’s coordinate changing.
+ _mbglMap->updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, symbolName.UTF8String });
+ [self updateCalloutView];
+ }
}
}
else if ([keyPath isEqualToString:@"coordinates"] && [object isKindOfClass:[MGLMultiPoint class]])
@@ -3068,12 +3088,18 @@ public:
for (auto const& annotationTag: annotationTags)
{
- if (!_annotationContextsByAnnotationTag.count(annotationTag))
+ if (!_annotationContextsByAnnotationTag.count(annotationTag) ||
+ annotationTag == MGLAnnotationTagNotFound)
{
continue;
}
+
MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
- [annotations addObject:annotationContext.annotation];
+ NSAssert(annotationContext.annotation, @"Missing annotation for tag %u.", annotationTag);
+ if (annotationContext.annotation)
+ {
+ [annotations addObject:annotationContext.annotation];
+ }
}
return [annotations copy];
@@ -3085,12 +3111,12 @@ public:
/// Returns the annotation assigned the given tag. Cheap.
- (id <MGLAnnotation>)annotationWithTag:(MGLAnnotationTag)tag
{
- if ( ! _annotationContextsByAnnotationTag.count(tag))
- {
+ if ( ! _annotationContextsByAnnotationTag.count(tag) ||
+ tag == MGLAnnotationTagNotFound) {
return nil;
}
- MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag[tag];
+ MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
return annotationContext.annotation;
}
@@ -3560,8 +3586,12 @@ public:
{
id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
NSAssert(annotation, @"Unknown annotation found nearby tap");
+ if ( ! annotation)
+ {
+ return true;
+ }
- MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag[annotationTag];
+ MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
CGRect annotationRect;
MGLAnnotationView *annotationView = annotationContext.annotationView;
@@ -3684,10 +3714,12 @@ public:
{
return self.userLocation;
}
- if ( ! _annotationContextsByAnnotationTag.count(_selectedAnnotationTag))
- {
+
+ if ( ! _annotationContextsByAnnotationTag.count(_selectedAnnotationTag) ||
+ _selectedAnnotationTag == MGLAnnotationTagNotFound) {
return nil;
}
+
MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(_selectedAnnotationTag);
return annotationContext.annotation;
}
@@ -3753,19 +3785,16 @@ public:
MGLAnnotationView *annotationView = nil;
if (annotation != self.userLocation)
- {
- MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
-
- annotationView = annotationContext.annotationView;
-
- if (annotationView && annotationView.enabled)
- {
- // Annotations represented by views use the view frame as the positioning rect.
- positioningRect = annotationView.frame;
-
- [annotationView.superview bringSubviewToFront:annotationView];
-
- [annotationView setSelected:YES animated:animated];
+ if (annotationTag != MGLAnnotationTagNotFound) {
+ MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
+ annotationView = annotationContext.annotationView;
+ if (annotationView && annotationView.enabled) {
+ {
+ // Annotations represented by views use the view frame as the positioning rect.
+ positioningRect = annotationView.frame;
+ [annotationView.superview bringSubviewToFront:annotationView];
+ [annotationView setSelected:YES animated:animated];
+ }
}
}
@@ -3787,7 +3816,14 @@ public:
UIView <MGLCalloutView> *calloutView;
if ([self.delegate respondsToSelector:@selector(mapView:calloutViewForAnnotation:)])
{
- calloutView = [self.delegate mapView:self calloutViewForAnnotation:annotation];
+ id providedCalloutView = [self.delegate mapView:self calloutViewForAnnotation:annotation];
+ if (providedCalloutView) {
+ if (![providedCalloutView isKindOfClass:[UIView class]]) {
+ [NSException raise:NSInvalidArgumentException format:@"Callout view must be a kind of UIView"];
+ }
+ NSAssert([providedCalloutView conformsToProtocol:@protocol(MGLCalloutView)], @"callout view must conform to MGLCalloutView");
+ calloutView = providedCalloutView;
+ }
}
if (!calloutView)
{
@@ -3868,8 +3904,6 @@ public:
/// and is appropriate for positioning a popover.
- (CGRect)positioningRectForCalloutForAnnotationWithTag:(MGLAnnotationTag)annotationTag
{
- MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag[annotationTag];
-
id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
if ( ! annotation)
{
@@ -5048,8 +5082,12 @@ public:
if (isAnchoredToAnnotation)
{
MGLAnnotationTag tag = [self annotationTagForAnnotation:annotation];
- MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
- MGLAnnotationView *annotationView = annotationContext.annotationView;
+ MGLAnnotationView *annotationView = nil;
+
+ if (tag != MGLAnnotationTagNotFound) {
+ MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
+ annotationView = annotationContext.annotationView;
+ }
CGRect rect = [self positioningRectForCalloutForAnnotationWithTag:tag];