From 673d8f90f24a89871905e80ef1bfd7970e61dc6c Mon Sep 17 00:00:00 2001 From: "Justin R. Miller" Date: Wed, 21 Sep 2016 15:07:44 -0700 Subject: [PATCH] [ios] revamp settings/debug UI in test app (#6421) --- platform/ios/app/MBXViewController.m | 691 +++++++++++++++++---------- 1 file changed, 438 insertions(+), 253 deletions(-) diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 0f81643f731..a34e0b12aeb 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -5,6 +5,7 @@ #import "MBXOfflinePacksTableViewController.h" #import "MBXAnnotationView.h" #import "MBXUserLocationAnnotationView.h" + #import "MGLFillStyleLayer.h" #import @@ -20,6 +21,52 @@ static NSString * const MBXViewControllerAnnotationViewReuseIdentifer = @"MBXViewControllerAnnotationViewReuseIdentifer"; +typedef NS_ENUM(NSInteger, MBXSettingsSections) { + MBXSettingsCoreRendering = 0, + MBXSettingsAnnotations, + MBXSettingsRuntimeStyling, + MBXSettingsMiscellaneous, +}; + +typedef NS_ENUM(NSInteger, MBXSettingsCoreRenderingRows) { + MBXSettingsCoreRenderingResetPosition = 0, + MBXSettingsCoreRenderingTileBoundaries, + MBXSettingsCoreRenderingTileInfo, + MBXSettingsCoreRenderingTimestamps, + MBXSettingsCoreRenderingCollisionBoxes, + MBXSettingsCoreRenderingOverdrawVisualization, +}; + +typedef NS_ENUM(NSInteger, MBXSettingsAnnotationsRows) { + MBXSettingsAnnotations100Views = 0, + MBXSettingsAnnotations1000Views, + MBXSettingsAnnotations10000Views, + MBXSettingsAnnotations100Sprites, + MBXSettingsAnnotations1000Sprites, + MBXSettingsAnnotations10000Sprites, + MBXSettingsAnnotationsTestShapes, + MBXSettingsAnnotationsCustomCallout, + MBXSettingsAnnotationsRemoveAnnotations, +}; + +typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) { + MBXSettingsRuntimeStylingWater = 0, + MBXSettingsRuntimeStylingRoads, + MBXSettingsRuntimeStylingRaster, + MBXSettingsRuntimeStylingGeoJSON, + MBXSettingsRuntimeStylingSymbols, + MBXSettingsRuntimeStylingBuildings, + MBXSettingsRuntimeStylingFerry, + MBXSettingsRuntimeStylingParks, +}; + +typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { + MBXSettingsMiscellaneousWorldTour = 0, + MBXSettingsMiscellaneousCustomUserDot, + MBXSettingsMiscellaneousPrintLogFile, + MBXSettingsMiscellaneousDeleteLogFile, +}; + @interface MBXDroppedPinAnnotation : MGLPointAnnotation @end @@ -38,7 +85,9 @@ @interface MBXSpriteBackedAnnotation : MGLPointAnnotation @implementation MBXSpriteBackedAnnotation @end -@interface MBXViewController () +@interface MBXViewController () @property (nonatomic) IBOutlet MGLMapView *mapView; @property (nonatomic) NSInteger styleIndex; @@ -52,7 +101,7 @@ @implementation MBXViewController BOOL _isTouringWorld; } -#pragma mark - Setup +#pragma mark - Setup & Teardown + (void)initialize { @@ -167,153 +216,271 @@ - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(__unused id)sender { } } -#pragma mark - Actions +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [self saveState:nil]; +} + +#pragma mark - Debugging Interface - (IBAction)showSettings:(__unused id)sender { + UITableViewController *settingsViewController = [[UITableViewController alloc] initWithStyle:UITableViewStyleGrouped]; + settingsViewController.tableView.delegate = self; + settingsViewController.tableView.dataSource = self; + settingsViewController.title = @"Debugging"; + settingsViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissSettings:)]; + UINavigationController *wrapper = [[UINavigationController alloc] initWithRootViewController:settingsViewController]; + wrapper.navigationBar.tintColor = self.navigationController.navigationBar.tintColor; + [self.navigationController presentViewController:wrapper animated:YES completion:nil]; +} + +- (void)dismissSettings:(__unused id)sender +{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (NSArray *)settingsSectionTitles +{ + return @[ + @"Core Rendering", + @"Annotations", + @"Runtime Styling", + @"Miscellaneous" + ]; +} + +- (NSArray *)settingsTitlesForSection:(NSInteger)section +{ + NSMutableArray *settingsTitles = [NSMutableArray array]; + MGLMapDebugMaskOptions debugMask = self.mapView.debugMask; - UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Map Settings" - delegate:self - cancelButtonTitle:@"Cancel" - destructiveButtonTitle:nil - otherButtonTitles: - @"Reset Position", - ((debugMask & MGLMapDebugTileBoundariesMask) - ? @"Hide Tile Boundaries" - : @"Show Tile Boundaries"), - ((debugMask & MGLMapDebugTileInfoMask) - ? @"Hide Tile Info" - : @"Show Tile Info"), - ((debugMask & MGLMapDebugTimestampsMask) - ? @"Hide Tile Timestamps" - : @"Show Tile Timestamps"), - ((debugMask & MGLMapDebugCollisionBoxesMask) - ? @"Hide Collision Boxes" - : @"Show Collision Boxes"), - ((debugMask & MGLMapDebugOverdrawVisualizationMask) - ? @"Hide Overdraw Visualization" - : @"Show Overdraw Visualization"), - @"Add 100 Views", - @"Add 1,000 Views", - @"Add 10,000 Views", - @"Add 100 Sprites", - @"Add 1,000 Sprites", - @"Add 10,000 Sprites", - @"Add Test Shapes", - @"Start World Tour", - @"Add Custom Callout Point", - @"Remove Annotations", - @"Manipulate Style", - ((_customUserLocationAnnnotationEnabled) - ? @"Disable Custom User Dot" - : @"Enable Custom User Dot"), - nil]; - - if (self.debugLoggingEnabled) + + switch (section) { - [sheet addButtonWithTitle:@"Print Telemetry Logfile"]; - [sheet addButtonWithTitle:@"Delete Telemetry Logfile"]; + case MBXSettingsCoreRendering: + [settingsTitles addObjectsFromArray:@[ + @"Reset Position", + [NSString stringWithFormat:@"%@ Tile Boundaries", + (debugMask & MGLMapDebugTileBoundariesMask ? @"Hide" :@"Show")], + [NSString stringWithFormat:@"%@ Tile Info", + (debugMask & MGLMapDebugTileInfoMask ? @"Hide" :@"Show")], + [NSString stringWithFormat:@"%@ Tile Timestamps", + (debugMask & MGLMapDebugTimestampsMask ? @"Hide" :@"Show")], + [NSString stringWithFormat:@"%@ Collision Boxes", + (debugMask & MGLMapDebugCollisionBoxesMask ? @"Hide" :@"Show")], + [NSString stringWithFormat:@"%@ Overdraw Visualization", + (debugMask & MGLMapDebugOverdrawVisualizationMask ? @"Hide" :@"Show")], + ]]; + break; + case MBXSettingsAnnotations: + [settingsTitles addObjectsFromArray:@[ + @"Add 100 Views", + @"Add 1,000 Views", + @"Add 10,000 Views", + @"Add 100 Sprites", + @"Add 1,000 Sprites", + @"Add 10,000 Sprites", + @"Add Test Shapes", + @"Add Point With Custom Callout", + @"Remove Annotations", + ]]; + break; + case MBXSettingsRuntimeStyling: + [settingsTitles addObjectsFromArray:@[ + @"Apply Water Functions", + @"Apply Road Line Functions", + @"Create Raster & Apply Function", + @"Create GeoJSON & Apply Fill", + @"Apply Symbol Color", + @"Apply Building Fill Color", + @"Apply Ferry Line Color", + @"Remove Park Layer", + ]]; + break; + case MBXSettingsMiscellaneous: + [settingsTitles addObjectsFromArray:@[ + @"Start World Tour", + [NSString stringWithFormat:@"%@ Custom User Dot", (_customUserLocationAnnnotationEnabled ? @"Disable" : @"Enable")], + ]]; + + if (self.debugLoggingEnabled) + { + [settingsTitles addObjectsFromArray:@[ + @"Print Telemetry Logfile", + @"Delete Telemetry Logfile", + ]]; + }; + break; + default: + NSAssert(NO, @"All settings sections should be implemented"); + break; } - [sheet showFromBarButtonItem:self.navigationItem.leftBarButtonItem animated:YES]; + return settingsTitles; } -- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex +- (void)performActionForSettingAtIndexPath:(NSIndexPath *)indexPath { - if (buttonIndex == actionSheet.firstOtherButtonIndex) - { - [self.mapView resetPosition]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 1) - { - self.mapView.debugMask ^= MGLMapDebugTileBoundariesMask; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 2) - { - self.mapView.debugMask ^= MGLMapDebugTileInfoMask; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 3) + switch (indexPath.section) { - self.mapView.debugMask ^= MGLMapDebugTimestampsMask; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 4) - { - self.mapView.debugMask ^= MGLMapDebugCollisionBoxesMask; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 5) - { - self.mapView.debugMask ^= MGLMapDebugOverdrawVisualizationMask; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 6) - { - [self parseFeaturesAddingCount:100 usingViews:YES]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 7) - { - [self parseFeaturesAddingCount:1000 usingViews:YES]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 8) - { - [self parseFeaturesAddingCount:10000 usingViews:YES]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 9) - { - [self parseFeaturesAddingCount:100 usingViews:NO]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 10) - { - [self parseFeaturesAddingCount:1000 usingViews:NO]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 11) - { - [self parseFeaturesAddingCount:10000 usingViews:NO]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 12) - { - [self addTestShapes]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 13) - { - [self startWorldTour:actionSheet]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 14) - { - [self presentAnnotationWithCustomCallout]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 15) - { - [self.mapView removeAnnotations:self.mapView.annotations]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 16) - { - [self testRuntimeStyling]; - } - else if (buttonIndex == actionSheet.firstOtherButtonIndex + 17) - { - _customUserLocationAnnnotationEnabled = !_customUserLocationAnnnotationEnabled; - self.mapView.showsUserLocation = NO; - self.mapView.userTrackingMode = MGLUserTrackingModeFollow; - } - else if (buttonIndex == actionSheet.numberOfButtons - 2 && self.debugLoggingEnabled) - { - NSString *fileContents = [NSString stringWithContentsOfFile:[self telemetryDebugLogfilePath] encoding:NSUTF8StringEncoding error:nil]; - NSLog(@"%@", fileContents); - } - else if (buttonIndex == actionSheet.numberOfButtons - 1 && self.debugLoggingEnabled) - { - NSString *filePath = [self telemetryDebugLogfilePath]; - if ([[NSFileManager defaultManager] isDeletableFileAtPath:filePath]) { - NSError *error; - BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; - if (success) { - NSLog(@"Deleted telemetry log."); - } else { - NSLog(@"Error deleting telemetry log: %@", error.localizedDescription); + case MBXSettingsCoreRendering: + switch (indexPath.row) + { + case MBXSettingsCoreRenderingResetPosition: + [self.mapView resetPosition]; + break; + case MBXSettingsCoreRenderingTileBoundaries: + self.mapView.debugMask ^= MGLMapDebugTileBoundariesMask; + break; + case MBXSettingsCoreRenderingTileInfo: + self.mapView.debugMask ^= MGLMapDebugTileInfoMask; + break; + case MBXSettingsCoreRenderingTimestamps: + self.mapView.debugMask ^= MGLMapDebugTimestampsMask; + break; + case MBXSettingsCoreRenderingCollisionBoxes: + self.mapView.debugMask ^= MGLMapDebugCollisionBoxesMask; + break; + case MBXSettingsCoreRenderingOverdrawVisualization: + self.mapView.debugMask ^= MGLMapDebugOverdrawVisualizationMask; + break; + default: + NSAssert(NO, @"All core rendering setting rows should be implemented"); + break; } - } + break; + case MBXSettingsAnnotations: + switch (indexPath.row) + { + case MBXSettingsAnnotations100Views: + [self parseFeaturesAddingCount:100 usingViews:YES]; + break; + case MBXSettingsAnnotations1000Views: + [self parseFeaturesAddingCount:1000 usingViews:YES]; + break; + case MBXSettingsAnnotations10000Views: + [self parseFeaturesAddingCount:10000 usingViews:YES]; + break; + case MBXSettingsAnnotations100Sprites: + [self parseFeaturesAddingCount:100 usingViews:NO]; + break; + case MBXSettingsAnnotations1000Sprites: + [self parseFeaturesAddingCount:1000 usingViews:NO]; + break; + case MBXSettingsAnnotations10000Sprites: + [self parseFeaturesAddingCount:10000 usingViews:NO]; + break; + case MBXSettingsAnnotationsTestShapes: + [self addTestShapes]; + break; + case MBXSettingsAnnotationsCustomCallout: + [self addAnnotationWithCustomCallout]; + break; + case MBXSettingsAnnotationsRemoveAnnotations: + [self.mapView removeAnnotations:self.mapView.annotations]; + break; + default: + NSAssert(NO, @"All annotations setting rows should be implemented"); + break; + } + break; + case MBXSettingsRuntimeStyling: + switch (indexPath.row) + { + case MBXSettingsRuntimeStylingWater: + [self styleWaterLayer]; + break; + case MBXSettingsRuntimeStylingRoads: + [self styleRoadLayer]; + break; + case MBXSettingsRuntimeStylingRaster: + [self styleRasterLayer]; + break; + case MBXSettingsRuntimeStylingGeoJSON: + [self styleGeoJSONSource]; + break; + case MBXSettingsRuntimeStylingSymbols: + [self styleSymbolLayer]; + break; + case MBXSettingsRuntimeStylingBuildings: + [self styleBuildingLayer]; + break; + case MBXSettingsRuntimeStylingFerry: + [self styleFerryLayer]; + break; + case MBXSettingsRuntimeStylingParks: + [self removeParkLayer]; + break; + default: + NSAssert(NO, @"All runtime styling setting rows should be implemented"); + break; + } + break; + case MBXSettingsMiscellaneous: + switch (indexPath.row) + { + case MBXSettingsMiscellaneousWorldTour: + [self startWorldTour]; + break; + case MBXSettingsMiscellaneousCustomUserDot: + [self toggleCustomUserDot]; + break; + case MBXSettingsMiscellaneousPrintLogFile: + [self printTelemetryLogFile]; + break; + case MBXSettingsMiscellaneousDeleteLogFile: + [self deleteTelemetryLogFile]; + break; + default: + NSAssert(NO, @"All miscellaneous setting rows should be implemented"); + break; + } + break; + default: + NSAssert(NO, @"All settings sections should be implemented"); + break; } } +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return [[self settingsSectionTitles] count]; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [[self settingsTitlesForSection:section] count]; +} + +- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section; +{ + return [[self settingsSectionTitles] objectAtIndex:section]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil]; + + cell.textLabel.text = [[self settingsTitlesForSection:indexPath.section] objectAtIndex:indexPath.row]; + + return cell; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:NO]; + + [self dismissViewControllerAnimated:YES completion:^ + { + [self performActionForSettingAtIndexPath:indexPath]; + }]; +} + +#pragma mark - Debugging Actions + - (void)parseFeaturesAddingCount:(NSUInteger)featuresCount usingViews:(BOOL)useViews { [self.mapView removeAnnotations:self.mapView.annotations]; @@ -441,68 +608,18 @@ - (void)addTestShapes [self.mapView addAnnotation:outerPolygon]; } -- (void)presentAnnotationWithCustomCallout +- (void)addAnnotationWithCustomCallout { [self.mapView removeAnnotations:self.mapView.annotations]; - + MBXCustomCalloutAnnotation *annotation = [[MBXCustomCalloutAnnotation alloc] init]; annotation.coordinate = CLLocationCoordinate2DMake(48.8533940, 2.3775439); annotation.title = @"Custom Callout"; - + [self.mapView addAnnotation:annotation]; [self.mapView showAnnotations:@[annotation] animated:YES]; } -- (void)testRuntimeStyling -{ - [self styleWaterLayer]; - [self styleRoadLayer]; - [self styleRasterLayer]; - [self styleGeoJSONSource]; - [self styleSymbolLayer]; - - MGLFillStyleLayer *buildingLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"building"]; - buildingLayer.fillColor = [UIColor blackColor]; - - MGLLineStyleLayer *ferryLineLayer = (MGLLineStyleLayer *)[self.mapView.style layerWithIdentifier:@"ferry"]; - ferryLineLayer.lineColor = [UIColor redColor]; - - MGLFillStyleLayer *parkLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"park"]; - [self.mapView.style removeLayer:parkLayer]; -} - -- (void)styleSymbolLayer -{ - MGLSymbolStyleLayer *stateLayer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:@"state-label-lg"]; - stateLayer.textColor = [UIColor redColor]; -} - -- (void)styleGeoJSONSource -{ - NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; - NSURL *geoJSONURL = [NSURL fileURLWithPath:filePath]; - MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithSourceIdentifier:@"ams" URL:geoJSONURL]; - [self.mapView.style addSource:source]; - - MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithLayerIdentifier:@"test" source:source]; - fillLayer.fillColor = [UIColor purpleColor]; - [self.mapView.style addLayer:fillLayer]; -} - -- (void)styleRasterLayer -{ - NSURL *rasterURL = [NSURL URLWithString:@"mapbox://mapbox.satellite"]; - MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithSourceIdentifier:@"my-raster-source" URL:rasterURL tileSize:512]; - [self.mapView.style addSource:rasterSource]; - - MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithLayerIdentifier:@"my-raster-layer" source:rasterSource]; - MGLStyleAttributeFunction *opacityFunction = [[MGLStyleAttributeFunction alloc] init]; - opacityFunction.stops = @{@20.0f: @1.0f, - @5.0f: @0.0f}; - rasterLayer.rasterOpacity = opacityFunction; - [self.mapView.style addLayer:rasterLayer]; -} - - (void)styleWaterLayer { MGLFillStyleLayer *waterLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"water"]; @@ -513,7 +630,7 @@ - (void)styleWaterLayer @12.0f: [UIColor greenColor], @14.0f: [UIColor blueColor]}; waterLayer.fillColor = waterColorFunction; - + MGLStyleAttributeFunction *fillAntialias = [[MGLStyleAttributeFunction alloc] init]; fillAntialias.stops = @{@11: @YES, @12: @NO, @@ -528,7 +645,7 @@ - (void)styleRoadLayer MGLLineStyleLayer *roadLayer = (MGLLineStyleLayer *)[self.mapView.style layerWithIdentifier:@"road-primary"]; roadLayer.lineColor = [UIColor blackColor]; MGLStyleAttributeFunction *lineWidthFunction = [[MGLStyleAttributeFunction alloc] init]; - + MGLStyleAttributeFunction *roadLineColor = [[MGLStyleAttributeFunction alloc] init]; roadLineColor.stops = @{@10: [UIColor purpleColor], @13: [UIColor yellowColor], @@ -536,12 +653,142 @@ - (void)styleRoadLayer roadLayer.lineColor = roadLineColor; roadLayer.lineWidth = lineWidthFunction; roadLayer.lineGapWidth = lineWidthFunction; - + roadLayer.visible = YES; roadLayer.maximumZoomLevel = 15; roadLayer.minimumZoomLevel = 13; } +- (void)styleRasterLayer +{ + NSURL *rasterURL = [NSURL URLWithString:@"mapbox://mapbox.satellite"]; + MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithSourceIdentifier:@"my-raster-source" URL:rasterURL tileSize:512]; + [self.mapView.style addSource:rasterSource]; + + MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithLayerIdentifier:@"my-raster-layer" source:rasterSource]; + MGLStyleAttributeFunction *opacityFunction = [[MGLStyleAttributeFunction alloc] init]; + opacityFunction.stops = @{@20.0f: @1.0f, + @5.0f: @0.0f}; + rasterLayer.rasterOpacity = opacityFunction; + [self.mapView.style addLayer:rasterLayer]; +} + +- (void)styleGeoJSONSource +{ + NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"]; + NSURL *geoJSONURL = [NSURL fileURLWithPath:filePath]; + MGLGeoJSONSource *source = [[MGLGeoJSONSource alloc] initWithSourceIdentifier:@"ams" URL:geoJSONURL]; + [self.mapView.style addSource:source]; + + MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithLayerIdentifier:@"test" source:source]; + fillLayer.fillColor = [UIColor purpleColor]; + [self.mapView.style addLayer:fillLayer]; +} + +- (void)styleSymbolLayer +{ + MGLSymbolStyleLayer *stateLayer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:@"state-label-lg"]; + stateLayer.textColor = [UIColor redColor]; +} + +- (void)styleBuildingLayer +{ + MGLFillStyleLayer *buildingLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"building"]; + buildingLayer.fillColor = [UIColor blackColor]; +} + +- (void)styleFerryLayer +{ + MGLLineStyleLayer *ferryLineLayer = (MGLLineStyleLayer *)[self.mapView.style layerWithIdentifier:@"ferry"]; + ferryLineLayer.lineColor = [UIColor redColor]; +} + +- (void)removeParkLayer +{ + MGLFillStyleLayer *parkLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"park"]; + [self.mapView.style removeLayer:parkLayer]; +} + +- (IBAction)startWorldTour +{ + _isTouringWorld = YES; + + [self.mapView removeAnnotations:self.mapView.annotations]; + NSUInteger numberOfAnnotations = sizeof(WorldTourDestinations) / sizeof(WorldTourDestinations[0]); + NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:numberOfAnnotations]; + for (NSUInteger i = 0; i < numberOfAnnotations; i++) + { + MBXDroppedPinAnnotation *annotation = [[MBXDroppedPinAnnotation alloc] init]; + annotation.coordinate = WorldTourDestinations[i]; + [annotations addObject:annotation]; + } + [self.mapView addAnnotations:annotations]; + [self continueWorldTourWithRemainingAnnotations:annotations]; +} + +- (void)continueWorldTourWithRemainingAnnotations:(NS_MUTABLE_ARRAY_OF(MGLPointAnnotation *) *)annotations +{ + MGLPointAnnotation *nextAnnotation = annotations.firstObject; + if (!nextAnnotation || !_isTouringWorld) + { + _isTouringWorld = NO; + return; + } + + [annotations removeObjectAtIndex:0]; + MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:nextAnnotation.coordinate + fromDistance:10 + pitch:arc4random_uniform(60) + heading:arc4random_uniform(360)]; + __weak MBXViewController *weakSelf = self; + [self.mapView flyToCamera:camera completionHandler:^{ + MBXViewController *strongSelf = weakSelf; + [strongSelf performSelector:@selector(continueWorldTourWithRemainingAnnotations:) + withObject:annotations + afterDelay:2]; + }]; +} + +- (void)toggleCustomUserDot +{ + _customUserLocationAnnnotationEnabled = !_customUserLocationAnnnotationEnabled; + self.mapView.showsUserLocation = NO; + self.mapView.userTrackingMode = MGLUserTrackingModeFollow; +} + +- (void)printTelemetryLogFile +{ + NSString *fileContents = [NSString stringWithContentsOfFile:[self telemetryDebugLogFilePath] encoding:NSUTF8StringEncoding error:nil]; + NSLog(@"%@", fileContents); +} + +- (void)deleteTelemetryLogFile +{ + NSString *filePath = [self telemetryDebugLogFilePath]; + if ([[NSFileManager defaultManager] isDeletableFileAtPath:filePath]) + { + NSError *error; + BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]; + if (success) { + NSLog(@"Deleted telemetry log."); + } else { + NSLog(@"Error deleting telemetry log: %@", error.localizedDescription); + } + } +} + +- (NSString *)telemetryDebugLogFilePath +{ + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd"]; + [dateFormatter setTimeZone:[NSTimeZone systemTimeZone]]; + NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"telemetry_log-%@.json", [dateFormatter stringFromDate:[NSDate date]]]]; + + return filePath; +} + +#pragma mark - User Actions + - (IBAction)handleLongPress:(UILongPressGestureRecognizer *)longPress { if (longPress.state == UIGestureRecognizerStateBegan) @@ -643,69 +890,7 @@ - (IBAction)locateUser:(id)sender [sender setAccessibilityValue:nextAccessibilityValue]; } -- (IBAction)startWorldTour:(__unused id)sender -{ - _isTouringWorld = YES; - - [self.mapView removeAnnotations:self.mapView.annotations]; - NSUInteger numberOfAnnotations = sizeof(WorldTourDestinations) / sizeof(WorldTourDestinations[0]); - NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:numberOfAnnotations]; - for (NSUInteger i = 0; i < numberOfAnnotations; i++) - { - MBXDroppedPinAnnotation *annotation = [[MBXDroppedPinAnnotation alloc] init]; - annotation.coordinate = WorldTourDestinations[i]; - [annotations addObject:annotation]; - } - [self.mapView addAnnotations:annotations]; - [self continueWorldTourWithRemainingAnnotations:annotations]; -} - -- (void)continueWorldTourWithRemainingAnnotations:(NS_MUTABLE_ARRAY_OF(MGLPointAnnotation *) *)annotations -{ - MGLPointAnnotation *nextAnnotation = annotations.firstObject; - if (!nextAnnotation || !_isTouringWorld) - { - _isTouringWorld = NO; - return; - } - - [annotations removeObjectAtIndex:0]; - MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:nextAnnotation.coordinate - fromDistance:10 - pitch:arc4random_uniform(60) - heading:arc4random_uniform(360)]; - __weak MBXViewController *weakSelf = self; - [self.mapView flyToCamera:camera completionHandler:^{ - MBXViewController *strongSelf = weakSelf; - [strongSelf performSelector:@selector(continueWorldTourWithRemainingAnnotations:) - withObject:annotations - afterDelay:2]; - }]; -} - -- (NSString *)telemetryDebugLogfilePath -{ - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd"]; - [dateFormatter setTimeZone:[NSTimeZone systemTimeZone]]; - NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"telemetry_log-%@.json", [dateFormatter stringFromDate:[NSDate date]]]]; - - return filePath; -} - -- (IBAction)unwindToMapViewController:(__unused UIStoryboardSegue *)sender { -} - -#pragma mark - Destruction - -- (void)dealloc -{ - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - [self saveState:nil]; -} - -#pragma mark - MGLMapViewDelegate +#pragma mark - Map Delegate - (MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id)annotation {