diff options
author | Minh Nguyễn <mxn@1ec5.org> | 2017-01-16 11:38:35 -0800 |
---|---|---|
committer | Minh Nguyễn <mxn@1ec5.org> | 2017-01-16 11:38:35 -0800 |
commit | 7ef2843e6a62116667be6a2c12de085951fdd5ea (patch) | |
tree | 40eca249e044e2706efd1193d617e6eb8e59d708 /platform/ios/src | |
parent | 76301b252cbc4bc3ae1fc84322bcbcdbd26cae8a (diff) | |
parent | 13b97dd0cebffe36b187bdb74923910def6bd87b (diff) | |
download | qtlocation-mapboxgl-7ef2843e6a62116667be6a2c12de085951fdd5ea.tar.gz |
Merge branch 'release-ios-v3.4.0' into 1ec5-release-ios-v3.4.0-beta.7
Diffstat (limited to 'platform/ios/src')
-rw-r--r-- | platform/ios/src/MGLAPIClient.h | 1 | ||||
-rw-r--r-- | platform/ios/src/MGLAPIClient.m | 11 | ||||
-rw-r--r-- | platform/ios/src/MGLAnnotationImage.h | 2 | ||||
-rw-r--r-- | platform/ios/src/MGLAnnotationImage.m | 35 | ||||
-rw-r--r-- | platform/ios/src/MGLAnnotationView.h | 2 | ||||
-rw-r--r-- | platform/ios/src/MGLAnnotationView.mm | 28 | ||||
-rw-r--r-- | platform/ios/src/MGLCalloutView.h | 18 | ||||
-rw-r--r-- | platform/ios/src/MGLCompactCalloutView.m | 8 | ||||
-rw-r--r-- | platform/ios/src/MGLMapView.h | 9 | ||||
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 89 | ||||
-rw-r--r-- | platform/ios/src/MGLMapViewDelegate.h | 17 | ||||
-rw-r--r-- | platform/ios/src/MGLMapView_Private.h | 6 | ||||
-rw-r--r-- | platform/ios/src/MGLMapboxEvents.m | 71 | ||||
-rw-r--r-- | platform/ios/src/MGLUserLocation.h | 2 | ||||
-rw-r--r-- | platform/ios/src/MGLUserLocation.m | 38 | ||||
-rw-r--r-- | platform/ios/src/Mapbox.h | 1 |
16 files changed, 236 insertions, 102 deletions
diff --git a/platform/ios/src/MGLAPIClient.h b/platform/ios/src/MGLAPIClient.h index 0f8926d360..4e5ea3b5e0 100644 --- a/platform/ios/src/MGLAPIClient.h +++ b/platform/ios/src/MGLAPIClient.h @@ -9,7 +9,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)postEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler; - (void)postEvent:(MGLMapboxEventAttributes *)event completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler; -- (void)cancelAll; @end diff --git a/platform/ios/src/MGLAPIClient.m b/platform/ios/src/MGLAPIClient.m index 7fb6538e5d..5e8ee5fe1d 100644 --- a/platform/ios/src/MGLAPIClient.m +++ b/platform/ios/src/MGLAPIClient.m @@ -21,7 +21,6 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST"; @property (nonatomic, copy) NSData *geoTrustCert; @property (nonatomic, copy) NSData *testServerCert; @property (nonatomic, copy) NSString *userAgent; -@property (nonatomic) NSMutableArray *dataTasks; @property (nonatomic) BOOL usesTestServer; @end @@ -33,7 +32,6 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST"; if (self) { _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil]; - _dataTasks = [NSMutableArray array]; [self loadCertificates]; [self setupBaseURL]; [self setupUserAgent]; @@ -59,24 +57,15 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST"; error = error ?: statusError; completionHandler(error); } - [self.dataTasks removeObject:dataTask]; dataTask = nil; }]; [dataTask resume]; - if (dataTask) { - [self.dataTasks addObject:dataTask]; - } } - (void)postEvent:(nonnull MGLMapboxEventAttributes *)event completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler { [self postEvents:@[event] completionHandler:completionHandler]; } -- (void)cancelAll { - [self.dataTasks makeObjectsPerformSelector:@selector(cancel)]; - [self.dataTasks removeAllObjects]; -} - #pragma mark Utilities - (NSURLRequest *)requestForEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events { diff --git a/platform/ios/src/MGLAnnotationImage.h b/platform/ios/src/MGLAnnotationImage.h index a7003d7f91..95bce21f51 100644 --- a/platform/ios/src/MGLAnnotationImage.h +++ b/platform/ios/src/MGLAnnotationImage.h @@ -8,7 +8,7 @@ NS_ASSUME_NONNULL_BEGIN objects and may be recycled later and put into a reuse queue that is maintained by the map view. */ -@interface MGLAnnotationImage : NSObject +@interface MGLAnnotationImage : NSObject <NSSecureCoding> #pragma mark Initializing and Preparing the Image Object diff --git a/platform/ios/src/MGLAnnotationImage.m b/platform/ios/src/MGLAnnotationImage.m index e1085be98d..9c9c175ab9 100644 --- a/platform/ios/src/MGLAnnotationImage.m +++ b/platform/ios/src/MGLAnnotationImage.m @@ -30,6 +30,41 @@ return self; } ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (instancetype)initWithCoder:(NSCoder *)decoder { + if (self = [super init]) { + _image = [decoder decodeObjectOfClass:[UIImage class] forKey:@"image"]; + _reuseIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"reuseIdentifier"]; + _enabled = [decoder decodeBoolForKey:@"enabled"]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:_image forKey:@"image"]; + [coder encodeObject:_reuseIdentifier forKey:@"reuseIdentifier"]; + [coder encodeBool:_enabled forKey:@"enabled"]; +} + +- (BOOL)isEqual:(id)other { + if (self == other) return YES; + if (![other isKindOfClass:[MGLAnnotationImage class]]) return NO; + + MGLAnnotationImage *otherAnnotationImage = other; + + return ((!_reuseIdentifier && !otherAnnotationImage.reuseIdentifier) + || [_reuseIdentifier isEqualToString:otherAnnotationImage.reuseIdentifier]) + && _enabled == otherAnnotationImage.enabled + && (_image == otherAnnotationImage.image || [UIImagePNGRepresentation(_image) isEqualToData:UIImagePNGRepresentation(otherAnnotationImage.image)]); +} + +- (NSUInteger)hash { + return _reuseIdentifier.hash + _enabled + _image.hash; +} + - (void)setImage:(UIImage *)image { _image = image; [self.delegate annotationImageNeedsRedisplay:self]; diff --git a/platform/ios/src/MGLAnnotationView.h b/platform/ios/src/MGLAnnotationView.h index 634e9ad723..d159976a4c 100644 --- a/platform/ios/src/MGLAnnotationView.h +++ b/platform/ios/src/MGLAnnotationView.h @@ -50,7 +50,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) { interactivity such as dragging, you can use an `MGLAnnotationImage` instead to conserve memory and optimize drawing performance. */ -@interface MGLAnnotationView : UIView +@interface MGLAnnotationView : UIView <NSSecureCoding> #pragma mark Initializing and Preparing the View diff --git a/platform/ios/src/MGLAnnotationView.mm b/platform/ios/src/MGLAnnotationView.mm index 96ed8c733e..d2243bdf23 100644 --- a/platform/ios/src/MGLAnnotationView.mm +++ b/platform/ios/src/MGLAnnotationView.mm @@ -33,6 +33,34 @@ return self; } ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (instancetype)initWithCoder:(NSCoder *)decoder { + if (self = [super initWithCoder:decoder]) { + _reuseIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"reuseIdentifier"]; + _annotation = [decoder decodeObjectOfClass:[NSObject class] forKey:@"annotation"]; + _centerOffset = [decoder decodeCGVectorForKey:@"centerOffset"]; + _scalesWithViewingDistance = [decoder decodeBoolForKey:@"scalesWithViewingDistance"]; + _selected = [decoder decodeBoolForKey:@"selected"]; + _enabled = [decoder decodeBoolForKey:@"enabled"]; + self.draggable = [decoder decodeBoolForKey:@"draggable"]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [super encodeWithCoder:coder]; + [coder encodeObject:_reuseIdentifier forKey:@"reuseIdentifier"]; + [coder encodeObject:_annotation forKey:@"annotation"]; + [coder encodeCGVector:_centerOffset forKey:@"centerOffset"]; + [coder encodeBool:_scalesWithViewingDistance forKey:@"scalesWithViewingDistance"]; + [coder encodeBool:_selected forKey:@"selected"]; + [coder encodeBool:_enabled forKey:@"enabled"]; + [coder encodeBool:_draggable forKey:@"draggable"]; +} + - (void)prepareForReuse { // Intentionally left blank. The default implementation of this method does nothing. diff --git a/platform/ios/src/MGLCalloutView.h b/platform/ios/src/MGLCalloutView.h index 6918aad614..4dc9a25be4 100644 --- a/platform/ios/src/MGLCalloutView.h +++ b/platform/ios/src/MGLCalloutView.h @@ -46,6 +46,24 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)dismissCalloutAnimated:(BOOL)animated; +@optional + +/** + A Boolean value indicating whether the callout view should be anchored to + the corresponding annotation. You can adjust the callout view’s precise location by + overriding -[UIView setCenter:]. The callout view will not be anchored to the + annotation if this optional property is unimplemented. + */ +@property (nonatomic, readonly, assign, getter=isAnchoredToAnnotation) BOOL anchoredToAnnotation; + +/** + A Boolean value indicating whether the callout view should be dismissed automatically + when the map view’s viewport changes. Note that a single tap on the map view + still dismisses the callout view regardless of the value of this property. + The callout view will be dismissed if this optional property is unimplemented. + */ +@property (nonatomic, readonly, assign) BOOL dismissesAutomatically; + @end /** diff --git a/platform/ios/src/MGLCompactCalloutView.m b/platform/ios/src/MGLCompactCalloutView.m index 49812c51a4..3d2118ca38 100644 --- a/platform/ios/src/MGLCompactCalloutView.m +++ b/platform/ios/src/MGLCompactCalloutView.m @@ -14,6 +14,14 @@ return [[self alloc] init]; } +- (BOOL)isAnchoredToAnnotation { + return YES; +} + +- (BOOL)dismissesAutomatically { + return NO; +} + - (void)setRepresentedObject:(id <MGLAnnotation>)representedObject { _representedObject = representedObject; diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index 771a48c7ff..62f053e96b 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -123,6 +123,13 @@ IB_DESIGNABLE Unlike the `styleURL` property, this property is set to an object that allows you to manipulate every aspect of the style locally. + If the style is loading, this property is set to `nil` until the style finishes + loading. If the style has failed to load, this property is set to `nil`. + Because the style loads asynchronously, you should manipulate it in the + `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or + `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` method. It is not possible + to manipulate the style before it has finished loading. + @note The default styles provided by Mapbox contain sources and layers with identifiers that will change over time. Applications that use APIs that manipulate a style's sources and layers must first set the style URL to an @@ -130,7 +137,7 @@ IB_DESIGNABLE `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL” inspectable in Interface Builder, or a manually constructed `NSURL`. */ -@property (nonatomic, readonly) MGLStyle *style; +@property (nonatomic, readonly, nullable) MGLStyle *style; /** URLs of the styles bundled with the library. diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 608acf016d..c211d4419b 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -7,6 +7,7 @@ #import <GLKit/GLKit.h> #import <OpenGLES/EAGL.h> +#include <mbgl/map/map.hpp> #include <mbgl/map/view.hpp> #include <mbgl/annotation/annotation.hpp> #include <mbgl/sprite/sprite_image.hpp> @@ -347,6 +348,11 @@ public: return self; } ++ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyle +{ + return [NSSet setWithObject:@"styleURL"]; +} + + (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL { return [NSSet setWithObjects:@"styleURL__", nil]; @@ -369,10 +375,8 @@ public: } styleURL = styleURL.mgl_URLByStandardizingScheme; - [self willChangeValueForKey:@"style"]; - _style = [[MGLStyle alloc] initWithMapView:self]; + self.style = nil; _mbglMap->setStyleURL([[styleURL absoluteString] UTF8String]); - [self didChangeValueForKey:@"style"]; } - (IBAction)reloadStyle:(__unused id)sender { @@ -1734,7 +1738,7 @@ public: _attributionInfos = [self.style attributionInfosWithFontSize:[UIFont buttonFontSize] linkColor:nil]; for (MGLAttributionInfo *info in _attributionInfos) { - NSString *title = [info.title.string capitalizedStringWithLocale:[NSLocale currentLocale]]; + NSString *title = [info.title.string mgl_titleCasedStringWithLocale:[NSLocale currentLocale]]; [self.attributionSheet addButtonWithTitle:title]; } @@ -3137,23 +3141,9 @@ public: - (double)alphaForShapeAnnotation:(MGLShape *)annotation { - // The explicit -mapView:alphaForShapeAnnotation: delegate method is deprecated - // but still used, if implemented. When not implemented, call the stroke or - // fill color delegate methods and pull the alpha from the returned color. if (_delegateHasAlphasForShapeAnnotations) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" return [self.delegate mapView:self alphaForShapeAnnotation:annotation]; -#pragma clang diagnostic pop - } - else if ([annotation isKindOfClass:[MGLPolygon class]]) - { - return [self fillColorForPolygonAnnotation:(MGLPolygon *)annotation].a ?: 1.0; - } - else if ([annotation isKindOfClass:[MGLShape class]]) - { - return [self strokeColorForShapeAnnotation:annotation].a ?: 1.0; } return 1.0; } @@ -4566,21 +4556,34 @@ public: || self.userTrackingMode == MGLUserTrackingModeNone || self.userTrackingState != MGLUserTrackingStateChanged) { - // Deselect annotation if it lies outside the viewport - if (self.selectedAnnotation) { - MGLAnnotationTag tag = [self annotationTagForAnnotation:self.selectedAnnotation]; - MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag); - MGLAnnotationView *annotationView = annotationContext.annotationView; - - CGRect rect = [self positioningRectForCalloutForAnnotationWithTag:tag]; - - if (annotationView) - { - rect = annotationView.frame; - } - - if ( ! CGRectIntersectsRect(rect, self.frame)) { - [self deselectAnnotation:self.selectedAnnotation animated:NO]; + UIView<MGLCalloutView> *calloutView = self.calloutViewForSelectedAnnotation; + BOOL dismissesAutomatically = (calloutView + && [calloutView respondsToSelector:@selector(dismissesAutomatically)] + && calloutView.dismissesAutomatically); + // dismissesAutomatically is an optional property and we want to dismiss + // the callout view if it's unimplemented. + if (dismissesAutomatically || ![calloutView respondsToSelector:@selector(dismissesAutomatically)]) + { + [self deselectAnnotation:self.selectedAnnotation animated:NO]; + } + else + { + // Deselect annotation if it lies outside the viewport + if (self.selectedAnnotation) { + MGLAnnotationTag tag = [self annotationTagForAnnotation:self.selectedAnnotation]; + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag); + MGLAnnotationView *annotationView = annotationContext.annotationView; + + CGRect rect = [self positioningRectForCalloutForAnnotationWithTag:tag]; + + if (annotationView) + { + rect = annotationView.frame; + } + + if ( ! CGRectIntersectsRect(rect, self.frame)) { + [self deselectAnnotation:self.selectedAnnotation animated:NO]; + } } } } @@ -4690,11 +4693,7 @@ public: } case mbgl::MapChangeDidFinishLoadingStyle: { - [self.style willChangeValueForKey:@"name"]; - [self.style willChangeValueForKey:@"sources"]; - [self.style didChangeValueForKey:@"sources"]; - [self.style willChangeValueForKey:@"layers"]; - [self.style didChangeValueForKey:@"layers"]; + self.style = [[MGLStyle alloc] initWithMapView:self]; if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)]) { [self.delegate mapView:self didFinishLoadingStyle:self.style]; @@ -4805,7 +4804,12 @@ public: else { CGRect adjustedFrame = annotationView.frame; - adjustedFrame.origin.x = CGRectGetWidth(annotationView.layer.presentationLayer.frame) * -2.0; + if (annotationView.layer.presentationLayer) { + adjustedFrame.origin.x = -CGRectGetWidth(annotationView.layer.presentationLayer.frame) * 10.0; + } else { + // views that are added off screen do not have a presentationLayer + adjustedFrame.origin.x = -CGRectGetWidth(adjustedFrame) * 10.0; + } annotationView.frame = adjustedFrame; [self enqueueAnnotationViewForAnnotationContext:annotationContext]; } @@ -4820,7 +4824,12 @@ public: UIView <MGLCalloutView> *calloutView = self.calloutViewForSelectedAnnotation; id <MGLAnnotation> annotation = calloutView.representedObject; - if (calloutView && annotation) + BOOL isAnchoredToAnnotation = (calloutView + && annotation + && [calloutView respondsToSelector:@selector(isAnchoredToAnnotation)] + && calloutView.isAnchoredToAnnotation); + + if (isAnchoredToAnnotation) { MGLAnnotationTag tag = [self annotationTagForAnnotation:annotation]; MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag); diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h index 777af4ba63..09e2465a28 100644 --- a/platform/ios/src/MGLMapViewDelegate.h +++ b/platform/ios/src/MGLMapViewDelegate.h @@ -228,7 +228,22 @@ NS_ASSUME_NONNULL_BEGIN */ - (nullable MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id <MGLAnnotation>)annotation; -- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation __attribute__((deprecated("Use -mapView:strokeColorForShapeAnnotation: or -mapView:fillColorForPolygonAnnotation:."))); +/** + Returns the alpha value to use when rendering a shape annotation. + + A value of `0.0` results in a completely transparent shape. A value of `1.0`, + the default, results in a completely opaque shape. + + This method sets the opacity of an entire shape, inclusive of its stroke and + fill. To independently set the values for stroke or fill, specify an alpha + component in the color returned by `-mapView:strokeColorForShapeAnnotation:` or + `-mapView:fillColorForPolygonAnnotation:`. + + @param mapView The map view rendering the shape annotation. + @param annotation The annotation being rendered. + @return An alpha value between `0` and `1.0`. + */ +- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(MGLShape *)annotation; /** Returns the color to use when rendering the outline of a shape annotation. diff --git a/platform/ios/src/MGLMapView_Private.h b/platform/ios/src/MGLMapView_Private.h index 6b6a898f93..4e2765377c 100644 --- a/platform/ios/src/MGLMapView_Private.h +++ b/platform/ios/src/MGLMapView_Private.h @@ -1,11 +1,13 @@ #import <Mapbox/Mapbox.h> -#import <mbgl/map/map.hpp> +namespace mbgl { + class Map; +} /// Minimum size of an annotation’s accessibility element. extern const CGSize MGLAnnotationAccessibilityElementMinimumSize; -@interface MGLMapView (Internal) +@interface MGLMapView (Private) /// Currently shown popover representing the selected annotation. @property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation; diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m index 2c25cf0a62..744b80047b 100644 --- a/platform/ios/src/MGLMapboxEvents.m +++ b/platform/ios/src/MGLMapboxEvents.m @@ -278,6 +278,7 @@ const NSTimeInterval MGLFlushInterval = 180; if (self.paused && enabled) { [self resumeMetricsCollection]; } else if (!self.paused && !enabled) { + [self flush]; [self pauseMetricsCollection]; } } @@ -434,25 +435,31 @@ const NSTimeInterval MGLFlushInterval = 180; } - (MGLMapboxEventAttributes *)locationEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - MGLMutableMapboxEventAttributes *attributes = [@{MGLEventKeyEvent: MGLEventTypeLocation, - MGLEventKeySource: MGLEventSource, - MGLEventKeySessionId: self.instanceID, - MGLEventKeyOperatingSystem: self.data.iOSVersion} mutableCopy]; - [self addApplicationStateToAttributes:attributes]; + MGLMutableMapboxEventAttributes *attributes = [NSMutableDictionary dictionary]; + attributes[MGLEventKeyEvent] = MGLEventTypeLocation; + attributes[MGLEventKeySource] = MGLEventSource; + attributes[MGLEventKeySessionId] = self.instanceID; + attributes[MGLEventKeyOperatingSystem] = self.data.iOSVersion; + NSString *currentApplicationState = [self applicationState]; + if (![currentApplicationState isEqualToString:MGLApplicationStateUnknown]) { + attributes[MGLEventKeyApplicationState] = currentApplicationState; + } + return [self eventForAttributes:attributes attributeDictionary:attributeDictionary]; } - (MGLMapboxEventAttributes *)mapLoadEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary { - MGLMutableMapboxEventAttributes *attributes = [@{MGLEventKeyEvent: MGLEventTypeMapLoad, - MGLEventKeyCreated: [self.rfc3339DateFormatter stringFromDate:[NSDate date]], - MGLEventKeyVendorID: self.data.vendorId, - MGLEventKeyModel: self.data.model, - MGLEventKeyOperatingSystem: self.data.iOSVersion, - MGLEventKeyResolution: @(self.data.scale), - MGLEventKeyAccessibilityFontScale: @([self contentSizeScale]), - MGLEventKeyOrientation: [self deviceOrientation], - MGLEventKeyWifi: @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi])} mutableCopy]; - [self addBatteryStateToAttributes:attributes]; + MGLMutableMapboxEventAttributes *attributes = [NSMutableDictionary dictionary]; + attributes[MGLEventKeyEvent] = MGLEventTypeMapLoad; + attributes[MGLEventKeyCreated] = [self.rfc3339DateFormatter stringFromDate:[NSDate date]]; + attributes[MGLEventKeyVendorID] = self.data.vendorId; + attributes[MGLEventKeyModel] = self.data.model; + attributes[MGLEventKeyOperatingSystem] = self.data.iOSVersion; + attributes[MGLEventKeyResolution] = @(self.data.scale); + attributes[MGLEventKeyAccessibilityFontScale] = @([self contentSizeScale]); + attributes[MGLEventKeyOrientation] = [self deviceOrientation]; + attributes[MGLEventKeyWifi] = @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi]); + return [self eventForAttributes:attributes attributeDictionary:attributeDictionary]; } @@ -465,19 +472,22 @@ const NSTimeInterval MGLFlushInterval = 180; - (MGLMapboxEventAttributes *)mapDragEndEventWithAttributes:(MGLMapboxEventAttributes *)attributeDictionary { MGLMutableMapboxEventAttributes *attributes = [self interactionEvent]; attributes[MGLEventKeyEvent] = MGLEventTypeMapDragEnd; + return [self eventForAttributes:attributes attributeDictionary:attributeDictionary]; } - (MGLMutableMapboxEventAttributes *)interactionEvent { - MGLMutableMapboxEventAttributes *attributes = [@{MGLEventKeyCreated: [self.rfc3339DateFormatter stringFromDate:[NSDate date]], - MGLEventKeyOrientation: [self deviceOrientation], - MGLEventKeyWifi: @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi])} mutableCopy]; - [self addBatteryStateToAttributes:attributes]; + MGLMutableMapboxEventAttributes *attributes = [NSMutableDictionary dictionary]; + attributes[MGLEventKeyCreated] = [self.rfc3339DateFormatter stringFromDate:[NSDate date]]; + attributes[MGLEventKeyOrientation] = [self deviceOrientation]; + attributes[MGLEventKeyWifi] = @([[MGLReachability reachabilityForLocalWiFi] isReachableViaWiFi]); + return attributes; } - (MGLMapboxEventAttributes *)eventForAttributes:(MGLMutableMapboxEventAttributes *)attributes attributeDictionary:(MGLMapboxEventAttributes *)attributeDictionary { [attributes addEntriesFromDictionary:attributeDictionary]; + return [attributes copy]; } @@ -594,29 +604,6 @@ const NSTimeInterval MGLFlushInterval = 180; return result; } -- (void)addBatteryStateToAttributes:(MGLMutableMapboxEventAttributes *)attributes { - UIDeviceBatteryState batteryState = [[UIDevice currentDevice] batteryState]; - switch (batteryState) { - case UIDeviceBatteryStateCharging: - case UIDeviceBatteryStateFull: - attributes[MGLEventKeyPluggedIn] = @(YES); - break; - case UIDeviceBatteryStateUnplugged: - attributes[MGLEventKeyPluggedIn] = @(NO); - break; - default: - // do nothing - break; - } -} - -- (void)addApplicationStateToAttributes:(MGLMutableMapboxEventAttributes *)attributes { - NSString *currentApplicationState = [self applicationState]; - if (![currentApplicationState isEqualToString:MGLApplicationStateUnknown]) { - attributes[MGLEventKeyApplicationState] = currentApplicationState; - } -} - + (void)ensureMetricsOptoutExists { NSNumber *shownInAppNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"]; BOOL metricsEnabledSettingShownInAppFlag = [shownInAppNumber boolValue]; diff --git a/platform/ios/src/MGLUserLocation.h b/platform/ios/src/MGLUserLocation.h index f2243815cf..1a27d31dd4 100644 --- a/platform/ios/src/MGLUserLocation.h +++ b/platform/ios/src/MGLUserLocation.h @@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN directly. Instead, you retrieve an existing MGLUserLocation object from the `userLocation` property of the map view displayed in your application. */ -@interface MGLUserLocation : NSObject <MGLAnnotation> +@interface MGLUserLocation : NSObject <MGLAnnotation, NSSecureCoding> #pragma mark Determining the User’s Position diff --git a/platform/ios/src/MGLUserLocation.m b/platform/ios/src/MGLUserLocation.m index a568ec8be1..97e3f740fc 100644 --- a/platform/ios/src/MGLUserLocation.m +++ b/platform/ios/src/MGLUserLocation.m @@ -26,6 +26,44 @@ NS_ASSUME_NONNULL_END return self; } ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (instancetype)initWithCoder:(NSCoder *)decoder { + if (self = [super init]) { + _location = [decoder decodeObjectOfClass:[CLLocation class] forKey:@"location"]; + _title = [decoder decodeObjectOfClass:[NSString class] forKey:@"title"]; + _subtitle = [decoder decodeObjectOfClass:[NSString class] forKey:@"subtitle"]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:_location forKey:@"location"]; + [coder encodeObject:_title forKey:@"title"]; + [coder encodeObject:_subtitle forKey:@"subtitle"]; +} + +- (BOOL)isEqual:(id)other { + if (self == other) return YES; + if (![other isKindOfClass:[MGLUserLocation class]]) return NO; + + MGLUserLocation *otherUserLocation = other; + return ((!self.location && !otherUserLocation.location) || [self.location distanceFromLocation:otherUserLocation.location] == 0) + && ((!self.title && !otherUserLocation.title) || [self.title isEqualToString:otherUserLocation.title]) + && ((!self.subtitle && !otherUserLocation.subtitle) || [self.subtitle isEqualToString:otherUserLocation.subtitle]); +} + +- (NSUInteger)hash { + NSUInteger hash = [super hash]; + hash += [_location hash]; + hash += [_heading hash]; + hash += [_title hash]; + hash += [_subtitle hash]; + return hash; +} + + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { return ! [key isEqualToString:@"location"] && ! [key isEqualToString:@"heading"]; diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h index 88efdd5cb4..37c649781e 100644 --- a/platform/ios/src/Mapbox.h +++ b/platform/ios/src/Mapbox.h @@ -54,6 +54,5 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[]; #import "MGLUserLocation.h" #import "MGLUserLocationAnnotationView.h" #import "NSValue+MGLAdditions.h" -#import "NSValue+MGLStyleEnumAttributeAdditions.h" #import "MGLStyleValue.h" #import "MGLAttributionInfo.h" |