Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
closes #1082, refs #756: user dot on map in iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
incanus committed Mar 26, 2015
1 parent c7b8cb1 commit f3058db
Show file tree
Hide file tree
Showing 14 changed files with 913 additions and 101 deletions.
31 changes: 31 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,34 @@ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

===========================================================================

Mapbox GL uses portions of the Mapbox iOS SDK, which was derived from the
Route-Me open source project, including the Alpstein fork of it.

The Route-Me license appears below.

Copyright (c) 2008-2013, Route-Me Contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
5 changes: 5 additions & 0 deletions gyp/platform-ios.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
'../include/mbgl/ios/MGLMapView.h',
'../platform/ios/MGLMapView.mm',
'../include/mbgl/ios/MGLAnnotation.h',
'../include/mbgl/ios/MGLUserLocation.h',
'../platform/ios/MGLUserLocation_Private.h',
'../platform/ios/MGLUserLocation.m',
'../platform/ios/MGLUserLocationAnnotationView.h',
'../platform/ios/MGLUserLocationAnnotationView.m',
'../include/mbgl/ios/MGLMetricsLocationManager.h',
'../platform/ios/MGLMetricsLocationManager.m',
'../include/mbgl/ios/MGLStyleFunctionValue.h',
Expand Down
49 changes: 49 additions & 0 deletions include/mbgl/ios/MGLMapView.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>

#import "MGLTypes.h"

@class MGLUserLocation;

@protocol MGLMapViewDelegate;
@protocol MGLAnnotation;

Expand Down Expand Up @@ -234,6 +238,30 @@
* @param animated If `YES`, the callout view is animated offscreen. */
- (void)deselectAnnotation:(id <MGLAnnotation>)annotation animated:(BOOL)animated;

#pragma mark - Displaying the User's Location

/** A Boolean value indicating whether the map may display the user location.
This property does not indicate whether the user’s position is actually visible on the map, only whether the map view is allowed to display it. To determine whether the user’s position is visible, use the userLocationVisible property. The default value of this property is `NO`.
Setting this property to `YES` causes the map view to use the Core Location framework to find the current location. As long as this property is `YES`, the map view continues to track the user’s location and update it periodically.
On iOS 8 and above, your app must specify a value for `NSLocationWhenInUseUsageDescription` in its `Info.plist` to satisfy the requirements of the underlying Core Location framework when enabling this property.
*/
@property (nonatomic, assign) BOOL showsUserLocation;

/// Returns a Boolean value indicating whether the user currently sees the user location annotation.
@property (nonatomic, assign, readonly, getter=isUserLocationVisible) BOOL userLocationVisible;

/// Returns the annotation object indicating the user’s current location.
@property (nonatomic, readonly) MGLUserLocation *userLocation;

/** The mode used to track the user location. */
@property (nonatomic, assign) MGLUserTrackingMode userTrackingMode;

/** Whether the map view should display a heading calibration alert when necessary. The default value is `YES`. */
@property (nonatomic, assign) BOOL displayHeadingCalibration;

#pragma mark - Debugging

/** @name Debugging */
Expand Down Expand Up @@ -333,6 +361,27 @@
// TODO
- (void)mapViewDidFinishRenderingMap:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;

#pragma mark - Tracking the User Location

/// Tells the delegate that the map view will begin tracking the user’s location.
- (void)mapViewWillStartLocatingUser:(MGLMapView *)mapView;

/// Tells the delegate that the map view has stopped tracking the user’s location.
- (void)mapViewDidStopLocatingUser:(MGLMapView *)mapView;

/// Tells the delegate that the map view has updated the user’s location to the given location.
- (void)mapView:(MGLMapView *)mapView didUpdateUserLocation:(MGLUserLocation *)userLocation;

/// Tells the delegate that the map view has failed to locate the user.
- (void)mapView:(MGLMapView *)mapView didFailToLocateUserWithError:(NSError *)error;

/**
Tells the delegate that the map view’s user tracking mode has changed.
This method is called after the map view asynchronously changes to reflect the new user tracking mode, for example by beginning to zoom or rotate.
*/
- (void)mapView:(MGLMapView *)mapView didChangeUserTrackingMode:(MGLUserTrackingMode)mode animated:(BOOL)animated;

#pragma mark - Managing Annotations

