-
-
Save charleshkang/2fecfdb1e359d4c16166 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NLMapViewController.m | |
// neverlate | |
// | |
// Created by Charles Kang on 11/16/15. | |
// Copyright © 2015 Charles Kang. All rights reserved. | |
// | |
#import <Parse/Parse.h> | |
#import <Venmo-iOS-SDK/Venmo.h> | |
#import "NLMapView.h" | |
#import "NLUser.h" | |
#import "NLGoal.h" | |
#import "NSDate+NLLocalTime.h" | |
@implementation NLMapView | |
- (void)awakeFromNib { | |
[super awakeFromNib]; | |
[self requestLocationPermission]; | |
[self regionForSavedLocation]; | |
// [self animateViewUp:YES]; | |
// [self setupTapGestureRecognizer]; | |
// set hasUserLocation to false | |
self.hasUserLocation = false; | |
// set delegates | |
self.locationManager.delegate = self; | |
[self.locationManager startUpdatingLocation]; | |
self.searchTextField.delegate = self; | |
CLLocationDegrees lat = [[self.geofence valueForKey:@"NeverLateGoalLocations"] doubleValue]; | |
CLLocationDegrees lon = [[self.geofence valueForKey:@"NeverLateGoalLocations"] doubleValue]; | |
CLLocationDistance radius = [[self.geofence valueForKey:@"radius"] doubleValue]; | |
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(lat, lon); | |
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(center, radius, radius); | |
// line 43 and 44 creates a geofence/overlay | |
[self.mapView setRegion:region]; | |
[self setUpMapViewAndPin:self.location]; | |
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] | |
initWithTarget:self | |
action:@selector(handleLongPress:)]; | |
[self.mapView addGestureRecognizer:longPress]; | |
self.mapView.showsUserLocation=TRUE; | |
[self performSelector:@selector(openCallout:) withObject:self.mapView.userLocation afterDelay:1.0]; | |
self.searchTextField.autocorrectionType = UITextAutocorrectionTypeYes; | |
} | |
- (void) viewDidAppear:(BOOL)animated { | |
[self requestLocationPermission]; | |
self.mapView.delegate = self; | |
if ([self hasPreviouslySavedLocation]) { | |
[self showPreviouslySavedLocation]; | |
[self dropPinAtPreviouslySavedLocation]; | |
self.hasUserLocation = YES; | |
} | |
[self updateGeoUI]; | |
} | |
//- (void)animateViewUp:(BOOL) up | |
//{ | |
// const int movementDistance = 30; // tweak as needed | |
// const float movementDuration = 0.3f; // tweak as needed | |
// | |
// int movement = (up ? -movementDistance : movementDistance); | |
// | |
// [UIView beginAnimations: @"anim" context: nil]; | |
// [UIView setAnimationBeginsFromCurrentState: YES]; | |
// [UIView setAnimationDuration: movementDuration]; | |
// // self.superview.window.frame = CGRectOffset(self.frame, 0, movement); | |
// // self.superview.frame = CGRectOffset(self.frame, 0, movement); | |
// self.frame = CGRectOffset(self.frame, 0, movement); | |
// | |
// [UIView commitAnimations]; | |
//} | |
//- (void)setupTapGestureRecognizer { | |
// // tap to dismiss keyboard! | |
// UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] | |
// initWithTarget:self | |
// action:@selector(dismissKeyboard)]; | |
// | |
// [self.view addGestureRecognizer:tap]; | |
// [tap setCancelsTouchesInView:YES]; | |
//} | |
// CHARLES LOOK AT THIS CODE | |
- (void)requestLocationPermission { | |
self.locationManager = [[CLLocationManager alloc] init]; | |
if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { | |
[self.locationManager requestAlwaysAuthorization]; | |
} | |
} | |
// CHARLES LOOK AT THIS CODE | |
- (BOOL)hasPreviouslySavedLocation { | |
// kinda hacky | |
MKCoordinateRegion region = [self regionForSavedLocation]; | |
return !(region.center.latitude == 0 && region.center.longitude == 0 && region.span.longitudeDelta == 0 && region.span.latitudeDelta == 0); | |
} | |
// CHARLES LOOK AT THIS CODE | |
- (void)showPreviouslySavedLocation { | |
MKCoordinateRegion region = [self regionForSavedLocation]; | |
[self.mapView setRegion:region animated:NO]; | |
} | |
// CHARLES LOOK AT THIS CODE | |
- (void)dropPinAtPreviouslySavedLocation { | |
MKCoordinateRegion region = [self regionForSavedLocation]; | |
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init]; | |
annotation.coordinate = region.center; | |
if (annotation) { | |
} | |
[self.mapView addAnnotation:annotation]; | |
} | |
- (void) setCurrentLocation{ | |
if (self.locationManager == nil){ | |
self.locationManager = [[CLLocationManager alloc]init]; | |
} | |
self.locationManager.delegate = self; | |
//mandatory check http://stackoverflow.com/questions/24062509/location-services-not-working-in-ios-8 | |
self.locationManager.distanceFilter = kCLDistanceFilterNone; | |
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; | |
} | |
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation { | |
MKCoordinateRegion mapRegion; | |
mapRegion.center = mapView.userLocation.coordinate; | |
mapRegion.span = MKCoordinateSpanMake(0.005, 0.005); | |
// set zoom to user's location | |
self.location = self.locationManager.location; | |
// zoom to region containing the user location | |
// MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800); | |
// [self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES]; | |
if (!self.hasUserLocation) { | |
self.hasUserLocation = YES; | |
[self.mapView setRegion:mapRegion animated:YES]; | |
// add the annotation | |
MKPointAnnotation *point = [[MKPointAnnotation alloc] init]; | |
point.coordinate = userLocation.coordinate; | |
} | |
} | |
- (MKOverlayView *)mapView:(MKMapView *)map viewForOverlay:(id <MKOverlay>)overlay { | |
MKCircleView *circleView = [[MKCircleView alloc] initWithOverlay:overlay]; | |
circleView.fillColor = [[UIColor blueColor] colorWithAlphaComponent:0.2]; | |
return circleView; | |
} | |
- (void)performSearch { | |
MKLocalSearchRequest *request = | |
[[MKLocalSearchRequest alloc] init]; | |
request.naturalLanguageQuery = self.searchTextField.text; | |
request.region = _mapView.region; | |
self.matchingSearchItems = [[NSMutableArray alloc] init]; | |
MKLocalSearch *search = | |
[[MKLocalSearch alloc]initWithRequest:request]; | |
[search startWithCompletionHandler:^(MKLocalSearchResponse | |
*response, NSError *error) { | |
if (response.mapItems.count == 0) { | |
NSLog(@"No Matches"); | |
} else { | |
MKMapItem *item = response.mapItems[0]; | |
[self.mapView setRegion:MKCoordinateRegionMake(item.placemark.coordinate, MKCoordinateSpanMake(0.005, 0.005))]; | |
for (MKMapItem *item in response.mapItems) | |
{ | |
[self.matchingSearchItems addObject:item]; | |
MKPointAnnotation *annotation = | |
[[MKPointAnnotation alloc]init]; | |
annotation.coordinate = item.placemark.coordinate; | |
annotation.title = item.name; | |
[_mapView addAnnotation:annotation]; | |
} | |
} | |
}]; | |
} | |
- (MKCoordinateRegion)regionForSavedLocation { | |
MKCoordinateRegion myRegion; | |
myRegion.center.latitude = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.latitude"]; | |
myRegion.center.longitude = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.center.longitude"]; | |
myRegion.span.latitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.latitude"]; | |
myRegion.span.longitudeDelta = [[NSUserDefaults standardUserDefaults] doubleForKey:@"map.location.span.longitude"]; | |
return myRegion; | |
} | |
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar | |
{ | |
[searchBar resignFirstResponder]; | |
[self.mapView removeAnnotations:self.mapView.annotations]; | |
[self performSearch]; | |
[self setCurrentLocation]; | |
MKLocalSearchRequest *request = | |
[[MKLocalSearchRequest alloc] init]; | |
request.naturalLanguageQuery = @"Places"; | |
request.region = _mapView.region; | |
MKLocalSearch *search = | |
[[MKLocalSearch alloc]initWithRequest:request]; | |
[search startWithCompletionHandler:^(MKLocalSearchResponse | |
*response, NSError *error) { | |
if (response.mapItems.count == 0) | |
NSLog(@"No Matches"); | |
}]; | |
} | |
-(MKAnnotationView*)annotationView{ | |
MKAnnotationView *annotationView = [[MKAnnotationView alloc]initWithAnnotation:self reuseIdentifier:@"MyCustomAnimation"]; | |
// annotationView.enabled = YES; | |
// annotationView.canShowCallout = YES; | |
// annotationView.image = [UIImage imageNamed:@"customPin.png"]; | |
// annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; | |
//annotationView.frame = CGRectMake(0, 0, 100, 100); | |
return annotationView; | |
} | |
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { | |
if ([annotation isKindOfClass:[MKUserLocation class]]) { | |
return nil; | |
} | |
MKPinAnnotationView *pin = [[MKPinAnnotationView alloc] init]; | |
pin.canShowCallout = YES; | |
pin.animatesDrop = YES; | |
pin.draggable = YES; | |
pin.rightCalloutAccessoryView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; | |
UIButton *addButton = [UIButton buttonWithType:UIButtonTypeContactAdd]; | |
// found a bug, add button keeps on appearing for some reason | |
pin.rightCalloutAccessoryView = addButton; | |
if ([annotation isKindOfClass:[CustomPin class]]){ | |
CustomPin *myLocation = (CustomPin*)annotation; | |
MKAnnotationView *annotationView = [self.mapView dequeueReusableAnnotationViewWithIdentifier:@"customAnnotation"]; | |
if (annotationView == nil){ | |
annotationView = myLocation.annotationView; | |
} else { | |
annotationView.annotation = annotation; | |
} | |
return annotationView; | |
} else { | |
return pin; | |
} | |
} | |
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views { | |
MKAnnotationView *aV; | |
for (aV in views) { | |
if ([aV.annotation isKindOfClass:[MKUserLocation class]]) { | |
MKAnnotationView* annotationView = aV; | |
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd]; | |
} | |
} | |
} | |
- (void)handleLongPress:(UIGestureRecognizer *)gestureRecognizer | |
{ | |
if (gestureRecognizer.state != UIGestureRecognizerStateBegan) | |
return; | |
[self.mapView removeAnnotations:self.mapView.annotations]; | |
CGPoint touchPoint = [gestureRecognizer locationInView:self.mapView]; | |
CLLocationCoordinate2D touchMapCoordinate = [self.mapView convertPoint:touchPoint toCoordinateFromView:self.mapView]; | |
// NLMapViewController *annotation = [[NLMapViewController alloc] init]; | |
// annotation.coordinate = touchMapCoordinate; | |
MKPointAnnotation *annotation = | |
[[MKPointAnnotation alloc]init]; | |
annotation.coordinate = touchMapCoordinate; | |
annotation.title = @"Destination"; | |
[self.mapView addAnnotation:annotation]; | |
} | |
#pragma mark - create geofence when save location plus button tapped | |
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control { | |
// remove all existing geofences | |
for (CLRegion *region in self.locationManager.monitoredRegions) { | |
[self.locationManager stopMonitoringForRegion:region]; | |
} | |
// saves the pin location and zooms the map to that pin, when a user opens the app again | |
CLLocationCoordinate2D location = view.annotation.coordinate; | |
[[NSUserDefaults standardUserDefaults] setDouble:location.latitude forKey:@"map.location.center.latitude"]; | |
[[NSUserDefaults standardUserDefaults] setDouble:location.longitude forKey:@"map.location.center.longitude"]; | |
[[NSUserDefaults standardUserDefaults] setDouble:0.05 forKey:@"map.location.span.latitude"]; | |
[[NSUserDefaults standardUserDefaults] setDouble:0.05 forKey:@"map.location.span.longitude"]; | |
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:location radius:40.0 identifier:@"hi"]; | |
// NSLog(@"%f, %f", region.center.latitude, region.center.longitude); | |
// create new geofence | |
[self.locationManager startMonitoringForRegion:region]; | |
MKCoordinateRegion myRegion = [self regionForSavedLocation]; | |
NSLog(@"%@", [NSString stringWithFormat:@"Region read : %f %f %f %f", myRegion.center.latitude, myRegion.center.longitude, myRegion.span.latitudeDelta, myRegion.span.longitudeDelta]); | |
NSLog(@"%@", [NSString stringWithFormat:@"Region on map: %f %f %f %f", self.mapView.region.center.latitude, self.mapView.region.center.longitude, self.mapView.region.span.latitudeDelta, self.mapView.region.span.longitudeDelta]); | |
NSLog(@"%@", self.locationManager); | |
// Update UI for new geofence | |
[self updateGeoUI]; | |
CLLocation *selectedLocation = [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude]; | |
[self.delegate mapView:self didSelectLocation:selectedLocation]; | |
} | |
#pragma mark - setup geofence circle (UI) around the selected location | |
- (void)updateGeoUI { | |
[self.mapView removeOverlay:self.overlay]; | |
for (CLCircularRegion *region in self.locationManager.monitoredRegions) { | |
self.overlay = [MKCircle circleWithCenterCoordinate:region.center radius:region.radius]; | |
[self.mapView addOverlay:self.overlay]; | |
} | |
} | |
// testing code below this line | |
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation | |
{ | |
[self.locationManager stopUpdatingLocation]; | |
[self setUpMapViewAndPin:newLocation]; // this should be doing it too!!! | |
} | |
- (void)setUpMapViewAndPin:(CLLocation *)location { | |
CLLocationCoordinate2D location2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude); | |
self.mapView.delegate = self; | |
self.mapView.showsUserLocation = YES; | |
//zoom in | |
MKMapCamera *camera = [MKMapCamera cameraLookingAtCenterCoordinate:location2D fromEyeCoordinate:location2D eyeAltitude:10000]; | |
[self.mapView setCamera:camera animated:NO]; | |
} | |
- (void)openCallout:(id<MKAnnotation>)annotation { | |
[self.mapView selectAnnotation:annotation animated:NO]; | |
} | |
-(void)dismissKeyboard { | |
[self.searchTextField resignFirstResponder]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment