1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-04 10:27:46 +01:00
Telegram/legacy/TelegraphKit/TGMapViewController.m
2015-10-01 19:19:52 +03:00

936 lines
36 KiB
Objective-C

#import "TGMapViewController.h"
#import <MapKit/MapKit.h>
#import "TGMapView.h"
#import "TGImageUtils.h"
#import "TGLocationAnnotation.h"
#import "TGMapAnnotationView.h"
#import "TGCalloutView.h"
#import "TGContactMediaAttachment.h"
#import "TGLocationMapModeControl.h"
#import "TGBackdropView.h"
#import "TGFont.h"
#import "TGActionSheet.h"
#import "TGAlertView.h"
typedef enum {
TGMapViewControllerModePick = 0,
TGMapViewControllerModeMap = 1
} TGMapViewControllerMode;
static CLLocation *lastUserLocation = nil;
static int selectedMapMode = 0;
static bool selectedMapModeInitialized = false;
@protocol TGApplicationWithCustomURLHandling <NSObject>
- (BOOL)openURL:(NSURL *)url forceNative:(BOOL)forceNative;
@end
static int defaultMapMode()
{
if (!selectedMapModeInitialized)
{
selectedMapModeInitialized = true;
selectedMapMode = [[[NSUserDefaults standardUserDefaults] objectForKey:@"TGMapViewController.defaultMapMode"] intValue];
}
return selectedMapMode;
}
static void setDefaultMapMode(int mode)
{
selectedMapModeInitialized = true;
selectedMapMode = mode;
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[[NSNumber alloc] initWithInt:mode] forKey:@"TGMapViewController.defaultMapMode"];
[userDefaults synchronize];
}
#pragma mark -
@interface TGMapViewController () <MKMapViewDelegate>
{
CLLocationManager *_locationManager;
}
@property (nonatomic) TGMapViewControllerMode mode;
@property (nonatomic) bool locationServicesDisabled;
@property (nonatomic, strong) TGUser *user;
@property (nonatomic, strong) TGMapView *mapView;
@property (nonatomic) bool modifiedPinLocation;
@property (nonatomic) bool modifiedRegion;
@property (nonatomic, strong) TGLocationAnnotation *highlightedLocationAnnotation;
@property (nonatomic, strong) CLLocation *mapLocation;
@property (nonatomic, strong) UIButton *locationButton;
@property (nonatomic, strong) UIView *locationIconsContainer;
@property (nonatomic, strong) UIActivityIndicatorView *locationActivityIndicator;
@property (nonatomic, strong) UIImageView *locationNormalIcon;
@property (nonatomic, strong) UIImageView *locationActiveIcon;
@property (nonatomic, strong) UIImageView *locationActiveHeadingIcon;
@property (nonatomic, strong) UISegmentedControl *segmentedControl;
@property (nonatomic) bool mapViewFinished;
@end
@implementation TGMapViewController
{
TGLocationMapModeControl *_mapModeControl;
}
- (id)initInPickingMode
{
self = [super initWithNibName:nil bundle:nil];
if (self)
{
_actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true];
_mode = TGMapViewControllerModePick;
_locationManager = [[CLLocationManager alloc] init];
if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
[_locationManager requestWhenInUseAuthorization];
}
return self;
}
- (id)initInMapModeWithLatitude:(double)latitude longitude:(double)longitude user:(TGUser *)user
{
self = [super initWithNibName:nil bundle:nil];
if (self)
{
_actionHandle = [[ASHandle alloc] initWithDelegate:self releaseOnMainThread:true];
_mode = TGMapViewControllerModeMap;
_locationManager = [[CLLocationManager alloc] init];
if ([_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
[_locationManager requestWhenInUseAuthorization];
_user = user;
_mapLocation = [[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
_highlightedLocationAnnotation = [[TGLocationAnnotation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) title:nil];
}
return self;
}
- (void)dealloc
{
[_actionHandle reset];
[ActionStageInstance() removeWatcher:self];
[self doUnloadView];
}
- (void)loadView
{
[super loadView];
_mapView = [[TGMapView alloc] initWithFrame:self.view.bounds];
_mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_mapView.zoomEnabled = true;
_mapView.scrollEnabled = true;
_mapView.delegate = self;
_mapView.userInteractionEnabled = true;
_mapView.showsUserLocation = true;
_mapView.mapType = defaultMapMode();
if (iosMajorVersion() >= 6)
{
for (UIView *subview in _mapView.subviews)
{
if ([subview isKindOfClass:[UILabel class]])
{
subview.autoresizingMask = 0;
CGRect frame = subview.frame;
frame.origin.y = 5;
frame.origin.x = 5;
subview.frame = frame;
break;
}
}
}
if (_mode == TGMapViewControllerModePick)
{
self.titleText = TGLocalized(@"Map.ChooseLocationTitle");
[self setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Cancel") style:UIBarButtonItemStylePlain target:self action:@selector(cancelButtonPressed)]];
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Map.Send") style:UIBarButtonItemStyleDone target:self action:@selector(doneButtonPressed)]];
self.navigationItem.rightBarButtonItem.enabled = false;
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(mapLongPressed:)];
[_mapView addGestureRecognizer:longPressRecognizer];
if (lastUserLocation != nil)
{
MKCoordinateRegion mapRegion;
mapRegion.center = lastUserLocation.coordinate;
mapRegion.span.latitudeDelta = 0.008;
mapRegion.span.longitudeDelta = 0.008;
@try
{
[_mapView setRegion:mapRegion animated:false];
}
@catch (NSException *exception) { TGLog(@"%@", exception); }
}
}
else if (_mode == TGMapViewControllerModeMap)
{
self.titleText = TGLocalized(@"Map.MapTitle");
if (TGIsPad())
{
[self setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.Done") style:UIBarButtonItemStyleDone target:self action:@selector(dismissButtonPressed)]];
}
if (iosMajorVersion() >= 7)
{
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(actionsButtonPressed)]];
}
else
{
[self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:TGLocalized(@"Common.More") style:UIBarButtonItemStylePlain target:self action:@selector(actionsButtonPressed)]];
}
MKCoordinateRegion mapRegion;
mapRegion.center = _highlightedLocationAnnotation.coordinate;
mapRegion.span.latitudeDelta = 0.008;
mapRegion.span.longitudeDelta = 0.008;
@try
{
[_mapView setRegion:mapRegion animated:false];
}
@catch (NSException *exception)
{
TGLog(@"%@", exception);
}
[_mapView addAnnotation:_highlightedLocationAnnotation];
[_mapView selectAnnotation:_highlightedLocationAnnotation animated:false];
}
[self.view addSubview:_mapView];
float retinaPixel = TGIsRetina() ? 0.5f : 0.0f;
UIView *_backgroundView;
if (TGBackdropEnabled())
{
_backgroundView = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0f, self.view.frame.size.height - 44.0f, self.view.frame.size.width, 44.0f)];
[self.view addSubview:_backgroundView];
}
else
{
_backgroundView = [TGBackdropView viewWithLightNavigationBarStyle];
_backgroundView.frame = CGRectMake(0.0f, self.view.frame.size.height - 44.0f, self.view.frame.size.width, 44.0f);
[self.view addSubview:_backgroundView];
UIView *_stripeView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, _backgroundView.frame.size.width, TGIsRetina() ? 0.5f : 1.0f)];
_stripeView.backgroundColor = UIColorRGB(0xb2b2b2);
[_backgroundView addSubview:_stripeView];
}
_backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
_locationButton = [[UIButton alloc] initWithFrame:CGRectMake(6, self.view.frame.size.height - 44.0f, 44, 44.0f)];
[_locationButton addTarget:self action:@selector(locationButtonPressed) forControlEvents:UIControlEventTouchUpInside];
_locationButton.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
[self.view addSubview:_locationButton];
CGPoint iconOffset = {1.0f, 6.0f};
_locationIconsContainer = [[UIView alloc] initWithFrame:_locationButton.bounds];
_locationIconsContainer.userInteractionEnabled = false;
[_locationButton addSubview:_locationIconsContainer];
_locationNormalIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MapLocationIcon.png"]];
_locationNormalIcon.frame = CGRectOffset(_locationNormalIcon.frame, 9 + iconOffset.x, 7 + iconOffset.y);
[_locationIconsContainer addSubview:_locationNormalIcon];
_locationActiveIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MapLocationIcon_Active.png"]];
_locationActiveIcon.frame = CGRectOffset(_locationActiveIcon.frame, 9 + iconOffset.x, 7 + iconOffset.y);
_locationActiveIcon.alpha = 0.0f;
[_locationIconsContainer addSubview:_locationActiveIcon];
_locationActiveHeadingIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"MapLocationIcon_ActiveHeading.png"]];
_locationActiveHeadingIcon.frame = CGRectOffset(_locationActiveIcon.frame, 1 + iconOffset.x, -6 + iconOffset.y);
_locationActiveHeadingIcon.alpha = 0.0f;
[_locationIconsContainer addSubview:_locationActiveHeadingIcon];
_locationActivityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
_locationActivityIndicator.userInteractionEnabled = false;
_locationActivityIndicator.frame = CGRectOffset(_locationActivityIndicator.frame, CGFloor((_locationButton.frame.size.width - _locationActivityIndicator.frame.size.width) / 2.0f) + retinaPixel, CGFloor((_locationButton.frame.size.height - _locationActivityIndicator.frame.size.height) / 2.0f) + retinaPixel);
_locationActivityIndicator.alpha = 0.0f;
_locationActivityIndicator.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
[_locationButton addSubview:_locationActivityIndicator];
static UIImage *clearImage = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
UIGraphicsBeginImageContextWithOptions(CGSizeMake(4.0f, 4.0f), false, 0.0f);
clearImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
});
// _segmentedControl = [[UISegmentedControl alloc] initWithItems:@[TGLocalized(@"Map.Map"), TGLocalized(@"Map.Satellite"), TGLocalized(@"Map.Hybrid")]];
// _segmentedControl.frame = CGRectMake(_backgroundView.frame.size.width - 240, 0.0f, 240, _backgroundView.frame.size.height);
// _segmentedControl.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
//
// [_segmentedControl setBackgroundImage:clearImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
// [_segmentedControl setBackgroundImage:clearImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
// [_segmentedControl setBackgroundImage:clearImage forState:UIControlStateSelected | UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
// [_segmentedControl setBackgroundImage:clearImage forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
// [_segmentedControl setDividerImage:clearImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
// [_segmentedControl setDividerImage:clearImage forLeftSegmentState:UIControlStateHighlighted rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
// [_segmentedControl setDividerImage:clearImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
//
// [_segmentedControl setTitleTextAttributes:@{UITextAttributeTextColor: UIColorRGB(0x666666), UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(14)} forState:UIControlStateNormal];
// [_segmentedControl setTitleTextAttributes:@{UITextAttributeTextColor: TGAccentColor(), UITextAttributeTextShadowColor: [UIColor clearColor], UITextAttributeFont: TGSystemFontOfSize(14)} forState:UIControlStateSelected];
//
// [_backgroundView addSubview:_segmentedControl];
//
// [_segmentedControl setSelectedSegmentIndex:MIN(2, MAX(0, _mapView.mapType))];
// [_segmentedControl addTarget:self action:@selector(segmentedControlChangedValue:) forControlEvents:UIControlEventValueChanged];
_mapModeControl = [[TGLocationMapModeControl alloc] init];
_mapModeControl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_mapModeControl.frame = CGRectMake(55, (_backgroundView.frame.size.height - 29) / 2 + 0.5f, _backgroundView.frame.size.width - 55 - 7.5f, 29);
_mapModeControl.selectedSegmentIndex = MAX(0, MIN(2, (NSInteger)_mapView.mapType));
[_mapModeControl addTarget:self action:@selector(mapModeControlValueChanged:) forControlEvents:UIControlEventValueChanged];
[_backgroundView addSubview:_mapModeControl];
/*_buttonGroupView = [[TGButtonGroupView alloc] initWithFrame:CGRectMake(self.view.frame.size.width - 219 - 6, self.view.frame.size.height - rawButtonLeft.size.height - 7, 219, rawButtonLeft.size.height) buttonLeftImage:buttonLeft buttonLeftHighlightedImage:buttonLeftHighlighted buttonCenterImage:buttonCenter buttonCenterHighlightedImage:buttonCenterHighlighted buttonRightImage:buttonRight buttonRightHighlightedImage:buttonRightHighlighted buttonSeparatorImage:buttonSeparator buttonSeparatorLeftHighlightedImage:buttonSeparatorLeftHighlighted buttonSeparatorRightHighlightedImage:buttonSeparatorRightHighlighted];
_buttonGroupView.delegate = self;
_buttonGroupView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
_buttonGroupView.selectedIndex = MIN(2, MAX(0, _mapView.mapType));
_buttonGroupView.buttonTopTextInset = 1;
_buttonGroupView.buttonSideTextInset = 3;
_buttonGroupView.buttonTextColorHighlighted = UIColorRGB(0x046dd0);
_buttonGroupView.buttonTextColor = UIColorRGB(0x595959);
_buttonGroupView.buttonShadowColor = UIColorRGBA(0xffffff, 0.6f);
_buttonGroupView.buttonShadowOffset = CGSizeMake(0, 1);
_buttonGroupView.buttonFont = [UIFont boldSystemFontOfSize:12];
_buttonGroupView.buttonsAreAlwaysDeselected = true;
[_buttonGroupView addButton:TGLocalized(@"Map.Map")];
[_buttonGroupView addButton:TGLocalized(@"Map.Satellite")];
[_buttonGroupView addButton:TGLocalized(@"Map.Hybrid")];
[self.view addSubview:_buttonGroupView];*/
}
- (void)doUnloadView
{
_mapView.delegate = nil;
_mapView = nil;
}
- (void)viewDidUnload
{
[self doUnloadView];
[super viewDidUnload];
}
- (BOOL)_shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
if ([self presentedViewController] != nil)
return false;
return toInterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown;
}
- (BOOL)shouldAutorotate
{
return [self _shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait];
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[_mapView setCenterCoordinate:_mapView.region.center animated:NO];
[super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
#pragma mark -
- (void)mapView:(MKMapView *)__unused mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
if (userLocation.coordinate.latitude == 0.0 && userLocation.coordinate.longitude == 0.0)
return;
_locationServicesDisabled = false;
lastUserLocation = userLocation.location;
if (_mode == TGMapViewControllerModePick)
{
if (!_modifiedPinLocation)
{
if (!_modifiedRegion)
{
_modifiedRegion = true;
MKCoordinateRegion mapRegion;
mapRegion.center = userLocation.coordinate;
mapRegion.span.latitudeDelta = 0.008;
mapRegion.span.longitudeDelta = 0.008;
@try
{
[_mapView setRegion:mapRegion animated:true];
}
@catch (NSException *exception) { TGLog(@"%@", exception); }
}
if (_highlightedLocationAnnotation != nil)
{
[_highlightedLocationAnnotation setCoordinate:userLocation.coordinate];
}
else
{
_highlightedLocationAnnotation = [[TGLocationAnnotation alloc] initWithCoordinate:userLocation.coordinate title:nil];
[_mapView addAnnotation:_highlightedLocationAnnotation];
}
}
}
if (_locationActivityIndicator.alpha > FLT_EPSILON)
{
[_mapView setUserTrackingMode:MKUserTrackingModeFollow animated:true];
[self updateLocationIcons];
}
[self updateLocationAvailability];
if (_mode == TGMapViewControllerModeMap)
{
//TGDispatchAfter(1.0, dispatch_get_main_queue(), ^{
[self updateAnnotationView:(TGMapAnnotationView *)[_mapView viewForAnnotation:_highlightedLocationAnnotation]];
//});
}
[self updateDoneButton];
}
- (void)mapView:(MKMapView *)__unused mapView annotationView:(MKAnnotationView *)__unused annotationView didChangeDragState:(MKAnnotationViewDragState)__unused newState fromOldState:(MKAnnotationViewDragState)__unused oldState
{
if (!_modifiedPinLocation)
_modifiedPinLocation = true;
if (newState == MKAnnotationViewDragStateEnding)
[self updateDoneButton];
}
- (void)mapView:(MKMapView *)__unused mapView didFailToLocateUserWithError:(NSError *)__unused error
{
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied)
{
_locationServicesDisabled = true;
[self updateLocationAvailability];
if (_locationServicesDisabled && _mode == TGMapViewControllerModePick)
{
TGAlertView *alertView = [[TGAlertView alloc] initWithTitle:nil message:TGLocalized(@"Map.AccessDeniedError") delegate:nil cancelButtonTitle:TGLocalized(@"Common.OK") otherButtonTitles:nil];
[alertView show];
}
}
}
- (void)mapView:(MKMapView *)__unused mapView didAddAnnotationViews:(NSArray *)views
{
if (_mode != TGMapViewControllerModePick)
return;
for (MKAnnotationView *annotationView in views)
{
if ([annotationView.annotation isKindOfClass:[MKUserLocation class]])
continue;
MKMapPoint point = MKMapPointForCoordinate(annotationView.annotation.coordinate);
if (!MKMapRectContainsPoint(self.mapView.visibleMapRect, point))
continue;
CGRect endFrame = annotationView.frame;
annotationView.frame = CGRectMake(annotationView.frame.origin.x, annotationView.frame.origin.y - self.view.frame.size.height, annotationView.frame.size.width, annotationView.frame.size.height);
id<MKAnnotation> annotation = annotationView.annotation;
[UIView animateWithDuration:0.5 delay:(0.04 * [views indexOfObject:annotationView]) options:0 animations:^
{
annotationView.frame = endFrame;
} completion:^(BOOL finished)
{
if (finished)
{
[UIView animateWithDuration:0.05 animations:^
{
annotationView.transform = CGAffineTransformMakeScale(1.0f, 0.8f);
} completion:^(BOOL finished)
{
[mapView selectAnnotation:annotation animated:true];
if (finished)
{
[UIView animateWithDuration:0.1 animations:^
{
annotationView.transform = CGAffineTransformIdentity;
}];
}
}];
}
}];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if (annotation == mapView.userLocation)
{
return nil;
}
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"Pin"];
if (annotationView == nil)
{
if (_mode == TGMapViewControllerModeMap)
{
annotationView = [[TGMapAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"Pin"];
((TGMapAnnotationView *)annotationView).watcherHandle = _actionHandle;
}
else
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"Pin"];
}
annotationView.canShowCallout = false;
annotationView.animatesDrop = false;
if (_mode == TGMapViewControllerModePick)
annotationView.draggable = true;
else
[self updateAnnotationView:(TGMapAnnotationView *)annotationView];
return annotationView;
}
- (void)mapView:(MKMapView *)__unused mapView didSelectAnnotationView:(MKAnnotationView *)view
{
if (_highlightedLocationAnnotation != nil && view.annotation == _highlightedLocationAnnotation)
{
if (_mode == TGMapViewControllerModeMap)
{
}
}
}
- (void)mapView:(MKMapView *)__unused mapView didDeselectAnnotationView:(MKAnnotationView *)view
{
if (_highlightedLocationAnnotation != nil && view.annotation == _highlightedLocationAnnotation)
{
if (_mode == TGMapViewControllerModeMap)
{
}
}
}
#pragma mark -
- (void)updateAnnotationView:(TGMapAnnotationView *)annotationView
{
[annotationView.calloutView setTitleText:_user.displayName];
if (_mapView.userLocation != nil && _mapView.userLocation.location != nil)
{
static bool metricUnits = true;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
NSLocale *locale = [NSLocale currentLocale];
metricUnits = [[locale objectForKey:NSLocaleUsesMetricSystem] boolValue];
});
NSString *distanceString = nil;
double distance = [_mapLocation distanceFromLocation:_mapView.userLocation.location];
if (metricUnits)
{
if (distance >= 1000 * 1000)
distanceString = [[NSString alloc] initWithFormat:@"%.1fK km away", distance / (1000.0 * 1000.0)];
else if (distance > 1000)
distanceString = [[NSString alloc] initWithFormat:@"%.1f km away", distance / 1000.0];
else
distanceString = [[NSString alloc] initWithFormat:@"%d m away", (int)distance];
}
else
{
double feetDistance = distance / 0.3048;
if (feetDistance >= 5280)
{
char buf[32];
snprintf(buf, 32, "%.1f", feetDistance / 5280.0);
bool dot = false;
for (int i = 0; i < 32; i++)
{
char c = buf[i];
if (c == '\0')
break;
else if (c < '0' || c > '9')
{
dot = true;
break;
}
}
distanceString = [[NSString alloc] initWithFormat:@"%s mile%s away", buf, dot || feetDistance / 5280.0 > 1.0 ? "s" : ""];
}
else
{
distanceString = [[NSString alloc] initWithFormat:@"%d %s away", (int)feetDistance, (int)feetDistance != 1 ? "feet" : "foot"];
}
}
[annotationView.calloutView setSubtitleText:distanceString];
}
else
[annotationView.calloutView setSubtitleText:nil];
[annotationView.calloutView sizeToFit];
[annotationView setNeedsLayout];
if (annotationView.calloutView.frame.origin.y < 0)
{
[UIView animateWithDuration:0.2 animations:^
{
[annotationView layoutIfNeeded];
}];
}
}
- (void)mapView:(MKMapView *)__unused mapView regionDidChangeAnimated:(BOOL)__unused animated
{
//TGLog(@"region change");
}
- (void)mapView:(MKMapView *)__unused mapView didChangeUserTrackingMode:(MKUserTrackingMode)__unused mode animated:(BOOL)__unused animated
{
[self updateLocationIcons];
}
- (void)updateDoneButton
{
if (_mode == TGMapViewControllerModePick)
{
self.navigationItem.rightBarButtonItem.enabled = ABS(_highlightedLocationAnnotation.coordinate.latitude) > DBL_EPSILON || ABS(_highlightedLocationAnnotation.coordinate.longitude) > DBL_EPSILON;
}
}
- (void)mapViewWillStartLoadingMap:(MKMapView *)__unused mapView
{
_mapViewFinished = false;
}
- (void)mapViewDidFinishLoadingMap:(MKMapView *)__unused mapView
{
_mapViewFinished = true;
}
#pragma mark - Actions
- (void)mapLongPressed:(UILongPressGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan)
{
_modifiedPinLocation = true;
if (_highlightedLocationAnnotation != nil)
{
[_mapView removeAnnotation:_highlightedLocationAnnotation];
_highlightedLocationAnnotation = nil;
}
CGPoint touchPoint = [recognizer locationInView:_mapView];
CLLocationCoordinate2D touchMapCoordinate = [_mapView convertPoint:touchPoint toCoordinateFromView:_mapView];
_highlightedLocationAnnotation = [[TGLocationAnnotation alloc] initWithCoordinate:touchMapCoordinate title:nil];
[_mapView addAnnotation:_highlightedLocationAnnotation];
[self updateDoneButton];
}
}
- (void)dismissButtonPressed
{
[self.presentingViewController dismissViewControllerAnimated:true completion:nil];
}
- (void)cancelButtonPressed
{
id<ASWatcher> watcherDelegate = _watcher == nil ? nil : _watcher.delegate;
if (watcherDelegate != nil && [watcherDelegate respondsToSelector:@selector(actionStageActionRequested:options:)])
{
[watcherDelegate actionStageActionRequested:@"mapViewFinished" options:nil];
}
}
- (void)doneButtonPressed
{
id<ASWatcher> watcherDelegate = _watcher == nil ? nil : _watcher.delegate;
if (watcherDelegate != nil && [watcherDelegate respondsToSelector:@selector(actionStageActionRequested:options:)])
{
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
if (_highlightedLocationAnnotation != nil && (_highlightedLocationAnnotation.coordinate.latitude != 0.0 || _highlightedLocationAnnotation.coordinate.longitude != 0.0))
{
[options setObject:[NSNumber numberWithDouble:_highlightedLocationAnnotation.coordinate.latitude] forKey:@"latitude"];
[options setObject:[NSNumber numberWithDouble:_highlightedLocationAnnotation.coordinate.longitude] forKey:@"longitude"];
}
else if (_mapView.userLocation != nil && (_mapView.userLocation.coordinate.latitude != 0.0 || _mapView.userLocation.coordinate.longitude != 0.0))
{
[options setObject:[NSNumber numberWithDouble:_mapView.userLocation.coordinate.latitude] forKey:@"latitude"];
[options setObject:[NSNumber numberWithDouble:_mapView.userLocation.coordinate.longitude] forKey:@"longitude"];
}
if (_mapViewFinished)
{
}
[watcherDelegate actionStageActionRequested:@"mapViewFinished" options:options];
}
}
- (void)locationButtonPressed
{
if (_mapView.userLocation != nil && _mapView.userLocation.location != nil)
{
if (_mapView.userTrackingMode == MKUserTrackingModeNone)
{
[_mapView setUserTrackingMode:MKUserTrackingModeFollow animated:true];
[self updateLocationIcons];
}
else if (_mapView.userTrackingMode == MKUserTrackingModeFollow)
{
[_mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:true];
[self updateLocationIcons];
}
else
{
[_mapView setUserTrackingMode:MKUserTrackingModeNone animated:true];
[self updateLocationIcons];
}
}
else
{
if (_locationServicesDisabled)
{
TGAlertView *alertView = [[TGAlertView alloc] initWithTitle:nil message:TGLocalized(@"Map.AccessDeniedError") delegate:nil cancelButtonTitle:TGLocalized(@"Common.OK") otherButtonTitles:nil];
[alertView show];
}
[self updateLocationAvailability];
}
}
- (void)mapModeControlValueChanged:(TGLocationMapModeControl *)sender
{
NSInteger mapMode = MAX(0, MIN(2, sender.selectedSegmentIndex));
setDefaultMapMode((int)mapMode);
[_mapView setMapType:(MKMapType)mapMode];
}
//- (void)segmentedControlChangedValue:(UISegmentedControl *)control
//{
// int mapMode = control.selectedSegmentIndex < 0 || control.selectedSegmentIndex > 2 ? 0 : control.selectedSegmentIndex;
// setDefaultMapMode(mapMode);
// [_mapView setMapType:(MKMapType)mapMode];
//}
/*- (void)buttonGroupViewButtonPressed:(TGButtonGroupView *)__unused buttonGroupView index:(int)index
{
int mapMode = index < 0 || index > 2 ? 0 : index;
setDefaultMapMode(mapMode);
[_mapView setMapType:(MKMapType)mapMode];
}*/
- (void)actionsButtonPressed
{
NSMutableArray *actions = [[NSMutableArray alloc] init];
[actions addObject:[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Map.GetDirections") action:@"getDirections"]];
if (_message != nil)
[actions addObject:[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Map.ForwardViaTelegram") action:@"forward"]];
if (iosMajorVersion() >= 6 && [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"comgooglemaps://"]])
[actions addObject:[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Map.OpenInGoogleMaps") action:@"googleMaps"]];
[actions addObject:[[TGActionSheetAction alloc] initWithTitle:TGLocalized(@"Common.Cancel") action:@"cancel" type:TGActionSheetActionTypeCancel]];
[[[TGActionSheet alloc] initWithTitle:nil actions:actions actionBlock:^(TGMapViewController *controller, NSString *action)
{
if ([action isEqualToString:@"getDirections"])
[controller _doGetDirections];
else if ([action isEqualToString:@"forward"])
[controller _doForward];
else if ([action isEqualToString:@"googleMaps"])
[controller _doOpenInGoogleMaps];
} target:self] showInView:self.view];
}
- (void)_doGetDirections
{
CLLocation *userLocation = _mapView.userLocation.location;
NSURL *addressUrl = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:@"https://maps.%@.com/?daddr=%f,%f%@", iosMajorVersion() < 6 ? @"google" : @"apple", _mapLocation.coordinate.latitude, _mapLocation.coordinate.longitude, userLocation == nil ? @"" : [[NSString alloc] initWithFormat:@"&saddr=%f,%f", userLocation.coordinate.latitude, userLocation.coordinate.longitude]]];
if ([[UIApplication sharedApplication] respondsToSelector:@selector(openURL:forceNative:)])
[(id<TGApplicationWithCustomURLHandling>)[UIApplication sharedApplication] openURL:addressUrl forceNative:true];
else
[[UIApplication sharedApplication] openURL:addressUrl];
}
- (void)_doForward
{
if (_message != nil)
{
[_watcher requestAction:@"mapViewForward" options:@{
@"controller": self,
@"message": _message
}];
}
}
- (void)_doOpenInGoogleMaps
{
CLLocationCoordinate2D centerLocation = _mapView.centerCoordinate;
NSURL *addressUrl = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:@"comgooglemaps-x-callback://?center=%f,%f&q=%f,%f&x-success=telegram://?resume=true&&x-source=Telegram", centerLocation.latitude, centerLocation.longitude, centerLocation.latitude, centerLocation.longitude]];
if ([[UIApplication sharedApplication] respondsToSelector:@selector(openURL:forceNative:)])
[(id<TGApplicationWithCustomURLHandling>)[UIApplication sharedApplication] openURL:addressUrl forceNative:true];
else
[[UIApplication sharedApplication] openURL:addressUrl];
}
#pragma mark -
- (void)updateLocationIcons
{
bool tracking = _mapView.userTrackingMode != MKUserTrackingModeNone;
bool trackingHeading = _mapView.userTrackingMode == MKUserTrackingModeFollowWithHeading;
float locationNormalAlpha = tracking ? 0.0f : 1.0f;
float locationActiveAlpha = tracking && !trackingHeading ? 1.0f : 0.0f;
float locationActiveHeadingAlpha = tracking && trackingHeading ? 1.0f : 0.0f;
bool animateTransition = (locationActiveHeadingAlpha < FLT_EPSILON) != (_locationActiveHeadingIcon.alpha < FLT_EPSILON);
if (!animateTransition)
{
_locationNormalIcon.alpha = locationNormalAlpha;
_locationActiveIcon.alpha = locationActiveAlpha;
_locationActiveHeadingIcon.alpha = locationActiveHeadingAlpha;
if (locationActiveHeadingAlpha < FLT_EPSILON)
{
_locationNormalIcon.transform = CGAffineTransformIdentity;
_locationActiveIcon.transform = CGAffineTransformIdentity;
_locationActiveHeadingIcon.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
}
else
{
_locationNormalIcon.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
_locationActiveIcon.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
_locationActiveHeadingIcon.transform = CGAffineTransformIdentity;
}
}
else
{
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
{
_locationNormalIcon.alpha = locationNormalAlpha;
_locationActiveIcon.alpha = locationActiveAlpha;
_locationActiveHeadingIcon.alpha = locationActiveHeadingAlpha;
if (locationActiveHeadingAlpha < FLT_EPSILON)
{
_locationNormalIcon.transform = CGAffineTransformIdentity;
_locationActiveIcon.transform = CGAffineTransformIdentity;
_locationActiveHeadingIcon.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
}
else
{
_locationNormalIcon.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
_locationActiveIcon.transform = CGAffineTransformMakeScale(0.1f, 0.1f);
_locationActiveHeadingIcon.transform = CGAffineTransformIdentity;
}
} completion:nil];
}
}
- (void)updateLocationAvailability
{
bool locationAvailable = (_mapView.userLocation != nil && _mapView.userLocation.location != nil) || _locationServicesDisabled;
if (locationAvailable == _locationActivityIndicator.alpha < FLT_EPSILON)
return;
if (!locationAvailable)
[_locationActivityIndicator startAnimating];
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
{
_locationIconsContainer.alpha = locationAvailable ? 1.0f : 0.0f;
_locationActivityIndicator.alpha = locationAvailable ? 0.0f : 1.0f;
_locationIconsContainer.transform = locationAvailable ? CGAffineTransformIdentity : CGAffineTransformMakeScale(0.1f, 0.1f);
_locationActivityIndicator.transform = locationAvailable ? CGAffineTransformMakeScale(0.1f, 0.1f) : CGAffineTransformIdentity;
} completion:^(BOOL finished)
{
if (finished)
{
if (locationAvailable)
[_locationActivityIndicator stopAnimating];
}
}];
}
#pragma mark -
- (void)actionStageActionRequested:(NSString *)action options:(id)__unused options
{
if ([action isEqualToString:@"calloutPressed"])
{
TGContactMediaAttachment *contactAttachment = [[TGContactMediaAttachment alloc] init];
contactAttachment.uid = _user.uid;
[_watcher requestAction:@"openContact" options:[[NSDictionary alloc] initWithObjectsAndKeys:contactAttachment, @"contactAttachment", nil]];
}
}
@end