/** @name Managing Annotations */
Expand Down
8 changes: 8 additions & 0 deletions include/mbgl/ios/MGLTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,11 @@ extern NSString *const MGLStyleValueTypeFunctionMaximumZoom;
extern NSString *const MGLStyleValueTypeFunctionLinear;
extern NSString *const MGLStyleValueTypeFunctionExponential;
extern NSString *const MGLStyleValueTypeFunctionStops;

/// The degree to which the map view tracks the user’s location.
typedef NS_ENUM(NSUInteger, MGLUserTrackingMode)
{
MGLUserTrackingModeNone = 0, ///< does not track the user’s location or heading
MGLUserTrackingModeFollow = 1, ///< tracks the user’s location
MGLUserTrackingModeFollowWithHeading = 2, ///< tracks the user’s location and heading
};
26 changes: 26 additions & 0 deletions include/mbgl/ios/MGLUserLocation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#import "MGLAnnotation.h"

@interface MGLUserLocation : NSObject <MGLAnnotation>

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

/** @name Determining the User’s Position */

/** The current location of the device. (read-only)
*
* This property contains `nil` if the map view is not currently showing the user location or if the user’s location has not yet been determined. */
@property (nonatomic, readonly) CLLocation *location;

/** A Boolean value indicating whether the user’s location is currently being updated. (read-only) */
@property (nonatomic, readonly, getter=isUpdating) BOOL updating; // FIXME

/** The heading of the user location. (read-only)
*
* This property is `nil` if the user location tracking mode is not `RMUserTrackingModeFollowWithHeading`. */
@property (nonatomic, readonly) CLHeading *heading;

@property (nonatomic, copy) NSString *title;

@property (nonatomic, copy) NSString *subtitle;

@end
1 change: 1 addition & 0 deletions include/mbgl/ios/MapboxGL.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#import "MGLMapView.h"
#import "MGLStyleFunctionValue.h"
#import "MGLTypes.h"
#import "MGLUserLocation.h"
#import "NSArray+MGLAdditions.h"
#import "NSDictionary+MGLAdditions.h"
#import "UIColor+MGLAdditions.h"
5 changes: 5 additions & 0 deletions include/mbgl/platform/darwin/settings_nsuserdefaults.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef MBGL_COMMON_SETTINGS_NSUSERDEFAULTS
#define MBGL_COMMON_SETTINGS_NSUSERDEFAULTS

#import <mbgl/ios/MGLTypes.h>

namespace mbgl {

class Settings_NSUserDefaults {
Expand All @@ -16,6 +18,9 @@ class Settings_NSUserDefaults {
double zoom = 0;
double bearing = 0;

MGLUserTrackingMode userTrackingMode = MGLUserTrackingModeNone;
bool showsUserLocation = false;

bool debug = false;
};

Expand Down
77 changes: 12 additions & 65 deletions ios/app/MBXViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@

static NSString *const kStyleVersion = @"v7";

@interface MBXViewController () <UIActionSheetDelegate, CLLocationManagerDelegate, MGLMapViewDelegate>
@interface MBXViewController () <UIActionSheetDelegate, MGLMapViewDelegate>

@property (nonatomic) MGLMapView *mapView;
@property (nonatomic) CLLocationManager *locationManager;

@end

Expand Down Expand Up @@ -66,11 +65,10 @@ - (void)viewDidLoad

self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds accessToken:accessToken];
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.view addSubview:self.mapView];

self.mapView.viewControllerForLayoutGuides = self;

self.mapView.showsUserLocation = YES;
self.mapView.delegate = self;
[self.view addSubview:self.mapView];

self.view.tintColor = kTintColor;
self.navigationController.navigationBar.tintColor = kTintColor;
Expand Down Expand Up @@ -109,6 +107,8 @@ - (void)saveState:(NSNotification *)notification
settings->zoom = self.mapView.zoomLevel;
settings->bearing = self.mapView.direction;
settings->debug = self.mapView.isDebugActive;
settings->userTrackingMode = self.mapView.userTrackingMode;
settings->showsUserLocation = self.mapView.showsUserLocation;
settings->save();
}
}
Expand All @@ -119,6 +119,8 @@ - (void)restoreState:(NSNotification *)notification
settings->load();
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(settings->latitude, settings->longitude) zoomLevel:settings->zoom animated:NO];
self.mapView.direction = settings->bearing;
self.mapView.userTrackingMode = settings->userTrackingMode;
self.mapView.showsUserLocation = settings->showsUserLocation;
[self.mapView setDebugActive:settings->debug];
}
}
Expand Down Expand Up @@ -254,40 +256,17 @@ - (void)cycleStyles

