From f5ac63dfeccc185bc198b21f3ff6f87a9017848d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Sun, 6 Mar 2016 23:57:09 -0800 Subject: [ios, osx] Renamed offline classes Renamed SDK classes related to offline viewing to more closely match the terminology used by mbgl and the Android SDK while remaining consistent with Cocoa naming principles. --- gyp/platform-ios.gypi | 12 +- gyp/platform-osx.gypi | 12 +- platform/darwin/include/MGLDownloadController.h | 30 ---- platform/darwin/include/MGLDownloadRegion.h | 13 -- platform/darwin/include/MGLDownloadable.h | 49 ------- platform/darwin/include/MGLOfflineRegion.h | 13 ++ platform/darwin/include/MGLOfflineStorage.h | 30 ++++ platform/darwin/include/MGLOfflineTask.h | 49 +++++++ .../darwin/include/MGLTilePyramidDownloadRegion.h | 19 --- .../darwin/include/MGLTilePyramidOfflineRegion.h | 19 +++ platform/darwin/src/MGLDownloadController.mm | 150 ------------------- .../darwin/src/MGLDownloadController_Private.h | 15 -- platform/darwin/src/MGLDownloadRegion_Private.h | 17 --- platform/darwin/src/MGLDownloadable.mm | 160 --------------------- platform/darwin/src/MGLDownloadable_Private.h | 26 ---- platform/darwin/src/MGLOfflineRegion_Private.h | 17 +++ platform/darwin/src/MGLOfflineStorage.mm | 150 +++++++++++++++++++ platform/darwin/src/MGLOfflineStorage_Private.h | 15 ++ platform/darwin/src/MGLOfflineTask.mm | 160 +++++++++++++++++++++ platform/darwin/src/MGLOfflineTask_Private.h | 26 ++++ .../darwin/src/MGLTilePyramidDownloadRegion.mm | 66 --------- platform/darwin/src/MGLTilePyramidOfflineRegion.mm | 66 +++++++++ platform/ios/app/MBXDownloadsTableViewController.m | 76 +++++----- platform/ios/framework/Mapbox.h | 8 +- platform/ios/framework/Mapbox.m | 6 +- platform/osx/sdk/Mapbox.h | 8 +- platform/osx/sdk/Mapbox.m | 10 +- 27 files changed, 611 insertions(+), 611 deletions(-) delete mode 100644 platform/darwin/include/MGLDownloadController.h delete mode 100644 platform/darwin/include/MGLDownloadRegion.h delete mode 100644 platform/darwin/include/MGLDownloadable.h create mode 100644 platform/darwin/include/MGLOfflineRegion.h create mode 100644 platform/darwin/include/MGLOfflineStorage.h create mode 100644 platform/darwin/include/MGLOfflineTask.h delete mode 100644 platform/darwin/include/MGLTilePyramidDownloadRegion.h create mode 100644 platform/darwin/include/MGLTilePyramidOfflineRegion.h delete mode 100644 platform/darwin/src/MGLDownloadController.mm delete mode 100644 platform/darwin/src/MGLDownloadController_Private.h delete mode 100644 platform/darwin/src/MGLDownloadRegion_Private.h delete mode 100644 platform/darwin/src/MGLDownloadable.mm delete mode 100644 platform/darwin/src/MGLDownloadable_Private.h create mode 100644 platform/darwin/src/MGLOfflineRegion_Private.h create mode 100644 platform/darwin/src/MGLOfflineStorage.mm create mode 100644 platform/darwin/src/MGLOfflineStorage_Private.h create mode 100644 platform/darwin/src/MGLOfflineTask.mm create mode 100644 platform/darwin/src/MGLOfflineTask_Private.h delete mode 100644 platform/darwin/src/MGLTilePyramidDownloadRegion.mm create mode 100644 platform/darwin/src/MGLTilePyramidOfflineRegion.mm diff --git a/gyp/platform-ios.gypi b/gyp/platform-ios.gypi index 15b2fef0cc..bece0a6a6f 100644 --- a/gyp/platform-ios.gypi +++ b/gyp/platform-ios.gypi @@ -44,12 +44,12 @@ '../platform/darwin/src/MGLPolyline.mm', '../platform/darwin/src/MGLPolygon.mm', '../platform/darwin/src/MGLMapCamera.mm', - '../platform/darwin/src/MGLDownloadable.mm', - '../platform/darwin/src/MGLDownloadable_Private.h', - '../platform/darwin/src/MGLDownloadController.mm', - '../platform/darwin/src/MGLDownloadController_Private.h', - '../platform/darwin/src/MGLDownloadRegion_Private.h', - '../platform/darwin/src/MGLTilePyramidDownloadRegion.mm', + '../platform/darwin/src/MGLOfflineTask.mm', + '../platform/darwin/src/MGLOfflineTask_Private.h', + '../platform/darwin/src/MGLOfflineStorage.mm', + '../platform/darwin/src/MGLOfflineStorage_Private.h', + '../platform/darwin/src/MGLOfflineRegion_Private.h', + '../platform/darwin/src/MGLTilePyramidOfflineRegion.mm', '../platform/darwin/src/MGLAccountManager_Private.h', '../platform/darwin/src/MGLAccountManager.m', '../platform/darwin/src/NSBundle+MGLAdditions.h', diff --git a/gyp/platform-osx.gypi b/gyp/platform-osx.gypi index ae09a60d99..252dbdb3cb 100644 --- a/gyp/platform-osx.gypi +++ b/gyp/platform-osx.gypi @@ -43,12 +43,12 @@ '../platform/darwin/src/MGLPolyline.mm', '../platform/darwin/src/MGLPolygon.mm', '../platform/darwin/src/MGLMapCamera.mm', - '../platform/darwin/src/MGLDownloadable.mm', - '../platform/darwin/src/MGLDownloadable_Private.h', - '../platform/darwin/src/MGLDownloadController.mm', - '../platform/darwin/src/MGLDownloadController_Private.h', - '../platform/darwin/src/MGLDownloadRegion_Private.h', - '../platform/darwin/src/MGLTilePyramidDownloadRegion.mm', + '../platform/darwin/src/MGLOfflineTask.mm', + '../platform/darwin/src/MGLOfflineTask_Private.h', + '../platform/darwin/src/MGLOfflineStorage.mm', + '../platform/darwin/src/MGLOfflineStorage_Private.h', + '../platform/darwin/src/MGLOfflineRegion_Private.h', + '../platform/darwin/src/MGLTilePyramidOfflineRegion.mm', '../platform/darwin/src/MGLAccountManager_Private.h', '../platform/darwin/src/MGLAccountManager.m', '../platform/darwin/src/NSBundle+MGLAdditions.h', diff --git a/platform/darwin/include/MGLDownloadController.h b/platform/darwin/include/MGLDownloadController.h deleted file mode 100644 index 86bd1e6573..0000000000 --- a/platform/darwin/include/MGLDownloadController.h +++ /dev/null @@ -1,30 +0,0 @@ -#import - -#import "MGLTypes.h" - -NS_ASSUME_NONNULL_BEGIN - -@class MGLDownloadable; -@protocol MGLDownloadRegion; - -typedef void (^MGLDownloadableRegistrationCompletionHandler)(MGLDownloadable *downloadable, NSError *error); -typedef void (^MGLDownloadableRemovalCompletionHandler)(NSError *error); -typedef void (^MGLDownloadablesRequestCompletionHandler)(NS_ARRAY_OF(MGLDownloadable *) *downloadables, NSError *error); - -@interface MGLDownloadController : NSObject - -+ (instancetype)sharedController; - -- (instancetype)init NS_UNAVAILABLE; - -- (void)addDownloadableForRegion:(id )downloadRegion withContext:(NSData *)context completionHandler:(MGLDownloadableRegistrationCompletionHandler)completion; - -- (void)removeDownloadable:(MGLDownloadable *)downloadable withCompletionHandler:(MGLDownloadableRemovalCompletionHandler)completion; - -- (void)requestDownloadablesWithCompletionHandler:(MGLDownloadablesRequestCompletionHandler)completion; - -- (void)setMaximumAllowedMapboxTiles:(uint64_t)maximumCount; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/include/MGLDownloadRegion.h b/platform/darwin/include/MGLDownloadRegion.h deleted file mode 100644 index 5910c2117b..0000000000 --- a/platform/darwin/include/MGLDownloadRegion.h +++ /dev/null @@ -1,13 +0,0 @@ -#import - -#import "MGLTypes.h" - -NS_ASSUME_NONNULL_BEGIN - -@protocol MGLDownloadRegion - -@property (nonatomic, readonly) NSURL *styleURL; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/include/MGLDownloadable.h b/platform/darwin/include/MGLDownloadable.h deleted file mode 100644 index 522a3c37ab..0000000000 --- a/platform/darwin/include/MGLDownloadable.h +++ /dev/null @@ -1,49 +0,0 @@ -#import - -#import "MGLDownloadRegion.h" - -NS_ASSUME_NONNULL_BEGIN - -@protocol MGLDownloadableDelegate; - -typedef NS_ENUM (NSInteger, MGLDownloadableState) { - MGLDownloadableStateInactive = 0, - MGLDownloadableStateActive = 1, - MGLDownloadableStateComplete = 2, -}; - -typedef struct MGLDownloadableProgress { - uint64_t countOfResourcesCompleted; - uint64_t countOfBytesCompleted; - uint64_t countOfResourcesExpected; - uint64_t maximumResourcesExpected; -} MGLDownloadableProgress; - -@interface MGLDownloadable : NSObject - -@property (nonatomic, readonly) id region; -@property (nonatomic, readonly) NSData *context; -@property (nonatomic, readonly) MGLDownloadableState state; -@property (nonatomic, readonly) MGLDownloadableProgress progress; -@property (nonatomic, weak, nullable) id delegate; - -- (instancetype)init NS_UNAVAILABLE; - -- (void)resume; -- (void)suspend; - -- (void)requestProgress; - -@end - -@protocol MGLDownloadableDelegate - -@optional - -- (void)downloadable:(MGLDownloadable *)downloadable progressDidChange:(MGLDownloadableProgress)progress; -- (void)downloadable:(MGLDownloadable *)downloadable didReceiveError:(NSError *)error; -- (void)downloadable:(MGLDownloadable *)downloadable didReceiveMaximumAllowedMapboxTiles:(uint64_t)maximumCount; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/include/MGLOfflineRegion.h b/platform/darwin/include/MGLOfflineRegion.h new file mode 100644 index 0000000000..6958e3bffe --- /dev/null +++ b/platform/darwin/include/MGLOfflineRegion.h @@ -0,0 +1,13 @@ +#import + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol MGLOfflineRegion + +@property (nonatomic, readonly) NSURL *styleURL; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/include/MGLOfflineStorage.h b/platform/darwin/include/MGLOfflineStorage.h new file mode 100644 index 0000000000..2d33f3ba69 --- /dev/null +++ b/platform/darwin/include/MGLOfflineStorage.h @@ -0,0 +1,30 @@ +#import + +#import "MGLTypes.h" + +NS_ASSUME_NONNULL_BEGIN + +@class MGLOfflineTask; +@protocol MGLOfflineRegion; + +typedef void (^MGLOfflineTaskRegistrationCompletionHandler)(MGLOfflineTask *task, NSError *error); +typedef void (^MGLOfflineTaskRemovalCompletionHandler)(NSError *error); +typedef void (^MGLOfflineTasksRetrievalCompletionHandler)(NS_ARRAY_OF(MGLOfflineTask *) *tasks, NSError *error); + +@interface MGLOfflineStorage : NSObject + ++ (instancetype)sharedOfflineStorage; + +- (instancetype)init NS_UNAVAILABLE; + +- (void)addTaskForRegion:(id )region withContext:(NSData *)context completionHandler:(MGLOfflineTaskRegistrationCompletionHandler)completion; + +- (void)removeTask:(MGLOfflineTask *)task withCompletionHandler:(MGLOfflineTaskRemovalCompletionHandler)completion; + +- (void)getTasksWithCompletionHandler:(MGLOfflineTasksRetrievalCompletionHandler)completion; + +- (void)setMaximumAllowedMapboxTiles:(uint64_t)maximumCount; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/include/MGLOfflineTask.h b/platform/darwin/include/MGLOfflineTask.h new file mode 100644 index 0000000000..72e66a50f5 --- /dev/null +++ b/platform/darwin/include/MGLOfflineTask.h @@ -0,0 +1,49 @@ +#import + +#import "MGLOfflineRegion.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol MGLOfflineTaskDelegate; + +typedef NS_ENUM (NSInteger, MGLOfflineTaskState) { + MGLOfflineTaskStateInactive = 0, + MGLOfflineTaskStateActive = 1, + MGLOfflineTaskStateComplete = 2, +}; + +typedef struct MGLOfflineTaskProgress { + uint64_t countOfResourcesCompleted; + uint64_t countOfBytesCompleted; + uint64_t countOfResourcesExpected; + uint64_t maximumResourcesExpected; +} MGLOfflineTaskProgress; + +@interface MGLOfflineTask : NSObject + +@property (nonatomic, readonly) id region; +@property (nonatomic, readonly) NSData *context; +@property (nonatomic, readonly) MGLOfflineTaskState state; +@property (nonatomic, readonly) MGLOfflineTaskProgress progress; +@property (nonatomic, weak, nullable) id delegate; + +- (instancetype)init NS_UNAVAILABLE; + +- (void)resume; +- (void)suspend; + +- (void)requestProgress; + +@end + +@protocol MGLOfflineTaskDelegate + +@optional + +- (void)offlineTask:(MGLOfflineTask *)task progressDidChange:(MGLOfflineTaskProgress)progress; +- (void)offlineTask:(MGLOfflineTask *)task didReceiveError:(NSError *)error; +- (void)offlineTask:(MGLOfflineTask *)task didReceiveMaximumAllowedMapboxTiles:(uint64_t)maximumCount; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/include/MGLTilePyramidDownloadRegion.h b/platform/darwin/include/MGLTilePyramidDownloadRegion.h deleted file mode 100644 index 6269775f19..0000000000 --- a/platform/darwin/include/MGLTilePyramidDownloadRegion.h +++ /dev/null @@ -1,19 +0,0 @@ -#import - -#import "MGLDownloadRegion.h" -#import "MGLGeometry.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface MGLTilePyramidDownloadRegion : NSObject - -@property (nonatomic, readonly) MGLCoordinateBounds bounds; -@property (nonatomic, readonly) double minimumZoomLevel; -@property (nonatomic, readonly) double maximumZoomLevel; - -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initWithStyleURL:(nullable NSURL *)styleURL bounds:(MGLCoordinateBounds)bounds fromZoomLevel:(double)minimumZoomLevel toZoomLevel:(double)maximumZoomLevel NS_DESIGNATED_INITIALIZER; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/include/MGLTilePyramidOfflineRegion.h b/platform/darwin/include/MGLTilePyramidOfflineRegion.h new file mode 100644 index 0000000000..7beca3390f --- /dev/null +++ b/platform/darwin/include/MGLTilePyramidOfflineRegion.h @@ -0,0 +1,19 @@ +#import + +#import "MGLOfflineRegion.h" +#import "MGLGeometry.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLTilePyramidOfflineRegion : NSObject + +@property (nonatomic, readonly) MGLCoordinateBounds bounds; +@property (nonatomic, readonly) double minimumZoomLevel; +@property (nonatomic, readonly) double maximumZoomLevel; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithStyleURL:(nullable NSURL *)styleURL bounds:(MGLCoordinateBounds)bounds fromZoomLevel:(double)minimumZoomLevel toZoomLevel:(double)maximumZoomLevel NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLDownloadController.mm b/platform/darwin/src/MGLDownloadController.mm deleted file mode 100644 index 95eae86b53..0000000000 --- a/platform/darwin/src/MGLDownloadController.mm +++ /dev/null @@ -1,150 +0,0 @@ -#import "MGLDownloadController_Private.h" - -#import "MGLAccountManager_Private.h" -#import "MGLGeometry_Private.h" -#import "MGLDownloadable_Private.h" -#import "MGLDownloadRegion_Private.h" -#import "MGLTilePyramidDownloadRegion.h" - -#include - -@interface MGLDownloadController () - -@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource; - -- (instancetype)initWithFileName:(NSString *)fileName NS_DESIGNATED_INITIALIZER; - -@end - -@implementation MGLDownloadController - -+ (instancetype)sharedController { - static dispatch_once_t onceToken; - static MGLDownloadController *sharedController; - dispatch_once(&onceToken, ^{ - sharedController = [[self alloc] initWithFileName:@"offline.db"]; - }); - return sharedController; -} - -- (instancetype)initWithFileName:(NSString *)fileName { - if (self = [super init]) { -#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *cachePath = [paths.firstObject stringByAppendingPathComponent:fileName]; -#elif TARGET_OS_MAC - NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory - inDomain:NSUserDomainMask - appropriateForURL:nil - create:YES - error:nil]; - cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent: - [NSBundle mainBundle].bundleIdentifier]; - [[NSFileManager defaultManager] createDirectoryAtURL:cacheDirectoryURL - withIntermediateDirectories:YES - attributes:nil - error:nil]; - NSURL *cacheURL = [cacheDirectoryURL URLByAppendingPathComponent:fileName]; - NSString *cachePath = cacheURL ? cacheURL.path : @""; -#endif - _mbglFileSource = new mbgl::DefaultFileSource(cachePath.UTF8String, [NSBundle mainBundle].resourceURL.path.UTF8String); - - // Observe for changes to the global access token (and find out the current one). - [[MGLAccountManager sharedManager] addObserver:self - forKeyPath:@"accessToken" - options:(NSKeyValueObservingOptionInitial | - NSKeyValueObservingOptionNew) - context:NULL]; - } - return self; -} - -- (void)dealloc { - [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"]; - - delete _mbglFileSource; - _mbglFileSource = nullptr; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(__unused void *)context { - // Synchronize the file source’s access token with the global one in MGLAccountManager. - if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) { - NSString *accessToken = change[NSKeyValueChangeNewKey]; - if (![accessToken isKindOfClass:[NSNull class]]) { - self.mbglFileSource->setAccessToken(accessToken.UTF8String); - } - } -} - -- (void)addDownloadableForRegion:(id )downloadRegion withContext:(NSData *)context completionHandler:(MGLDownloadableRegistrationCompletionHandler)completion { - if (![downloadRegion conformsToProtocol:@protocol(MGLDownloadRegion_Private)]) { - [NSException raise:@"Unsupported region type" format: - @"Regions of type %@ are unsupported.", NSStringFromClass([downloadRegion class])]; - return; - } - - const mbgl::OfflineTilePyramidRegionDefinition regionDefinition = [(id )downloadRegion offlineRegionDefinition]; - mbgl::OfflineRegionMetadata metadata(context.length); - [context getBytes:&metadata[0] length:metadata.size()]; - self.mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](std::exception_ptr exception, mbgl::optional region) { - NSError *error; - if (exception) { - NSString *errorDescription = @(mbgl::util::toString(exception).c_str()); - error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:errorDescription ? @{ - NSLocalizedDescriptionKey: errorDescription, - } : nil]; - } - if (completion) { - MGLDownloadable *downloadable = [[MGLDownloadable alloc] initWithMBGLRegion:new mbgl::OfflineRegion(std::move(*region))]; - dispatch_async(dispatch_get_main_queue(), [&, completion, error, downloadable](void) { - completion(downloadable, error); - }); - } - }); -} - -- (void)removeDownloadable:(MGLDownloadable *)downloadable withCompletionHandler:(MGLDownloadableRemovalCompletionHandler)completion { - self.mbglFileSource->deleteOfflineRegion(std::move(*downloadable.mbglOfflineRegion), [&, completion](std::exception_ptr exception) { - NSError *error; - if (exception) { - error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{ - NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), - }]; - } - if (completion) { - dispatch_async(dispatch_get_main_queue(), [&, completion, error](void) { - completion(error); - }); - } - }); -} - -- (void)requestDownloadablesWithCompletionHandler:(MGLDownloadablesRequestCompletionHandler)completion { - self.mbglFileSource->listOfflineRegions([&, completion](std::exception_ptr exception, mbgl::optional> regions) { - NSError *error; - if (exception) { - error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{ - NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), - }]; - } - NSMutableArray *downloadables; - if (regions) { - downloadables = [NSMutableArray arrayWithCapacity:regions->size()]; - for (mbgl::OfflineRegion ®ion : *regions) { - MGLDownloadable *downloadable = [[MGLDownloadable alloc] initWithMBGLRegion:new mbgl::OfflineRegion(std::move(region))]; - [downloadables addObject:downloadable]; - } - } - if (completion) { - dispatch_async(dispatch_get_main_queue(), [&, completion, error, downloadables](void) { - completion(downloadables, error); - }); - } - }); -} - -- (void)setMaximumAllowedMapboxTiles:(uint64_t)maximumCount { - _mbglFileSource->setOfflineMapboxTileCountLimit(maximumCount); -} - -@end diff --git a/platform/darwin/src/MGLDownloadController_Private.h b/platform/darwin/src/MGLDownloadController_Private.h deleted file mode 100644 index 2e26ab90cb..0000000000 --- a/platform/darwin/src/MGLDownloadController_Private.h +++ /dev/null @@ -1,15 +0,0 @@ -#import "MGLDownloadController.h" - -#import "MGLDownloadable.h" - -#include - -NS_ASSUME_NONNULL_BEGIN - -@interface MGLDownloadController (Private) - -@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLDownloadRegion_Private.h b/platform/darwin/src/MGLDownloadRegion_Private.h deleted file mode 100644 index 785775198a..0000000000 --- a/platform/darwin/src/MGLDownloadRegion_Private.h +++ /dev/null @@ -1,17 +0,0 @@ -#import - -#import "MGLDownloadRegion.h" - -#include - -NS_ASSUME_NONNULL_BEGIN - -@protocol MGLDownloadRegion_Private - -- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineRegionDefinition &)definition; - -- (const mbgl::OfflineRegionDefinition)offlineRegionDefinition; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLDownloadable.mm b/platform/darwin/src/MGLDownloadable.mm deleted file mode 100644 index 507461b4b7..0000000000 --- a/platform/darwin/src/MGLDownloadable.mm +++ /dev/null @@ -1,160 +0,0 @@ -#import "MGLDownloadable_Private.h" - -#import "MGLDownloadController_Private.h" -#import "MGLDownloadRegion_Private.h" -#import "MGLTilePyramidDownloadRegion.h" - -#include -#include - -class MBGLOfflineRegionObserver; - -@interface MGLDownloadable () - -@property (nonatomic, readwrite) mbgl::OfflineRegion *mbglOfflineRegion; -@property (nonatomic, readwrite) MBGLOfflineRegionObserver *mbglOfflineRegionObserver; -@property (nonatomic, readwrite) MGLDownloadableState state; -@property (nonatomic, readwrite) MGLDownloadableProgress progress; - -@end - -@implementation MGLDownloadable - -- (instancetype)init { - [NSException raise:@"Method unavailable" - format: - @"-[MGLDownloadable init] is unavailable. " - @"Use +[MGLDownloadController addDownloadRegion:context:completionHandler:] instead."]; - return nil; -} - -- (instancetype)initWithMBGLRegion:(mbgl::OfflineRegion *)region { - if (self = [super init]) { - _mbglOfflineRegion = region; - _state = MGLDownloadableStateInactive; - _mbglOfflineRegionObserver = new MBGLOfflineRegionObserver(self); - - mbgl::DefaultFileSource *mbglFileSource = [[MGLDownloadController sharedController] mbglFileSource]; - mbglFileSource->setOfflineRegionObserver(*_mbglOfflineRegion, std::make_unique(*_mbglOfflineRegionObserver)); - } - return self; -} - -- (void)dealloc { - delete _mbglOfflineRegionObserver; - _mbglOfflineRegionObserver = nullptr; -} - -- (id )region { - const mbgl::OfflineRegionDefinition ®ionDefinition = _mbglOfflineRegion->getDefinition(); - NSAssert([MGLTilePyramidDownloadRegion conformsToProtocol:@protocol(MGLDownloadRegion_Private)], @"MGLTilePyramidDownloadRegion should conform to MGLDownloadRegion_Private."); - return [(id )[MGLTilePyramidDownloadRegion alloc] initWithOfflineRegionDefinition:regionDefinition]; -} - -- (NSData *)context { - const mbgl::OfflineRegionMetadata &metadata = _mbglOfflineRegion->getMetadata(); - return [NSData dataWithBytes:&metadata[0] length:metadata.size()]; -} - -- (void)resume { - mbgl::DefaultFileSource *mbglFileSource = [[MGLDownloadController sharedController] mbglFileSource]; - mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Active); - self.state = MGLDownloadableStateActive; -} - -- (void)suspend { - mbgl::DefaultFileSource *mbglFileSource = [[MGLDownloadController sharedController] mbglFileSource]; - mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Inactive); - self.state = MGLDownloadableStateInactive; -} - -- (void)requestProgress { - mbgl::DefaultFileSource *mbglFileSource = [[MGLDownloadController sharedController] mbglFileSource]; - - __weak MGLDownloadable *weakSelf = self; - mbglFileSource->getOfflineRegionStatus(*_mbglOfflineRegion, [&, weakSelf](__unused std::exception_ptr exception, mbgl::optional status) { - if (status) { - mbgl::OfflineRegionStatus checkedStatus = *status; - dispatch_async(dispatch_get_main_queue(), ^{ - MGLDownloadable *strongSelf = weakSelf; - [strongSelf offlineRegionStatusDidChange:checkedStatus]; - }); - } - }); -} - -- (void)offlineRegionStatusDidChange:(mbgl::OfflineRegionStatus)status { - switch (status.downloadState) { - case mbgl::OfflineRegionDownloadState::Inactive: - self.state = status.complete() ? MGLDownloadableStateComplete : MGLDownloadableStateInactive; - break; - - case mbgl::OfflineRegionDownloadState::Active: - self.state = MGLDownloadableStateActive; - break; - } - - MGLDownloadableProgress progress; - progress.countOfResourcesCompleted = status.completedResourceCount; - progress.countOfBytesCompleted = status.completedResourceSize; - progress.countOfResourcesExpected = status.requiredResourceCount; - progress.maximumResourcesExpected = status.requiredResourceCountIsPrecise ? status.requiredResourceCount : UINT64_MAX; - self.progress = progress; - - if ([self.delegate respondsToSelector:@selector(downloadable:progressDidChange:)]) { - [self.delegate downloadable:self progressDidChange:progress]; - } -} - -NSError *MGLErrorFromResponseError(mbgl::Response::Error error) { - NSInteger errorCode = MGLErrorCodeUnknown; - switch (error.reason) { - case mbgl::Response::Error::Reason::NotFound: - errorCode = MGLErrorCodeNotFound; - break; - - case mbgl::Response::Error::Reason::Server: - errorCode = MGLErrorCodeBadServerResponse; - break; - - case mbgl::Response::Error::Reason::Connection: - errorCode = MGLErrorCodeConnectionFailed; - break; - - default: - break; - } - return [NSError errorWithDomain:MGLErrorDomain code:errorCode userInfo:@{ - NSLocalizedFailureReasonErrorKey: @(error.message.c_str()) - }]; -} - -void MBGLOfflineRegionObserver::statusChanged(mbgl::OfflineRegionStatus status) { - dispatch_async(dispatch_get_main_queue(), ^{ - NSCAssert(downloadable, @"MBGLOfflineRegionObserver is dangling without an associated MGLDownloadable."); - - [downloadable offlineRegionStatusDidChange:status]; - }); -} - -void MBGLOfflineRegionObserver::responseError(mbgl::Response::Error error) { - dispatch_async(dispatch_get_main_queue(), ^{ - NSCAssert(downloadable, @"MBGLOfflineRegionObserver is dangling without an associated MGLDownloadable."); - - if ([downloadable.delegate respondsToSelector:@selector(downloadable:didReceiveError:)]) { - [downloadable.delegate downloadable:downloadable didReceiveError:MGLErrorFromResponseError(error)]; - } - }); -} - -void MBGLOfflineRegionObserver::mapboxTileCountLimitExceeded(uint64_t limit) { - dispatch_async(dispatch_get_main_queue(), ^{ - NSCAssert(downloadable, @"MBGLOfflineRegionObserver is dangling without an associated MGLDownloadable."); - - if ([downloadable.delegate respondsToSelector:@selector(downloadable:didReceiveMaximumAllowedMapboxTiles:)]) { - [downloadable.delegate downloadable:downloadable didReceiveMaximumAllowedMapboxTiles:limit]; - } - }); -} - -@end diff --git a/platform/darwin/src/MGLDownloadable_Private.h b/platform/darwin/src/MGLDownloadable_Private.h deleted file mode 100644 index a9b2460c19..0000000000 --- a/platform/darwin/src/MGLDownloadable_Private.h +++ /dev/null @@ -1,26 +0,0 @@ -#import "MGLDownloadable.h" - -#include - -class MBGLOfflineRegionObserver; - -@interface MGLDownloadable (Private) - -@property (nonatomic) mbgl::OfflineRegion *mbglOfflineRegion; -@property (nonatomic, readonly) MBGLOfflineRegionObserver *mbglOfflineRegionObserver; - -- (instancetype)initWithMBGLRegion:(mbgl::OfflineRegion *)region; - -@end - -class MBGLOfflineRegionObserver : public mbgl::OfflineRegionObserver { -public: - MBGLOfflineRegionObserver(MGLDownloadable *downloadable_) : downloadable(downloadable_) {} - - void statusChanged(mbgl::OfflineRegionStatus status) override; - void responseError(mbgl::Response::Error error) override; - void mapboxTileCountLimitExceeded(uint64_t limit) override; - -private: - __weak MGLDownloadable *downloadable = nullptr; -}; diff --git a/platform/darwin/src/MGLOfflineRegion_Private.h b/platform/darwin/src/MGLOfflineRegion_Private.h new file mode 100644 index 0000000000..41cd5843f6 --- /dev/null +++ b/platform/darwin/src/MGLOfflineRegion_Private.h @@ -0,0 +1,17 @@ +#import + +#import "MGLOfflineRegion.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@protocol MGLOfflineRegion_Private + +- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineRegionDefinition &)definition; + +- (const mbgl::OfflineRegionDefinition)offlineRegionDefinition; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm new file mode 100644 index 0000000000..17537452a3 --- /dev/null +++ b/platform/darwin/src/MGLOfflineStorage.mm @@ -0,0 +1,150 @@ +#import "MGLOfflineStorage_Private.h" + +#import "MGLAccountManager_Private.h" +#import "MGLGeometry_Private.h" +#import "MGLOfflineTask_Private.h" +#import "MGLOfflineRegion_Private.h" +#import "MGLTilePyramidOfflineRegion.h" + +#include + +@interface MGLOfflineStorage () + +@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource; + +- (instancetype)initWithFileName:(NSString *)fileName NS_DESIGNATED_INITIALIZER; + +@end + +@implementation MGLOfflineStorage + ++ (instancetype)sharedOfflineStorage { + static dispatch_once_t onceToken; + static MGLOfflineStorage *sharedOfflineStorage; + dispatch_once(&onceToken, ^{ + sharedOfflineStorage = [[self alloc] initWithFileName:@"offline.db"]; + }); + return sharedOfflineStorage; +} + +- (instancetype)initWithFileName:(NSString *)fileName { + if (self = [super init]) { +#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *cachePath = [paths.firstObject stringByAppendingPathComponent:fileName]; +#elif TARGET_OS_MAC + NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory + inDomain:NSUserDomainMask + appropriateForURL:nil + create:YES + error:nil]; + cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent: + [NSBundle mainBundle].bundleIdentifier]; + [[NSFileManager defaultManager] createDirectoryAtURL:cacheDirectoryURL + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSURL *cacheURL = [cacheDirectoryURL URLByAppendingPathComponent:fileName]; + NSString *cachePath = cacheURL ? cacheURL.path : @""; +#endif + _mbglFileSource = new mbgl::DefaultFileSource(cachePath.UTF8String, [NSBundle mainBundle].resourceURL.path.UTF8String); + + // Observe for changes to the global access token (and find out the current one). + [[MGLAccountManager sharedManager] addObserver:self + forKeyPath:@"accessToken" + options:(NSKeyValueObservingOptionInitial | + NSKeyValueObservingOptionNew) + context:NULL]; + } + return self; +} + +- (void)dealloc { + [[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"]; + + delete _mbglFileSource; + _mbglFileSource = nullptr; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(__unused void *)context { + // Synchronize the file source’s access token with the global one in MGLAccountManager. + if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) { + NSString *accessToken = change[NSKeyValueChangeNewKey]; + if (![accessToken isKindOfClass:[NSNull class]]) { + self.mbglFileSource->setAccessToken(accessToken.UTF8String); + } + } +} + +- (void)addTaskForRegion:(id )region withContext:(NSData *)context completionHandler:(MGLOfflineTaskRegistrationCompletionHandler)completion { + if (![region conformsToProtocol:@protocol(MGLOfflineRegion_Private)]) { + [NSException raise:@"Unsupported region type" format: + @"Regions of type %@ are unsupported.", NSStringFromClass([region class])]; + return; + } + + const mbgl::OfflineTilePyramidRegionDefinition regionDefinition = [(id )region offlineRegionDefinition]; + mbgl::OfflineRegionMetadata metadata(context.length); + [context getBytes:&metadata[0] length:metadata.size()]; + self.mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](std::exception_ptr exception, mbgl::optional mbglOfflineRegion) { + NSError *error; + if (exception) { + NSString *errorDescription = @(mbgl::util::toString(exception).c_str()); + error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:errorDescription ? @{ + NSLocalizedDescriptionKey: errorDescription, + } : nil]; + } + if (completion) { + MGLOfflineTask *task = [[MGLOfflineTask alloc] initWithMBGLRegion:new mbgl::OfflineRegion(std::move(*mbglOfflineRegion))]; + dispatch_async(dispatch_get_main_queue(), [&, completion, error, task](void) { + completion(task, error); + }); + } + }); +} + +- (void)removeTask:(MGLOfflineTask *)task withCompletionHandler:(MGLOfflineTaskRemovalCompletionHandler)completion { + self.mbglFileSource->deleteOfflineRegion(std::move(*task.mbglOfflineRegion), [&, completion](std::exception_ptr exception) { + NSError *error; + if (exception) { + error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{ + NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), + }]; + } + if (completion) { + dispatch_async(dispatch_get_main_queue(), [&, completion, error](void) { + completion(error); + }); + } + }); +} + +- (void)getTasksWithCompletionHandler:(MGLOfflineTasksRetrievalCompletionHandler)completion { + self.mbglFileSource->listOfflineRegions([&, completion](std::exception_ptr exception, mbgl::optional> regions) { + NSError *error; + if (exception) { + error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{ + NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), + }]; + } + NSMutableArray *tasks; + if (regions) { + tasks = [NSMutableArray arrayWithCapacity:regions->size()]; + for (mbgl::OfflineRegion ®ion : *regions) { + MGLOfflineTask *task = [[MGLOfflineTask alloc] initWithMBGLRegion:new mbgl::OfflineRegion(std::move(region))]; + [tasks addObject:task]; + } + } + if (completion) { + dispatch_async(dispatch_get_main_queue(), [&, completion, error, tasks](void) { + completion(tasks, error); + }); + } + }); +} + +- (void)setMaximumAllowedMapboxTiles:(uint64_t)maximumCount { + _mbglFileSource->setOfflineMapboxTileCountLimit(maximumCount); +} + +@end diff --git a/platform/darwin/src/MGLOfflineStorage_Private.h b/platform/darwin/src/MGLOfflineStorage_Private.h new file mode 100644 index 0000000000..48f87a7785 --- /dev/null +++ b/platform/darwin/src/MGLOfflineStorage_Private.h @@ -0,0 +1,15 @@ +#import "MGLOfflineStorage.h" + +#import "MGLOfflineTask.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface MGLOfflineStorage (Private) + +@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLOfflineTask.mm b/platform/darwin/src/MGLOfflineTask.mm new file mode 100644 index 0000000000..a5b6e66031 --- /dev/null +++ b/platform/darwin/src/MGLOfflineTask.mm @@ -0,0 +1,160 @@ +#import "MGLOfflineTask_Private.h" + +#import "MGLOfflineStorage_Private.h" +#import "MGLOfflineRegion_Private.h" +#import "MGLTilePyramidOfflineRegion.h" + +#include +#include + +class MBGLOfflineRegionObserver; + +@interface MGLOfflineTask () + +@property (nonatomic, readwrite) mbgl::OfflineRegion *mbglOfflineRegion; +@property (nonatomic, readwrite) MBGLOfflineRegionObserver *mbglOfflineRegionObserver; +@property (nonatomic, readwrite) MGLOfflineTaskState state; +@property (nonatomic, readwrite) MGLOfflineTaskProgress progress; + +@end + +@implementation MGLOfflineTask + +- (instancetype)init { + [NSException raise:@"Method unavailable" + format: + @"-[MGLOfflineTask init] is unavailable. " + @"Use +[MGLOfflineStorage addTaskForRegion:withContext:completionHandler:] instead."]; + return nil; +} + +- (instancetype)initWithMBGLRegion:(mbgl::OfflineRegion *)region { + if (self = [super init]) { + _mbglOfflineRegion = region; + _state = MGLOfflineTaskStateInactive; + _mbglOfflineRegionObserver = new MBGLOfflineRegionObserver(self); + + mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; + mbglFileSource->setOfflineRegionObserver(*_mbglOfflineRegion, std::make_unique(*_mbglOfflineRegionObserver)); + } + return self; +} + +- (void)dealloc { + delete _mbglOfflineRegionObserver; + _mbglOfflineRegionObserver = nullptr; +} + +- (id )region { + const mbgl::OfflineRegionDefinition ®ionDefinition = _mbglOfflineRegion->getDefinition(); + NSAssert([MGLTilePyramidOfflineRegion conformsToProtocol:@protocol(MGLOfflineRegion_Private)], @"MGLTilePyramidOfflineRegion should conform to MGLOfflineRegion_Private."); + return [(id )[MGLTilePyramidOfflineRegion alloc] initWithOfflineRegionDefinition:regionDefinition]; +} + +- (NSData *)context { + const mbgl::OfflineRegionMetadata &metadata = _mbglOfflineRegion->getMetadata(); + return [NSData dataWithBytes:&metadata[0] length:metadata.size()]; +} + +- (void)resume { + mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; + mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Active); + self.state = MGLOfflineTaskStateActive; +} + +- (void)suspend { + mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; + mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Inactive); + self.state = MGLOfflineTaskStateInactive; +} + +- (void)requestProgress { + mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; + + __weak MGLOfflineTask *weakSelf = self; + mbglFileSource->getOfflineRegionStatus(*_mbglOfflineRegion, [&, weakSelf](__unused std::exception_ptr exception, mbgl::optional status) { + if (status) { + mbgl::OfflineRegionStatus checkedStatus = *status; + dispatch_async(dispatch_get_main_queue(), ^{ + MGLOfflineTask *strongSelf = weakSelf; + [strongSelf offlineRegionStatusDidChange:checkedStatus]; + }); + } + }); +} + +- (void)offlineRegionStatusDidChange:(mbgl::OfflineRegionStatus)status { + switch (status.downloadState) { + case mbgl::OfflineRegionDownloadState::Inactive: + self.state = status.complete() ? MGLOfflineTaskStateComplete : MGLOfflineTaskStateInactive; + break; + + case mbgl::OfflineRegionDownloadState::Active: + self.state = MGLOfflineTaskStateActive; + break; + } + + MGLOfflineTaskProgress progress; + progress.countOfResourcesCompleted = status.completedResourceCount; + progress.countOfBytesCompleted = status.completedResourceSize; + progress.countOfResourcesExpected = status.requiredResourceCount; + progress.maximumResourcesExpected = status.requiredResourceCountIsPrecise ? status.requiredResourceCount : UINT64_MAX; + self.progress = progress; + + if ([self.delegate respondsToSelector:@selector(offlineTask:progressDidChange:)]) { + [self.delegate offlineTask:self progressDidChange:progress]; + } +} + +NSError *MGLErrorFromResponseError(mbgl::Response::Error error) { + NSInteger errorCode = MGLErrorCodeUnknown; + switch (error.reason) { + case mbgl::Response::Error::Reason::NotFound: + errorCode = MGLErrorCodeNotFound; + break; + + case mbgl::Response::Error::Reason::Server: + errorCode = MGLErrorCodeBadServerResponse; + break; + + case mbgl::Response::Error::Reason::Connection: + errorCode = MGLErrorCodeConnectionFailed; + break; + + default: + break; + } + return [NSError errorWithDomain:MGLErrorDomain code:errorCode userInfo:@{ + NSLocalizedFailureReasonErrorKey: @(error.message.c_str()) + }]; +} + +void MBGLOfflineRegionObserver::statusChanged(mbgl::OfflineRegionStatus status) { + dispatch_async(dispatch_get_main_queue(), ^{ + NSCAssert(offlineTask, @"MBGLOfflineRegionObserver is dangling without an associated MGLOfflineTask."); + + [offlineTask offlineRegionStatusDidChange:status]; + }); +} + +void MBGLOfflineRegionObserver::responseError(mbgl::Response::Error error) { + dispatch_async(dispatch_get_main_queue(), ^{ + NSCAssert(offlineTask, @"MBGLOfflineRegionObserver is dangling without an associated MGLOfflineTask."); + + if ([offlineTask.delegate respondsToSelector:@selector(offlineTask:didReceiveError:)]) { + [offlineTask.delegate offlineTask:offlineTask didReceiveError:MGLErrorFromResponseError(error)]; + } + }); +} + +void MBGLOfflineRegionObserver::mapboxTileCountLimitExceeded(uint64_t limit) { + dispatch_async(dispatch_get_main_queue(), ^{ + NSCAssert(offlineTask, @"MBGLOfflineRegionObserver is dangling without an associated MGLOfflineTask."); + + if ([offlineTask.delegate respondsToSelector:@selector(offlineTask:didReceiveMaximumAllowedMapboxTiles:)]) { + [offlineTask.delegate offlineTask:offlineTask didReceiveMaximumAllowedMapboxTiles:limit]; + } + }); +} + +@end diff --git a/platform/darwin/src/MGLOfflineTask_Private.h b/platform/darwin/src/MGLOfflineTask_Private.h new file mode 100644 index 0000000000..ad0e597a8d --- /dev/null +++ b/platform/darwin/src/MGLOfflineTask_Private.h @@ -0,0 +1,26 @@ +#import "MGLOfflineTask.h" + +#include + +class MBGLOfflineRegionObserver; + +@interface MGLOfflineTask (Private) + +@property (nonatomic) mbgl::OfflineRegion *mbglOfflineRegion; +@property (nonatomic, readonly) MBGLOfflineRegionObserver *mbglOfflineRegionObserver; + +- (instancetype)initWithMBGLRegion:(mbgl::OfflineRegion *)region; + +@end + +class MBGLOfflineRegionObserver : public mbgl::OfflineRegionObserver { +public: + MBGLOfflineRegionObserver(MGLOfflineTask *offlineTask_) : offlineTask(offlineTask_) {} + + void statusChanged(mbgl::OfflineRegionStatus status) override; + void responseError(mbgl::Response::Error error) override; + void mapboxTileCountLimitExceeded(uint64_t limit) override; + +private: + __weak MGLOfflineTask *offlineTask = nullptr; +}; diff --git a/platform/darwin/src/MGLTilePyramidDownloadRegion.mm b/platform/darwin/src/MGLTilePyramidDownloadRegion.mm deleted file mode 100644 index 94c0ac6358..0000000000 --- a/platform/darwin/src/MGLTilePyramidDownloadRegion.mm +++ /dev/null @@ -1,66 +0,0 @@ -#import "MGLTilePyramidDownloadRegion.h" - -#if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - #import -#endif - -#import "MGLDownloadRegion_Private.h" -#import "MGLGeometry_Private.h" -#import "MGLStyle.h" - -@interface MGLTilePyramidDownloadRegion () - -@end - -@implementation MGLTilePyramidDownloadRegion { - NSURL *_styleURL; -} - -@synthesize styleURL = _styleURL; - -- (instancetype)init { - [NSException raise:@"Method unavailable" - format: - @"-[MGLTilePyramidDownloadRegion init] is unavailable. " - @"Use -initWithStyleURL:bounds:fromZoomLevel:toZoomLevel: instead."]; - return nil; -} - -- (instancetype)initWithStyleURL:(NSURL *)styleURL bounds:(MGLCoordinateBounds)bounds fromZoomLevel:(double)minimumZoomLevel toZoomLevel:(double)maximumZoomLevel { - if (self = [super init]) { - if (!styleURL) { - styleURL = [MGLStyle streetsStyleURL]; - } - - if (!styleURL.scheme) { - // Assume a relative path into the application bundle. - styleURL = [NSURL URLWithString:[@"asset://" stringByAppendingString:styleURL.absoluteString]]; - } - - _styleURL = styleURL; - _bounds = bounds; - _minimumZoomLevel = minimumZoomLevel; - _maximumZoomLevel = maximumZoomLevel; - } - return self; -} - -- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineRegionDefinition &)definition { - NSURL *styleURL = [NSURL URLWithString:@(definition.styleURL.c_str())]; - MGLCoordinateBounds bounds = MGLCoordinateBoundsFromLatLngBounds(definition.bounds); - return [self initWithStyleURL:styleURL bounds:bounds fromZoomLevel:definition.minZoom toZoomLevel:definition.maxZoom]; -} - -- (const mbgl::OfflineRegionDefinition)offlineRegionDefinition { -#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR - const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; -#elif TARGET_OS_MAC - const float scaleFactor = [NSScreen mainScreen].backingScaleFactor; -#endif - return mbgl::OfflineTilePyramidRegionDefinition(_styleURL.absoluteString.UTF8String, - MGLLatLngBoundsFromCoordinateBounds(_bounds), - _minimumZoomLevel, _maximumZoomLevel, - scaleFactor); -} - -@end diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm new file mode 100644 index 0000000000..3d51917c3e --- /dev/null +++ b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm @@ -0,0 +1,66 @@ +#import "MGLTilePyramidOfflineRegion.h" + +#if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + #import +#endif + +#import "MGLOfflineRegion_Private.h" +#import "MGLGeometry_Private.h" +#import "MGLStyle.h" + +@interface MGLTilePyramidOfflineRegion () + +@end + +@implementation MGLTilePyramidOfflineRegion { + NSURL *_styleURL; +} + +@synthesize styleURL = _styleURL; + +- (instancetype)init { + [NSException raise:@"Method unavailable" + format: + @"-[MGLTilePyramidOfflineRegion init] is unavailable. " + @"Use -initWithStyleURL:bounds:fromZoomLevel:toZoomLevel: instead."]; + return nil; +} + +- (instancetype)initWithStyleURL:(NSURL *)styleURL bounds:(MGLCoordinateBounds)bounds fromZoomLevel:(double)minimumZoomLevel toZoomLevel:(double)maximumZoomLevel { + if (self = [super init]) { + if (!styleURL) { + styleURL = [MGLStyle streetsStyleURL]; + } + + if (!styleURL.scheme) { + // Assume a relative path into the application bundle. + styleURL = [NSURL URLWithString:[@"asset://" stringByAppendingString:styleURL.absoluteString]]; + } + + _styleURL = styleURL; + _bounds = bounds; + _minimumZoomLevel = minimumZoomLevel; + _maximumZoomLevel = maximumZoomLevel; + } + return self; +} + +- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineRegionDefinition &)definition { + NSURL *styleURL = [NSURL URLWithString:@(definition.styleURL.c_str())]; + MGLCoordinateBounds bounds = MGLCoordinateBoundsFromLatLngBounds(definition.bounds); + return [self initWithStyleURL:styleURL bounds:bounds fromZoomLevel:definition.minZoom toZoomLevel:definition.maxZoom]; +} + +- (const mbgl::OfflineRegionDefinition)offlineRegionDefinition { +#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR + const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; +#elif TARGET_OS_MAC + const float scaleFactor = [NSScreen mainScreen].backingScaleFactor; +#endif + return mbgl::OfflineTilePyramidRegionDefinition(_styleURL.absoluteString.UTF8String, + MGLLatLngBoundsFromCoordinateBounds(_bounds), + _minimumZoomLevel, _maximumZoomLevel, + scaleFactor); +} + +@end diff --git a/platform/ios/app/MBXDownloadsTableViewController.m b/platform/ios/app/MBXDownloadsTableViewController.m index db80fdef52..db79d77d3e 100644 --- a/platform/ios/app/MBXDownloadsTableViewController.m +++ b/platform/ios/app/MBXDownloadsTableViewController.m @@ -2,26 +2,26 @@ #import -static NSString * const MBXDownloadContextNameKey = @"Name"; +static NSString * const MBXOfflineTaskContextNameKey = @"Name"; static NSString * const MBXDownloadsTableViewInactiveCellReuseIdentifier = @"Inactive"; static NSString * const MBXDownloadsTableViewActiveCellReuseIdentifier = @"Active"; -@implementation MGLDownloadable (MBXAdditions) +@implementation MGLOfflineTask (MBXAdditions) - (NSString *)name { NSDictionary *userInfo = [NSKeyedUnarchiver unarchiveObjectWithData:self.context]; - NSAssert([userInfo isKindOfClass:[NSDictionary class]], @"Context of downloadable isn’t a dictionary."); - NSString *name = userInfo[MBXDownloadContextNameKey]; - NSAssert([name isKindOfClass:[NSString class]], @"Name of downloadable isn’t a string."); + NSAssert([userInfo isKindOfClass:[NSDictionary class]], @"Context of offline task isn’t a dictionary."); + NSString *name = userInfo[MBXOfflineTaskContextNameKey]; + NSAssert([name isKindOfClass:[NSString class]], @"Name of offline task isn’t a string."); return name; } @end -@interface MBXDownloadsTableViewController () +@interface MBXDownloadsTableViewController () -@property (nonatomic, strong) NS_MUTABLE_ARRAY_OF(MGLDownloadable *) *downloadables; +@property (nonatomic, strong) NS_MUTABLE_ARRAY_OF(MGLOfflineTask *) *offlineTasks; @end @@ -33,14 +33,14 @@ static NSString * const MBXDownloadsTableViewActiveCellReuseIdentifier = @"Activ [super viewDidLoad]; __weak MBXDownloadsTableViewController *weakSelf = self; - [[MGLDownloadController sharedController] requestDownloadablesWithCompletionHandler:^(NS_ARRAY_OF(MGLDownloadable *) *downloadables, NSError *error) { + [[MGLOfflineStorage sharedOfflineStorage] getTasksWithCompletionHandler:^(NS_ARRAY_OF(MGLOfflineTask *) *tasks, NSError *error) { MBXDownloadsTableViewController *strongSelf = weakSelf; - strongSelf.downloadables = downloadables.mutableCopy; + strongSelf.offlineTasks = tasks.mutableCopy; [strongSelf.tableView reloadData]; - for (MGLDownloadable *downloadable in strongSelf.downloadables) { - downloadable.delegate = strongSelf; - [downloadable requestProgress]; + for (MGLOfflineTask *task in strongSelf.offlineTasks) { + task.delegate = strongSelf; + [task requestProgress]; } if (error) { @@ -67,13 +67,13 @@ static NSString * const MBXDownloadsTableViewActiveCellReuseIdentifier = @"Activ name = [NSString stringWithFormat:@"Untitled %lu", (unsigned long)++_untitledRegionCount]; } - MGLTilePyramidDownloadRegion *region = [[MGLTilePyramidDownloadRegion alloc] initWithStyleURL:mapView.styleURL bounds:mapView.visibleCoordinateBounds fromZoomLevel:mapView.zoomLevel toZoomLevel:mapView.maximumZoomLevel]; + MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:mapView.styleURL bounds:mapView.visibleCoordinateBounds fromZoomLevel:mapView.zoomLevel toZoomLevel:mapView.maximumZoomLevel]; NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{ - MBXDownloadContextNameKey: name, + MBXOfflineTaskContextNameKey: name, }]; __weak MBXDownloadsTableViewController *weakSelf = self; - [[MGLDownloadController sharedController] addDownloadableForRegion:region withContext:context completionHandler:^(MGLDownloadable *downloadable, NSError *error) { + [[MGLOfflineStorage sharedOfflineStorage] addTaskForRegion:region withContext:context completionHandler:^(MGLOfflineTask *task, NSError *error) { MBXDownloadsTableViewController *strongSelf = weakSelf; if (error) { NSString *message = [NSString stringWithFormat:@"Mapbox GL was unable to add the download “%@”.", name]; @@ -81,11 +81,11 @@ static NSString * const MBXDownloadsTableViewActiveCellReuseIdentifier = @"Activ [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alertController animated:YES completion:nil]; } else { - downloadable.delegate = strongSelf; - [downloadable resume]; + task.delegate = strongSelf; + [task resume]; - NSIndexPath *indexPath = [NSIndexPath indexPathForRow:strongSelf.downloadables.count inSection:0]; - [strongSelf.downloadables addObject:downloadable]; + NSIndexPath *indexPath = [NSIndexPath indexPathForRow:strongSelf.offlineTasks.count inSection:0]; + [strongSelf.offlineTasks addObject:task]; [strongSelf.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } }]; @@ -99,16 +99,16 @@ static NSString * const MBXDownloadsTableViewActiveCellReuseIdentifier = @"Activ #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return self.downloadables.count; + return self.offlineTasks.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - MGLDownloadable *downloadable = self.downloadables[indexPath.row]; + MGLOfflineTask *task = self.offlineTasks[indexPath.row]; - NSString *reuseIdentifier = downloadable.state == MGLDownloadableStateActive ? MBXDownloadsTableViewActiveCellReuseIdentifier : MBXDownloadsTableViewInactiveCellReuseIdentifier; + NSString *reuseIdentifier = task.state == MGLOfflineTaskStateActive ? MBXDownloadsTableViewActiveCellReuseIdentifier : MBXDownloadsTableViewInactiveCellReuseIdentifier; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath]; - cell.textLabel.text = downloadable.name; - MGLDownloadableProgress progress = downloadable.progress; + cell.textLabel.text = task.name; + MGLOfflineTaskProgress progress = task.progress; NSString *completedString = [NSNumberFormatter localizedStringFromNumber:@(progress.countOfResourcesCompleted) numberStyle:NSNumberFormatterDecimalStyle]; NSString *expectedString = [NSNumberFormatter localizedStringFromNumber:@(progress.countOfResourcesExpected) @@ -116,14 +116,14 @@ static NSString * const MBXDownloadsTableViewActiveCellReuseIdentifier = @"Activ NSString *byteCountString = [NSByteCountFormatter stringFromByteCount:progress.countOfBytesCompleted countStyle:NSByteCountFormatterCountStyleFile]; NSString *statusString; - switch (downloadable.state) { - case MGLDownloadableStateInactive: - case MGLDownloadableStateComplete: + switch (task.state) { + case MGLOfflineTaskStateInactive: + case MGLOfflineTaskStateComplete: statusString = [NSString stringWithFormat:@"%@ of %@ resources (%@)", completedString, expectedString, byteCountString]; break; - case MGLDownloadableStateActive: + case MGLOfflineTaskStateActive: if (progress.countOfResourcesExpected) { completedString = [NSNumberFormatter localizedStringFromNumber:@(progress.countOfResourcesCompleted + 1) numberStyle:NSNumberFormatterDecimalStyle]; @@ -142,20 +142,20 @@ static NSString * const MBXDownloadsTableViewActiveCellReuseIdentifier = @"Activ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { - MGLDownloadable *downloadable = self.downloadables[indexPath.row]; + MGLOfflineTask *task = self.offlineTasks[indexPath.row]; __weak MBXDownloadsTableViewController *weakSelf = self; - [[MGLDownloadController sharedController] removeDownloadable:downloadable withCompletionHandler:^(NSError *error) { + [[MGLOfflineStorage sharedOfflineStorage] removeTask:task withCompletionHandler:^(NSError *error) { MBXDownloadsTableViewController *strongSelf = weakSelf; - [strongSelf.downloadables removeObjectAtIndex:indexPath.row]; + [strongSelf.offlineTasks removeObjectAtIndex:indexPath.row]; [strongSelf.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; }]; } } -#pragma mark - Downloadable delegate +#pragma mark - Offline task delegate -- (void)downloadable:(MGLDownloadable *)downloadable progressDidChange:(MGLDownloadableProgress)progress { - NSUInteger index = [self.downloadables indexOfObject:downloadable]; +- (void)offlineTask:(MGLOfflineTask *)task progressDidChange:(MGLOfflineTaskProgress)progress { + NSUInteger index = [self.offlineTasks indexOfObject:task]; if (index == NSNotFound) { return; } @@ -164,12 +164,12 @@ static NSString * const MBXDownloadsTableViewActiveCellReuseIdentifier = @"Activ [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; } -- (void)downloadable:(MGLDownloadable *)downloadable didReceiveError:(NSError *)error { - NSLog(@"Downloadable “%@” received error: %@", downloadable.name, error.localizedFailureReason); +- (void)offlineTask:(MGLOfflineTask *)task didReceiveError:(NSError *)error { + NSLog(@"Offline task “%@” received error: %@", task.name, error.localizedFailureReason); } -- (void)downloadable:(MGLDownloadable *)downloadable didReceiveMaximumAllowedMapboxTiles:(uint64_t)maximumCount { - NSLog(@"Downloadable “%@” reached limit of %llu tiles.", downloadable.name, maximumCount); +- (void)offlineTask:(MGLOfflineTask *)task didReceiveMaximumAllowedMapboxTiles:(uint64_t)maximumCount { + NSLog(@"Offline task “%@” reached limit of %llu tiles.", task.name, maximumCount); } @end diff --git a/platform/ios/framework/Mapbox.h b/platform/ios/framework/Mapbox.h index f13a542ac2..f88a75c8c5 100644 --- a/platform/ios/framework/Mapbox.h +++ b/platform/ios/framework/Mapbox.h @@ -12,19 +12,19 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[]; #import "MGLCalloutView.h" #import "MGLMapCamera.h" #import "MGLGeometry.h" -#import "MGLDownloadable.h" -#import "MGLDownloadRegion.h" -#import "MGLDownloadController.h" #import "MGLMapView.h" #import "MGLMapView+IBAdditions.h" #import "MGLMapView+MGLCustomStyleLayerAdditions.h" #import "MGLMultiPoint.h" +#import "MGLOfflineRegion.h" +#import "MGLOfflineStorage.h" +#import "MGLOfflineTask.h" #import "MGLOverlay.h" #import "MGLPointAnnotation.h" #import "MGLPolygon.h" #import "MGLPolyline.h" #import "MGLShape.h" #import "MGLStyle.h" -#import "MGLTilePyramidDownloadRegion.h" +#import "MGLTilePyramidOfflineRegion.h" #import "MGLTypes.h" #import "MGLUserLocation.h" diff --git a/platform/ios/framework/Mapbox.m b/platform/ios/framework/Mapbox.m index cc3be1e2b2..094cbd3506 100644 --- a/platform/ios/framework/Mapbox.m +++ b/platform/ios/framework/Mapbox.m @@ -17,16 +17,16 @@ static void InitializeMapbox() { [MGLAccountManager class]; [MGLAnnotationImage class]; - [MGLDownloadable class]; - [MGLDownloadController class]; [MGLMapCamera class]; [MGLMapView class]; [MGLMultiPoint class]; + [MGLOfflineStorage class]; + [MGLOfflineTask class]; [MGLPointAnnotation class]; [MGLPolygon class]; [MGLPolyline class]; [MGLShape class]; [MGLStyle class]; - [MGLTilePyramidDownloadRegion class]; + [MGLTilePyramidOfflineRegion class]; [MGLUserLocation class]; } diff --git a/platform/osx/sdk/Mapbox.h b/platform/osx/sdk/Mapbox.h index 018d16b3c0..62f050130b 100644 --- a/platform/osx/sdk/Mapbox.h +++ b/platform/osx/sdk/Mapbox.h @@ -9,20 +9,20 @@ FOUNDATION_EXPORT const unsigned char MapboxVersionString[]; #import #import #import -#import -#import -#import #import #import #import #import #import #import +#import +#import +#import #import #import #import #import #import #import -#import +#import #import diff --git a/platform/osx/sdk/Mapbox.m b/platform/osx/sdk/Mapbox.m index 5246124088..2ec28260d2 100644 --- a/platform/osx/sdk/Mapbox.m +++ b/platform/osx/sdk/Mapbox.m @@ -1,8 +1,8 @@ #import #import "../src/MGLMapView_Private.h" -#import "../src/NSBundle+MGLAdditions.h" -#import "../src/NSProcessInfo+MGLAdditions.h" +#import "../../darwin/src/NSBundle+MGLAdditions.h" +#import "../../darwin/src/NSProcessInfo+MGLAdditions.h" #import "../../darwin/src/NSString+MGLAdditions.h" __attribute__((constructor)) @@ -19,15 +19,15 @@ static void InitializeMapbox() { [MGLAccountManager class]; [MGLAnnotationImage class]; - [MGLDownloadable class]; - [MGLDownloadController class]; [MGLMapCamera class]; [MGLMapView class]; [MGLMultiPoint class]; + [MGLOfflineStorage class]; + [MGLOfflineTask class]; [MGLPointAnnotation class]; [MGLPolygon class]; [MGLPolyline class]; [MGLShape class]; [MGLStyle class]; - [MGLTilePyramidDownloadRegion class]; + [MGLTilePyramidOfflineRegion class]; } -- cgit v1.2.1