summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2016-03-03 18:19:23 -0800
committerMinh Nguyễn <mxn@1ec5.org>2016-03-10 17:08:58 -0800
commit081ee9fbefbdb37f116a5bf2c0383586bce6608a (patch)
treef8ceae6517ced39b1fd09f79b1f037b76d6a2dde
parent77657b38969a55377117dfde5fc9d5e3478208d1 (diff)
downloadqtlocation-mapboxgl-081ee9fbefbdb37f116a5bf2c0383586bce6608a.tar.gz
[ios] Added download manager to iosapp
-rw-r--r--platform/ios/app/MBXDownloadsTableViewController.h9
-rw-r--r--platform/ios/app/MBXDownloadsTableViewController.m175
-rw-r--r--platform/ios/app/MBXViewController.mm63
-rw-r--r--platform/ios/app/Storyboard.storyboard93
-rw-r--r--platform/ios/app/mapboxgl-app.gypi2
5 files changed, 310 insertions, 32 deletions
diff --git a/platform/ios/app/MBXDownloadsTableViewController.h b/platform/ios/app/MBXDownloadsTableViewController.h
new file mode 100644
index 0000000000..f0b5b8a68b
--- /dev/null
+++ b/platform/ios/app/MBXDownloadsTableViewController.h
@@ -0,0 +1,9 @@
+#import <UIKit/UIKit.h>
+
+@class MGLMapView;
+
+@interface MBXDownloadsTableViewController : UITableViewController
+
+@property (nonatomic, weak) MGLMapView *mapView;
+
+@end
diff --git a/platform/ios/app/MBXDownloadsTableViewController.m b/platform/ios/app/MBXDownloadsTableViewController.m
new file mode 100644
index 0000000000..db80fdef52
--- /dev/null
+++ b/platform/ios/app/MBXDownloadsTableViewController.m
@@ -0,0 +1,175 @@
+#import "MBXDownloadsTableViewController.h"
+
+#import <Mapbox/Mapbox.h>
+
+static NSString * const MBXDownloadContextNameKey = @"Name";
+
+static NSString * const MBXDownloadsTableViewInactiveCellReuseIdentifier = @"Inactive";
+static NSString * const MBXDownloadsTableViewActiveCellReuseIdentifier = @"Active";
+
+@implementation MGLDownloadable (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.");
+ return name;
+}
+
+@end
+
+@interface MBXDownloadsTableViewController () <MGLDownloadableDelegate>
+
+@property (nonatomic, strong) NS_MUTABLE_ARRAY_OF(MGLDownloadable *) *downloadables;
+
+@end
+
+@implementation MBXDownloadsTableViewController {
+ NSUInteger _untitledRegionCount;
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ __weak MBXDownloadsTableViewController *weakSelf = self;
+ [[MGLDownloadController sharedController] requestDownloadablesWithCompletionHandler:^(NS_ARRAY_OF(MGLDownloadable *) *downloadables, NSError *error) {
+ MBXDownloadsTableViewController *strongSelf = weakSelf;
+ strongSelf.downloadables = downloadables.mutableCopy;
+ [strongSelf.tableView reloadData];
+
+ for (MGLDownloadable *downloadable in strongSelf.downloadables) {
+ downloadable.delegate = strongSelf;
+ [downloadable requestProgress];
+ }
+
+ if (error) {
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Can’t Find Downloads" message:@"Mapbox GL was unable to find the existing downloads." preferredStyle:UIAlertControllerStyleAlert];
+ [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
+ [self presentViewController:alertController animated:YES completion:^{
+ [strongSelf dismissViewControllerAnimated:YES completion:nil];
+ }];
+ }
+ }];
+}
+
+- (IBAction)addCurrentRegion:(id)sender {
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Add Download" message:@"Choose a name for the download:" preferredStyle:UIAlertControllerStyleAlert];
+ [alertController addTextFieldWithConfigurationHandler:nil];
+ [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
+
+ UIAlertAction *downloadAction = [UIAlertAction actionWithTitle:@"Download" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
+ MGLMapView *mapView = self.mapView;
+ NSAssert(mapView, @"No map view to get the current region from.");
+
+ NSString *name = alertController.textFields.firstObject.text;
+ if (!name.length) {
+ name = [NSString stringWithFormat:@"Untitled %lu", (unsigned long)++_untitledRegionCount];
+ }
+
+ MGLTilePyramidDownloadRegion *region = [[MGLTilePyramidDownloadRegion alloc] initWithStyleURL:mapView.styleURL bounds:mapView.visibleCoordinateBounds fromZoomLevel:mapView.zoomLevel toZoomLevel:mapView.maximumZoomLevel];
+ NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{
+ MBXDownloadContextNameKey: name,
+ }];
+
+ __weak MBXDownloadsTableViewController *weakSelf = self;
+ [[MGLDownloadController sharedController] addDownloadableForRegion:region withContext:context completionHandler:^(MGLDownloadable *downloadable, NSError *error) {
+ MBXDownloadsTableViewController *strongSelf = weakSelf;
+ if (error) {
+ NSString *message = [NSString stringWithFormat:@"Mapbox GL was unable to add the download “%@”.", name];
+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Can’t Add Download" message:message preferredStyle:UIAlertControllerStyleAlert];
+ [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
+ [self presentViewController:alertController animated:YES completion:nil];
+ } else {
+ downloadable.delegate = strongSelf;
+ [downloadable resume];
+
+ NSIndexPath *indexPath = [NSIndexPath indexPathForRow:strongSelf.downloadables.count inSection:0];
+ [strongSelf.downloadables addObject:downloadable];
+ [strongSelf.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
+ }
+ }];
+ }];
+ [alertController addAction:downloadAction];
+ alertController.preferredAction = downloadAction;
+
+ [self presentViewController:alertController animated:YES completion:nil];
+}
+
+#pragma mark - Table view data source
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+ return self.downloadables.count;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+ MGLDownloadable *downloadable = self.downloadables[indexPath.row];
+
+ NSString *reuseIdentifier = downloadable.state == MGLDownloadableStateActive ? MBXDownloadsTableViewActiveCellReuseIdentifier : MBXDownloadsTableViewInactiveCellReuseIdentifier;
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath];
+ cell.textLabel.text = downloadable.name;
+ MGLDownloadableProgress progress = downloadable.progress;
+ NSString *completedString = [NSNumberFormatter localizedStringFromNumber:@(progress.countOfResourcesCompleted)
+ numberStyle:NSNumberFormatterDecimalStyle];
+ NSString *expectedString = [NSNumberFormatter localizedStringFromNumber:@(progress.countOfResourcesExpected)
+ numberStyle:NSNumberFormatterDecimalStyle];
+ NSString *byteCountString = [NSByteCountFormatter stringFromByteCount:progress.countOfBytesCompleted
+ countStyle:NSByteCountFormatterCountStyleFile];
+ NSString *statusString;
+ switch (downloadable.state) {
+ case MGLDownloadableStateInactive:
+ case MGLDownloadableStateComplete:
+ statusString = [NSString stringWithFormat:@"%@ of %@ resources (%@)",
+ completedString, expectedString, byteCountString];
+ break;
+
+ case MGLDownloadableStateActive:
+ if (progress.countOfResourcesExpected) {
+ completedString = [NSNumberFormatter localizedStringFromNumber:@(progress.countOfResourcesCompleted + 1)
+ numberStyle:NSNumberFormatterDecimalStyle];
+ }
+ if (progress.maximumResourcesExpected > progress.countOfResourcesExpected) {
+ expectedString = [@"at least " stringByAppendingString:expectedString];
+ }
+ statusString = [NSString stringWithFormat:@"Downloading %@ of %@ resources (%@ so far)…",
+ completedString, expectedString, byteCountString];
+ break;
+ }
+ cell.detailTextLabel.text = statusString;
+
+ return cell;
+}
+
+- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
+ if (editingStyle == UITableViewCellEditingStyleDelete) {
+ MGLDownloadable *downloadable = self.downloadables[indexPath.row];
+ __weak MBXDownloadsTableViewController *weakSelf = self;
+ [[MGLDownloadController sharedController] removeDownloadable:downloadable withCompletionHandler:^(NSError *error) {
+ MBXDownloadsTableViewController *strongSelf = weakSelf;
+ [strongSelf.downloadables removeObjectAtIndex:indexPath.row];
+ [strongSelf.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
+ }];
+ }
+}
+
+#pragma mark - Downloadable delegate
+
+- (void)downloadable:(MGLDownloadable *)downloadable progressDidChange:(MGLDownloadableProgress)progress {
+ NSUInteger index = [self.downloadables indexOfObject:downloadable];
+ if (index == NSNotFound) {
+ return;
+ }
+
+ NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
+ [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
+}
+
+- (void)downloadable:(MGLDownloadable *)downloadable didReceiveError:(NSError *)error {
+ NSLog(@"Downloadable “%@” received error: %@", downloadable.name, error.localizedFailureReason);
+}
+
+- (void)downloadable:(MGLDownloadable *)downloadable didReceiveMaximumAllowedMapboxTiles:(uint64_t)maximumCount {
+ NSLog(@"Downloadable “%@” reached limit of %llu tiles.", downloadable.name, maximumCount);
+}
+
+@end
diff --git a/platform/ios/app/MBXViewController.mm b/platform/ios/app/MBXViewController.mm
index 548a5e7100..ba35feed62 100644
--- a/platform/ios/app/MBXViewController.mm
+++ b/platform/ios/app/MBXViewController.mm
@@ -1,5 +1,6 @@
#import "MBXViewController.h"
#import "MBXCustomCalloutView.h"
+#import "MBXDownloadsTableViewController.h"
#import <Mapbox/Mapbox.h>
#import "../../../include/mbgl/util/default_styles.hpp"
@@ -100,6 +101,13 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
return UIInterfaceOrientationMaskAll;
}
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(__unused id)sender {
+ if ([segue.identifier isEqualToString:@"ShowDownloads"]) {
+ MBXDownloadsTableViewController *controller = [segue destinationViewController];
+ controller.mapView = self.mapView;
+ }
+}
+
#pragma mark - Actions
- (IBAction)showSettings:(__unused id)sender
@@ -109,33 +117,34 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
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"),
- @"Empty Memory",
- @"Add 100 Points",
- @"Add 1,000 Points",
- @"Add 10,000 Points",
- @"Add Test Shapes",
- @"Start World Tour",
- @"Add Custom Callout Point",
- @"Remove Annotations",
- (_isShowingCustomStyleLayer
- ? @"Hide Custom Style Layer"
- : @"Show Custom Style Layer"),
- @"Print Telemetry Logfile",
- @"Delete Telemetry Logfile",
- 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"),
+ @"Empty Memory",
+ @"Add 100 Points",
+ @"Add 1,000 Points",
+ @"Add 10,000 Points",
+ @"Add Test Shapes",
+ @"Start World Tour",
+ @"Add Custom Callout Point",
+ @"Remove Annotations",
+ (_isShowingCustomStyleLayer
+ ? @"Hide Custom Style Layer"
+ : @"Show Custom Style Layer"),
+ @"Print Telemetry Logfile",
+ @"Delete Telemetry Logfile",
+ nil];
[sheet showFromBarButtonItem:self.navigationItem.leftBarButtonItem animated:YES];
}
diff --git a/platform/ios/app/Storyboard.storyboard b/platform/ios/app/Storyboard.storyboard
index 68ee45b8d2..7e1eded47e 100644
--- a/platform/ios/app/Storyboard.storyboard
+++ b/platform/ios/app/Storyboard.storyboard
@@ -3,6 +3,7 @@
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10083"/>
+ <capability name="Navigation items with more than one left or right bar item" minToolsVersion="7.0"/>
</dependencies>
<scenes>
<!--Map View Controller-->
@@ -51,11 +52,18 @@
<action selector="cycleStyles:" destination="WaX-pd-UZQ" eventType="touchUpInside" id="PnY-mb-J6m"/>
</connections>
</button>
- <barButtonItem key="rightBarButtonItem" image="TrackingLocationOffMask.png" id="CQ1-GP-M6x">
- <connections>
- <action selector="locateUser:" destination="WaX-pd-UZQ" id="XgF-DB-z3f"/>
- </connections>
- </barButtonItem>
+ <rightBarButtonItems>
+ <barButtonItem image="TrackingLocationOffMask.png" id="CQ1-GP-M6x">
+ <connections>
+ <action selector="locateUser:" destination="WaX-pd-UZQ" id="XgF-DB-z3f"/>
+ </connections>
+ </barButtonItem>
+ <barButtonItem systemItem="organize" id="5IK-vz-jKQ">
+ <connections>
+ <segue destination="7q0-lI-zqb" kind="show" identifier="ShowDownloads" id="xjx-0t-0LD"/>
+ </connections>
+ </barButtonItem>
+ </rightBarButtonItems>
</navigationItem>
<connections>
<outlet property="mapView" destination="kNe-zV-9ha" id="VNR-WO-1q4"/>
@@ -70,6 +78,81 @@
</objects>
<point key="canvasLocation" x="1366" y="350"/>
</scene>
+ <!--Downloads-->
+ <scene sceneID="xIg-PA-7r3">
+ <objects>
+ <tableViewController id="7q0-lI-zqb" customClass="MBXDownloadsTableViewController" sceneMemberID="viewController">
+ <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="eeN-6b-zqe">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+ <prototypes>
+ <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Inactive" editingAccessoryType="detailDisclosureButton" textLabel="JtH-Ce-MI5" detailTextLabel="tTJ-jv-U9v" style="IBUITableViewCellStyleSubtitle" id="fGu-Ys-Eh1">
+ <rect key="frame" x="0.0" y="92" width="600" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="fGu-Ys-Eh1" id="sUf-bc-8xG">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Inactive Download" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="JtH-Ce-MI5">
+ <rect key="frame" x="15" y="6" width="159" height="19.5"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <fontDescription key="fontDescription" type="system" pointSize="16"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="456 resources (789 MB)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="tTJ-jv-U9v">
+ <rect key="frame" x="15" y="25.5" width="128" height="13.5"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <fontDescription key="fontDescription" type="system" pointSize="11"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ </tableViewCellContentView>
+ </tableViewCell>
+ <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="Active" editingAccessoryType="detailDisclosureButton" textLabel="9ZK-gS-wJ4" detailTextLabel="0xK-p8-Mmh" style="IBUITableViewCellStyleSubtitle" id="mKB-tz-Zfl">
+ <rect key="frame" x="0.0" y="136" width="600" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="mKB-tz-Zfl" id="nS3-aU-nBr">
+ <rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="My Active Download" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9ZK-gS-wJ4">
+ <rect key="frame" x="15" y="6" width="147.5" height="19.5"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <fontDescription key="fontDescription" type="system" pointSize="16"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Downloading 123 of 456 resources… (789 MB downloaded)" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="0xK-p8-Mmh">
+ <rect key="frame" x="15" y="25.5" width="310.5" height="13.5"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <fontDescription key="fontDescription" type="system" pointSize="11"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ </tableViewCellContentView>
+ </tableViewCell>
+ </prototypes>
+ <connections>
+ <outlet property="dataSource" destination="7q0-lI-zqb" id="oe8-d5-Rjo"/>
+ <outlet property="delegate" destination="7q0-lI-zqb" id="D5X-oy-DSc"/>
+ </connections>
+ </tableView>
+ <navigationItem key="navigationItem" title="Downloads" id="UcK-PK-eQA">
+ <barButtonItem key="rightBarButtonItem" systemItem="add" id="gCV-hl-Mzc">
+ <connections>
+ <action selector="addCurrentRegion:" destination="7q0-lI-zqb" id="G2O-3V-aEA"/>
+ </connections>
+ </barButtonItem>
+ </navigationItem>
+ </tableViewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="Dga-Vh-IxZ" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="2075" y="350"/>
+ </scene>
<!--Navigation Controller-->
<scene sceneID="LFg-oU-zTK">
<objects>
diff --git a/platform/ios/app/mapboxgl-app.gypi b/platform/ios/app/mapboxgl-app.gypi
index 21941e309d..fd10a685d9 100644
--- a/platform/ios/app/mapboxgl-app.gypi
+++ b/platform/ios/app/mapboxgl-app.gypi
@@ -29,6 +29,8 @@
'MBXAppDelegate.m',
'MBXCustomCalloutView.h',
'MBXCustomCalloutView.m',
+ 'MBXDownloadsTableViewController.h',
+ 'MBXDownloadsTableViewController.m',
'MBXViewController.h',
'MBXViewController.mm',
],