- (void)locateUser
{
if ( ! self.locationManager)
if (self.mapView.userTrackingMode == MGLUserTrackingModeNone)
{
self.locationManager = [CLLocationManager new];
self.locationManager.delegate = self;
self.mapView.userTrackingMode = MGLUserTrackingModeFollow;
}

if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied)
else if (self.mapView.userTrackingMode == MGLUserTrackingModeFollow)
{
[[[UIAlertView alloc] initWithTitle:@"Authorization Denied"
message:@"Please enable location services for this app in Privacy settings."
delegate:nil
cancelButtonTitle:nil otherButtonTitles:@"OK", nil] show];
self.mapView.userTrackingMode = MGLUserTrackingModeFollowWithHeading;
}
else
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)])
{
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse)
{
[self.locationManager startUpdatingLocation];
}
else
{
[_locationManager requestWhenInUseAuthorization];
}
}
else
{
[self.locationManager startUpdatingLocation];
}
#else
[self.locationManager startUpdatingLocation];
#endif
self.mapView.userTrackingMode = MGLUserTrackingModeNone;
}
}

Expand All @@ -305,41 +284,9 @@ - (void)dealloc
}
}

#pragma mark - CLLocationManagerDelegate

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status)
{
case kCLAuthorizationStatusAuthorizedAlways:
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
case kCLAuthorizationStatusAuthorizedWhenInUse:
#endif
{
[manager startUpdatingLocation];
break;
}
default:
{
}
}
}

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *latestLocation = locations.lastObject;

if ([latestLocation distanceFromLocation:[[CLLocation alloc] initWithLatitude:self.mapView.centerCoordinate.latitude longitude:self.mapView.centerCoordinate.longitude]] > 100)
{
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(latestLocation.coordinate.latitude, latestLocation.coordinate.longitude) zoomLevel:17 animated:YES];
}

[self.locationManager stopUpdatingLocation];
}

#pragma mark - MGLMapViewDelegate

- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation
Expand Down
36 changes: 26 additions & 10 deletions platform/darwin/settings_nsuserdefaults.mm
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@

Settings_NSUserDefaults::Settings_NSUserDefaults()
{
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"longitude" : @(longitude),
@"latitude" : @(latitude),
@"zoom" : @(zoom),
@"bearing" : @(bearing),
@"debug" : @(debug) }];
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
@"longitude" : @(longitude),
@"latitude" : @(latitude),
@"zoom" : @(zoom),
@"bearing" : @(bearing),
@"userTrackingMode" : @(userTrackingMode),
@"showsUserLocation" : @(showsUserLocation),
@"debug" : @(debug),
}];
load();
}

Expand All @@ -23,15 +27,27 @@
zoom = [settings[@"zoom"] doubleValue];
bearing = [settings[@"bearing"] doubleValue];
debug = [settings[@"debug"] boolValue];

unsigned uncheckedTrackingMode = [settings[@"trackingMode"] unsignedIntValue];
if (uncheckedTrackingMode > MGLUserTrackingModeNone &&
uncheckedTrackingMode <= MGLUserTrackingModeFollowWithHeading)
{
userTrackingMode = (MGLUserTrackingMode)uncheckedTrackingMode;
}
showsUserLocation = [settings[@"showsUserLocation"] boolValue];
}

void Settings_NSUserDefaults::save()
{
[[NSUserDefaults standardUserDefaults] setValuesForKeysWithDictionary:@{ @"longitude" : @(longitude),
@"latitude" : @(latitude),
@"zoom" : @(zoom),
@"bearing" : @(bearing),
@"debug" : @(debug) }];
[[NSUserDefaults standardUserDefaults] setValuesForKeysWithDictionary:@{
@"longitude" : @(longitude),
@"latitude" : @(latitude),
@"zoom" : @(zoom),
@"bearing" : @(bearing),
@"userTrackingMode" : @(userTrackingMode),
@"showsUserLocation" : @(showsUserLocation),
@"debug" : @(debug),
}];
[[NSUserDefaults standardUserDefaults] synchronize];
}

Expand Down
Loading

0 comments on commit f3058db

Please sign in to comment.