diff options
author | Minh Nguyễn <mxn@1ec5.org> | 2016-03-03 18:19:23 -0800 |
---|---|---|
committer | Minh Nguyễn <mxn@1ec5.org> | 2016-03-10 17:08:58 -0800 |
commit | 081ee9fbefbdb37f116a5bf2c0383586bce6608a (patch) | |
tree | f8ceae6517ced39b1fd09f79b1f037b76d6a2dde /platform | |
parent | 77657b38969a55377117dfde5fc9d5e3478208d1 (diff) | |
download | qtlocation-mapboxgl-081ee9fbefbdb37f116a5bf2c0383586bce6608a.tar.gz |
[ios] Added download manager to iosapp
Diffstat (limited to 'platform')
-rw-r--r-- | platform/ios/app/MBXDownloadsTableViewController.h | 9 | ||||
-rw-r--r-- | platform/ios/app/MBXDownloadsTableViewController.m | 175 | ||||
-rw-r--r-- | platform/ios/app/MBXViewController.mm | 63 | ||||
-rw-r--r-- | platform/ios/app/Storyboard.storyboard | 93 | ||||
-rw-r--r-- | platform/ios/app/mapboxgl-app.gypi | 2 |
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', ], |