Skip to content

Commit

Permalink
feat: Show different error for 401 responses
Browse files Browse the repository at this point in the history
This aims at providing a slightly more precise error in case the
selected map type requires an API key and SatelliteEyes has not been
provided with a valid key.
  • Loading branch information
paulschuberth committed Oct 8, 2023
1 parent fb4bbcb commit 87cf59c
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 64 deletions.
2 changes: 1 addition & 1 deletion SatelliteEyes/TTMapImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
logo:(NSImage *)_logoImage NS_DESIGNATED_INITIALIZER;

- (void)fetchTilesWithSuccess:(void (^)(NSURL *filePath))success
failure:(void (^)(NSError *error))failure
failure:(void (^)(NSError *error, NSInteger statusCode))failure
skipCache:(BOOL)skipCache;

@property (NS_NONATOMIC_IOSONLY, readonly, copy) NSURL *fileURL;
Expand Down
6 changes: 4 additions & 2 deletions SatelliteEyes/TTMapImage.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ - (NSArray *)tilesArray {
}

- (void)fetchTilesWithSuccess:(void (^)(NSURL *filePath))success
failure:(void (^)(NSError *error))failure
failure:(void (^)(NSError *error, NSInteger statusCode))failure
skipCache:(BOOL)skipCache
{
dispatch_async(dispatch_get_global_queue(0, 0), ^(void) {
Expand All @@ -107,6 +107,7 @@ - (void)fetchTilesWithSuccess:(void (^)(NSURL *filePath))success
DDLogInfo(@"Not found, or skipping cache, so fetching file at: %@", [fileURL path]);

__block NSError *error;
__block NSInteger statusCode;
[self->tiles enumerateObjectsUsingBlock:^(NSArray *rowArray, NSUInteger idx, BOOL *stop) {
[rowArray enumerateObjectsUsingBlock:^(TTMapTile *mapTile, NSUInteger rowIndex, BOOL *rowStop) {
AFHTTPRequestOperation *httpOperation = [[AFHTTPRequestOperation alloc] initWithRequest:[mapTile urlRequest]];
Expand All @@ -115,6 +116,7 @@ - (void)fetchTilesWithSuccess:(void (^)(NSURL *filePath))success
mapTile.imageData = responseData;
} failure:^(AFHTTPRequestOperation *operation, NSError *_error) {
error = _error;
statusCode = operation.response.statusCode;
DDLogError(@"Fetching tile error: %@", error);
}];
[self->tileQueue addOperation:httpOperation];
Expand All @@ -123,7 +125,7 @@ - (void)fetchTilesWithSuccess:(void (^)(NSURL *filePath))success
[self->tileQueue waitUntilAllOperationsAreFinished];

if (error) {
failure(error);
failure(error, statusCode);
} else {
NSURL *fileURL = [self writeImageData];
success(fileURL);
Expand Down
1 change: 1 addition & 0 deletions SatelliteEyes/TTMapManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

static NSString *const TTMapManagerStartedLoad = @"TTMapManagerStartedLoad";
static NSString *const TTMapManagerFailedLoad = @"TTMapManagerFailedLoad";
static NSString *const TTMapManagerFailedUnauthorized = @"TTMapManagerFailedUnauthorized";
static NSString *const TTMapManagerFinishedLoad = @"TTMapManagerFinishedLoad";
static NSString *const TTMapManagerLocationUpdated = @"TTMapManagerLocationUpdated";
static NSString *const TTMapManagerLocationLost = @"TTMapManagerLocationLost";
Expand Down
10 changes: 8 additions & 2 deletions SatelliteEyes/TTMapManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,14 @@ - (void)updateMapToCoordinate:(CLLocationCoordinate2D)coordinate force:(BOOL)for
}


} failure:^(NSError *error) {
[[NSNotificationCenter defaultCenter] postNotificationName:TTMapManagerFailedLoad object:nil];
} failure:^(NSError *error, NSInteger statusCode) {
// Stadia maps will return 401 in case of invalid or missing API key.
// https://docs.stadiamaps.com/authentication/#authentication
if (statusCode == 401) {
[[NSNotificationCenter defaultCenter] postNotificationName:TTMapManagerFailedUnauthorized object:nil];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:TTMapManagerFailedLoad object:nil];
}
DDLogError(@"Error fetching image: %@", error);
} skipCache:force];
});
Expand Down
1 change: 1 addition & 0 deletions SatelliteEyes/TTStatusItemController.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
BOOL mapManagerhasLocation;
BOOL mapManagerisActive;
BOOL mapManagerdidError;
BOOL mapManagerUnauthorized;
NSDate *mapLastUpdated;
NSUInteger activityAnimationFrameIndex;
NSTimer *activityAnimationTimer;
Expand Down
142 changes: 83 additions & 59 deletions SatelliteEyes/TTStatusItemController.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,83 +21,96 @@ - (instancetype)init
NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Menu"];
menu.delegate = self;
[menu setAutoenablesItems:NO];

statusMenuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
[statusMenuItem setEnabled:NO];
[menu addItem:statusMenuItem];

forceMapUpdateMenuItem = [[NSMenuItem alloc] initWithTitle:@"Refresh the map now" action:@selector(forceMapUpdate:) keyEquivalent:@""];
[forceMapUpdateMenuItem setEnabled:NO];
[menu addItem:forceMapUpdateMenuItem];

