Skip to content

Commit

Permalink
Merge pull request #1272 from mapbox/jerrad/exit-view
Browse files Browse the repository at this point in the history
Adding "Exit View" to Instructions Banner
  • Loading branch information
JThramer authored Apr 19, 2018
2 parents 1ba5939 + c40fd5e commit d7f8c4d
Show file tree
Hide file tree
Showing 54 changed files with 676 additions and 216 deletions.
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ To build this SDK, you need Xcode 9 and [Carthage](https://github.com/Carthage/C

See [the README](./README.md#running-the-example-project) for instructions on building and running the included Swift and Objective-C example projects.

## Testing the SDK

It is important to test the SDK using the `iPhone 8 Plus` simulator for the `FBSnapshotter` tests.

## Opening a pull request

Pull requests are appreciated. If your PR includes any changes that would impact developers or end users, please mention those changes in the “master” section of [CHANGELOG.md](CHANGELOG.md), noting the PR number. Examples of noteworthy changes include new features, fixes for user-visible bugs, renamed or deleted public symbols, and changes that affect bridging to Objective-C.
Expand Down
32 changes: 32 additions & 0 deletions MapboxNavigation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,11 @@
8D24A2F820409A890098CBF8 /* CGSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24A2F720409A890098CBF8 /* CGSize.swift */; };
8D24A2FA20449B430098CBF8 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24A2F920449B430098CBF8 /* Dictionary.swift */; };
8D391CE21FD71E78006BB91F /* Waypoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D391CE11FD71E78006BB91F /* Waypoint.swift */; };
8D53136B20653FA20044891E /* ExitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D53136A20653FA20044891E /* ExitView.swift */; };
8D54F14A206ECF720038736D /* InstructionPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D54F149206ECF720038736D /* InstructionPresenterTests.swift */; };
8D5DFFF1207C04840093765A /* NSAttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D5DFFF0207C04840093765A /* NSAttributedString.swift */; };
8D8EA9BC20575CD80077F478 /* FeedbackCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D8EA9BB20575CD80077F478 /* FeedbackCollectionViewCell.swift */; };
8D9CD7FF20880581004DC4B3 /* XCTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D9CD7FD20880581004DC4B3 /* XCTestCase.swift */; };
8DB45E90201698EB001EA6A3 /* UIStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DB45E8F201698EB001EA6A3 /* UIStackView.swift */; };
8DB63A3A1FBBCA2200928389 /* RatingControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DB63A391FBBCA2200928389 /* RatingControl.swift */; };
8DE879661FBB9980002F06C0 /* EndOfRouteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DE879651FBB9980002F06C0 /* EndOfRouteViewController.swift */; };
Expand Down Expand Up @@ -319,6 +323,13 @@
remoteGlobalIDString = C5ADFBC81DDCC7840011824B;
remoteInfo = MapboxCoreNavigation;
};
8DBCA7772080174600981EB2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C5ADFBC01DDCC7840011824B /* Project object */;
proxyType = 1;
remoteGlobalIDString = 358D14621E5E3B7700ADE590;
remoteInfo = "Example-Swift";
};
C5ADFBD41DDCC7840011824B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C5ADFBC01DDCC7840011824B /* Project object */;
Expand Down Expand Up @@ -544,7 +555,11 @@
8D24A2F720409A890098CBF8 /* CGSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGSize.swift; sourceTree = "<group>"; };
8D24A2F920449B430098CBF8 /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = "<group>"; };
8D391CE11FD71E78006BB91F /* Waypoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Waypoint.swift; sourceTree = "<group>"; };
8D53136A20653FA20044891E /* ExitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExitView.swift; sourceTree = "<group>"; };
8D54F149206ECF720038736D /* InstructionPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstructionPresenterTests.swift; sourceTree = "<group>"; };
8D5DFFF0207C04840093765A /* NSAttributedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAttributedString.swift; sourceTree = "<group>"; };
8D8EA9BB20575CD80077F478 /* FeedbackCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackCollectionViewCell.swift; sourceTree = "<group>"; };
8D9CD7FD20880581004DC4B3 /* XCTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestCase.swift; sourceTree = "<group>"; };
8DB45E8F201698EB001EA6A3 /* UIStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackView.swift; sourceTree = "<group>"; };
8DB63A391FBBCA2200928389 /* RatingControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingControl.swift; sourceTree = "<group>"; };
8DE879651FBB9980002F06C0 /* EndOfRouteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndOfRouteViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -978,10 +993,12 @@
children = (
35B711D31E5E7AD2001EDA8D /* Info.plist */,
160D827A2059973C00D278D6 /* DataCacheTests.swift */,
8D9CD7FD20880581004DC4B3 /* XCTestCase.swift */,
1662244A2029059C00EA4824 /* ImageCacheTests.swift */,
16A509D4202A87B20011D788 /* ImageDownloaderTests.swift */,
166224442025699600EA4824 /* ImageRepositoryTests.swift */,
35DC585C1FABC61100B5A956 /* InstructionsBannerViewIntegrationTests.swift */,
8D54F149206ECF720038736D /* InstructionPresenterTests.swift */,
35A262B82050A5CD00AEFF6D /* InstructionsBannerViewSnapshotTests.swift */,
3510300E1F54B67000E3B7E7 /* LaneTests.swift */,
3540514E1F73F3F300ED572D /* ManeuverViewTests.swift */,
Expand Down Expand Up @@ -1034,6 +1051,7 @@
35D825F91E6A2DBE0088F83B /* MGLMapView+MGLNavigationAdditions.h */,
35D825FA1E6A2DBE0088F83B /* MGLMapView+MGLNavigationAdditions.m */,
C58159001EA6D02700FC6C3D /* MGLVectorSource.swift */,
8D5DFFF0207C04840093765A /* NSAttributedString.swift */,
351BEBF01E5BCC63006FE110 /* UIView.swift */,
8D24A2F720409A890098CBF8 /* CGSize.swift */,
8DB45E8F201698EB001EA6A3 /* UIStackView.swift */,
Expand All @@ -1051,6 +1069,7 @@
isa = PBXGroup;
children = (
351BEC091E5BCC72006FE110 /* DashedLineView.swift */,
8D53136A20653FA20044891E /* ExitView.swift */,
351BEC031E5BCC6C006FE110 /* LaneView.swift */,
359A8AEE1FA7B25800BDB486 /* LanesStyleKit.swift */,
351BEBED1E5BCC63006FE110 /* ManeuversStyleKit.swift */,
Expand Down Expand Up @@ -1345,6 +1364,7 @@
dependencies = (
3525449C1E663D2C004C8F1C /* PBXTargetDependency */,
35B711D61E5E7AD2001EDA8D /* PBXTargetDependency */,
8DBCA7782080174600981EB2 /* PBXTargetDependency */,
);
name = MapboxNavigationTests;
productName = MapboxNavigationTests;
Expand Down Expand Up @@ -1446,6 +1466,7 @@
DevelopmentTeam = GJZR2MEM28;
LastSwiftMigration = 0910;
ProvisioningStyle = Automatic;
TestTargetID = 358D14621E5E3B7700ADE590;
};
C5ADFBC81DDCC7840011824B = {
CreatedOnToolsVersion = 8.1;
Expand Down Expand Up @@ -1752,6 +1773,7 @@
8D24A2F62040960C0098CBF8 /* UIEdgeInsets.swift in Sources */,
DADAD82F20350849002E25CA /* MBRouteVoiceController.m in Sources */,
C57491DF1FACC42F006F97BC /* CGPoint.swift in Sources */,
8D53136B20653FA20044891E /* ExitView.swift in Sources */,
C58159011EA6D02700FC6C3D /* MGLVectorSource.swift in Sources */,
351BEC011E5BCC63006FE110 /* ManeuverView.swift in Sources */,
35B1E2951F1FF8EC00A13D32 /* UserCourseView.swift in Sources */,
Expand All @@ -1768,6 +1790,7 @@
351BEC0D1E5BCC72006FE110 /* Bundle.swift in Sources */,
8DF399B21FB257B30034904C /* UIGestureRecognizer.swift in Sources */,
35B7837E1F9547B300291F9A /* Transitioning.swift in Sources */,
8D5DFFF1207C04840093765A /* NSAttributedString.swift in Sources */,
C565168B1FE1E23E00A0AD18 /* MapboxVoiceController.swift in Sources */,
35CF34B11F0A733200C2692E /* UIFont.swift in Sources */,
C51DF8671F38C337006C6A15 /* Date.swift in Sources */,
Expand Down Expand Up @@ -1842,6 +1865,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8D9CD7FF20880581004DC4B3 /* XCTestCase.swift in Sources */,
35DC585D1FABC61100B5A956 /* InstructionsBannerViewIntegrationTests.swift in Sources */,
3502231A205BC94E00E1449A /* Constants.swift in Sources */,
1662244720256C0700EA4824 /* ImageLoadingURLProtocolSpy.swift in Sources */,
Expand All @@ -1850,6 +1874,7 @@
35A262B92050A5CD00AEFF6D /* InstructionsBannerViewSnapshotTests.swift in Sources */,
35F1F5931FD57EFD00F8E502 /* StyleManagerTests.swift in Sources */,
16A509D5202A87B20011D788 /* ImageDownloaderTests.swift in Sources */,
8D54F14A206ECF720038736D /* InstructionPresenterTests.swift in Sources */,
166224452025699600EA4824 /* ImageRepositoryTests.swift in Sources */,
160D827B2059973C00D278D6 /* DataCacheTests.swift in Sources */,
16E3625C201265D600DF0592 /* ImageDownloadOperationSpy.swift in Sources */,
Expand Down Expand Up @@ -1970,6 +1995,11 @@
target = C5ADFBC81DDCC7840011824B /* MapboxCoreNavigation */;
targetProxy = 35CEA3571E5CEBBC009F2255 /* PBXContainerItemProxy */;
};
8DBCA7782080174600981EB2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 358D14621E5E3B7700ADE590 /* Example-Swift */;
targetProxy = 8DBCA7772080174600981EB2 /* PBXContainerItemProxy */;
};
C5ADFBD51DDCC7840011824B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C5ADFBC81DDCC7840011824B /* MapboxCoreNavigation */;
Expand Down Expand Up @@ -2411,6 +2441,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example-Swift.app/Example-Swift";
};
name = Debug;
};
Expand All @@ -2429,6 +2460,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Off;
SWIFT_VERSION = 4.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example-Swift.app/Example-Swift";
};
name = Release;
};
Expand Down
4 changes: 4 additions & 0 deletions MapboxNavigation/CGSize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ extension CGSize: ExpressibleByFloatLiteral {
public init(floatLiteral value: FloatLiteralType) {
self.init(size: value)
}

var aspectRatio: CGFloat {
return width / height
}
}
18 changes: 3 additions & 15 deletions MapboxNavigation/Cache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,8 @@ internal class FileCache {
Stores data in the file cache for the given key, and calls the completion handler when finished.
*/
public func store(_ data: Data, forKey key: String, completion: CompletionHandler?) {
let dispatchCompletion = {
if let completion = completion {
DispatchQueue.main.async {
completion()
}
}
}

guard let fileManager = fileManager else {
dispatchCompletion()
completion?()
return
}

Expand All @@ -75,7 +67,7 @@ internal class FileCache {
} catch {
NSLog("================> Failed to write data to URL \(cacheURL)")
}
dispatchCompletion()
completion?()
}

}
Expand Down Expand Up @@ -113,11 +105,7 @@ internal class FileCache {

self.createCacheDirIfNeeded(cacheURL, fileManager: fileManager)

if let completion = completion {
DispatchQueue.main.async {
completion()
}
}
completion?()
}
}

