forked from organicmaps/organicmaps
Merge pull request #3681 from igrechuhin/new-location-manager
[ios] Refactored location manager.
This commit is contained in:
commit
ce8f47d82c
65 changed files with 1185 additions and 1159 deletions
|
@ -1,7 +1,6 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MWMTableViewController.h"
|
||||
|
||||
@interface BookmarksVC : MWMTableViewController <LocationObserver, UITextFieldDelegate>
|
||||
@interface BookmarksVC : MWMTableViewController <UITextFieldDelegate>
|
||||
{
|
||||
size_t m_categoryIndex;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMBookmarkNameCell.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "Statistics.h"
|
||||
#import "UIColor+MapsMeColor.h"
|
||||
|
@ -25,7 +27,7 @@
|
|||
|
||||
extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotification";
|
||||
|
||||
@interface BookmarksVC() <MFMailComposeViewControllerDelegate>
|
||||
@interface BookmarksVC() <MFMailComposeViewControllerDelegate, MWMLocationObserver>
|
||||
{
|
||||
int m_trackSection;
|
||||
int m_bookmarkSection;
|
||||
|
@ -48,11 +50,6 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
return self;
|
||||
}
|
||||
|
||||
- (LocationManager *)locationManager
|
||||
{
|
||||
return [MapsAppDelegate theApp].locationManager;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
@ -162,17 +159,14 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
bmCell.textLabel.text = @(bm->GetName().c_str());
|
||||
bmCell.imageView.image = [CircleView createCircleImageWith:PINDIAMETER andColor:[ColorPickerView colorForName:@(bm->GetType().c_str())]];
|
||||
|
||||
// Get current position and compass "north" direction
|
||||
double azimut = -1.0;
|
||||
double lat, lon;
|
||||
|
||||
if ([self.locationManager getLat:lat Lon:lon])
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (lastLocation)
|
||||
{
|
||||
double north = -1.0;
|
||||
[self.locationManager getNorthRad:north];
|
||||
|
||||
double north = location_helpers::headingToNorthRad([MWMLocationManager lastHeading]);
|
||||
string distance;
|
||||
fr.GetDistanceAndAzimut(bm->GetPivot(), lat, lon, north, distance, azimut);
|
||||
double azimut = -1.0;
|
||||
fr.GetDistanceAndAzimut(bm->GetPivot(), lastLocation.coordinate.latitude,
|
||||
lastLocation.coordinate.longitude, north, distance, azimut);
|
||||
|
||||
bmCell.detailTextLabel.text = @(distance.c_str());
|
||||
}
|
||||
|
@ -327,8 +321,8 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
}
|
||||
}
|
||||
|
||||
//******************************************************************
|
||||
//*********** Location manager callbacks ***************************
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
// Refresh distance
|
||||
|
@ -347,7 +341,7 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
m2::PointD const center = bm->GetPivot();
|
||||
double const metres = ms::DistanceOnEarth(info.m_latitude, info.m_longitude,
|
||||
MercatorBounds::YToLat(center.y), MercatorBounds::XToLon(center.x));
|
||||
cell.detailTextLabel.text = [LocationManager formattedDistance:metres];
|
||||
cell.detailTextLabel.text = location_helpers::formattedDistance(metres);
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
@ -359,7 +353,7 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[self.locationManager start:self];
|
||||
[MWMLocationManager addObserver:self];
|
||||
|
||||
// Display Edit button only if table is not empty
|
||||
BookmarkCategory * cat = GetFramework().GetBmCategory(m_categoryIndex);
|
||||
|
@ -386,7 +380,8 @@ extern NSString * const kBookmarksChangedNotification = @"BookmarksChangedNotifi
|
|||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[self.locationManager stop:self];
|
||||
[MWMLocationManager removeObserver:self];
|
||||
|
||||
// Save possibly edited set name
|
||||
UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
|
||||
if ([cell isKindOfClass:[MWMBookmarkNameCell class]])
|
||||
|
|
7
iphone/Maps/CLLocation+Mercator.h
Normal file
7
iphone/Maps/CLLocation+Mercator.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "geometry/point2d.hpp"
|
||||
|
||||
@interface CLLocation (Mercator)
|
||||
|
||||
- (m2::PointD)mercator;
|
||||
|
||||
@end
|
8
iphone/Maps/CLLocation+Mercator.mm
Normal file
8
iphone/Maps/CLLocation+Mercator.mm
Normal file
|
@ -0,0 +1,8 @@
|
|||
#import "CLLocation+Mercator.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
|
||||
@implementation CLLocation (Mercator)
|
||||
|
||||
- (m2::PointD)mercator { return location_helpers::ToMercator(self.coordinate); }
|
||||
|
||||
@end
|
|
@ -1,4 +1,3 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#import "MWMButton.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "MWMSearchManager.h"
|
||||
#import "SettingsAndMoreVC.h"
|
||||
|
@ -293,8 +294,8 @@ typedef NS_ENUM(NSUInteger, MWMBottomMenuViewCell)
|
|||
{
|
||||
[Statistics logEvent:kStatMenu withParameters:@{kStatButton : kStatShare}];
|
||||
[Alohalytics logEvent:kAlohalyticsTapEventKey withValue:@"share@"];
|
||||
CLLocation * location = [MapsAppDelegate theApp].locationManager.lastLocation;
|
||||
if (!location)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
{
|
||||
[[[UIAlertView alloc] initWithTitle:L(@"unknown_current_position")
|
||||
message:nil
|
||||
|
@ -303,7 +304,7 @@ typedef NS_ENUM(NSUInteger, MWMBottomMenuViewCell)
|
|||
otherButtonTitles:nil] show];
|
||||
return;
|
||||
}
|
||||
CLLocationCoordinate2D const coord = location.coordinate;
|
||||
CLLocationCoordinate2D const coord = lastLocation.coordinate;
|
||||
NSIndexPath * cellIndex = [NSIndexPath indexPathForItem:MWMBottomMenuViewCellShare inSection:0];
|
||||
MWMBottomMenuCollectionViewCell * cell =
|
||||
(MWMBottomMenuCollectionViewCell *)[self.additionalButtons cellForItemAtIndexPath:cellIndex];
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#import "MWMButton.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "MWMObjectsCategorySelectorController.h"
|
||||
#import "MWMPlacePageEntity.h"
|
||||
|
@ -90,9 +91,9 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
}
|
||||
else
|
||||
{
|
||||
LocationManager * m = MapsAppDelegate.theApp.locationManager;
|
||||
self.routeSource = m.lastLocationIsValid ? MWMRoutePoint(m.lastLocation.mercator)
|
||||
: MWMRoutePoint::MWMRoutePointZero();
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
self.routeSource =
|
||||
lastLocation ? MWMRoutePoint(lastLocation.mercator) : MWMRoutePoint::MWMRoutePointZero();
|
||||
}
|
||||
self.routeDestination = MWMRoutePoint::MWMRoutePointZero();
|
||||
}
|
||||
|
@ -383,8 +384,11 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
|
||||
- (void)restoreRouteTo:(m2::PointD const &)to
|
||||
{
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
auto & f = GetFramework();
|
||||
m2::PointD const myPosition = [MapsAppDelegate theApp].locationManager.lastLocation.mercator;
|
||||
m2::PointD const myPosition = lastLocation.mercator;
|
||||
f.SetRouter(f.GetBestRouter(myPosition, to));
|
||||
self.routeSource = MWMRoutePoint(myPosition);
|
||||
self.routeDestination = {to, @"Destination"};
|
||||
|
@ -498,8 +502,8 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
if (!self.isPossibleToBuildRoute)
|
||||
return;
|
||||
|
||||
LocationManager * locMgr = [MapsAppDelegate theApp].locationManager;
|
||||
if (!locMgr.lastLocation && self.routeSource.IsMyPosition())
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation && self.routeSource.IsMyPosition())
|
||||
{
|
||||
MWMAlertViewController * alert =
|
||||
[[MWMAlertViewController alloc] initWithViewController:self.ownerController];
|
||||
|
@ -507,14 +511,14 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
return;
|
||||
}
|
||||
|
||||
m2::PointD const locationPoint = locMgr.lastLocation.mercator;
|
||||
m2::PointD const locationPoint = lastLocation.mercator;
|
||||
if (self.routeSource.IsMyPosition())
|
||||
{
|
||||
[Statistics
|
||||
logEvent:kStatPointToPoint
|
||||
withParameters:@{kStatAction : kStatBuildRoute, kStatValue : kStatFromMyPosition}];
|
||||
self.routeSource = MWMRoutePoint(locationPoint);
|
||||
[locMgr start:self.navigationManager];
|
||||
[MWMLocationManager addObserver:self.navigationManager];
|
||||
}
|
||||
else if (self.routeDestination.IsMyPosition())
|
||||
{
|
||||
|
@ -567,9 +571,9 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
if (!isSourceMyPosition)
|
||||
{
|
||||
MWMAlertViewController * controller = [[MWMAlertViewController alloc] initWithViewController:self.ownerController];
|
||||
LocationManager * manager = MapsAppDelegate.theApp.locationManager;
|
||||
BOOL const needToRebuild = manager.lastLocationIsValid && !manager.isLocationPendingOrNoPosition && !isDestinationMyPosition;
|
||||
m2::PointD const locationPoint = manager.lastLocation.mercator;
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
BOOL const needToRebuild = lastLocation && !location_helpers::isMyPositionPendingOrNoPosition() && !isDestinationMyPosition;
|
||||
m2::PointD const locationPoint = lastLocation.mercator;
|
||||
[controller presentPoint2PointAlertWithOkBlock:^
|
||||
{
|
||||
self.routeSource = MWMRoutePoint(locationPoint);
|
||||
|
@ -596,7 +600,7 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
- (void)didCancelRouting
|
||||
{
|
||||
[Statistics logEvent:kStatEventName(kStatPointToPoint, kStatClose)];
|
||||
[[MapsAppDelegate theApp].locationManager stop:self.navigationManager];
|
||||
[MWMLocationManager removeObserver:self.navigationManager];
|
||||
self.navigationManager.state = MWMNavigationDashboardStateHidden;
|
||||
self.disableStandbyOnRouteFollowing = NO;
|
||||
[MapsAppDelegate theApp].routingPlaneMode = MWMRoutingPlaneModeNone;
|
||||
|
@ -634,9 +638,9 @@ extern NSString * const kAlohalyticsTapEventKey;
|
|||
|
||||
- (void)resetRoutingPoint
|
||||
{
|
||||
LocationManager * m = MapsAppDelegate.theApp.locationManager;
|
||||
self.routeSource = m.lastLocationIsValid ? MWMRoutePoint(m.lastLocation.mercator) :
|
||||
MWMRoutePoint::MWMRoutePointZero();
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
self.routeSource =
|
||||
lastLocation ? MWMRoutePoint(lastLocation.mercator) : MWMRoutePoint::MWMRoutePointZero();
|
||||
self.routeDestination = MWMRoutePoint::MWMRoutePointZero();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMConsole.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMNoMapsViewController.h"
|
||||
#import "MWMRoutingProtocol.h"
|
||||
#import "MWMSearchManager.h"
|
||||
|
@ -173,7 +173,7 @@ extern NSString * const kSearchStateKey = @"SearchStateKey";
|
|||
- (void)tapMyPositionFromHistory
|
||||
{
|
||||
MapsAppDelegate * a = MapsAppDelegate.theApp;
|
||||
MWMRoutePoint const p = MWMRoutePoint::MWMRoutePoint(a.locationManager.lastLocation.mercator);
|
||||
MWMRoutePoint const p = MWMRoutePoint::MWMRoutePoint([MWMLocationManager lastLocation].mercator);
|
||||
if (a.routingPlaneMode == MWMRoutingPlaneModeSearchSource)
|
||||
[self.delegate buildRouteFrom:p];
|
||||
else if (a.routingPlaneMode == MWMRoutingPlaneModeSearchDestination)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "Macros.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMSearchHistoryClearCell.h"
|
||||
#import "MWMSearchHistoryManager.h"
|
||||
#import "MWMSearchHistoryMyPositionCell.h"
|
||||
|
@ -27,9 +27,9 @@ static NSString * const kMyPositionCellIdentifier = @"MWMSearchHistoryMyPosition
|
|||
- (BOOL)isRouteSearchMode
|
||||
{
|
||||
MWMRoutingPlaneMode const m = MapsAppDelegate.theApp.routingPlaneMode;
|
||||
return (m == MWMRoutingPlaneModeSearchSource ||
|
||||
m == MWMRoutingPlaneModeSearchDestination) &&
|
||||
MapsAppDelegate.theApp.locationManager.lastLocationIsValid;
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
return lastLocation &&
|
||||
(m == MWMRoutingPlaneModeSearchSource || m == MWMRoutingPlaneModeSearchDestination);
|
||||
}
|
||||
|
||||
- (void)attachCell:(MWMSearchTabbedCollectionViewCell *)cell
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMSearchCommonCell.h"
|
||||
#import "UIColor+MapsMeColor.h"
|
||||
#import "UIFont+MapsMeFonts.h"
|
||||
|
@ -57,12 +57,10 @@
|
|||
if (result.HasPoint())
|
||||
{
|
||||
string distanceStr;
|
||||
double lat, lon;
|
||||
LocationManager * locationManager = MapsAppDelegate.theApp.locationManager;
|
||||
if ([locationManager getLat:lat Lon:lon])
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (lastLocation)
|
||||
{
|
||||
m2::PointD const mercLoc = MercatorBounds::FromLatLon(lat, lon);
|
||||
double const dist = MercatorBounds::DistanceOnEarth(mercLoc, result.GetFeatureCenter());
|
||||
double const dist = MercatorBounds::DistanceOnEarth(lastLocation.mercator, result.GetFeatureCenter());
|
||||
MeasurementUtils::FormatDistance(dist, distanceStr);
|
||||
}
|
||||
self.distanceLabel.text = @(distanceStr.c_str());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "LocationManager.h"
|
||||
#import "Macros.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMSearchCommonCell.h"
|
||||
#import "MWMSearchShowOnMapCell.h"
|
||||
#import "MWMSearchSuggestionCell.h"
|
||||
|
@ -35,8 +35,7 @@ NSString * identifierForType(MWMSearchTableCellType type)
|
|||
}
|
||||
}
|
||||
|
||||
@interface MWMSearchTableViewController () <UITableViewDataSource, UITableViewDelegate,
|
||||
LocationObserver>
|
||||
@interface MWMSearchTableViewController () <UITableViewDataSource, UITableViewDelegate, MWMLocationObserver>
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UITableView * tableView;
|
||||
|
||||
|
@ -292,7 +291,7 @@ forRowAtIndexPath:(NSIndexPath *)indexPath
|
|||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - LocationObserver
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
|
@ -360,9 +359,9 @@ forRowAtIndexPath:(NSIndexPath *)indexPath
|
|||
return;
|
||||
_watchLocationUpdates = watchLocationUpdates;
|
||||
if (watchLocationUpdates)
|
||||
[[MapsAppDelegate theApp].locationManager start:self];
|
||||
[MWMLocationManager addObserver:self];
|
||||
else
|
||||
[[MapsAppDelegate theApp].locationManager stop:self];
|
||||
[MWMLocationManager removeObserver:self];
|
||||
}
|
||||
|
||||
@synthesize searchOnMap = _searchOnMap;
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMFirstLaunchController.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMPageController.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
@interface MWMFirstLaunchController () <LocationObserver>
|
||||
@interface MWMLocationManager ()
|
||||
|
||||
@property (nonatomic) BOOL started;
|
||||
+ (MWMLocationManager *)manager;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMFirstLaunchController ()
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView * containerView;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView * image;
|
||||
|
@ -22,8 +29,6 @@
|
|||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * titleTopOffset;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint * titleImageOffset;
|
||||
|
||||
@property (nonatomic) BOOL locationError;
|
||||
|
||||
@end
|
||||
|
||||
namespace
|
||||
|
@ -50,12 +55,11 @@ void zoomToCurrentPosition()
|
|||
{
|
||||
auto & f = GetFramework();
|
||||
f.SwitchMyPositionNextMode();
|
||||
LocationManager * locationManager = MapsAppDelegate.theApp.locationManager;
|
||||
if (![locationManager lastLocationIsValid])
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
m2::PointD const centerPt = locationManager.lastLocation.mercator;
|
||||
int const zoom = 13;
|
||||
f.SetViewportCenter(centerPt, zoom);
|
||||
f.SetViewportCenter(lastLocation.mercator, zoom);
|
||||
}
|
||||
|
||||
NSInteger constexpr kRequestLocationPage = 2;
|
||||
|
@ -117,16 +121,6 @@ NSArray<TMWMWelcomeConfigBlock> * pagesConfigBlocks = @[
|
|||
return pagesConfigBlocks;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
if (self.pageIndex == kRequestLocationPage)
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(appWillEnterForeground:)
|
||||
name:UIApplicationWillEnterForegroundNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
@ -136,24 +130,9 @@ NSArray<TMWMWelcomeConfigBlock> * pagesConfigBlocks = @[
|
|||
requestNotifications();
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
if (self.locationError)
|
||||
[MapsAppDelegate.theApp.locationManager reset];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)requestLocation
|
||||
{
|
||||
MapsAppDelegate * app = MapsAppDelegate.theApp;
|
||||
LocationManager * lm = app.locationManager;
|
||||
[lm onForeground];
|
||||
[lm start:self];
|
||||
[MWMLocationManager manager].started = YES;
|
||||
}
|
||||
|
||||
- (void)close
|
||||
|
@ -162,23 +141,6 @@ NSArray<TMWMWelcomeConfigBlock> * pagesConfigBlocks = @[
|
|||
zoomToCurrentPosition();
|
||||
}
|
||||
|
||||
- (void)appWillEnterForeground:(NSNotification *)notification
|
||||
{
|
||||
[self requestLocation];
|
||||
}
|
||||
|
||||
#pragma mark - LocationManager Callbacks
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
}
|
||||
|
||||
- (void)onLocationError:(location::TLocationError)errorCode
|
||||
{
|
||||
if (errorCode == location::EDenied)
|
||||
self.locationError = YES;
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (void)setSize:(CGSize)size
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMNavigationDashboardEntity.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
@ -23,11 +23,12 @@ using namespace routing::turns;
|
|||
_targetUnits = @(info.m_targetUnitsSuffix.c_str());
|
||||
_progress = info.m_completionPercent;
|
||||
auto & f = GetFramework();
|
||||
if (f.GetRouter() == routing::RouterType::Pedestrian)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (lastLocation && f.GetRouter() == routing::RouterType::Pedestrian)
|
||||
{
|
||||
_isPedestrian = YES;
|
||||
string distance;
|
||||
CLLocationCoordinate2D const & coordinate ([MapsAppDelegate theApp].locationManager.lastLocation.coordinate);
|
||||
CLLocationCoordinate2D const & coordinate = lastLocation.coordinate;
|
||||
ms::LatLon const & directionPos = info.m_pedestrianDirectionPos;
|
||||
//TODO: Not the best solution, but this solution is temporary and will be replaced in future
|
||||
MeasurementUtils::FormatDistance(ms::DistanceOnEarth(coordinate.latitude, coordinate.longitude,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MWMCircularProgress.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMNavigationViewProtocol.h"
|
||||
#import "MWMRoutePreview.h"
|
||||
|
||||
|
@ -30,7 +30,7 @@ typedef NS_ENUM(NSUInteger, MWMNavigationDashboardState)
|
|||
|
||||
@class MWMNavigationDashboardEntity;
|
||||
|
||||
@interface MWMNavigationDashboardManager : NSObject <LocationObserver>
|
||||
@interface MWMNavigationDashboardManager : NSObject <MWMLocationObserver>
|
||||
|
||||
@property (nonatomic, readonly) MWMNavigationDashboardEntity * entity;
|
||||
@property (weak, nonatomic, readonly) MWMRoutePreview * routePreview;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#import "Macros.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLanesPanel.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMNavigationDashboard.h"
|
||||
#import "MWMNavigationDashboardEntity.h"
|
||||
#import "MWMNavigationDashboardManager.h"
|
||||
|
@ -432,23 +433,16 @@ extern NSString * const kTTSStatusWasChangedNotification;
|
|||
}
|
||||
}
|
||||
|
||||
#pragma mark - LocationObserver
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onLocationUpdate:(const location::GpsInfo &)info
|
||||
{
|
||||
// We don't need information about location update in this class,
|
||||
// but in LocationObserver protocol this method is required
|
||||
// since we don't want runtime overhead for introspection.
|
||||
}
|
||||
|
||||
- (void)onCompassUpdate:(location::CompassInfo const &)info
|
||||
- (void)onHeadingUpdate:(location::CompassInfo const &)info
|
||||
{
|
||||
auto & f = GetFramework();
|
||||
if (f.GetRouter() != routing::RouterType::Pedestrian)
|
||||
return;
|
||||
|
||||
CLLocation * location = [MapsAppDelegate theApp].locationManager.lastLocation;
|
||||
if (!location)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
|
||||
location::FollowingInfo res;
|
||||
|
@ -456,9 +450,10 @@ extern NSString * const kTTSStatusWasChangedNotification;
|
|||
if (!res.IsValid())
|
||||
return;
|
||||
|
||||
CGFloat const angle = ang::AngleTo(location.mercator,
|
||||
ToMercator(res.m_pedestrianDirectionPos)) + info.m_bearing;
|
||||
CGAffineTransform const transform (CGAffineTransformMakeRotation(M_PI_2 - angle));
|
||||
CGFloat const angle = ang::AngleTo(lastLocation.mercator,
|
||||
location_helpers::ToMercator(res.m_pedestrianDirectionPos)) +
|
||||
info.m_bearing;
|
||||
CGAffineTransform const transform(CGAffineTransformMakeRotation(M_PI_2 - angle));
|
||||
self.navigationDashboardPortrait.direction.transform = transform;
|
||||
self.navigationDashboardLandscape.direction.transform = transform;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#import "Common.h"
|
||||
#import "EAGLView.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MWMDirectionView.h"
|
||||
|
||||
#import "../Platform/opengl/iosOGLContextFactory.h"
|
||||
|
@ -64,7 +63,7 @@ double getExactDPI(double contentScaleFactor)
|
|||
{
|
||||
NSLog(@"EAGLView initWithCoder Started");
|
||||
self = [super initWithCoder:coder];
|
||||
if (self && !MapsAppDelegate.theApp.isDaemonMode)
|
||||
if (self)
|
||||
[self initialize];
|
||||
|
||||
NSLog(@"EAGLView initWithCoder Ended");
|
||||
|
@ -74,7 +73,6 @@ double getExactDPI(double contentScaleFactor)
|
|||
- (void)initialize
|
||||
{
|
||||
lastViewSize = CGRectZero;
|
||||
_widgetsManager = [[MWMMapWidgets alloc] init];
|
||||
|
||||
// Setup Layer Properties
|
||||
CAEAGLLayer * eaglLayer = (CAEAGLLayer *)self.layer;
|
||||
|
@ -92,8 +90,6 @@ double getExactDPI(double contentScaleFactor)
|
|||
- (void)createDrapeEngineWithWidth:(int)width height:(int)height
|
||||
{
|
||||
LOG(LINFO, ("EAGLView createDrapeEngine Started"));
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return;
|
||||
|
||||
Framework::DrapeCreationParams p;
|
||||
p.m_surfaceWidth = width;
|
||||
|
@ -181,4 +177,11 @@ double getExactDPI(double contentScaleFactor)
|
|||
m_factory->CastFactory<iosOGLContextFactory>()->setPresentAvailable(available);
|
||||
}
|
||||
|
||||
- (MWMMapWidgets *)widgetsManager
|
||||
{
|
||||
if (!_widgetsManager)
|
||||
_widgetsManager = [[MWMMapWidgets alloc] init];
|
||||
return _widgetsManager;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "CLLocation+Mercator.h"
|
||||
#import "Common.h"
|
||||
#import "LocalNotificationManager.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMStorage.h"
|
||||
|
|
110
iphone/Maps/Classes/Location/MWMLocationHelpers.h
Normal file
110
iphone/Maps/Classes/Location/MWMLocationHelpers.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
#import "MWMLocationManager.h"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
#include "platform/measurement_utils.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
namespace location_helpers
|
||||
{
|
||||
static inline char const * getSpeedSymbol(CLLocationSpeed const & metersPerSecond)
|
||||
{
|
||||
// 0-1 m/s
|
||||
static char const * turtle = "\xF0\x9F\x90\xA2 ";
|
||||
// 1-2 m/s
|
||||
static char const * pedestrian = "\xF0\x9F\x9A\xB6 ";
|
||||
// 2-5 m/s
|
||||
static char const * tractor = "\xF0\x9F\x9A\x9C ";
|
||||
// 5-10 m/s
|
||||
static char const * bicycle = "\xF0\x9F\x9A\xB2 ";
|
||||
// 10-36 m/s
|
||||
static char const * car = "\xF0\x9F\x9A\x97 ";
|
||||
// 36-120 m/s
|
||||
static char const * train = "\xF0\x9F\x9A\x85 ";
|
||||
// 120-278 m/s
|
||||
static char const * airplane = "\xE2\x9C\x88\xEF\xB8\x8F ";
|
||||
// 278+
|
||||
static char const * rocket = "\xF0\x9F\x9A\x80 ";
|
||||
|
||||
if (metersPerSecond <= 1.)
|
||||
return turtle;
|
||||
else if (metersPerSecond <= 2.)
|
||||
return pedestrian;
|
||||
else if (metersPerSecond <= 5.)
|
||||
return tractor;
|
||||
else if (metersPerSecond <= 10.)
|
||||
return bicycle;
|
||||
else if (metersPerSecond <= 36.)
|
||||
return car;
|
||||
else if (metersPerSecond <= 120.)
|
||||
return train;
|
||||
else if (metersPerSecond <= 278.)
|
||||
return airplane;
|
||||
else
|
||||
return rocket;
|
||||
}
|
||||
|
||||
static inline NSString * formattedSpeedAndAltitude(CLLocation * location)
|
||||
{
|
||||
if (!location)
|
||||
return nil;
|
||||
string result;
|
||||
if (location.altitude)
|
||||
result = "\xE2\x96\xB2 " /* this is simple mountain symbol */ +
|
||||
MeasurementUtils::FormatAltitude(location.altitude);
|
||||
// Speed is actual only for just received location
|
||||
if (location.speed > 0. && [location.timestamp timeIntervalSinceNow] >= -2.0)
|
||||
{
|
||||
if (!result.empty())
|
||||
result += " ";
|
||||
result += getSpeedSymbol(location.speed) + MeasurementUtils::FormatSpeed(location.speed);
|
||||
}
|
||||
return result.empty() ? nil : @(result.c_str());
|
||||
}
|
||||
|
||||
static inline NSString * formattedDistance(double const & meters)
|
||||
{
|
||||
if (meters < 0.)
|
||||
return nil;
|
||||
|
||||
string s;
|
||||
MeasurementUtils::FormatDistance(meters, s);
|
||||
return @(s.c_str());
|
||||
}
|
||||
|
||||
static inline BOOL isMyPositionPendingOrNoPosition()
|
||||
{
|
||||
location::EMyPositionMode mode;
|
||||
if (!settings::Get(settings::kLocationStateMode, mode))
|
||||
return true;
|
||||
return mode == location::EMyPositionMode::PendingPosition ||
|
||||
mode == location::EMyPositionMode::NotFollowNoPosition;
|
||||
}
|
||||
|
||||
static inline BOOL isLocationProhibited()
|
||||
{
|
||||
auto const status = [MWMLocationManager lastLocationStatus];
|
||||
return status == location::TLocationError::EDenied || status == location::TLocationError::EGPSIsOff;
|
||||
}
|
||||
|
||||
static inline double headingToNorthRad(CLHeading * heading)
|
||||
{
|
||||
double north = -1.0;
|
||||
if (heading)
|
||||
{
|
||||
north = (heading.trueHeading < 0) ? heading.magneticHeading : heading.trueHeading;
|
||||
north = my::DegToRad(north);
|
||||
}
|
||||
return north;
|
||||
}
|
||||
|
||||
static inline ms::LatLon ToLatLon(m2::PointD const & p) { return MercatorBounds::ToLatLon(p); }
|
||||
|
||||
static inline m2::PointD ToMercator(CLLocationCoordinate2D const & l)
|
||||
{
|
||||
return MercatorBounds::FromLatLon(l.latitude, l.longitude);
|
||||
}
|
||||
|
||||
static inline m2::PointD ToMercator(ms::LatLon const & l) { return MercatorBounds::FromLatLon(l); }
|
||||
|
||||
} // namespace MWMLocationHelpers
|
35
iphone/Maps/Classes/Location/MWMLocationManager.h
Normal file
35
iphone/Maps/Classes/Location/MWMLocationManager.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#import "CLLocation+Mercator.h"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
|
||||
@protocol MWMLocationObserver <NSObject>
|
||||
|
||||
@optional
|
||||
- (void)onHeadingUpdate:(location::CompassInfo const &)compassinfo;
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)gpsInfo;
|
||||
- (void)onLocationError:(location::TLocationError)locationError;
|
||||
|
||||
@end
|
||||
|
||||
@interface MWMLocationManager : NSObject
|
||||
|
||||
+ (void)addObserver:(id<MWMLocationObserver>)observer;
|
||||
+ (void)removeObserver:(id<MWMLocationObserver>)observer;
|
||||
|
||||
+ (void)setMyPositionMode:(location::EMyPositionMode)mode;
|
||||
|
||||
+ (CLLocation *)lastLocation;
|
||||
+ (location::TLocationError)lastLocationStatus;
|
||||
+ (CLHeading *)lastHeading;
|
||||
|
||||
+ (void)applicationDidBecomeActive;
|
||||
+ (void)applicationWillResignActive;
|
||||
|
||||
- (instancetype)init __attribute__((unavailable("call +manager instead")));
|
||||
- (instancetype)copy __attribute__((unavailable("call +manager instead")));
|
||||
- (instancetype)copyWithZone:(NSZone *)zone __attribute__((unavailable("call +manager instead")));
|
||||
+ (instancetype)alloc __attribute__((unavailable("call +manager instead")));
|
||||
+ (instancetype)allocWithZone:(struct _NSZone *)zone __attribute__((unavailable("call +manager instead")));
|
||||
+ (instancetype)new __attribute__((unavailable("call +manager instead")));
|
||||
|
||||
@end
|
555
iphone/Maps/Classes/Location/MWMLocationManager.mm
Normal file
555
iphone/Maps/Classes/Location/MWMLocationManager.mm
Normal file
|
@ -0,0 +1,555 @@
|
|||
#import "Common.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
#import "MWMController.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMLocationPredictor.h"
|
||||
#import "Statistics.h"
|
||||
|
||||
#import "3party/Alohalytics/src/alohalytics_objc.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
#include "map/gps_tracker.hpp"
|
||||
|
||||
#include "std/map.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
using TObserver = id<MWMLocationObserver>;
|
||||
using TObservers = NSHashTable<__kindof TObserver>;
|
||||
|
||||
void runAsyncOnMainQueue(dispatch_block_t block)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), block);
|
||||
}
|
||||
|
||||
location::GpsInfo gpsInfoFromLocation(CLLocation * l)
|
||||
{
|
||||
location::GpsInfo info;
|
||||
info.m_source = location::EAppleNative;
|
||||
|
||||
info.m_latitude = l.coordinate.latitude;
|
||||
info.m_longitude = l.coordinate.longitude;
|
||||
info.m_timestamp = l.timestamp.timeIntervalSince1970;
|
||||
|
||||
if (l.horizontalAccuracy >= 0.0)
|
||||
info.m_horizontalAccuracy = l.horizontalAccuracy;
|
||||
|
||||
if (l.verticalAccuracy >= 0.0)
|
||||
{
|
||||
info.m_verticalAccuracy = l.verticalAccuracy;
|
||||
info.m_altitude = l.altitude;
|
||||
}
|
||||
|
||||
if (l.course >= 0.0)
|
||||
info.m_bearing = l.course;
|
||||
|
||||
if (l.speed >= 0.0)
|
||||
info.m_speed = l.speed;
|
||||
return info;
|
||||
}
|
||||
|
||||
location::CompassInfo compassInfoFromHeading(CLHeading * h)
|
||||
{
|
||||
location::CompassInfo info;
|
||||
if (h.trueHeading >= 0.0)
|
||||
info.m_bearing = my::DegToRad(h.trueHeading);
|
||||
else if (h.headingAccuracy >= 0.0)
|
||||
info.m_bearing = my::DegToRad(h.magneticHeading);
|
||||
return info;
|
||||
}
|
||||
|
||||
enum class GeoMode
|
||||
{
|
||||
Pending,
|
||||
InPosition,
|
||||
NotInPosition,
|
||||
FollowAndRotate,
|
||||
VehicleRouting,
|
||||
PedestrianRouting,
|
||||
BicycleRouting
|
||||
};
|
||||
|
||||
struct DesiredAccuracy
|
||||
{
|
||||
CLLocationAccuracy charging;
|
||||
CLLocationAccuracy battery;
|
||||
};
|
||||
|
||||
struct GeoModeSettings
|
||||
{
|
||||
CLLocationDistance distanceFilter;
|
||||
DesiredAccuracy accuracy;
|
||||
};
|
||||
|
||||
map<GeoMode, GeoModeSettings> const kGeoSettings{
|
||||
{GeoMode::Pending,
|
||||
{.distanceFilter = kCLDistanceFilterNone,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBestForNavigation}}},
|
||||
{GeoMode::InPosition,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::NotInPosition,
|
||||
{.distanceFilter = 5,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::FollowAndRotate,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::VehicleRouting,
|
||||
{.distanceFilter = kCLDistanceFilterNone,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::PedestrianRouting,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::BicycleRouting,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}}};
|
||||
|
||||
BOOL keepRunningInBackground()
|
||||
{
|
||||
bool const needGPSForTrackRecorder = GpsTracker::Instance().IsEnabled();
|
||||
if (needGPSForTrackRecorder)
|
||||
return YES;
|
||||
|
||||
auto const & f = GetFramework();
|
||||
bool const isRouteBuilt = f.IsRouteBuilt();
|
||||
bool const isRouteFinished = f.IsRouteFinished();
|
||||
bool const isRouteRebuildingOnly = f.IsRouteRebuildingOnly();
|
||||
bool const needGPSForRouting = ((isRouteBuilt || isRouteRebuildingOnly) && !isRouteFinished);
|
||||
if (needGPSForRouting)
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
MWMAlertViewController * alertController()
|
||||
{
|
||||
UIWindow * window = UIApplication.sharedApplication.delegate.window;
|
||||
UIViewController * rootViewController = window.rootViewController;
|
||||
ASSERT([rootViewController isKindOfClass:[UINavigationController class]], ());
|
||||
UINavigationController * navigationController = static_cast<UINavigationController *>(rootViewController);
|
||||
UIViewController * topViewController = navigationController.topViewController;
|
||||
ASSERT([topViewController conformsToProtocol:@protocol(MWMController)], ());
|
||||
UIViewController<MWMController> * mwmController = static_cast<UIViewController<MWMController> *>(topViewController);
|
||||
return mwmController.alertController;
|
||||
}
|
||||
|
||||
void sendInfoToFramework(dispatch_block_t block)
|
||||
{
|
||||
MapsAppDelegate * delegate = static_cast<MapsAppDelegate *>(UIApplication.sharedApplication.delegate);
|
||||
if (delegate.isDrapeEngineCreated)
|
||||
{
|
||||
block();
|
||||
}
|
||||
else
|
||||
{
|
||||
runAsyncOnMainQueue(^
|
||||
{
|
||||
sendInfoToFramework(block);
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@interface MWMLocationManager () <CLLocationManagerDelegate>
|
||||
|
||||
@property (nonatomic) BOOL started;
|
||||
@property (nonatomic) CLLocationManager * locationManager;
|
||||
@property (nonatomic) GeoMode geoMode;
|
||||
@property (nonatomic) CLHeading * lastHeadingInfo;
|
||||
@property (nonatomic) CLLocation * lastLocationInfo;
|
||||
@property (nonatomic) location::TLocationError lastLocationStatus;
|
||||
@property (nonatomic) MWMLocationPredictor * predictor;
|
||||
@property (nonatomic) TObservers * observers;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMLocationManager
|
||||
|
||||
#pragma mark - Init
|
||||
|
||||
+ (MWMLocationManager *)manager
|
||||
{
|
||||
static MWMLocationManager * manager;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{ manager = [[super alloc] initManager]; });
|
||||
return manager;
|
||||
}
|
||||
|
||||
- (instancetype)initManager
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
_observers = [TObservers weakObjectsHashTable];
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Add/Remove Observers
|
||||
|
||||
+ (void)addObserver:(TObserver)observer
|
||||
{
|
||||
runAsyncOnMainQueue(^
|
||||
{
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
[manager.observers addObject:observer];
|
||||
[manager processLocationUpdate:manager.lastLocationInfo];
|
||||
});
|
||||
}
|
||||
|
||||
+ (void)removeObserver:(TObserver)observer
|
||||
{
|
||||
runAsyncOnMainQueue(^
|
||||
{
|
||||
[[MWMLocationManager manager].observers removeObject:observer];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - App Life Cycle
|
||||
|
||||
+ (void)applicationDidBecomeActive
|
||||
{
|
||||
if (![Alohalytics isFirstSession])
|
||||
[MWMLocationManager manager].started = YES;
|
||||
}
|
||||
|
||||
+ (void)applicationWillResignActive
|
||||
{
|
||||
BOOL const keepRunning = keepRunningInBackground();
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
CLLocationManager * locationManager = manager.locationManager;
|
||||
if ([locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
|
||||
[locationManager setAllowsBackgroundLocationUpdates:keepRunning];
|
||||
manager.started = keepRunning;
|
||||
}
|
||||
|
||||
#pragma mark - Getters
|
||||
|
||||
+ (CLLocation *)lastLocation
|
||||
{
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
if (!manager.started || !manager.lastLocationInfo ||
|
||||
manager.lastLocationInfo.horizontalAccuracy < 0 ||
|
||||
manager.lastLocationStatus != location::TLocationError::ENoError)
|
||||
return nil;
|
||||
return manager.lastLocationInfo;
|
||||
}
|
||||
|
||||
+ (location::TLocationError)lastLocationStatus
|
||||
{
|
||||
return [MWMLocationManager manager].lastLocationStatus;
|
||||
}
|
||||
|
||||
+ (CLHeading *)lastHeading
|
||||
{
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
if (!manager.started || !manager.lastHeadingInfo || manager.lastHeadingInfo.headingAccuracy < 0)
|
||||
return nil;
|
||||
return manager.lastHeadingInfo;
|
||||
}
|
||||
|
||||
#pragma mark - Observer notifications
|
||||
|
||||
- (void)processLocationStatus:(location::TLocationError)locationError
|
||||
{
|
||||
// if (self.lastLocationStatus == locationError)
|
||||
// return;
|
||||
self.lastLocationStatus = locationError;
|
||||
sendInfoToFramework(^
|
||||
{
|
||||
if (self.lastLocationStatus != location::TLocationError::ENoError)
|
||||
GetFramework().OnLocationError(self.lastLocationStatus);
|
||||
});
|
||||
for (TObserver observer in self.observers)
|
||||
{
|
||||
if ([observer respondsToSelector:@selector(onLocationError:)])
|
||||
[observer onLocationError:self.lastLocationStatus];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)processHeadingUpdate:(CLHeading *)headingInfo
|
||||
{
|
||||
self.lastHeadingInfo = headingInfo;
|
||||
sendInfoToFramework(^
|
||||
{
|
||||
GetFramework().OnCompassUpdate(compassInfoFromHeading(self.lastHeadingInfo));
|
||||
});
|
||||
location::CompassInfo const compassInfo = compassInfoFromHeading(headingInfo);
|
||||
for (TObserver observer in self.observers)
|
||||
{
|
||||
if ([observer respondsToSelector:@selector(onHeadingUpdate:)])
|
||||
[observer onHeadingUpdate:compassInfo];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)processLocationUpdate:(CLLocation *)locationInfo
|
||||
{
|
||||
if (!locationInfo)
|
||||
return;
|
||||
location::GpsInfo const gpsInfo = gpsInfoFromLocation(locationInfo);
|
||||
[self onLocationUpdate:gpsInfo];
|
||||
if (self.lastLocationInfo == locationInfo)
|
||||
return;
|
||||
self.lastLocationInfo = locationInfo;
|
||||
self.lastLocationStatus = location::TLocationError::ENoError;
|
||||
[self.predictor reset:gpsInfo];
|
||||
}
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)gpsInfo
|
||||
{
|
||||
GpsTracker::Instance().OnLocationUpdated(gpsInfo);
|
||||
sendInfoToFramework([gpsInfo]
|
||||
{
|
||||
GetFramework().OnLocationUpdate(gpsInfo);
|
||||
});
|
||||
for (TObserver observer in self.observers)
|
||||
{
|
||||
if ([observer respondsToSelector:@selector(onLocationUpdate:)])
|
||||
[observer onLocationUpdate:gpsInfo];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Location Status
|
||||
|
||||
- (void)setLastLocationStatus:(location::TLocationError)lastLocationStatus
|
||||
{
|
||||
_lastLocationStatus = lastLocationStatus;
|
||||
switch (lastLocationStatus)
|
||||
{
|
||||
case location::ENoError:
|
||||
break;
|
||||
case location::ENotSupported:
|
||||
[alertController() presentLocationServiceNotSupportedAlert];
|
||||
break;
|
||||
case location::EDenied:
|
||||
[alertController() presentLocationAlert];
|
||||
break;
|
||||
case location::EGPSIsOff:
|
||||
// iOS shows its own alert.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - My Position
|
||||
|
||||
+ (void)setMyPositionMode:(location::EMyPositionMode)mode
|
||||
{
|
||||
MWMLocationManager * manager = [MWMLocationManager manager];
|
||||
[manager.predictor setMyPositionMode:mode];
|
||||
[manager processLocationStatus:manager.lastLocationStatus];
|
||||
auto const & f = GetFramework();
|
||||
if (f.IsRoutingActive())
|
||||
{
|
||||
switch (f.GetRouter())
|
||||
{
|
||||
case routing::RouterType::Vehicle:
|
||||
manager.geoMode = GeoMode::VehicleRouting;
|
||||
break;
|
||||
case routing::RouterType::Pedestrian:
|
||||
manager.geoMode = GeoMode::PedestrianRouting;
|
||||
break;
|
||||
case routing::RouterType::Bicycle:
|
||||
manager.geoMode = GeoMode::BicycleRouting;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case location::EMyPositionMode::PendingPosition:
|
||||
manager.geoMode = GeoMode::Pending;
|
||||
break;
|
||||
case location::EMyPositionMode::NotFollowNoPosition:
|
||||
case location::EMyPositionMode::NotFollow:
|
||||
manager.geoMode = GeoMode::NotInPosition;
|
||||
break;
|
||||
case location::EMyPositionMode::Follow:
|
||||
manager.geoMode = GeoMode::InPosition;
|
||||
break;
|
||||
case location::EMyPositionMode::FollowAndRotate:
|
||||
manager.geoMode = GeoMode::FollowAndRotate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Prediction
|
||||
|
||||
- (MWMLocationPredictor *)predictor
|
||||
{
|
||||
if (!_predictor)
|
||||
{
|
||||
__weak MWMLocationManager * weakSelf = self;
|
||||
_predictor = [[MWMLocationPredictor alloc] initWithOnPredictionBlock:^(location::GpsInfo const & gpsInfo)
|
||||
{
|
||||
[weakSelf onLocationUpdate:gpsInfo];
|
||||
}];
|
||||
}
|
||||
return _predictor;
|
||||
}
|
||||
|
||||
#pragma mark - Device notifications
|
||||
|
||||
- (void)orientationChanged
|
||||
{
|
||||
self.locationManager.headingOrientation = (CLDeviceOrientation)[UIDevice currentDevice].orientation;
|
||||
}
|
||||
|
||||
- (void)batteryStateChangedNotification:(NSNotification *)notification
|
||||
{
|
||||
[self refreshGeoModeSettings];
|
||||
}
|
||||
|
||||
#pragma mark - Location manager
|
||||
|
||||
- (void)setGeoMode:(GeoMode)geoMode
|
||||
{
|
||||
if (_geoMode == geoMode)
|
||||
return;
|
||||
_geoMode = geoMode;
|
||||
CLLocationManager * locationManager = self.locationManager;
|
||||
switch (geoMode)
|
||||
{
|
||||
case GeoMode::Pending:
|
||||
case GeoMode::InPosition:
|
||||
case GeoMode::NotInPosition:
|
||||
case GeoMode::FollowAndRotate:
|
||||
locationManager.activityType = CLActivityTypeOther;
|
||||
break;
|
||||
case GeoMode::VehicleRouting:
|
||||
locationManager.activityType = CLActivityTypeAutomotiveNavigation;
|
||||
break;
|
||||
case GeoMode::PedestrianRouting:
|
||||
case GeoMode::BicycleRouting:
|
||||
locationManager.activityType = CLActivityTypeFitness;
|
||||
break;
|
||||
}
|
||||
[self refreshGeoModeSettings];
|
||||
}
|
||||
|
||||
- (void)refreshGeoModeSettings
|
||||
{
|
||||
UIDeviceBatteryState const state = [UIDevice currentDevice].batteryState;
|
||||
BOOL const isCharging = (state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull);
|
||||
GeoModeSettings const settings = kGeoSettings.at(self.geoMode);
|
||||
CLLocationManager * locationManager = self.locationManager;
|
||||
locationManager.desiredAccuracy = isCharging ? settings.accuracy.charging : settings.accuracy.battery;
|
||||
locationManager.distanceFilter = settings.distanceFilter;
|
||||
}
|
||||
|
||||
- (CLLocationManager *)locationManager
|
||||
{
|
||||
if (!_locationManager)
|
||||
{
|
||||
_locationManager = [[CLLocationManager alloc] init];
|
||||
_locationManager.delegate = self;
|
||||
[self refreshGeoModeSettings];
|
||||
_locationManager.pausesLocationUpdatesAutomatically = YES;
|
||||
_locationManager.headingFilter = 3.0;
|
||||
}
|
||||
return _locationManager;
|
||||
}
|
||||
|
||||
#pragma mark - CLLocationManagerDelegate
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)heading
|
||||
{
|
||||
[self processHeadingUpdate:heading];
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
|
||||
{
|
||||
CLLocation * location = locations.lastObject;
|
||||
// According to documentation, lat and lon are valid only if horizontalAccuracy is non-negative.
|
||||
// So we filter out such events completely.
|
||||
if (location.horizontalAccuracy < 0.)
|
||||
return;
|
||||
[self processLocationUpdate:location];
|
||||
[[Statistics instance] logLocation:location];
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
|
||||
{
|
||||
if (self.lastLocationStatus == location::TLocationError::ENoError && error.code == kCLErrorDenied)
|
||||
[self processLocationStatus:location::EDenied];
|
||||
}
|
||||
|
||||
#pragma mark - Start / Stop
|
||||
|
||||
- (void)setStarted:(BOOL)started
|
||||
{
|
||||
if (_started == started)
|
||||
return;
|
||||
UIDevice * device = [UIDevice currentDevice];
|
||||
NSNotificationCenter * notificationCenter = [NSNotificationCenter defaultCenter];
|
||||
if (started)
|
||||
{
|
||||
_started = [self start];
|
||||
device.batteryMonitoringEnabled = YES;
|
||||
[notificationCenter addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
[notificationCenter addObserver:self selector:@selector(batteryStateChangedNotification:) name:UIDeviceBatteryStateDidChangeNotification object:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
_started = NO;
|
||||
[self stop];
|
||||
device.batteryMonitoringEnabled = NO;
|
||||
[notificationCenter removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
[notificationCenter removeObserver:self name:UIDeviceBatteryStateDidChangeNotification object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)start
|
||||
{
|
||||
auto const doStart = ^
|
||||
{
|
||||
LOG(LINFO, ("startUpdatingLocation"));
|
||||
CLLocationManager * locationManager = self.locationManager;
|
||||
if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
|
||||
[locationManager requestWhenInUseAuthorization];
|
||||
[locationManager startUpdatingLocation];
|
||||
if ([CLLocationManager headingAvailable])
|
||||
[locationManager startUpdatingHeading];
|
||||
};
|
||||
if ([CLLocationManager locationServicesEnabled])
|
||||
{
|
||||
switch ([CLLocationManager authorizationStatus])
|
||||
{
|
||||
case kCLAuthorizationStatusAuthorizedWhenInUse:
|
||||
case kCLAuthorizationStatusAuthorizedAlways:
|
||||
case kCLAuthorizationStatusNotDetermined:
|
||||
doStart();
|
||||
return YES;
|
||||
case kCLAuthorizationStatusRestricted:
|
||||
case kCLAuthorizationStatusDenied:
|
||||
[self processLocationStatus:location::EDenied];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Call start to make iOS show its alert to request geo service.
|
||||
doStart();
|
||||
[self processLocationStatus:location::EGPSIsOff];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)stop
|
||||
{
|
||||
LOG(LINFO, ("stopUpdatingLocation"));
|
||||
CLLocationManager * locationManager = self.locationManager;
|
||||
[locationManager stopUpdatingLocation];
|
||||
if ([CLLocationManager headingAvailable])
|
||||
[locationManager stopUpdatingHeading];
|
||||
}
|
||||
|
||||
@end
|
13
iphone/Maps/Classes/Location/MWMLocationPredictor.h
Normal file
13
iphone/Maps/Classes/Location/MWMLocationPredictor.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#import "MWMTypes.h"
|
||||
|
||||
#include "platform/location.hpp"
|
||||
|
||||
using TPredictionBlock = void (^)(location::GpsInfo const &);
|
||||
|
||||
@interface MWMLocationPredictor : NSObject
|
||||
|
||||
- (instancetype)initWithOnPredictionBlock:(TPredictionBlock)onPredictBlock;
|
||||
- (void)reset:(location::GpsInfo const &)info;
|
||||
- (void)setMyPositionMode:(location::EMyPositionMode)mode;
|
||||
|
||||
@end
|
81
iphone/Maps/Classes/Location/MWMLocationPredictor.mm
Normal file
81
iphone/Maps/Classes/Location/MWMLocationPredictor.mm
Normal file
|
@ -0,0 +1,81 @@
|
|||
#import "MWMLocationPredictor.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
NSTimeInterval constexpr kPredictionIntervalInSeconds = 0.5;
|
||||
NSUInteger constexpr kMaxPredictionCount = 20;
|
||||
} // namespace
|
||||
|
||||
@interface MWMLocationPredictor ()
|
||||
|
||||
@property (nonatomic) location::GpsInfo lastLocationInfo;
|
||||
@property (nonatomic) BOOL isLastLocationInfoValid;
|
||||
@property (nonatomic) BOOL isLastPositionModeValid;
|
||||
@property (nonatomic) NSUInteger predictionsCount;
|
||||
@property (copy, nonatomic) TPredictionBlock onPredictionBlock;
|
||||
|
||||
@end
|
||||
|
||||
@implementation MWMLocationPredictor
|
||||
|
||||
- (instancetype)initWithOnPredictionBlock:(TPredictionBlock)onPredictionBlock
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
_onPredictionBlock = [onPredictionBlock copy];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setMyPositionMode:(location::EMyPositionMode)mode
|
||||
{
|
||||
self.isLastPositionModeValid = (mode == location::FollowAndRotate);
|
||||
[self restart];
|
||||
}
|
||||
|
||||
- (void)reset:(location::GpsInfo const &)locationInfo
|
||||
{
|
||||
self.isLastLocationInfoValid = (locationInfo.HasSpeed() && locationInfo.HasBearing());
|
||||
if (self.isLastLocationInfoValid)
|
||||
self.lastLocationInfo = locationInfo;
|
||||
|
||||
[self restart];
|
||||
}
|
||||
|
||||
- (BOOL)isActive
|
||||
{
|
||||
return self.isLastLocationInfoValid && self.isLastPositionModeValid && self.predictionsCount < kMaxPredictionCount;
|
||||
}
|
||||
|
||||
- (void)restart
|
||||
{
|
||||
self.predictionsCount = 0;
|
||||
[self schedule];
|
||||
}
|
||||
|
||||
- (void)schedule
|
||||
{
|
||||
SEL const predict = @selector(predict);
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:predict object:nil];
|
||||
[self performSelector:predict withObject:nil afterDelay:kPredictionIntervalInSeconds];
|
||||
}
|
||||
|
||||
- (void)predict
|
||||
{
|
||||
if (!self.isActive)
|
||||
return;
|
||||
|
||||
self.predictionsCount++;
|
||||
|
||||
location::GpsInfo info = self.lastLocationInfo;
|
||||
info.m_source = location::EPredictor;
|
||||
info.m_timestamp = [NSDate date].timeIntervalSince1970;
|
||||
Framework::PredictLocation(info.m_latitude, info.m_longitude, info.m_horizontalAccuracy,
|
||||
info.m_bearing, info.m_speed,
|
||||
info.m_timestamp - self.lastLocationInfo.m_timestamp);
|
||||
self.onPredictionBlock(info);
|
||||
[self schedule];
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#import "../Platform/LocationManager.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface LocationPredictor : NSObject
|
||||
|
||||
-(id)initWithObserver:(NSObject<LocationObserver> *) observer;
|
||||
-(void)reset:(location::GpsInfo const &) info;
|
||||
-(void)setMode:(location::EMyPositionMode) mode;
|
||||
|
||||
@end
|
|
@ -1,106 +0,0 @@
|
|||
#import "LocationPredictor.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
#include "base/timer.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
NSTimeInterval const PREDICTION_INTERVAL = 0.2; // in seconds
|
||||
int const MAX_PREDICTION_COUNT = 20;
|
||||
}
|
||||
|
||||
@implementation LocationPredictor
|
||||
{
|
||||
NSObject<LocationObserver> * m_observer;
|
||||
NSTimer * m_timer;
|
||||
|
||||
location::GpsInfo m_lastGpsInfo;
|
||||
bool m_gpsInfoIsValid;
|
||||
|
||||
int m_connectionSlot;
|
||||
bool m_generatePredictions;
|
||||
int m_predictionCount;
|
||||
}
|
||||
|
||||
-(id)initWithObserver:(NSObject<LocationObserver> *)observer
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
m_observer = observer;
|
||||
m_timer = nil;
|
||||
m_gpsInfoIsValid = false;
|
||||
m_generatePredictions = false;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)setMode:(location::EMyPositionMode)mode
|
||||
{
|
||||
m_generatePredictions = (mode == location::FollowAndRotate);
|
||||
if (mode == location::PendingPosition || mode == location::NotFollowNoPosition)
|
||||
m_gpsInfoIsValid = false;
|
||||
|
||||
[self resetTimer];
|
||||
}
|
||||
|
||||
-(void)reset:(location::GpsInfo const &)info
|
||||
{
|
||||
if (info.HasSpeed() && info.HasBearing())
|
||||
{
|
||||
m_gpsInfoIsValid = true;
|
||||
m_lastGpsInfo = info;
|
||||
m_lastGpsInfo.m_timestamp = my::Timer::LocalTime();
|
||||
m_lastGpsInfo.m_source = location::EPredictor;
|
||||
}
|
||||
else
|
||||
m_gpsInfoIsValid = false;
|
||||
|
||||
[self resetTimer];
|
||||
}
|
||||
|
||||
-(bool)isPredict
|
||||
{
|
||||
return m_gpsInfoIsValid && m_generatePredictions;
|
||||
}
|
||||
|
||||
-(void)resetTimer
|
||||
{
|
||||
m_predictionCount = 0;
|
||||
|
||||
if (m_timer != nil)
|
||||
{
|
||||
[m_timer invalidate];
|
||||
m_timer = nil;
|
||||
}
|
||||
|
||||
if ([self isPredict])
|
||||
{
|
||||
m_timer = [NSTimer scheduledTimerWithTimeInterval:PREDICTION_INTERVAL
|
||||
target:self
|
||||
selector:@selector(timerFired)
|
||||
userInfo:nil
|
||||
repeats:YES];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)timerFired
|
||||
{
|
||||
if (![self isPredict])
|
||||
return;
|
||||
|
||||
if (m_predictionCount < MAX_PREDICTION_COUNT)
|
||||
{
|
||||
++m_predictionCount;
|
||||
|
||||
location::GpsInfo info = m_lastGpsInfo;
|
||||
info.m_timestamp = my::Timer::LocalTime();
|
||||
::Framework::PredictLocation(info.m_latitude, info.m_longitude, info.m_horizontalAccuracy, info.m_bearing,
|
||||
info.m_speed, info.m_timestamp - m_lastGpsInfo.m_timestamp);
|
||||
|
||||
[m_observer onLocationUpdate:info];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,10 +1,10 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMBasePlacePageView.h"
|
||||
#import "MWMCircularProgress.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMPlacePage.h"
|
||||
#import "MWMPlacePageActionBar.h"
|
||||
#import "MWMPlacePageBookmarkCell.h"
|
||||
|
@ -257,7 +257,7 @@ using namespace storage;
|
|||
self.bookingRatingLabel.text = entity.bookingRating;
|
||||
self.bookingView.hidden = !entity.bookingPrice.length && !entity.bookingRating.length;
|
||||
BOOL const isHeadingAvaible = [CLLocationManager headingAvailable];
|
||||
BOOL const noLocation = MapsAppDelegate.theApp.locationManager.isLocationPendingOrNoPosition;
|
||||
BOOL const noLocation = location_helpers::isMyPositionPendingOrNoPosition();
|
||||
self.distanceLabel.hidden = noLocation || isMyPosition;
|
||||
BOOL const hideDirection = noLocation || isMyPosition || !isHeadingAvaible;
|
||||
self.directionArrow.hidden = hideDirection;
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MWMAPIBar.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMActivityViewController.h"
|
||||
#import "MWMAPIBar.h"
|
||||
#import "MWMBasePlacePageView.h"
|
||||
#import "MWMDirectionView.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMiPadPlacePage.h"
|
||||
#import "MWMiPhoneLandscapePlacePage.h"
|
||||
#import "MWMiPhonePortraitPlacePage.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMPlacePage.h"
|
||||
#import "MWMPlacePageActionBar.h"
|
||||
#import "MWMPlacePageEntity.h"
|
||||
#import "MWMPlacePageNavigationBar.h"
|
||||
#import "MWMPlacePageViewManager.h"
|
||||
#import "MWMPlacePageViewManagerDelegate.h"
|
||||
#import "MWMiPadPlacePage.h"
|
||||
#import "MWMiPhoneLandscapePlacePage.h"
|
||||
#import "MWMiPhonePortraitPlacePage.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "Statistics.h"
|
||||
|
||||
#import "3party/Alohalytics/src/alohalytics_objc.h"
|
||||
|
@ -27,7 +28,7 @@
|
|||
extern NSString * const kAlohalyticsTapEventKey;
|
||||
extern NSString * const kBookmarksChangedNotification;
|
||||
|
||||
@interface MWMPlacePageViewManager () <LocationObserver>
|
||||
@interface MWMPlacePageViewManager () <MWMLocationObserver>
|
||||
|
||||
@property (weak, nonatomic) MWMViewController * ownerViewController;
|
||||
@property (nonatomic, readwrite) MWMPlacePageEntity * entity;
|
||||
|
@ -61,14 +62,14 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
{
|
||||
[self.delegate placePageDidClose];
|
||||
[self.placePage dismiss];
|
||||
[[MapsAppDelegate theApp].locationManager stop:self];
|
||||
[MWMLocationManager removeObserver:self];
|
||||
GetFramework().DeactivateMapSelection(false);
|
||||
self.placePage = nil;
|
||||
}
|
||||
|
||||
- (void)showPlacePage:(place_page::Info const &)info
|
||||
{
|
||||
[[MapsAppDelegate theApp].locationManager start:self];
|
||||
[MWMLocationManager addObserver:self];
|
||||
self.entity = [[MWMPlacePageEntity alloc] initWithInfo:info];
|
||||
if (IPAD)
|
||||
[self setPlacePageForiPad];
|
||||
|
@ -111,10 +112,8 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
- (void)configPlacePage
|
||||
{
|
||||
if (self.entity.isMyPosition)
|
||||
{
|
||||
BOOL hasSpeed;
|
||||
self.entity.subtitle = [[MapsAppDelegate theApp].locationManager formattedSpeedAndAltitude:hasSpeed];
|
||||
}
|
||||
self.entity.subtitle =
|
||||
location_helpers::formattedSpeedAndAltitude([MWMLocationManager lastLocation]);
|
||||
self.placePage.parentViewHeight = self.ownerViewController.view.height;
|
||||
[self.placePage configure];
|
||||
self.placePage.topBound = self.topBound;
|
||||
|
@ -147,11 +146,9 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
|
||||
- (void)updateMyPositionSpeedAndAltitude
|
||||
{
|
||||
if (!self.entity.isMyPosition)
|
||||
return;
|
||||
BOOL hasSpeed = NO;
|
||||
[self.placePage updateMyPositionStatus:[[MapsAppDelegate theApp].locationManager
|
||||
formattedSpeedAndAltitude:hasSpeed]];
|
||||
if (self.entity.isMyPosition)
|
||||
[self.placePage updateMyPositionStatus:location_helpers::formattedSpeedAndAltitude(
|
||||
[MWMLocationManager lastLocation])];
|
||||
}
|
||||
|
||||
- (void)setPlacePageForiPhoneWithOrientation:(UIInterfaceOrientation)orientation
|
||||
|
@ -188,9 +185,10 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
withParameters:@{kStatValue : kStatDestination}];
|
||||
[Alohalytics logEvent:kAlohalyticsTapEventKey withValue:@"ppRoute"];
|
||||
|
||||
LocationManager * lm = MapsAppDelegate.theApp.locationManager;
|
||||
[self.delegate buildRouteFrom:lm.isLocationPendingOrNoPosition ? MWMRoutePoint::MWMRoutePointZero()
|
||||
: MWMRoutePoint(lm.lastLocation.mercator)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
BOOL const noLocation = location_helpers::isMyPositionPendingOrNoPosition() || !lastLocation;
|
||||
[self.delegate buildRouteFrom:noLocation ? MWMRoutePoint::MWMRoutePointZero()
|
||||
: MWMRoutePoint(lastLocation.mercator)
|
||||
to:self.target];
|
||||
}
|
||||
|
||||
|
@ -249,8 +247,6 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
- (void)book:(BOOL)isDescription
|
||||
{
|
||||
NSMutableDictionary * stat = [@{kStatProvider : kStatBooking} mutableCopy];
|
||||
LocationManager * lm = MapsAppDelegate.theApp.locationManager;
|
||||
CLLocation * loc = lm.lastLocationIsValid ? lm.lastLocation : nil;
|
||||
MWMPlacePageEntity * en = self.entity;
|
||||
auto const latLon = en.latlon;
|
||||
stat[kStatHotel] = en.hotelId;
|
||||
|
@ -258,7 +254,7 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
stat[kStatHotelLon] = @(latLon.lon);
|
||||
[Statistics logEvent:isDescription ? kPlacePageHotelDetails : kPlacePageHotelBook
|
||||
withParameters:stat
|
||||
atLocation:loc];
|
||||
atLocation:[MWMLocationManager lastLocation]];
|
||||
|
||||
UIViewController * vc = static_cast<UIViewController *>(MapsAppDelegate.theApp.mapViewController);
|
||||
NSURL * url = isDescription ? [NSURL URLWithString:[self.entity getCellValue:MWMPlacePageCellTypeBookingMore]] : self.entity.bookingUrl;
|
||||
|
@ -353,12 +349,6 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
[self.delegate dragPlacePage:frame];
|
||||
}
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
[self updateDistance];
|
||||
[self updateMyPositionSpeedAndAltitude];
|
||||
}
|
||||
|
||||
- (void)updateDistance
|
||||
{
|
||||
NSString * distance = [self distance];
|
||||
|
@ -368,33 +358,17 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
|
||||
- (NSString *)distance
|
||||
{
|
||||
CLLocation * location = [MapsAppDelegate theApp].locationManager.lastLocation;
|
||||
// TODO(AlexZ): Do we REALLY need this check? Why this method is called if user mark/m_info is empty?
|
||||
// TODO(AlexZ): Can location be checked before calling this method?
|
||||
if (!location/* || !m_userMark*/)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return @"";
|
||||
string distance;
|
||||
CLLocationCoordinate2D const coord = location.coordinate;
|
||||
CLLocationCoordinate2D const coord = lastLocation.coordinate;
|
||||
ms::LatLon const target = self.entity.latlon;
|
||||
MeasurementUtils::FormatDistance(ms::DistanceOnEarth(coord.latitude, coord.longitude,
|
||||
target.lat, target.lon), distance);
|
||||
return @(distance.c_str());
|
||||
}
|
||||
|
||||
- (void)onCompassUpdate:(location::CompassInfo const &)info
|
||||
{
|
||||
CLLocation * location = [MapsAppDelegate theApp].locationManager.lastLocation;
|
||||
// TODO(AlexZ): Do we REALLY need this check? Why compass update is here if user mark/m_info is empty?
|
||||
// TODO(AlexZ): Can location be checked before calling this method?
|
||||
if (!location/* || !m_userMark*/)
|
||||
return;
|
||||
|
||||
CGFloat const angle = ang::AngleTo(location.mercator, self.entity.mercator) + info.m_bearing;
|
||||
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_2 - angle);
|
||||
[self.placePage setDirectionArrowTransform:transform];
|
||||
[self.directionView setDirectionArrowTransform:transform];
|
||||
}
|
||||
|
||||
- (void)showDirectionViewWithTitle:(NSString *)title type:(NSString *)type
|
||||
{
|
||||
MWMDirectionView * directionView = self.directionView;
|
||||
|
@ -423,6 +397,25 @@ extern NSString * const kBookmarksChangedNotification;
|
|||
((MWMiPadPlacePage *)self.placePage).height = height;
|
||||
}
|
||||
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onHeadingUpdate:(location::CompassInfo const &)info
|
||||
{
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
CGFloat const angle = ang::AngleTo(lastLocation.mercator, self.entity.mercator) + info.m_bearing;
|
||||
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_2 - angle);
|
||||
[self.placePage setDirectionArrowTransform:transform];
|
||||
[self.directionView setDirectionArrowTransform:transform];
|
||||
}
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)locationInfo
|
||||
{
|
||||
[self updateDistance];
|
||||
[self updateMyPositionSpeedAndAltitude];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (MWMDirectionView *)directionView
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapDownloaderExtendedDataSource.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
@ -31,12 +31,12 @@ using namespace storage;
|
|||
|
||||
- (void)configNearMeSection
|
||||
{
|
||||
LocationManager * lm = MapsAppDelegate.theApp.locationManager;
|
||||
if (!lm.lastLocationIsValid)
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return;
|
||||
auto & countryInfoGetter = GetFramework().CountryInfoGetter();
|
||||
TCountriesVec closestCoutryIds;
|
||||
countryInfoGetter.GetRegionsCountryId(lm.lastLocation.mercator, closestCoutryIds);
|
||||
countryInfoGetter.GetRegionsCountryId(lastLocation.mercator, closestCoutryIds);
|
||||
NSMutableArray<NSString *> * nearmeCountries = [@[] mutableCopy];
|
||||
for (auto const & countryId : closestCoutryIds)
|
||||
[nearmeCountries addObject:@(countryId.c_str())];
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#import "LocationManager.h"
|
||||
#import "LocationPredictor.h"
|
||||
#import "MWMMapDownloaderTypes.h"
|
||||
#import "MWMViewController.h"
|
||||
#import <MyTargetSDKCorp/MTRGNativeAppwallAd.h>
|
||||
|
@ -13,19 +11,12 @@ namespace search { struct AddressInfo; }
|
|||
@class MWMMapViewControlsManager;
|
||||
@class MWMAPIBar;
|
||||
|
||||
@interface MapViewController : MWMViewController <LocationObserver>
|
||||
{
|
||||
LocationPredictor * m_predictor;
|
||||
}
|
||||
@interface MapViewController : MWMViewController
|
||||
|
||||
// called when app is terminated by system
|
||||
- (void)onTerminate;
|
||||
- (void)onEnterForeground;
|
||||
- (void)onEnterBackground;
|
||||
- (void)onGetFocus:(BOOL)isOnFocus;
|
||||
|
||||
- (void)setMapStyle:(MapStyle)mapStyle;
|
||||
|
||||
- (void)updateStatusBarStyle;
|
||||
|
||||
- (void)showAPIBar;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#import "MWMFirstLaunchController.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationHelpers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapDownloadDialog.h"
|
||||
#import "MWMMapDownloaderViewController.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
|
@ -115,7 +117,7 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
|
||||
@interface MapViewController ()<MTRGNativeAppwallAdDelegate, MWMFrameworkRouteBuilderObserver,
|
||||
MWMFrameworkDrapeObserver, MWMFrameworkStorageObserver,
|
||||
MWMPageControllerProtocol>
|
||||
MWMPageControllerProtocol, MWMLocationObserver>
|
||||
|
||||
@property (nonatomic, readwrite) MWMMapViewControlsManager * controlsManager;
|
||||
@property (nonatomic) MWMBottomMenuState menuRestoreState;
|
||||
|
@ -133,45 +135,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
|
||||
@implementation MapViewController
|
||||
|
||||
#pragma mark - LocationManager Callbacks
|
||||
|
||||
- (void)onLocationError:(location::TLocationError)errorCode
|
||||
{
|
||||
GetFramework().OnLocationError(errorCode);
|
||||
|
||||
switch (errorCode)
|
||||
{
|
||||
case location::EDenied:
|
||||
{
|
||||
[self.alertController presentLocationAlert];
|
||||
[[MapsAppDelegate theApp].locationManager stop:self];
|
||||
break;
|
||||
}
|
||||
case location::ENotSupported:
|
||||
{
|
||||
[self.alertController presentLocationServiceNotSupportedAlert];
|
||||
[[MapsAppDelegate theApp].locationManager stop:self];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
if (info.m_source != location::EPredictor)
|
||||
[m_predictor reset:info];
|
||||
Framework & frm = GetFramework();
|
||||
frm.OnLocationUpdate(info);
|
||||
LOG_MEMORY_INFO();
|
||||
|
||||
[self updateRoutingInfo];
|
||||
|
||||
if (self.forceRoutingStateChange == ForceRoutingStateChangeRestoreRoute)
|
||||
[self restoreRoute];
|
||||
}
|
||||
|
||||
- (void)updateRoutingInfo
|
||||
{
|
||||
Framework & frm = GetFramework();
|
||||
|
@ -188,9 +151,14 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
[[MWMTextToSpeech tts] playTurnNotifications];
|
||||
}
|
||||
|
||||
- (void)onCompassUpdate:(location::CompassInfo const &)info
|
||||
#pragma mark - MWMLocationObserver
|
||||
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
GetFramework().OnCompassUpdate(info);
|
||||
[self updateRoutingInfo];
|
||||
|
||||
if (self.forceRoutingStateChange == ForceRoutingStateChangeRestoreRoute)
|
||||
[self restoreRoute];
|
||||
}
|
||||
|
||||
#pragma mark - Restore route
|
||||
|
@ -343,25 +311,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
[(EAGLView *)self.view deallocateNative];
|
||||
}
|
||||
|
||||
- (void)onEnterBackground
|
||||
{
|
||||
// Save state and notify about entering background.
|
||||
GetFramework().EnterBackground();
|
||||
}
|
||||
|
||||
- (void)setMapStyle:(MapStyle)mapStyle
|
||||
{
|
||||
GetFramework().SetMapStyle(mapStyle);
|
||||
}
|
||||
|
||||
- (void)onEnterForeground
|
||||
{
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return;
|
||||
// Notify about entering foreground (should be called on the first launch too).
|
||||
GetFramework().EnterForeground();
|
||||
}
|
||||
|
||||
- (void)onGetFocus:(BOOL)isOnFocus
|
||||
{
|
||||
[(EAGLView *)self.view setPresentAvailable:isOnFocus];
|
||||
|
@ -370,8 +319,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
|
||||
self.controlsManager.menuState = self.menuRestoreState;
|
||||
|
@ -382,6 +329,7 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
GetFramework().InvalidateRendering();
|
||||
[self showWelcomeScreenIfNeeded];
|
||||
[self showViralAlertIfNeeded];
|
||||
[MWMLocationManager addObserver:self];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
|
@ -393,8 +341,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return;
|
||||
self.view.clipsToBounds = YES;
|
||||
[MTRGManager setMyCom:YES];
|
||||
[self processMyPositionStateModeEvent:location::PendingPosition];
|
||||
|
@ -460,6 +406,7 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
[super viewWillDisappear:animated];
|
||||
self.menuRestoreState = self.controlsManager.menuState;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
[MWMLocationManager removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)presentViewController:(UIViewController *)viewControllerToPresent
|
||||
|
@ -502,7 +449,7 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
{
|
||||
NSLog(@"MapViewController initWithCoder Started");
|
||||
self = [super initWithCoder:coder];
|
||||
if (self && !MapsAppDelegate.theApp.isDaemonMode)
|
||||
if (self)
|
||||
[self initialize];
|
||||
|
||||
NSLog(@"MapViewController initWithCoder Ended");
|
||||
|
@ -524,7 +471,6 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
[self processMyPositionStateModeEvent:mode];
|
||||
});
|
||||
|
||||
m_predictor = [[LocationPredictor alloc] initWithObserver:self];
|
||||
self.forceRoutingStateChange = ForceRoutingStateChangeNone;
|
||||
self.userTouchesAction = UserTouchesActionNone;
|
||||
self.menuRestoreState = MWMBottomMenuStateInactive;
|
||||
|
@ -566,49 +512,35 @@ BOOL gIsFirstMyPositionMode = YES;
|
|||
|
||||
- (void)processMyPositionStateModeEvent:(location::EMyPositionMode)mode
|
||||
{
|
||||
[m_predictor setMode:mode];
|
||||
|
||||
LocationManager * lm = [MapsAppDelegate theApp].locationManager;
|
||||
[lm processMyPositionStateModeEvent:mode];
|
||||
[MWMLocationManager setMyPositionMode:mode];
|
||||
[self.controlsManager processMyPositionStateModeEvent:mode];
|
||||
self.disableStandbyOnLocationStateMode = NO;
|
||||
switch (mode)
|
||||
{
|
||||
case location::PendingPosition:
|
||||
self.disableStandbyOnLocationStateMode = NO;
|
||||
[lm start:self];
|
||||
break;
|
||||
case location::NotFollowNoPosition:
|
||||
if (gIsFirstMyPositionMode && ![Alohalytics isFirstSession])
|
||||
case location::NotFollowNoPosition:
|
||||
if (gIsFirstMyPositionMode && ![Alohalytics isFirstSession])
|
||||
{
|
||||
GetFramework().SwitchMyPositionNextMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL const isMapVisible = (self.navigationController.visibleViewController == self);
|
||||
if (isMapVisible && !location_helpers::isLocationProhibited())
|
||||
{
|
||||
GetFramework().SwitchMyPositionNextMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
self.disableStandbyOnLocationStateMode = NO;
|
||||
BOOL const isMapVisible = (self.navigationController.visibleViewController == self);
|
||||
if (isMapVisible && lm.isStarted)
|
||||
[self.alertController presentLocationNotFoundAlertWithOkBlock:^
|
||||
{
|
||||
[lm stop:self];
|
||||
BOOL const isLocationProhibited =
|
||||
lm.lastLocationError == location::TLocationError::EDenied ||
|
||||
lm.lastLocationError == location::TLocationError::EGPSIsOff;
|
||||
if (!isLocationProhibited)
|
||||
{
|
||||
[self.alertController presentLocationNotFoundAlertWithOkBlock:^
|
||||
{
|
||||
GetFramework().SwitchMyPositionNextMode();
|
||||
}];
|
||||
}
|
||||
}
|
||||
GetFramework().SwitchMyPositionNextMode();
|
||||
}];
|
||||
}
|
||||
break;
|
||||
case location::NotFollow:
|
||||
self.disableStandbyOnLocationStateMode = NO;
|
||||
break;
|
||||
case location::Follow:
|
||||
case location::FollowAndRotate:
|
||||
self.disableStandbyOnLocationStateMode = YES;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case location::PendingPosition:
|
||||
case location::NotFollow:
|
||||
break;
|
||||
case location::Follow:
|
||||
case location::FollowAndRotate:
|
||||
self.disableStandbyOnLocationStateMode = YES;
|
||||
break;
|
||||
}
|
||||
gIsFirstMyPositionMode = NO;
|
||||
}
|
||||
|
|
|
@ -29,8 +29,7 @@ typedef NS_ENUM(NSUInteger, MWMRoutingPlaneMode)
|
|||
@property (nonatomic) MWMRoutingPlaneMode routingPlaneMode;
|
||||
|
||||
@property (nonatomic, readonly) MapViewController * mapViewController;
|
||||
@property (nonatomic, readonly) LocationManager * locationManager;
|
||||
@property (nonatomic, readonly) BOOL isDaemonMode;
|
||||
@property (nonatomic, readonly) BOOL isDrapeEngineCreated;
|
||||
|
||||
+ (MapsAppDelegate *)theApp;
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#import "Common.h"
|
||||
#import "EAGLView.h"
|
||||
#import "LocalNotificationManager.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
|
@ -10,6 +9,7 @@
|
|||
#import "MWMController.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMStorage.h"
|
||||
#import "MWMTextToSpeech.h"
|
||||
#import "Preferences.h"
|
||||
|
@ -140,7 +140,6 @@ using namespace osm_auth_ios;
|
|||
@property (weak, nonatomic) NSTimer * mapStyleSwitchTimer;
|
||||
|
||||
@property (nonatomic, readwrite) LocationManager * locationManager;
|
||||
@property (nonatomic, readwrite) BOOL isDaemonMode;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -214,9 +213,14 @@ using namespace osm_auth_ios;
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isDrapeEngineCreated
|
||||
{
|
||||
return ((EAGLView *)self.mapViewController.view).drapeEngineCreated;
|
||||
}
|
||||
|
||||
- (void)handleURLs
|
||||
{
|
||||
if (!((EAGLView *)self.mapViewController.view).drapeEngineCreated)
|
||||
if (!self.isDrapeEngineCreated)
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{ [self handleURLs]; });
|
||||
return;
|
||||
|
@ -347,35 +351,40 @@ using namespace osm_auth_ios;
|
|||
{
|
||||
NSAssert([MapsAppDelegate isAutoNightMode], @"Invalid auto switcher's state");
|
||||
auto & f = GetFramework();
|
||||
MapsAppDelegate * app = MapsAppDelegate.theApp;
|
||||
CLLocation * l = app.locationManager.lastLocation;
|
||||
if (!l || !f.IsRoutingActive())
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation || !f.IsRoutingActive())
|
||||
return;
|
||||
dispatch_async(dispatch_get_main_queue(), [&f, l, self, app]
|
||||
CLLocationCoordinate2D const coord = lastLocation.coordinate;
|
||||
dispatch_async(dispatch_get_main_queue(), [coord]
|
||||
{
|
||||
auto const dayTime = GetDayTime(static_cast<time_t>(NSDate.date.timeIntervalSince1970), l.coordinate.latitude, l.coordinate.longitude);
|
||||
id<MWMController> vc = static_cast<id<MWMController>>(app.mapViewController.navigationController.topViewController);
|
||||
auto & f = GetFramework();
|
||||
MapsAppDelegate * app = MapsAppDelegate.theApp;
|
||||
auto const dayTime =
|
||||
GetDayTime(static_cast<time_t>(NSDate.date.timeIntervalSince1970),
|
||||
coord.latitude, coord.longitude);
|
||||
id<MWMController> vc = static_cast<id<MWMController>>(
|
||||
app.mapViewController.navigationController.topViewController);
|
||||
auto style = f.GetMapStyle();
|
||||
switch (dayTime)
|
||||
{
|
||||
case DayTimeType::Day:
|
||||
case DayTimeType::PolarDay:
|
||||
if (style != MapStyleClear && style != MapStyleLight)
|
||||
{
|
||||
f.SetMapStyle(MapStyleClear);
|
||||
[UIColor setNightMode:NO];
|
||||
[vc mwm_refreshUI];
|
||||
}
|
||||
break;
|
||||
case DayTimeType::Night:
|
||||
case DayTimeType::PolarNight:
|
||||
if (style != MapStyleDark)
|
||||
{
|
||||
f.SetMapStyle(MapStyleDark);
|
||||
[UIColor setNightMode:YES];
|
||||
[vc mwm_refreshUI];
|
||||
}
|
||||
break;
|
||||
case DayTimeType::Day:
|
||||
case DayTimeType::PolarDay:
|
||||
if (style != MapStyleClear && style != MapStyleLight)
|
||||
{
|
||||
f.SetMapStyle(MapStyleClear);
|
||||
[UIColor setNightMode:NO];
|
||||
[vc mwm_refreshUI];
|
||||
}
|
||||
break;
|
||||
case DayTimeType::Night:
|
||||
case DayTimeType::PolarNight:
|
||||
if (style != MapStyleDark)
|
||||
{
|
||||
f.SetMapStyle(MapStyleDark);
|
||||
[UIColor setNightMode:YES];
|
||||
[vc mwm_refreshUI];
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -386,11 +395,6 @@ using namespace osm_auth_ios;
|
|||
|
||||
// Initialize all 3party engines.
|
||||
BOOL returnValue = [self initStatistics:application didFinishLaunchingWithOptions:launchOptions];
|
||||
if (launchOptions[UIApplicationLaunchOptionsLocationKey])
|
||||
{
|
||||
self.isDaemonMode = YES;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
// We send Alohalytics installation id to Fabric.
|
||||
// To make sure id is created, ConfigCrashTrackers must be called after Statistics initialization.
|
||||
|
@ -407,8 +411,7 @@ using namespace osm_auth_ios;
|
|||
InitLocalizedStrings();
|
||||
[self determineMapStyle];
|
||||
|
||||
[self.mapViewController onEnterForeground];
|
||||
self.isDaemonMode = NO;
|
||||
GetFramework().EnterForeground();
|
||||
|
||||
[self initPushNotificationsWithLaunchOptions:launchOptions];
|
||||
[self commonInit];
|
||||
|
@ -531,16 +534,13 @@ using namespace osm_auth_ios;
|
|||
|
||||
- (void)applicationWillTerminate:(UIApplication *)application
|
||||
{
|
||||
[self.locationManager beforeTerminate];
|
||||
[self.mapViewController onTerminate];
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||
{
|
||||
LOG(LINFO, ("applicationDidEnterBackground"));
|
||||
[self.locationManager stop:self.mapViewController];
|
||||
[self.locationManager onBackground];
|
||||
[self.mapViewController onEnterBackground];
|
||||
GetFramework().EnterBackground();
|
||||
if (m_activeDownloadsCounter)
|
||||
{
|
||||
m_backgroundTask = [application beginBackgroundTaskWithExpirationHandler:^{
|
||||
|
@ -579,42 +579,25 @@ using namespace osm_auth_ios;
|
|||
[self.mapViewController.appWallAd close];
|
||||
[RouteState save];
|
||||
GetFramework().SetRenderingEnabled(false);
|
||||
[MWMLocationManager applicationWillResignActive];
|
||||
}
|
||||
|
||||
- (void)applicationWillEnterForeground:(UIApplication *)application
|
||||
{
|
||||
LOG(LINFO, ("applicationWillEnterForeground"));
|
||||
BOOL const needInit = self.isDaemonMode;
|
||||
self.isDaemonMode = NO;
|
||||
if (needInit)
|
||||
{
|
||||
[self.mapViewController initialize];
|
||||
[(EAGLView *)self.mapViewController.view initialize];
|
||||
[self.mapViewController.view setNeedsLayout];
|
||||
[self.mapViewController.view layoutIfNeeded];
|
||||
[self commonInit];
|
||||
[self incrementSessionsCountAndCheckForAlert];
|
||||
}
|
||||
[self.mapViewController onEnterForeground];
|
||||
GetFramework().EnterForeground();
|
||||
[MWMTextToSpeech activateAudioSession];
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
if (application.applicationState == UIApplicationStateBackground)
|
||||
{
|
||||
LOG(LINFO, ("applicationDidBecomeActive, applicationState = UIApplicationStateBackground"));
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(LINFO, ("applicationDidBecomeActive"));
|
||||
[self.mapViewController onGetFocus: YES];
|
||||
[self handleURLs];
|
||||
[self restoreRouteState];
|
||||
[[Statistics instance] applicationDidBecomeActive];
|
||||
GetFramework().SetRenderingEnabled(true);
|
||||
if (![Alohalytics isFirstSession])
|
||||
[self.locationManager start:self.mapViewController];
|
||||
[MWMLocationManager applicationDidBecomeActive];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
|
@ -674,7 +657,7 @@ using namespace osm_auth_ios;
|
|||
|
||||
- (void)setMapStyle:(MapStyle)mapStyle
|
||||
{
|
||||
[self.mapViewController setMapStyle: mapStyle];
|
||||
GetFramework().SetMapStyle(mapStyle);
|
||||
}
|
||||
|
||||
+ (NSDictionary *)navigationBarTextAttributes
|
||||
|
@ -829,33 +812,6 @@ using namespace osm_auth_ios;
|
|||
return [(UINavigationController *)self.window.rootViewController viewControllers].firstObject;
|
||||
}
|
||||
|
||||
- (LocationManager *)locationManager
|
||||
{
|
||||
if (!_locationManager)
|
||||
_locationManager = [[LocationManager alloc] init];
|
||||
return _locationManager;
|
||||
}
|
||||
|
||||
@synthesize isDaemonMode = _isDaemonMode;
|
||||
|
||||
- (BOOL)isDaemonMode
|
||||
{
|
||||
if ([Alohalytics isFirstSession])
|
||||
return NO;
|
||||
return _isDaemonMode;
|
||||
}
|
||||
|
||||
- (void)setIsDaemonMode:(BOOL)isDaemonMode
|
||||
{
|
||||
if ([Alohalytics isFirstSession] && _isDaemonMode == isDaemonMode)
|
||||
return;
|
||||
_isDaemonMode = isDaemonMode;
|
||||
if (isDaemonMode)
|
||||
[self.locationManager onDaemonMode];
|
||||
else
|
||||
[self.locationManager onForeground];
|
||||
}
|
||||
|
||||
#pragma mark - Route state
|
||||
|
||||
- (void)restoreRouteState
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
#import "MWMCircularProgress.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapDownloaderViewController.h"
|
||||
#import "MWMMigrationView.h"
|
||||
#import "MWMMigrationViewController.h"
|
||||
|
@ -64,10 +64,11 @@ using namespace storage;
|
|||
[Statistics logEvent:kStatDownloaderMigrationStarted
|
||||
withParameters:@{kStatType : limited ? kStatCurrentMap : kStatAllMaps}];
|
||||
auto & f = GetFramework();
|
||||
LocationManager * lm = [MapsAppDelegate theApp].locationManager;
|
||||
ms::LatLon position{};
|
||||
if (![lm getLat:position.lat Lon:position.lon])
|
||||
position = MercatorBounds::ToLatLon(f.GetViewportCenter());
|
||||
|
||||
ms::LatLon position = MercatorBounds::ToLatLon(f.GetViewportCenter());
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (lastLocation)
|
||||
position = ms::LatLon(lastLocation.coordinate.latitude, lastLocation.coordinate.longitude);
|
||||
|
||||
auto migrate = ^
|
||||
{
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMAlertViewController.h"
|
||||
#import "MWMCircularProgress.h"
|
||||
#import "MWMFrameworkListener.h"
|
||||
#import "MWMFrameworkObservers.h"
|
||||
#import "MWMLocationManager.h"
|
||||
#import "MWMMapDownloadDialog.h"
|
||||
#import "MWMStorage.h"
|
||||
#import "Statistics.h"
|
||||
|
@ -27,13 +27,13 @@ BOOL canAutoDownload(TCountryId const & countryId)
|
|||
(void)settings::Get(kAutoDownloadEnabledKey, autoDownloadEnabled);
|
||||
if (!autoDownloadEnabled)
|
||||
return NO;
|
||||
LocationManager * locationManager = MapsAppDelegate.theApp.locationManager;
|
||||
if (![locationManager lastLocationIsValid])
|
||||
return NO;
|
||||
if (GetPlatform().ConnectionStatus() != Platform::EConnectionType::CONNECTION_WIFI)
|
||||
return NO;
|
||||
CLLocation * lastLocation = [MWMLocationManager lastLocation];
|
||||
if (!lastLocation)
|
||||
return NO;
|
||||
auto const & countryInfoGetter = GetFramework().CountryInfoGetter();
|
||||
if (countryId != countryInfoGetter.GetRegionCountryId(locationManager.lastLocation.mercator))
|
||||
if (countryId != countryInfoGetter.GetRegionCountryId(lastLocation.mercator))
|
||||
return NO;
|
||||
return !platform::migrate::NeedMigrate();
|
||||
}
|
||||
|
|
|
@ -144,8 +144,6 @@
|
|||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>NSLocationAlwaysUsageDescription</key>
|
||||
<string></string>
|
||||
<key>UIApplicationShortcutItems</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
|
|
@ -97,6 +97,8 @@
|
|||
343FAC4B1CBFBDFC00A45D3B /* MWMNoMapsView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 343FAC491CBFBDFC00A45D3B /* MWMNoMapsView.mm */; };
|
||||
34479C7C1C60C6130065D261 /* MWMFrameworkListener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34479C781C60C6130065D261 /* MWMFrameworkListener.mm */; };
|
||||
34479C7D1C60C6130065D261 /* MWMFrameworkListener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34479C781C60C6130065D261 /* MWMFrameworkListener.mm */; };
|
||||
344D77B41D1BD7C800DBED70 /* MWMLocationManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 344D77B31D1BD7C800DBED70 /* MWMLocationManager.mm */; };
|
||||
344D77B51D1BD7C800DBED70 /* MWMLocationManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 344D77B31D1BD7C800DBED70 /* MWMLocationManager.mm */; };
|
||||
34570A391B13219600E6D4FD /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97C98653186C5F0500AF7E9E /* AudioToolbox.framework */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
34570A3B1B13222600E6D4FD /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 34570A3A1B13222600E6D4FD /* libz.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
34570A3D1B13223000E6D4FD /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 34570A3C1B13223000E6D4FD /* libsqlite3.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||
|
@ -288,6 +290,7 @@
|
|||
34D349FC1CD0A3EE00895216 /* MWMWhatsNewEditorController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34D349FA1CD0A3EE00895216 /* MWMWhatsNewEditorController.mm */; };
|
||||
34D37E171CD2373C001DEFC3 /* MWMMapDownloaderCellHeader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34D37E161CD2373C001DEFC3 /* MWMMapDownloaderCellHeader.mm */; };
|
||||
34D37E181CD2373C001DEFC3 /* MWMMapDownloaderCellHeader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34D37E161CD2373C001DEFC3 /* MWMMapDownloaderCellHeader.mm */; };
|
||||
34D866DE1D213E8B00B593F8 /* MWMLocationPredictor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FED54C1D1D45B900183B1B /* MWMLocationPredictor.mm */; };
|
||||
34DCDE3A1C75CD8100652CAC /* Framework.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34479C751C60C6130065D261 /* Framework.cpp */; };
|
||||
34DCDE3B1C75CE1F00652CAC /* MWMOpeningHoursDeleteScheduleTableViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 347FD85A1C60B2CE002FB65E /* MWMOpeningHoursDeleteScheduleTableViewCell.mm */; };
|
||||
34DDD5341BFDB0B600407F2F /* MWMMapDownloaderViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 342AF0DF1BE24E9A0016F3AE /* MWMMapDownloaderViewController.mm */; };
|
||||
|
@ -317,6 +320,9 @@
|
|||
34F9FB921C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 34F9FB8F1C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib */; };
|
||||
34F9FB931C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 34F9FB8F1C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib */; };
|
||||
34FE4C451BCC013500066718 /* MWMMapWidgets.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FE4C441BCC013500066718 /* MWMMapWidgets.mm */; };
|
||||
34FED54D1D1D45B900183B1B /* MWMLocationPredictor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FED54C1D1D45B900183B1B /* MWMLocationPredictor.mm */; };
|
||||
34FED5501D21121000183B1B /* CLLocation+Mercator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FED54F1D21121000183B1B /* CLLocation+Mercator.mm */; };
|
||||
34FED5511D21121000183B1B /* CLLocation+Mercator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34FED54F1D21121000183B1B /* CLLocation+Mercator.mm */; };
|
||||
4519503A1B7A3E070085DA05 /* patterns.txt in Resources */ = {isa = PBXBuildFile; fileRef = 451950391B7A3E070085DA05 /* patterns.txt */; };
|
||||
452FCA3B1B6A3DF7007019AB /* colors.txt in Resources */ = {isa = PBXBuildFile; fileRef = 452FCA3A1B6A3DF7007019AB /* colors.txt */; };
|
||||
46F26C7310F61FD600ECCA39 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 46F26C7210F61FD600ECCA39 /* OpenGLES.framework */; };
|
||||
|
@ -448,7 +454,6 @@
|
|||
6741A9B81BF340DE002C974C /* MapViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = EED10A4411F78D120095FAD4 /* MapViewController.mm */; };
|
||||
6741A9B91BF340DE002C974C /* MWMRateAlert.mm in Sources */ = {isa = PBXBuildFile; fileRef = F61579331AC2CE9A0032D8E9 /* MWMRateAlert.mm */; };
|
||||
6741A9BA1BF340DE002C974C /* MWMRoutePointCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F6BB6CC51BB18C0900DF1DF2 /* MWMRoutePointCell.m */; };
|
||||
6741A9BB1BF340DE002C974C /* LocationPredictor.mm in Sources */ = {isa = PBXBuildFile; fileRef = A3CC2CD21A1C723900B832E1 /* LocationPredictor.mm */; };
|
||||
6741A9BE1BF340DE002C974C /* UILabel+RuntimeAttributes.mm in Sources */ = {isa = PBXBuildFile; fileRef = F62404FA1AAF3DB200B58DB6 /* UILabel+RuntimeAttributes.mm */; };
|
||||
6741A9BF1BF340DE002C974C /* MWMSearchTabbedCollectionViewCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34CC4C0C1B82069C00E44C1F /* MWMSearchTabbedCollectionViewCell.mm */; };
|
||||
6741A9C01BF340DE002C974C /* MWMTextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6588E2B1B15C26700EE1E58 /* MWMTextView.mm */; };
|
||||
|
@ -486,7 +491,6 @@
|
|||
6741A9E91BF340DE002C974C /* Preferences.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA29FDA9141E77F8004ADF66 /* Preferences.mm */; };
|
||||
6741A9EB1BF340DE002C974C /* ContextViews.mm in Sources */ = {isa = PBXBuildFile; fileRef = F6D409F91B319BD70041730F /* ContextViews.mm */; };
|
||||
6741A9EC1BF340DE002C974C /* MWMCircularProgress.mm in Sources */ = {isa = PBXBuildFile; fileRef = 349A35761B53D4C9009677EE /* MWMCircularProgress.mm */; };
|
||||
6741A9ED1BF340DE002C974C /* LocationManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAA5C2A1144F135F005337F6 /* LocationManager.mm */; };
|
||||
6741A9EE1BF340DE002C974C /* MWMSearchCell.mm in Sources */ = {isa = PBXBuildFile; fileRef = 34B82AD91B847FFC00180497 /* MWMSearchCell.mm */; };
|
||||
6741A9EF1BF340DE002C974C /* MWMiPadPlacePage.mm in Sources */ = {isa = PBXBuildFile; fileRef = F66A8FAB1B09F137001B9C97 /* MWMiPadPlacePage.mm */; };
|
||||
6741A9F01BF340DE002C974C /* SettingsViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 978F9239183B660F000D6C7C /* SettingsViewController.mm */; };
|
||||
|
@ -653,7 +657,6 @@
|
|||
A32B6D4C1A14980500E54A65 /* iosOGLContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = A32B6D491A14980500E54A65 /* iosOGLContext.mm */; };
|
||||
A32B6D4D1A14980500E54A65 /* iosOGLContextFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = A32B6D4B1A14980500E54A65 /* iosOGLContextFactory.mm */; };
|
||||
A367C93B1B17334800E2B6E7 /* resources-default in Resources */ = {isa = PBXBuildFile; fileRef = A367C93A1B17334800E2B6E7 /* resources-default */; };
|
||||
A3CC2CD41A1C723900B832E1 /* LocationPredictor.mm in Sources */ = {isa = PBXBuildFile; fileRef = A3CC2CD21A1C723900B832E1 /* LocationPredictor.mm */; };
|
||||
B00510FB1A11015900A61AA4 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 972CDCC51887F1B7006641CA /* CFNetwork.framework */; };
|
||||
B00511021A1101E000A61AA4 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 97C98655186C734000AF7E9E /* AVFoundation.framework */; };
|
||||
B00511041A1101F600A61AA4 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B00511031A1101F600A61AA4 /* CoreData.framework */; };
|
||||
|
@ -837,7 +840,6 @@
|
|||
FA85F633145DDDC20090E1A0 /* packed_polygons.bin in Resources */ = {isa = PBXBuildFile; fileRef = FA85F632145DDDC20090E1A0 /* packed_polygons.bin */; };
|
||||
FA87151B12B1518F00592DAF /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA87151A12B1518F00592DAF /* SystemConfiguration.framework */; };
|
||||
FA99CB73147089B100689A9A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA99CB71147089B100689A9A /* Localizable.strings */; };
|
||||
FAA5C2A2144F135F005337F6 /* LocationManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAA5C2A1144F135F005337F6 /* LocationManager.mm */; };
|
||||
FAA614B8155F16950031C345 /* AddSetVC.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAA614B7155F16950031C345 /* AddSetVC.mm */; };
|
||||
FAAEA7D1161BD26600CCD661 /* synonyms.txt in Resources */ = {isa = PBXBuildFile; fileRef = FAAEA7D0161BD26600CCD661 /* synonyms.txt */; };
|
||||
FAAEA7D5161D8D3100CCD661 /* BookmarksRootVC.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAAEA7D3161D8D3100CCD661 /* BookmarksRootVC.mm */; };
|
||||
|
@ -991,6 +993,8 @@
|
|||
34479C781C60C6130065D261 /* MWMFrameworkListener.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMFrameworkListener.mm; sourceTree = "<group>"; };
|
||||
34479C791C60C6130065D261 /* MWMFrameworkObservers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMFrameworkObservers.h; sourceTree = "<group>"; };
|
||||
344BDB021B9069810076DB31 /* MWMSearchTabbedViewProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMSearchTabbedViewProtocol.h; sourceTree = "<group>"; };
|
||||
344D77B21D1BD7C800DBED70 /* MWMLocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMLocationManager.h; sourceTree = "<group>"; };
|
||||
344D77B31D1BD7C800DBED70 /* MWMLocationManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMLocationManager.mm; sourceTree = "<group>"; };
|
||||
34570A3A1B13222600E6D4FD /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
34570A3C1B13223000E6D4FD /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
|
||||
34570A3E1B13225500E6D4FD /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; };
|
||||
|
@ -1221,6 +1225,11 @@
|
|||
34F9FB8F1C43AF2400F71201 /* MWMStreetEditorEditTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MWMStreetEditorEditTableViewCell.xib; sourceTree = "<group>"; };
|
||||
34FE4C431BCC013500066718 /* MWMMapWidgets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMMapWidgets.h; sourceTree = "<group>"; };
|
||||
34FE4C441BCC013500066718 /* MWMMapWidgets.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMMapWidgets.mm; sourceTree = "<group>"; };
|
||||
34FED54B1D1D45B900183B1B /* MWMLocationPredictor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MWMLocationPredictor.h; sourceTree = "<group>"; };
|
||||
34FED54C1D1D45B900183B1B /* MWMLocationPredictor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MWMLocationPredictor.mm; sourceTree = "<group>"; };
|
||||
34FED54E1D21121000183B1B /* CLLocation+Mercator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CLLocation+Mercator.h"; sourceTree = "<group>"; };
|
||||
34FED54F1D21121000183B1B /* CLLocation+Mercator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "CLLocation+Mercator.mm"; sourceTree = "<group>"; };
|
||||
34FED5521D2123CE00183B1B /* MWMLocationHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MWMLocationHelpers.h; sourceTree = "<group>"; };
|
||||
3D443C9C19E421EE0025C2FC /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
451950391B7A3E070085DA05 /* patterns.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = patterns.txt; path = ../../data/patterns.txt; sourceTree = "<group>"; };
|
||||
452FCA3A1B6A3DF7007019AB /* colors.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = colors.txt; path = ../../data/colors.txt; sourceTree = "<group>"; };
|
||||
|
@ -1347,8 +1356,6 @@
|
|||
A32B6D4A1A14980500E54A65 /* iosOGLContextFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iosOGLContextFactory.h; path = Platform/opengl/iosOGLContextFactory.h; sourceTree = "<group>"; };
|
||||
A32B6D4B1A14980500E54A65 /* iosOGLContextFactory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = iosOGLContextFactory.mm; path = Platform/opengl/iosOGLContextFactory.mm; sourceTree = "<group>"; };
|
||||
A367C93A1B17334800E2B6E7 /* resources-default */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "resources-default"; path = "../../data/resources-default"; sourceTree = "<group>"; };
|
||||
A3CC2CD21A1C723900B832E1 /* LocationPredictor.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = LocationPredictor.mm; sourceTree = "<group>"; };
|
||||
A3CC2CD31A1C723900B832E1 /* LocationPredictor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocationPredictor.h; sourceTree = "<group>"; };
|
||||
B00511031A1101F600A61AA4 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||
B00511051A1101FC00A61AA4 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
|
||||
B08AA8D81A26299A00810B1C /* TimeUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TimeUtils.h; path = Categories/TimeUtils.h; sourceTree = "<group>"; };
|
||||
|
@ -1587,8 +1594,6 @@
|
|||
FA971562150920C600916690 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
FA99CB72147089B100689A9A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
FAA4B13E13EC1C8C00BCAB63 /* DiskFreeSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiskFreeSpace.h; sourceTree = "<group>"; };
|
||||
FAA5C2A0144F135F005337F6 /* LocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocationManager.h; path = Platform/LocationManager.h; sourceTree = "<group>"; };
|
||||
FAA5C2A1144F135F005337F6 /* LocationManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; name = LocationManager.mm; path = Platform/LocationManager.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
FAA614B6155F16950031C345 /* AddSetVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AddSetVC.h; path = Bookmarks/AddSetVC.h; sourceTree = SOURCE_ROOT; };
|
||||
FAA614B7155F16950031C345 /* AddSetVC.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AddSetVC.mm; path = Bookmarks/AddSetVC.mm; sourceTree = SOURCE_ROOT; };
|
||||
FAAEA7D0161BD26600CCD661 /* synonyms.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = synonyms.txt; path = ../../data/synonyms.txt; sourceTree = "<group>"; };
|
||||
|
@ -1738,6 +1743,7 @@
|
|||
080E96DDFE201D6D7F000001 /* Classes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
344D77B11D1BD79700DBED70 /* Location */,
|
||||
34479C741C60C6130065D261 /* Framework */,
|
||||
34CE8A641C7740CF00F4351A /* Storage */,
|
||||
34ABA61D1C2D514A00FE1BEC /* Input Validators */,
|
||||
|
@ -1766,8 +1772,6 @@
|
|||
348D1DF91C525B8300860465 /* MWMTypes.h */,
|
||||
F6DF5F321CD1136800A87154 /* LocaleTranslator.h */,
|
||||
F6381BF41CD12045004CA943 /* LocaleTranslator.mm */,
|
||||
A3CC2CD21A1C723900B832E1 /* LocationPredictor.mm */,
|
||||
A3CC2CD31A1C723900B832E1 /* LocationPredictor.h */,
|
||||
458287C21AD3BE2000BA8940 /* DownloadIndicatorProtocol.h */,
|
||||
F6F9BD221AD3C3A600308C33 /* Macros.h */,
|
||||
);
|
||||
|
@ -2033,6 +2037,18 @@
|
|||
path = Framework;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
344D77B11D1BD79700DBED70 /* Location */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
34FED54B1D1D45B900183B1B /* MWMLocationPredictor.h */,
|
||||
34FED54C1D1D45B900183B1B /* MWMLocationPredictor.mm */,
|
||||
344D77B21D1BD7C800DBED70 /* MWMLocationManager.h */,
|
||||
344D77B31D1BD7C800DBED70 /* MWMLocationManager.mm */,
|
||||
34FED5521D2123CE00183B1B /* MWMLocationHelpers.h */,
|
||||
);
|
||||
path = Location;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
345C34661CE9D32500BB2224 /* SideButtons */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2567,6 +2583,8 @@
|
|||
34ABA61A1C2D4DCC00FE1BEC /* UITextField+RuntimeAttributes.mm */,
|
||||
F64DA8001C524BDE00330E9E /* UISwitch+RuntimeAttributes.h */,
|
||||
F64DA8011C524BDE00330E9E /* UISwitch+RuntimeAttributes.m */,
|
||||
34FED54E1D21121000183B1B /* CLLocation+Mercator.h */,
|
||||
34FED54F1D21121000183B1B /* CLLocation+Mercator.mm */,
|
||||
);
|
||||
name = Categories;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3189,8 +3207,6 @@
|
|||
A32B6D491A14980500E54A65 /* iosOGLContext.mm */,
|
||||
A32B6D4A1A14980500E54A65 /* iosOGLContextFactory.h */,
|
||||
A32B6D4B1A14980500E54A65 /* iosOGLContextFactory.mm */,
|
||||
FAA5C2A0144F135F005337F6 /* LocationManager.h */,
|
||||
FAA5C2A1144F135F005337F6 /* LocationManager.mm */,
|
||||
);
|
||||
name = Platform;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3660,11 +3676,13 @@
|
|||
F6BC1E521ACBF98600EF0360 /* MWMFacebookAlert.mm in Sources */,
|
||||
F64F199D1AB81A00006EAF7E /* MWMDefaultAlert.mm in Sources */,
|
||||
F6E9BF321CE3658D0050E534 /* MWMBookmarkTitleCell.m in Sources */,
|
||||
344D77B41D1BD7C800DBED70 /* MWMLocationManager.mm in Sources */,
|
||||
3438CDF81B8616760051AA78 /* MWMSearchShowOnMapCell.mm in Sources */,
|
||||
34F45E8E1B96E88100AC93F8 /* MWMSearchTabButtonsView.mm in Sources */,
|
||||
3490D2DE1CE9DD2500D0B838 /* MWMSideButtons.mm in Sources */,
|
||||
342FDDE51C6C9071000038A0 /* MWMMapDownloaderDataSource.mm in Sources */,
|
||||
347FD86B1C60B2CE002FB65E /* MWMOpeningHoursAddScheduleTableViewCell.mm in Sources */,
|
||||
34FED5501D21121000183B1B /* CLLocation+Mercator.mm in Sources */,
|
||||
34CD81BB1C91C24D007D2A60 /* MWMWelcomeController.mm in Sources */,
|
||||
F6C934401AE64E4200DDC624 /* MWMSpringAnimation.mm in Sources */,
|
||||
34B82ACA1B8465C100180497 /* MWMSearchCategoryCell.mm in Sources */,
|
||||
|
@ -3683,7 +3701,6 @@
|
|||
34CCFDD11C21945500F28959 /* MWMPlacePageOpeningHoursDayView.mm in Sources */,
|
||||
F61579341AC2CE9A0032D8E9 /* MWMRateAlert.mm in Sources */,
|
||||
F6BB6CC61BB18C0900DF1DF2 /* MWMRoutePointCell.m in Sources */,
|
||||
A3CC2CD41A1C723900B832E1 /* LocationPredictor.mm in Sources */,
|
||||
347D7C691C2C0703006B2D0A /* UITextView+RuntimeAttributes.mm in Sources */,
|
||||
34181EB91C0ED1C30081B586 /* MWMOpeningHoursSection.mm in Sources */,
|
||||
F6D4A72F1CC1030E00BD4E5B /* MWMEditorNotesFooter.mm in Sources */,
|
||||
|
@ -3758,7 +3775,6 @@
|
|||
347FD8851C60B2CE002FB65E /* MWMOpeningHoursTimeSelectorTableViewCell.mm in Sources */,
|
||||
34EB84581C073DF70004689F /* MWMOpeningHoursEditorViewController.mm in Sources */,
|
||||
349A357A1B53D4C9009677EE /* MWMCircularProgress.mm in Sources */,
|
||||
FAA5C2A2144F135F005337F6 /* LocationManager.mm in Sources */,
|
||||
34B82ADA1B847FFC00180497 /* MWMSearchCell.mm in Sources */,
|
||||
F6FEA82D1C58E89B007223CC /* MWMButton.mm in Sources */,
|
||||
F66A8FAC1B09F137001B9C97 /* MWMiPadPlacePage.mm in Sources */,
|
||||
|
@ -3823,6 +3839,7 @@
|
|||
34B82AE21B84AC5E00180497 /* MWMSearchCategoriesManager.mm in Sources */,
|
||||
34CE8A671C7740E100F4351A /* MWMStorage.mm in Sources */,
|
||||
F6F533A31B3C248900C1940B /* UIColor+MapsMeColor.mm in Sources */,
|
||||
34FED54D1D1D45B900183B1B /* MWMLocationPredictor.mm in Sources */,
|
||||
346EDADB1B9F0E35004F8DB5 /* MWMMultilineLabel.mm in Sources */,
|
||||
34C9BD041C6DB693000DC38D /* MWMViewController.mm in Sources */,
|
||||
CB252D6F16FF82C9001E41E9 /* Statistics.mm in Sources */,
|
||||
|
@ -3877,6 +3894,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
6741A9A21BF340DE002C974C /* CommunityVC.mm in Sources */,
|
||||
34FED5511D21121000183B1B /* CLLocation+Mercator.mm in Sources */,
|
||||
6741A9A31BF340DE002C974C /* main.mm in Sources */,
|
||||
6741A9A41BF340DE002C974C /* MWMSearchTabbedViewController.mm in Sources */,
|
||||
6741A9A51BF340DE002C974C /* MWMShareLocationActivityItem.mm in Sources */,
|
||||
|
@ -3886,6 +3904,7 @@
|
|||
6741A9A81BF340DE002C974C /* MWMFacebookAlert.mm in Sources */,
|
||||
6741A9A91BF340DE002C974C /* MWMDefaultAlert.mm in Sources */,
|
||||
F6E9BF331CE3658D0050E534 /* MWMBookmarkTitleCell.m in Sources */,
|
||||
344D77B51D1BD7C800DBED70 /* MWMLocationManager.mm in Sources */,
|
||||
6741A9AA1BF340DE002C974C /* MWMSearchShowOnMapCell.mm in Sources */,
|
||||
6741A9AC1BF340DE002C974C /* MWMSearchTabButtonsView.mm in Sources */,
|
||||
3490D2DF1CE9DD2500D0B838 /* MWMSideButtons.mm in Sources */,
|
||||
|
@ -3907,7 +3926,6 @@
|
|||
34CCFDD21C21945500F28959 /* MWMPlacePageOpeningHoursDayView.mm in Sources */,
|
||||
6741A9B91BF340DE002C974C /* MWMRateAlert.mm in Sources */,
|
||||
6741A9BA1BF340DE002C974C /* MWMRoutePointCell.m in Sources */,
|
||||
6741A9BB1BF340DE002C974C /* LocationPredictor.mm in Sources */,
|
||||
347D7C6A1C2C0703006B2D0A /* UITextView+RuntimeAttributes.mm in Sources */,
|
||||
6741A9BE1BF340DE002C974C /* UILabel+RuntimeAttributes.mm in Sources */,
|
||||
6741A9BF1BF340DE002C974C /* MWMSearchTabbedCollectionViewCell.mm in Sources */,
|
||||
|
@ -3948,6 +3966,7 @@
|
|||
6741A9D41BF340DE002C974C /* MWMAlertViewController.mm in Sources */,
|
||||
F6FE3C391CC50FFD00A73196 /* MWMPlaceDoesntExistAlert.mm in Sources */,
|
||||
34C9BD0A1C6DBCDA000DC38D /* MWMNavigationController.mm in Sources */,
|
||||
34D866DE1D213E8B00B593F8 /* MWMLocationPredictor.mm in Sources */,
|
||||
3406FA161C6E0C3300E9FAD2 /* MWMMapDownloadDialog.mm in Sources */,
|
||||
6741A9D51BF340DE002C974C /* WebViewController.mm in Sources */,
|
||||
34C9BD031C6DB693000DC38D /* MWMTableViewController.mm in Sources */,
|
||||
|
@ -3981,7 +4000,6 @@
|
|||
6741A9EB1BF340DE002C974C /* ContextViews.mm in Sources */,
|
||||
6741A9EC1BF340DE002C974C /* MWMCircularProgress.mm in Sources */,
|
||||
342CC5F21C2D7730005F3FE5 /* MWMAuthorizationLoginViewController.mm in Sources */,
|
||||
6741A9ED1BF340DE002C974C /* LocationManager.mm in Sources */,
|
||||
6741A9EE1BF340DE002C974C /* MWMSearchCell.mm in Sources */,
|
||||
6741A9EF1BF340DE002C974C /* MWMiPadPlacePage.mm in Sources */,
|
||||
6741A9F01BF340DE002C974C /* SettingsViewController.mm in Sources */,
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import <UIKit/UIApplication.h>
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
#include "platform/location.hpp"
|
||||
#include "std/utility.hpp"
|
||||
|
||||
@protocol LocationObserver
|
||||
@required
|
||||
- (void)onLocationUpdate:(location::GpsInfo const &)info;
|
||||
@optional
|
||||
- (void)onLocationError:(location::TLocationError)errorCode;
|
||||
- (void)onCompassUpdate:(location::CompassInfo const &)info;
|
||||
@end
|
||||
|
||||
@interface LocationManager : NSObject <CLLocationManagerDelegate>
|
||||
|
||||
@property (nonatomic, readonly) BOOL isStarted;
|
||||
@property (nonatomic, readonly) location::TLocationError lastLocationError;
|
||||
|
||||
- (void)start:(id <LocationObserver>)observer;
|
||||
- (void)stop:(id <LocationObserver>)observer;
|
||||
- (CLLocation *)lastLocation;
|
||||
- (CLHeading *)lastHeading;
|
||||
// Fixes compass angle orientation when rotating screen to landscape
|
||||
- (void)orientationChanged;
|
||||
|
||||
- (bool)getLat:(double &)lat Lon:(double &)lon;
|
||||
- (bool)getNorthRad:(double &)rad;
|
||||
|
||||
+ (NSString *)formattedDistance:(double)meters;
|
||||
// Returns nil if neither speed nor altitude are available
|
||||
- (NSString *)formattedSpeedAndAltitude:(BOOL &)hasSpeed;
|
||||
|
||||
- (bool)lastLocationIsValid;
|
||||
- (bool)isLocationPendingOrNoPosition;
|
||||
- (BOOL)enabledOnMap;
|
||||
|
||||
- (void)onDaemonMode;
|
||||
- (void)onForeground;
|
||||
- (void)onBackground;
|
||||
- (void)beforeTerminate;
|
||||
|
||||
- (void)reset;
|
||||
|
||||
- (void)processMyPositionStateModeEvent:(location::EMyPositionMode)mode;
|
||||
|
||||
@end
|
||||
|
||||
@interface CLLocation (Mercator)
|
||||
|
||||
- (m2::PointD)mercator;
|
||||
|
||||
@end
|
||||
|
||||
static inline ms::LatLon ToLatLon(m2::PointD const & p)
|
||||
{
|
||||
return MercatorBounds::ToLatLon(p);
|
||||
}
|
||||
|
||||
static inline m2::PointD ToMercator(CLLocationCoordinate2D const & l)
|
||||
{
|
||||
return MercatorBounds::FromLatLon(l.latitude, l.longitude);
|
||||
}
|
||||
|
||||
static inline m2::PointD ToMercator(ms::LatLon const & l)
|
||||
{
|
||||
return MercatorBounds::FromLatLon(l);
|
||||
}
|
|
@ -1,549 +0,0 @@
|
|||
#import "Common.h"
|
||||
#import "LocationManager.h"
|
||||
#import "MapsAppDelegate.h"
|
||||
#import "MapViewController.h"
|
||||
#import "MWMMapViewControlsManager.h"
|
||||
#import "Statistics.h"
|
||||
|
||||
#import "3party/Alohalytics/src/alohalytics_objc.h"
|
||||
|
||||
#include "Framework.h"
|
||||
|
||||
#include "map/gps_tracker.hpp"
|
||||
#include "routing/router.hpp"
|
||||
#include "platform/file_logging.hpp"
|
||||
#include "platform/measurement_utils.hpp"
|
||||
#include "platform/settings.hpp"
|
||||
|
||||
#include "base/math.hpp"
|
||||
|
||||
static CLAuthorizationStatus const kRequestAuthStatus = kCLAuthorizationStatusAuthorizedAlways;
|
||||
static NSString * const kAlohalyticsLocationRequestAlwaysFailed = @"$locationAlwaysRequestErrorDenied";
|
||||
|
||||
namespace
|
||||
{
|
||||
enum class GeoMode
|
||||
{
|
||||
Pending,
|
||||
InPosition,
|
||||
NotInPosition,
|
||||
FollowAndRotate,
|
||||
VehicleRouting,
|
||||
PedestrianRouting,
|
||||
BicycleRouting
|
||||
};
|
||||
|
||||
struct DesiredAccuracy
|
||||
{
|
||||
CLLocationAccuracy charging;
|
||||
CLLocationAccuracy battery;
|
||||
};
|
||||
|
||||
struct GeoModeSettings
|
||||
{
|
||||
CLLocationDistance distanceFilter;
|
||||
DesiredAccuracy accuracy;
|
||||
};
|
||||
|
||||
map<GeoMode, GeoModeSettings> const kGeoSettings{
|
||||
{GeoMode::Pending,
|
||||
{.distanceFilter = kCLDistanceFilterNone,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBestForNavigation}}},
|
||||
{GeoMode::InPosition,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::NotInPosition,
|
||||
{.distanceFilter = 5,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::FollowAndRotate,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::VehicleRouting,
|
||||
{.distanceFilter = kCLDistanceFilterNone,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::PedestrianRouting,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}},
|
||||
{GeoMode::BicycleRouting,
|
||||
{.distanceFilter = 2,
|
||||
.accuracy = {.charging = kCLLocationAccuracyBestForNavigation,
|
||||
.battery = kCLLocationAccuracyBest}}}};
|
||||
} // namespace
|
||||
|
||||
@interface LocationManager ()
|
||||
|
||||
@property (nonatomic) BOOL deferringUpdates;
|
||||
|
||||
@property (nonatomic) CLLocationManager * locationManager;
|
||||
|
||||
@property (nonatomic, readwrite) BOOL isStarted;
|
||||
@property (nonatomic, readwrite) location::TLocationError lastLocationError;
|
||||
@property (nonatomic) NSMutableSet * observers;
|
||||
@property (nonatomic) NSDate * lastLocationTime;
|
||||
|
||||
@property (nonatomic) GeoMode geoMode;
|
||||
|
||||
@end
|
||||
|
||||
@implementation LocationManager
|
||||
|
||||
- (void)batteryStateChangedNotification:(NSNotification *)notification
|
||||
{
|
||||
[self refreshGeoModeSettings];
|
||||
}
|
||||
|
||||
- (void)refreshGeoModeSettings
|
||||
{
|
||||
UIDeviceBatteryState const state = [UIDevice currentDevice].batteryState;
|
||||
BOOL const isCharging = (state == UIDeviceBatteryStateCharging || state == UIDeviceBatteryStateFull);
|
||||
GeoModeSettings const settings = kGeoSettings.at(self.geoMode);
|
||||
self.locationManager.desiredAccuracy = isCharging ? settings.accuracy.charging : settings.accuracy.battery;
|
||||
self.locationManager.distanceFilter = settings.distanceFilter;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self reset];
|
||||
}
|
||||
|
||||
- (void)onDaemonMode
|
||||
{
|
||||
[self.locationManager stopMonitoringSignificantLocationChanges];
|
||||
LOG(LINFO, ("startUpdatingLocation"));
|
||||
[self.locationManager startUpdatingLocation];
|
||||
}
|
||||
|
||||
- (void)onBackground
|
||||
{
|
||||
if (!GpsTracker::Instance().IsEnabled())
|
||||
{
|
||||
LOG(LINFO, ("stopUpdatingLocation"));
|
||||
[self.locationManager stopUpdatingLocation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)beforeTerminate
|
||||
{
|
||||
if (!GpsTracker::Instance().IsEnabled())
|
||||
return;
|
||||
[self.locationManager startMonitoringSignificantLocationChanges];
|
||||
}
|
||||
|
||||
- (void)onForeground
|
||||
{
|
||||
[self onDaemonMode];
|
||||
[self.locationManager disallowDeferredLocationUpdates];
|
||||
self.deferringUpdates = NO;
|
||||
[self orientationChanged];
|
||||
}
|
||||
|
||||
- (void)start:(id <LocationObserver>)observer
|
||||
{
|
||||
if (!self.isStarted)
|
||||
{
|
||||
//YES if location services are enabled; NO if they are not.
|
||||
if ([CLLocationManager locationServicesEnabled])
|
||||
{
|
||||
CLAuthorizationStatus const authStatus = [CLLocationManager authorizationStatus];
|
||||
switch (authStatus)
|
||||
{
|
||||
case kCLAuthorizationStatusAuthorizedWhenInUse:
|
||||
case kCLAuthorizationStatusAuthorizedAlways:
|
||||
case kCLAuthorizationStatusNotDetermined:
|
||||
if (kRequestAuthStatus == kCLAuthorizationStatusAuthorizedAlways && [self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
|
||||
[self.locationManager requestAlwaysAuthorization];
|
||||
LOG(LINFO, ("startUpdatingLocation"));
|
||||
[self.locationManager startUpdatingLocation];
|
||||
if ([CLLocationManager headingAvailable])
|
||||
[self.locationManager startUpdatingHeading];
|
||||
self.isStarted = YES;
|
||||
[self.observers addObject:observer];
|
||||
break;
|
||||
case kCLAuthorizationStatusRestricted:
|
||||
case kCLAuthorizationStatusDenied:
|
||||
[self observer:observer onLocationError:location::EDenied];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
[self observer:observer onLocationError:location::EGPSIsOff];
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOL updateLocation = ![self.observers containsObject:observer];
|
||||
[self.observers addObject:observer];
|
||||
if ([self lastLocationIsValid] && updateLocation)
|
||||
{
|
||||
// pass last location known location when new observer is attached
|
||||
// (default CLLocationManagerDelegate behaviour)
|
||||
[observer onLocationUpdate:gpsInfoFromLocation(self.lastLocation)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stop:(id <LocationObserver>)observer
|
||||
{
|
||||
[self.observers removeObject:observer];
|
||||
if (self.isStarted && self.observers.count == 0)
|
||||
{
|
||||
// stop only if no more observers are subsribed
|
||||
self.isStarted = NO;
|
||||
if ([CLLocationManager headingAvailable])
|
||||
[self.locationManager stopUpdatingHeading];
|
||||
LOG(LINFO, ("stopUpdatingLocation"));
|
||||
[self.locationManager stopUpdatingLocation];
|
||||
}
|
||||
}
|
||||
|
||||
- (CLLocation *)lastLocation
|
||||
{
|
||||
if (!self.isStarted || self.locationManager.location.horizontalAccuracy < 0.)
|
||||
return nil;
|
||||
return self.locationManager.location;
|
||||
}
|
||||
|
||||
- (CLHeading *)lastHeading
|
||||
{
|
||||
if (!self.isStarted || self.locationManager.heading.headingAccuracy < 0.)
|
||||
return nil;
|
||||
return self.locationManager.heading;
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)heading
|
||||
{
|
||||
[self notifyCompassUpdate:compasInfoFromHeading(heading)];
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
|
||||
{
|
||||
[self processLocation:locations.lastObject];
|
||||
if (!self.deferringUpdates)
|
||||
return;
|
||||
[self.locationManager allowDeferredLocationUpdatesUntilTraveled:300 timeout:15];
|
||||
self.deferringUpdates = NO;
|
||||
}
|
||||
|
||||
- (BOOL)deferringUpdates
|
||||
{
|
||||
return _deferringUpdates && [CLLocationManager deferredLocationUpdatesAvailable] &&
|
||||
[UIApplication sharedApplication].applicationState == UIApplicationStateBackground;
|
||||
}
|
||||
|
||||
- (void)processLocation:(CLLocation *)location
|
||||
{
|
||||
// According to documentation, lat and lon are valid only if horz acc is non-negative.
|
||||
// So we filter out such events completely.
|
||||
if (location.horizontalAccuracy < 0.)
|
||||
return;
|
||||
|
||||
self.lastLocationError = location::TLocationError::ENoError;
|
||||
// Save current device time for location.
|
||||
self.lastLocationTime = [NSDate date];
|
||||
[[Statistics instance] logLocation:location];
|
||||
auto const newInfo = gpsInfoFromLocation(location);
|
||||
if (!MapsAppDelegate.theApp.isDaemonMode)
|
||||
{
|
||||
for (id observer in self.observers.copy)
|
||||
[observer onLocationUpdate:newInfo];
|
||||
// TODO(AlexZ): Temporary, remove in the future.
|
||||
}
|
||||
GpsTracker::Instance().OnLocationUpdated(newInfo);
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error
|
||||
{
|
||||
self.deferringUpdates = YES;
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
|
||||
{
|
||||
NSLog(@"locationManager failed with error: %ld, %@", (long)error.code, error.description);
|
||||
if (error.code == kCLErrorDenied)
|
||||
{
|
||||
if (kRequestAuthStatus == kCLAuthorizationStatusAuthorizedAlways && [self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
|
||||
[Alohalytics logEvent:kAlohalyticsLocationRequestAlwaysFailed];
|
||||
for (id observer in self.observers.copy)
|
||||
[self observer:observer onLocationError:location::EDenied];
|
||||
}
|
||||
else if (error.code != kCLErrorLocationUnknown)
|
||||
{
|
||||
for (id observer in self.observers.copy)
|
||||
[self observer:observer onLocationError:location::ENotSupported];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
|
||||
{
|
||||
if (MapsAppDelegate.theApp.isDaemonMode)
|
||||
return NO;
|
||||
bool on = false;
|
||||
settings::Get("CompassCalibrationEnabled", on);
|
||||
if (!on)
|
||||
return NO;
|
||||
|
||||
if (!MapsAppDelegate.theApp.mapViewController.controlsManager.searchHidden)
|
||||
return NO;
|
||||
if (!manager.heading)
|
||||
return YES;
|
||||
else if (manager.heading.headingAccuracy < 0)
|
||||
return YES;
|
||||
else if (manager.heading.headingAccuracy > 5)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (bool)getLat:(double &)lat Lon:(double &)lon
|
||||
{
|
||||
CLLocation * l = [self lastLocation];
|
||||
|
||||
// Return last saved location if it's not later than 5 minutes.
|
||||
if ([self lastLocationIsValid])
|
||||
{
|
||||
lat = l.coordinate.latitude;
|
||||
lon = l.coordinate.longitude;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
- (bool)getNorthRad:(double &)rad
|
||||
{
|
||||
CLHeading * h = [self lastHeading];
|
||||
|
||||
if (h != nil)
|
||||
{
|
||||
rad = (h.trueHeading < 0) ? h.magneticHeading : h.trueHeading;
|
||||
rad = my::DegToRad(rad);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
+ (NSString *)formattedDistance:(double)meters
|
||||
{
|
||||
if (meters < 0.)
|
||||
return nil;
|
||||
|
||||
string s;
|
||||
MeasurementUtils::FormatDistance(meters, s);
|
||||
return @(s.c_str());
|
||||
}
|
||||
|
||||
+ (char const *)getSpeedSymbol:(double)metersPerSecond
|
||||
{
|
||||
// 0-1 m/s
|
||||
static char const * turtle = "\xF0\x9F\x90\xA2 ";
|
||||
// 1-2 m/s
|
||||
static char const * pedestrian = "\xF0\x9F\x9A\xB6 ";
|
||||
// 2-5 m/s
|
||||
static char const * tractor = "\xF0\x9F\x9A\x9C ";
|
||||
// 5-10 m/s
|
||||
static char const * bicycle = "\xF0\x9F\x9A\xB2 ";
|
||||
// 10-36 m/s
|
||||
static char const * car = "\xF0\x9F\x9A\x97 ";
|
||||
// 36-120 m/s
|
||||
static char const * train = "\xF0\x9F\x9A\x85 ";
|
||||
// 120-278 m/s
|
||||
static char const * airplane = "\xE2\x9C\x88\xEF\xB8\x8F ";
|
||||
// 278+
|
||||
static char const * rocket = "\xF0\x9F\x9A\x80 ";
|
||||
|
||||
if (metersPerSecond <= 1.) return turtle;
|
||||
else if (metersPerSecond <= 2.) return pedestrian;
|
||||
else if (metersPerSecond <= 5.) return tractor;
|
||||
else if (metersPerSecond <= 10.) return bicycle;
|
||||
else if (metersPerSecond <= 36.) return car;
|
||||
else if (metersPerSecond <= 120.) return train;
|
||||
else if (metersPerSecond <= 278.) return airplane;
|
||||
else return rocket;
|
||||
}
|
||||
|
||||
- (NSString *)formattedSpeedAndAltitude:(BOOL &)hasSpeed
|
||||
{
|
||||
hasSpeed = NO;
|
||||
CLLocation * l = [self lastLocation];
|
||||
if (l)
|
||||
{
|
||||
string result;
|
||||
if (l.altitude)
|
||||
result = "\xE2\x96\xB2 " /* this is simple mountain symbol */ + MeasurementUtils::FormatAltitude(l.altitude);
|
||||
// Speed is actual only for just received location
|
||||
if (l.speed > 0. && [l.timestamp timeIntervalSinceNow] >= -2.0)
|
||||
{
|
||||
hasSpeed = YES;
|
||||
if (!result.empty())
|
||||
result += " ";
|
||||
result += [LocationManager getSpeedSymbol:l.speed] + MeasurementUtils::FormatSpeed(l.speed);
|
||||
}
|
||||
return result.empty() ? nil : @(result.c_str());
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (bool)lastLocationIsValid
|
||||
{
|
||||
return (([self lastLocation] != nil) && ([self.lastLocationTime timeIntervalSinceNow] > -300.0));
|
||||
}
|
||||
|
||||
- (bool)isLocationPendingOrNoPosition
|
||||
{
|
||||
using location::EMyPositionMode;
|
||||
EMyPositionMode mode;
|
||||
if (!settings::Get(settings::kLocationStateMode, mode))
|
||||
return true;
|
||||
return mode == EMyPositionMode::PendingPosition || mode == EMyPositionMode::NotFollowNoPosition;
|
||||
}
|
||||
|
||||
- (BOOL)enabledOnMap
|
||||
{
|
||||
for (id observer in self.observers.copy)
|
||||
if ([observer isKindOfClass:[MapViewController class]])
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)orientationChanged
|
||||
{
|
||||
self.locationManager.headingOrientation = (CLDeviceOrientation)[UIDevice currentDevice].orientation;
|
||||
}
|
||||
|
||||
- (void)notifyCompassUpdate:(location::CompassInfo const &)newInfo
|
||||
{
|
||||
for (id observer in self.observers.copy)
|
||||
if ([observer respondsToSelector:@selector(onCompassUpdate:)])
|
||||
[observer onCompassUpdate:newInfo];
|
||||
}
|
||||
|
||||
- (void)observer:(id<LocationObserver>)observer onLocationError:(location::TLocationError)errorCode
|
||||
{
|
||||
self.lastLocationError = errorCode;
|
||||
if ([(NSObject *)observer respondsToSelector:@selector(onLocationError:)])
|
||||
[observer onLocationError:errorCode];
|
||||
}
|
||||
|
||||
location::GpsInfo gpsInfoFromLocation(CLLocation const * l)
|
||||
{
|
||||
location::GpsInfo info;
|
||||
info.m_source = location::EAppleNative;
|
||||
|
||||
info.m_latitude = l.coordinate.latitude;
|
||||
info.m_longitude = l.coordinate.longitude;
|
||||
info.m_timestamp = [l.timestamp timeIntervalSince1970];
|
||||
|
||||
if (l.horizontalAccuracy >= 0.0)
|
||||
info.m_horizontalAccuracy = l.horizontalAccuracy;
|
||||
|
||||
if (l.verticalAccuracy >= 0.0)
|
||||
{
|
||||
info.m_verticalAccuracy = l.verticalAccuracy;
|
||||
info.m_altitude = l.altitude;
|
||||
}
|
||||
|
||||
if (l.course >= 0.0)
|
||||
info.m_bearing = l.course;
|
||||
|
||||
if (l.speed >= 0.0)
|
||||
info.m_speed = l.speed;
|
||||
return info;
|
||||
}
|
||||
|
||||
location::CompassInfo compasInfoFromHeading(CLHeading const * h)
|
||||
{
|
||||
location::CompassInfo info;
|
||||
if (h.trueHeading >= 0.0)
|
||||
info.m_bearing = my::DegToRad(h.trueHeading);
|
||||
else if (h.headingAccuracy >= 0.0)
|
||||
info.m_bearing = my::DegToRad(h.magneticHeading);
|
||||
return info;
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
_isStarted = NO;
|
||||
_lastLocationTime = nil;
|
||||
_observers = [NSMutableSet set];
|
||||
_locationManager.delegate = nil;
|
||||
_locationManager = nil;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)processMyPositionStateModeEvent:(location::EMyPositionMode)mode
|
||||
{
|
||||
auto const & f = GetFramework();
|
||||
if (f.IsRoutingActive())
|
||||
{
|
||||
switch (f.GetRouter())
|
||||
{
|
||||
case routing::RouterType::Vehicle:
|
||||
self.geoMode = GeoMode::VehicleRouting;
|
||||
break;
|
||||
case routing::RouterType::Pedestrian:
|
||||
self.geoMode = GeoMode::PedestrianRouting;
|
||||
break;
|
||||
case routing::RouterType::Bicycle:
|
||||
self.geoMode = GeoMode::BicycleRouting;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case location::EMyPositionMode::PendingPosition:
|
||||
self.geoMode = GeoMode::Pending;
|
||||
break;
|
||||
case location::EMyPositionMode::NotFollowNoPosition:
|
||||
case location::EMyPositionMode::NotFollow:
|
||||
self.geoMode = GeoMode::NotInPosition;
|
||||
break;
|
||||
case location::EMyPositionMode::Follow:
|
||||
self.geoMode = GeoMode::InPosition;
|
||||
break;
|
||||
case location::EMyPositionMode::FollowAndRotate:
|
||||
self.geoMode = GeoMode::FollowAndRotate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self refreshGeoModeSettings];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
|
||||
- (CLLocationManager *)locationManager
|
||||
{
|
||||
if (!_locationManager)
|
||||
{
|
||||
[self reset];
|
||||
_locationManager = [[CLLocationManager alloc] init];
|
||||
_locationManager.delegate = self;
|
||||
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
|
||||
[self refreshGeoModeSettings];
|
||||
if (!(isIOS7 || isIOS8))
|
||||
_locationManager.allowsBackgroundLocationUpdates = YES;
|
||||
_locationManager.pausesLocationUpdatesAutomatically = YES;
|
||||
_locationManager.headingFilter = 3.0;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(batteryStateChangedNotification:) name:UIDeviceBatteryStateDidChangeNotification object:nil];
|
||||
}
|
||||
return _locationManager;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation CLLocation (Mercator)
|
||||
|
||||
- (m2::PointD)mercator
|
||||
{
|
||||
return ToMercator(self.coordinate);
|
||||
}
|
||||
|
||||
@end
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "إن تحديد موقعك الحالي في الخلفية أمر ضروري للاستمتاع بكامل وظائف التطبيق. حيث أنه يُستخدم بشكل أساسي في خيارات متابعة المسار وحفظ الطرق التي تنقلت معها مؤخرا.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "تستخدم خاصية تحديد الموقع الحالي في خيارات اتباع الطريق وحفظ أحدث مسار مشيت عليه.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Chcete-li si užívat plnou funkčnost aplikace, pak musíte určit aktuální polohu na pozadí. Používá se především k sledování trasy a ukládání vaší nedávno uskutečněné cesty.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Stanovení současného umístění se používá v možnostech sledování trasy a uložení vaší nedávno uskutečněné cesty.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Det er nødvendigt at fastslå den gældende placering i baggrunden for at udnytte appens funktionalitet fuldt ud. Dette anvendes først og fremmest, når en rute skal følges, og når din sidste rejserute skal gemmes.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Definition af aktuel placering bruges i indstillingerne for at følge ruten og lagring af din seneste rejserute.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Das Bestimmen des aktuellen Standortes im Hintergrund ist erforderlich, um den vollen Funktionsumfang der App zu genießen. Dies wird hauptsächlich dafür genutzt, der Route zu folgen und, um Ihren bereits bestrittenen Weg zu speichern.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Die Angabe des aktuellen Standortes wird in den Optionen bei der Verfolgung der Route und beim Speichern Ihres zuletzt zurückgelegten Weges verwendet.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Defining current location in the background is necessary to fully enjoy the functionality of the app. It is mainly used in the options of following the route and saving your recent travelled path.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Determining your location is necessary for navigation and for saving your recently travelled track. ]";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Es necesario definir la ubicación actual en el entorno para disfrutar al máximo de la funcionalidad de la aplicación. Se emplea principalmente en las opciones de seguir la ruta y guardar el camino recorrido reciente.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "La definición de la ubicación actual se utiliza en las opciones de seguir la ruta y guardar el camino recorrido reciente.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Tämänhetkisen sijainnin selvittäminen sovellusta ajettaessa taustalla on tärkeää sovelluksen täydellisen toiminnan takaamiseksi. Sijaintitietoja käytetään pääasiassa reittiopastukseen sekä kuljetun reitin tallennukseen.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Sijaintitietojasi käytetään reittivalintoihin ja viimeaikaisten matkojesi tallentamiseen.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "La localisation actuelle en arrière-plan est nécessaire pour profiter pleinement de toutes les fonctionnalités de l'application. Elle est principalement utilisée dans les options de navigation et d'enregistrement de votre chemin récemment parcouru.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "La définition de l'emplacement actuel est utilisée dans certaines fonctions comme le suivi d'un trajet et la sauvegarde des trajets récemment effectués.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "A jelenlegi helymeghatározásra a háttérben azért van szükség, hogy teljesen ki lehessen használni az alkalmazás funkcióit. Elsősorban a navigációs opcióknál és a nemrég megtett út regisztrálásánál használatos.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "A jelenlegi helyzet meghatározása az út követésének és a nemrég érintett útvonal mentésének opciói között használatos.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Menentukan lokasi saat ini di latar belakang diperlukan untuk menikmati fungsi aplikasi. Digunakan terutama dalam opsi mengikuti rute dan menyimpan jalur yang telah Anda tempuh baru-baru ini.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Mendefinisikan lokasi saat ini digunakan dalam opsi-opsi mengikuti rute dan menghemat jalur yang Anda tempuh saat ini.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Chcete-li si užívat plnou funkčnost aplikace, pak musíte určit aktuální polohu na pozadí. Používá se především k sledování trasy a ukládání vaší nedávno uskutečněné cesty.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "La definizione della posizione corrente viene utilizzata nelle opzioni di tracciamento del percorso e salvataggio del percorso effettuato di recente.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "バックグラウンドでの現在位置の定義は、アプリの機能を完全にご利用いただくために必要です。主にルート追跡と最近の道のりの保存に使用されます。";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "現在位置の定義はルート追跡オプションと最近使用したルートの保存に使用されます。";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "백그라운드에서 현재 위치를 정의하는 것은 완전히 앱의 기능을 즐길 수 있도록 해줍니다. 이는 주로 경로를 따르고 최근 여행 경로를 저장하는 옵션에 사용됩니다.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "현재 위치를 정의하는 것은 경로를 따르고 최근 여행한 경로를 저장하는 옵션에서 사용됩니다.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Det er nødvendig å fastslå den gjeldende posisjonen i bakgrunnen for å utnytte appens funksjonalitet til fulle. Dette brukes først og fremst når en rute skal følges og når den siste reiseruten din skal lagres.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Definerer nåværende plassering brukes i alternativene hvor man følger ruten og lagrer din nylige reiseretning.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Het op de achtergrond vaststellen van de huidige locatie is noodzakelijk om volledig gebruik te maken van de functionaliteit van de app. Dit wordt voornamelijk gebruikt bij de opties voor het volgen van de route en het opslaan van je recent afgelegde pad.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Bepaling van de huidige locatie wordt gebruikt in de opties voor het volgen van de route en het opslaan van uw onlangs afgelegde weg.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Określanie w tle bieżącej lokalizacji jest konieczne, aby w pełni korzystać z funkcjonalności aplikacji. Funkcji tej używa się głównie w ramach opcji podążania zgodnie z trasą i zapisywania niedawno przebytej trasy.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Określanie bieżącej lokalizacji używane jest w przypadku opcji podążania trasą i zapisywania ostatnio przebytej trasy.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "A definição da localização atual em segundo plano é necessária para desfrutar totalmente da funcionalidade do aplicativo. Ela é utilizada principalmente nas opções de seguir a rota e salvar seu caminho recém-viajado.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "A definição da localização atual é utilizada em determinadas funções, tais como o acompanhamento de um trajeto e o backup de trajetos feitos recentemente.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Definirea locației curente în fundal este necesară pentru a vă bucura pe deplin de funcționalitatea aplicației. Acest lucru este utilizat în principal în opțiunile de urmărire a traseului și salvare a căii parcurse recent.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Definirea locației curente este folosită în opțiunile de urmărire a traseului și salvarea rutelor recente.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Определение местоположения в фоне необходимо для полноценного пользования приложением. Оно используется в движении по маршруту и сохранении недавно пройденного пути.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Определение местоположения используется в движении по маршруту и сохранении недавно пройденного пути.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Definovanie súčasnej polohy na pozadí je potrebné pre plnú funkčnosť appky. Využíva sa to najmä v možnostiach nasledovania trasy či uloženia Vašej nedávnej cesty.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Údaj o aktuálnej polohe bude použitý v možnostiach pri sledovaní trasy a pri uložení Vašej naposledy prejdenej cesty.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Att fastställa aktuell position i bakgrunden är nödvändigt för att fullt ut använda funktionaliteten hos appen. Det används främst när en rutt ska följas och när din senaste resväg skall sparas.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Definitionen av aktuell plats används i vissa funktioner som t.ex. att spåra rutt eller att spara nyligen tillryggalagda rutter.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "จำเป็นต้องทำการระบุตำแหน่งปัจจุบันในพื้นหลังเพื่อเพลิดเพลินกับการใช้งานแอปอย่างเต็มรูปแบบ มันจะได้รับการใช้เป็นหลักสำหรับตัวเลือกในการติดตามเส้นทางและการบันทึกเส้นทางที่คุณเดินทางเมื่อเร็ว ๆ นี้";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "มีการใช้การระบุตำแหน่งปัจจุบันในตัวเลือกการเดินทางตามเส้นทางและการบันทึกเส้นทางที่คุณเดินทางล่าสุด";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Uygulamanın özelliklerini tamamıyla çıkartmak için arka planda mevcut konumu tanımlamak gereklidir. Genellikle rota izleme ve en son gezilen yolları kaydetme seçeneği için kullanılır.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Mevcut konumunuzun tayini rota takibi ve en son seyahat edilen yolu kaydetme seçeneklerinde kullanılır.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Визначення місцезнаходження у фоновому режимі необхідно для повноцінного користування додатком. Воно використовується під час руху по маршруту та для збереження шляху, що було нещодавно пройдено.";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Визначення місцезнаходження використовується в русі за маршрутом і збереженні нещодавно пройденого шляху.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "Xác định vị trí hiện tại ở trạng thái nền là cần thiết để tận hưởng đầy đủ chức năng của ứng dụng. Nó được sử dụng chủ yếu trong các tùy chọn để đi theo tuyến đường và lưu đường đi gần đây của bạn";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "Xác định vị trí hiện tại được sử dụng trong các tùy chọn theo tuyến đường và lưu đường đi gần đây của bạn.";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "在背景中定义当前位置对于充分享受此应用的功能来说是必要的。它被主要使用于跟随路线与保存您最近走过的路径的选项。";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "定义当前位置在跟随路线和保存您的最近行进路径的选项中被使用。";
|
||||
|
|
|
@ -22,3 +22,6 @@
|
|||
|
||||
/* Needed to explain why we always require access to GPS coordinates, and not only when the app is active. */
|
||||
"NSLocationAlwaysUsageDescription" = "在背景中定義當前位置對於充分享受此應用程式的功能是必要的。它被主要使用於跟隨路線與保存您最近走過的路徑的選項。";
|
||||
|
||||
/* Needed to explain why we require access to GPS coordinates when the app is active. */
|
||||
"NSLocationWhenInUseUsageDescription" = "定義當前位置在跟隨路線和保存您的最近行進路徑的選項中被使用。";
|
||||
|
|
|
@ -167,3 +167,33 @@
|
|||
pl = Określanie w tle bieżącej lokalizacji jest konieczne, aby w pełni korzystać z funkcjonalności aplikacji. Funkcji tej używa się głównie w ramach opcji podążania zgodnie z trasą i zapisywania niedawno przebytej trasy.
|
||||
nl = Het op de achtergrond vaststellen van de huidige locatie is noodzakelijk om volledig gebruik te maken van de functionaliteit van de app. Dit wordt voornamelijk gebruikt bij de opties voor het volgen van de route en het opslaan van je recent afgelegde pad.
|
||||
pt = A definição da localização atual em segundo plano é necessária para desfrutar totalmente da funcionalidade do aplicativo. Ela é utilizada principalmente nas opções de seguir a rota e salvar seu caminho recém-viajado.
|
||||
|
||||
[NSLocationWhenInUseUsageDescription]
|
||||
comment = Needed to explain why we require access to GPS coordinates when the app is active.
|
||||
en = Determining your location is necessary for navigation and for saving your recently travelled track. ]
|
||||
ru = Определение местоположения используется в движении по маршруту и сохранении недавно пройденного пути.
|
||||
fr = La définition de l'emplacement actuel est utilisée dans certaines fonctions comme le suivi d'un trajet et la sauvegarde des trajets récemment effectués.
|
||||
da = Definition af aktuel placering bruges i indstillingerne for at følge ruten og lagring af din seneste rejserute.
|
||||
id = Mendefinisikan lokasi saat ini digunakan dalam opsi-opsi mengikuti rute dan menghemat jalur yang Anda tempuh saat ini.
|
||||
ko = 현재 위치를 정의하는 것은 경로를 따르고 최근 여행한 경로를 저장하는 옵션에서 사용됩니다.
|
||||
sv = Definitionen av aktuell plats används i vissa funktioner som t.ex. att spåra rutt eller att spara nyligen tillryggalagda rutter.
|
||||
tr = Mevcut konumunuzun tayini rota takibi ve en son seyahat edilen yolu kaydetme seçeneklerinde kullanılır.
|
||||
uk = Визначення місцезнаходження використовується в русі за маршрутом і збереженні нещодавно пройденого шляху.
|
||||
vi = Xác định vị trí hiện tại được sử dụng trong các tùy chọn theo tuyến đường và lưu đường đi gần đây của bạn.
|
||||
hu = A jelenlegi helyzet meghatározása az út követésének és a nemrég érintett útvonal mentésének opciói között használatos.
|
||||
de = Die Angabe des aktuellen Standortes wird in den Optionen bei der Verfolgung der Route und beim Speichern Ihres zuletzt zurückgelegten Weges verwendet.
|
||||
fi = Sijaintitietojasi käytetään reittivalintoihin ja viimeaikaisten matkojesi tallentamiseen.
|
||||
cs = Stanovení současného umístění se používá v možnostech sledování trasy a uložení vaší nedávno uskutečněné cesty.
|
||||
it = La definizione della posizione corrente viene utilizzata nelle opzioni di tracciamento del percorso e salvataggio del percorso effettuato di recente.
|
||||
nb = Definerer nåværende plassering brukes i alternativene hvor man følger ruten og lagrer din nylige reiseretning.
|
||||
zh-Hant = 定義當前位置在跟隨路線和保存您的最近行進路徑的選項中被使用。
|
||||
zh-Hans = 定义当前位置在跟随路线和保存您的最近行进路径的选项中被使用。
|
||||
th = มีการใช้การระบุตำแหน่งปัจจุบันในตัวเลือกการเดินทางตามเส้นทางและการบันทึกเส้นทางที่คุณเดินทางล่าสุด
|
||||
ja = 現在位置の定義はルート追跡オプションと最近使用したルートの保存に使用されます。
|
||||
ro = Definirea locației curente este folosită în opțiunile de urmărire a traseului și salvarea rutelor recente.
|
||||
ar = تستخدم خاصية تحديد الموقع الحالي في خيارات اتباع الطريق وحفظ أحدث مسار مشيت عليه.
|
||||
sk = Údaj o aktuálnej polohe bude použitý v možnostiach pri sledovaní trasy a pri uložení Vašej naposledy prejdenej cesty.
|
||||
es = La definición de la ubicación actual se utiliza en las opciones de seguir la ruta y guardar el camino recorrido reciente.
|
||||
pl = Określanie bieżącej lokalizacji używane jest w przypadku opcji podążania trasą i zapisywania ostatnio przebytej trasy.
|
||||
nl = Bepaling van de huidige locatie wordt gebruikt in de opties voor het volgen van de route en het opslaan van uw onlangs afgelegde weg.
|
||||
pt = A definição da localização atual é utilizada em determinadas funções, tais como o acompanhamento de um trajeto e o backup de trajetos feitos recentemente.
|
||||
|
|
Loading…
Add table
Reference in a new issue