// _____ _
// |_ _| |_ _ _ ___ ___ _ __ __ _
// | | | ' \| '_/ -_) -_) ' \/ _` |_
// |_| |_||_|_| \___\___|_|_|_\__,_(_)
//
// Threema iOS Client
// Copyright (c) 2012-2020 Threema GmbH
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License, version 3,
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#import "LocationViewController.h"
#import "LocationMessage.h"
#import "Conversation.h"
#import "Contact.h"
#import "MyIdentityStore.h"
#import "UIImage+ColoredImage.h"
#ifdef DEBUG
static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
#else
static const DDLogLevel ddLogLevel = DDLogLevelWarning;
#endif
@interface LocationViewController ()
@property CLLocationManager *locationManager;
@end
@implementation LocationViewController {
NSInteger showInMapsButtonIndex;
NSInteger calculateRouteButtonIndex;
BOOL annotationSelected;
}
@synthesize locationMessage;
- (void)dealloc {
self.mapView.delegate = nil;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.mapView.userTrackingMode = MKUserTrackingModeNone;
self.mapView.showsUserLocation = YES;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.coordinate, 1000, 1000);
[self.mapView setRegion:region animated:NO];
[self setupColors];
}
- (void)setupColors {
[self.view setBackgroundColor:[Colors backgroundLight]];
[self.toolbar setTintColor:[Colors main]];
[self.toolbar setBarTintColor:[Colors background]];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self checkPermissions];
[self.mapView removeAnnotation:self];
[self.mapView addAnnotation:self];
[self.mapView removeOverlays:self.mapView.overlays];
DDLogVerbose(@"accuracy: %f", self.locationMessage.accuracy.doubleValue);
if (self.locationMessage.accuracy != nil && self.locationMessage.accuracy.doubleValue > 5.0) {
MKCircle *accuracyCircle = [MKCircle circleWithCenterCoordinate:self.coordinate radius:self.locationMessage.accuracy.doubleValue];
[self.mapView addOverlay:accuracyCircle];
}
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.coordinate, 1000, 1000);
[self.mapView setRegion:region animated:NO];
}
- (void)viewDidDisappear:(BOOL)animated {
/* must remove annotation or we will cause retain cycle */
[self.mapView removeAnnotation:self];
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotate {
return YES;
}
-(UIInterfaceOrientationMask)supportedInterfaceOrientations {
if (SYSTEM_IS_IPAD) {
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskAllButUpsideDown;
}
- (CLLocationCoordinate2D)coordinate {
return CLLocationCoordinate2DMake(self.locationMessage.latitude.doubleValue, self.locationMessage.longitude.doubleValue);
}
- (IBAction)actionButton:(id)sender {
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
[actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"show_in_maps", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
[self showInMaps];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"calculate_route", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
[self calculateRoute];
}]];
[actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"cancel", nil) style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:actionSheet animated:YES completion:nil];
}
- (IBAction)mapTypeChanged:(id)sender {
switch (self.mapTypeControl.selectedSegmentIndex) {
case 0:
self.mapView.mapType = MKMapTypeStandard;
break;
case 1:
self.mapView.mapType = MKMapTypeHybrid;
break;
case 2:
self.mapView.mapType = MKMapTypeSatellite;
break;
}
}
- (IBAction)gotoUserLocationButtonTapped:(id)sender {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.mapView.userLocation.location.coordinate, 1000, 1000);
[self.mapView setRegion:region animated:YES];
}
- (IBAction)gotoLocationButtonTapped:(id)sender {
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(self.coordinate, 1000, 1000);
[self.mapView setRegion:region animated:YES];
}
- (NSString *)title {
if (self.locationMessage.isOwn.boolValue) {
if ([MyIdentityStore sharedMyIdentityStore].pushFromName != nil)
return [MyIdentityStore sharedMyIdentityStore].pushFromName;
else
return [MyIdentityStore sharedMyIdentityStore].identity;
} else {
if (self.locationMessage.sender != nil)
return self.locationMessage.sender.displayName;
else
return self.locationMessage.conversation.contact.displayName;
}
}
- (NSString *)subtitle {
return [DateFormatter mediumStyleDateTime:self.locationMessage.remoteSentDate];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation {
if (annotation == self) {
if (@available(iOS 11.0, *)) {
static NSString *markerAnnotationIdentifier = @"MarkerAnnotation";
MKMarkerAnnotationView *markerAnnotation = (MKMarkerAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:markerAnnotationIdentifier];
if (markerAnnotation == nil) {
markerAnnotation = [[MKMarkerAnnotationView alloc] initWithAnnotation:self reuseIdentifier:markerAnnotationIdentifier];
markerAnnotation.canShowCallout = true;
markerAnnotation.markerTintColor = [Colors main];
markerAnnotation.animatesWhenAdded = true;
}
return markerAnnotation;
} else {
static NSString *pinAnnotationIdentifier = @"PinAnnotation";
MKPinAnnotationView *pinAnnotation = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:pinAnnotationIdentifier];
if (pinAnnotation == nil) {
pinAnnotation = [[MKPinAnnotationView alloc] initWithAnnotation:self reuseIdentifier:pinAnnotationIdentifier];
pinAnnotation.canShowCallout = YES;
pinAnnotation.pinTintColor = [Colors main];
pinAnnotation.animatesDrop = true;
}
return pinAnnotation;
}
}
return nil;
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay {
if ([overlay isKindOfClass:[MKCircle class]]) {
MKCircleRenderer *circelRenderer = [[MKCircleRenderer alloc] initWithCircle:overlay];
circelRenderer.fillColor = [UIColor colorWithRed:0.48 green:0.86 blue:0.11 alpha:0.3];
circelRenderer.strokeColor = [UIColor colorWithRed:0.48 green:0.86 blue:0.11 alpha:0.7];
circelRenderer.lineWidth = 2.0 * [UIScreen mainScreen].scale;
return circelRenderer;
}
return nil;
}
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {
if (!annotationSelected) {
[mapView selectAnnotation:self animated:YES];
annotationSelected = YES;
}
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
/* do nothing */
}
- (void)showInMaps {
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:@selector(openMapsWithItems:launchOptions:)]) {
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:self.coordinate addressDictionary:nil]];
mapItem.name = self.title;
[mapItem openInMapsWithLaunchOptions:nil];
} else {
/* IOS 5 */
NSString *mapsUrl = [NSString stringWithFormat:@"http://maps.apple.com/maps?ll=%f,%f", self.coordinate.latitude, self.coordinate.longitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:mapsUrl] options:@{} completionHandler:nil];
}
}
- (void)calculateRoute {
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:@selector(openMapsWithItems:launchOptions:)]) {
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:[[MKPlacemark alloc] initWithCoordinate:self.coordinate addressDictionary:nil]];
mapItem.name = self.title;
[mapItem openInMapsWithLaunchOptions:[NSDictionary dictionaryWithObject:MKLaunchOptionsDirectionsModeDriving forKey:MKLaunchOptionsDirectionsModeKey]];
} else {
/* IOS 5 */
CLLocation *myLocation = self.mapView.userLocation.location;
NSString *mapsUrl = [NSString stringWithFormat:@"http://maps.apple.com/maps?saddr=%f,%f&daddr=%f,%f",
myLocation.coordinate.latitude, myLocation.coordinate.longitude, self.coordinate.latitude, self.coordinate.longitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:mapsUrl] options:@{} completionHandler:nil];
}
}
- (void)checkPermissions {
_locationManager = [[CLLocationManager alloc] init];
[_locationManager requestWhenInUseAuthorization];
_locationManager.delegate = self;
}
#pragma mark - CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) {
self.mapView.showsUserLocation = YES;
} else {
self.mapView.showsUserLocation = NO;
}
}
@end