Expand Down
10 changes: 1 addition & 9 deletions MapboxNavigation/DataCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,7 @@ public class DataCache: NSObject, BimodalDataCache {
public func store(_ data: Data, forKey key: String, toDisk: Bool, completion: CompletionHandler?) {
storeDataInMemoryCache(data, forKey: key)

if toDisk == true {
fileCache.store(data, forKey: key, completion: completion)
} else {
if let completion = completion {
DispatchQueue.main.async {
completion()
}
}
}
toDisk == true ? fileCache.store(data, forKey: key, completion: completion) : completion?()
}

/*
Expand Down
5 changes: 5 additions & 0 deletions MapboxNavigation/DayStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ open class DayStyle: Style {
EndOfRouteStaticLabel.appearance().normalTextColor = #colorLiteral(red: 0.217173934, green: 0.3645851612, blue: 0.489295125, alpha: 1)
EndOfRouteTitleLabel.appearance().normalFont = .systemFont(ofSize: 36.0)
EndOfRouteTitleLabel.appearance().normalTextColor = .black
ExitView.appearance().backgroundColor = .clear
ExitView.appearance().foregroundColor = .black
ExitView.appearance().borderWidth = 1.0
ExitView.appearance().cornerRadius = 5.0
FloatingButton.appearance().backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
FloatingButton.appearance().tintColor = tintColor
InstructionsBannerContentView.appearance().backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
Expand Down Expand Up @@ -181,6 +185,7 @@ open class NightStyle: DayStyle {
EndOfRouteStaticLabel.appearance().alpha = 1.0
EndOfRouteStaticLabel.appearance().textColor = UIColor.white.withAlphaComponent(0.9)
EndOfRouteTitleLabel.appearance().textColor = .white
ExitView.appearance().foregroundColor = .white
FloatingButton.appearance().backgroundColor = backgroundColor
FloatingButton.appearance().tintColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1)
InstructionsBannerContentView.appearance().backgroundColor = backgroundColor
Expand Down
128 changes: 128 additions & 0 deletions MapboxNavigation/ExitView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import UIKit

enum ExitSide: String{
case left, right, other

var exitImage: UIImage {
return self == .left ? ExitView.leftExitImage : ExitView.rightExitImage
}
}

class ExitView: StylableView {
static let leftExitImage = UIImage(named: "exit-left", in: .mapboxNavigation, compatibleWith: nil)!.withRenderingMode(.alwaysTemplate)
static let rightExitImage = UIImage(named: "exit-right", in: .mapboxNavigation, compatibleWith: nil)!.withRenderingMode(.alwaysTemplate)

static let labelFontSizeScaleFactor: CGFloat = 2.0/3.0

@objc dynamic var foregroundColor: UIColor? {
didSet {
layer.borderColor = foregroundColor?.cgColor
imageView.tintColor = foregroundColor
exitNumberLabel.textColor = foregroundColor
setNeedsDisplay()
}
}

var side: ExitSide = .right {
didSet {
populateExitImage()
rebuildConstraints()
}
}

lazy var imageView: UIImageView = {
let view = UIImageView(image: self.side.exitImage)
view.tintColor = foregroundColor
view.translatesAutoresizingMaskIntoConstraints = false
view.contentMode = .scaleAspectFit
return view
}()

lazy var exitNumberLabel: UILabel = {
let label: UILabel = .forAutoLayout()
label.text = exitText
label.textColor = .black
label.font = UIFont.boldSystemFont(ofSize: pointSize * ExitView.labelFontSizeScaleFactor)

return label
}()

var exitText: String? {
didSet {
exitNumberLabel.text = exitText
invalidateIntrinsicContentSize()
}
}
var pointSize: CGFloat {
didSet {
exitNumberLabel.font = exitNumberLabel.font.withSize(pointSize * ExitView.labelFontSizeScaleFactor)
rebuildConstraints()
}
}

convenience init(pointSize: CGFloat, side: ExitSide = .right, text: String) {
self.init(frame: .zero)
self.pointSize = pointSize
self.side = side
self.exitText = text
commonInit()
}

override init(frame: CGRect) {
pointSize = 0.0
super.init(frame: frame)
}

required init?(coder aDecoder: NSCoder) {
pointSize = 0.0
super.init(coder: aDecoder)
commonInit()
}

func rebuildConstraints() {
NSLayoutConstraint.deactivate(self.constraints)
buildConstraints()
}

func commonInit() {
layer.masksToBounds = true

//build view hierarchy
[imageView, exitNumberLabel].forEach(addSubview(_:))
buildConstraints()
}

func populateExitImage() {
imageView.image = self.side.exitImage
}

func buildConstraints() {
let height = heightAnchor.constraint(equalToConstant: pointSize * 1.2)

let imageHeight = imageView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.4)
let imageAspect = imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor, multiplier: imageView.image?.size.aspectRatio ?? 1.0)

let imageCenterY = imageView.centerYAnchor.constraint(equalTo: centerYAnchor)
let labelCenterY = exitNumberLabel.centerYAnchor.constraint(equalTo: centerYAnchor)

let sideConstraints = self.side != .left ? rightExitConstraints() : leftExitConstraints()

let constraints = [height, imageHeight, imageAspect,
imageCenterY, labelCenterY] + sideConstraints

addConstraints(constraints)
}
func rightExitConstraints() -> [NSLayoutConstraint] {
let labelLeading = exitNumberLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8)
let imageLabelSpacing = exitNumberLabel.trailingAnchor.constraint(equalTo: imageView.leadingAnchor, constant: -8)
let imageTrailing = trailingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 8)
return [labelLeading, imageLabelSpacing, imageTrailing]
}

func leftExitConstraints() -> [NSLayoutConstraint] {
let imageLeading = imageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8)
let imageLabelSpacing = imageView.trailingAnchor.constraint(equalTo: exitNumberLabel.leadingAnchor, constant: -8)
let labelTrailing = trailingAnchor.constraint(equalTo: exitNumberLabel.trailingAnchor, constant: 8)
return [imageLeading, imageLabelSpacing, labelTrailing]
}
}
17 changes: 6 additions & 11 deletions MapboxNavigation/ImageCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,13 @@ internal class ImageCache: BimodalImageCache {
*/
public func store(_ image: UIImage, forKey key: String, toDisk: Bool, completion: CompletionHandler?) {
storeImageInMemoryCache(image, forKey: key)

if toDisk == true {
if let data = UIImagePNGRepresentation(image) {
fileCache.store(data, forKey: key, completion: completion)
}
} else {
if let completion = completion {
DispatchQueue.main.async {
completion()
}
}

guard toDisk == true, let data = UIImagePNGRepresentation(image) else {
completion?()
return
}

fileCache.store(data, forKey: key, completion: completion)
}

/*
Expand Down
Loading

0 comments on commit d7f8c4d

Please sign in to comment.