openInBrowserMenuItem = [[NSMenuItem alloc] initWithTitle:@"Open in browser" action:@selector(openMapInBrowser:) keyEquivalent:@""];
[openInBrowserMenuItem setEnabled:NO];
[menu addItem:openInBrowserMenuItem];

[menu addItem:[NSMenuItem separatorItem]];

NSMenuItem *aboutMenuItem = [[NSMenuItem alloc] initWithTitle:@"About" action:@selector(showAbout:) keyEquivalent:@""];
[menu addItem:aboutMenuItem];

NSMenuItem *preferencesMenuItem = [[NSMenuItem alloc] initWithTitle:@"Open preferences..." action:@selector(showPreferences:) keyEquivalent:@""];
[menu addItem:preferencesMenuItem];

NSMenuItem *updatesMenuItem = [[NSMenuItem alloc] initWithTitle:@"Check for updates..." action:@selector(checkForUpdates:) keyEquivalent:@""];
[menu addItem:updatesMenuItem];

NSMenuItem *itemExit = [[NSMenuItem alloc] initWithTitle:@"Exit" action:@selector(menuActionExit:) keyEquivalent:@""];
[menu addItem:itemExit];

statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:22];
[statusItem setHighlightMode:YES];
statusItem.menu = menu;

[self updateStatus];
[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerStartedLoad
object:nil
queue:nil

[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerStartedLoad
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
self->mapManagerdidError = NO;
self->mapManagerisActive = YES;
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
}];

[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerFinishedLoad
object:nil
queue:nil
self->mapManagerdidError = NO;
self->mapManagerUnauthorized = NO;
self->mapManagerisActive = YES;
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
}];

[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerFinishedLoad
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
self->mapManagerdidError = NO;
self->mapManagerUnauthorized = NO;
self->mapManagerisActive = NO;
self->mapLastUpdated = [NSDate date];
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];

}];

[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerFailedLoad
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
self->mapManagerdidError = NO;
self->mapManagerisActive = NO;
self->mapLastUpdated = [NSDate date];
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];

}];

[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerFailedLoad
object:nil
queue:nil
self->mapManagerdidError = YES;
self->mapManagerUnauthorized = NO;
self->mapManagerisActive = NO;
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
}];

[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerFailedUnauthorized
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
self->mapManagerdidError = YES;
self->mapManagerisActive = NO;
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
}];

[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerLocationUpdated
object:nil
queue:nil
self->mapManagerdidError = YES;
self->mapManagerUnauthorized = YES;
self->mapManagerisActive = NO;
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
}];

[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerLocationUpdated
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
self->mapManagerhasLocation = YES;
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
}];
self->mapManagerhasLocation = YES;
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
}];

[[NSNotificationCenter defaultCenter] addObserverForName:TTMapManagerLocationLost
object:nil
queue:nil
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
self->mapManagerhasLocation = NO;
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
}];
self->mapManagerhasLocation = NO;
[self performSelectorOnMainThread:@selector(updateStatus) withObject:nil waitUntilDone:YES];
}];
}
return self;
}
Expand All @@ -106,27 +119,31 @@ - (void)updateStatus {
if (mapManagerhasLocation) {
[forceMapUpdateMenuItem setEnabled:YES];
[self enableOpenInBrowser];

if (mapManagerisActive) {
[self startActivityAnimation];

} else if (mapManagerdidError) {
[self stopActivityAnimation];
[self showError];

if (mapManagerUnauthorized) {
[self showUnauthorizedError];
} else {
[self showGenericError];
}

} else { // is idle
[self stopActivityAnimation];
[self showNormal];
}

} else {
[self stopActivityAnimation];
[self showOffline];
[forceMapUpdateMenuItem setEnabled:NO];
[self disableOpenInBrowser];
}
}

- (void)showOffline {
NSImage *image = [NSImage imageNamed:@"status-icon-offline"];
image.template = YES;
Expand All @@ -140,10 +157,10 @@ - (void)showNormal {
statusItem.image = image;

[forceMapUpdateMenuItem setHidden:NO];

if (mapLastUpdated) {
statusMenuItem.title = [NSString stringWithFormat:@"Map updated %@", [mapLastUpdated distanceOfTimeInWords].lowercaseString];

} else {
statusMenuItem.title = @"Waiting for map update";
}
Expand Down Expand Up @@ -185,17 +202,24 @@ - (void)stopActivityAnimation {
activityAnimationTimer = nil;
}

- (void)showError {
- (void)showGenericError {
NSImage *image = [NSImage imageNamed:@"status-icon-error"];
image.template = YES;
statusItem.image = image;
statusMenuItem.title = @"Problem updating the map";
}

- (void)showUnauthorizedError {
NSImage *image = [NSImage imageNamed:@"status-icon-error"];
image.template = YES;
statusItem.image = image;
statusMenuItem.title = @"Please provide a valid API key for the selected map type.";
}

- (void)enableOpenInBrowser {
// It's a bit hacky to reach up into the App Delegate for this, but hey.
TTAppDelegate *appDelegate = (TTAppDelegate *)[NSApplication sharedApplication].delegate;

if ([appDelegate visibleMapBrowserURL]) {
[openInBrowserMenuItem setEnabled:YES];
} else {
Expand Down

0 comments on commit 87cf59c

Please sign in to comment.