Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LaneView snapshot tests. #3976

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
109 changes: 51 additions & 58 deletions Sources/MapboxNavigation/DayStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -258,14 +258,10 @@ open class DayStyle: Style {
NextInstructionLabel.appearance(for: phoneTraitCollection, whenContainedInInstancesOf: [NextBannerView.self]).textColorHighlighted = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
NextInstructionLabel.appearance(for: phoneTraitCollection, whenContainedInInstancesOf: [NextBannerView.self]).normalFont = UIFont.systemFont(ofSize: 14.0).adjustedFont

LaneView.appearance(for: phoneTraitCollection).primaryColor = .defaultLaneArrowPrimaryCarPlay
LaneView.appearance(for: phoneTraitCollection).secondaryColor = .defaultLaneArrowSecondaryCarPlay
LaneView.appearance(for: phoneTraitCollection).primaryColor = .defaultLaneArrowPrimary
LaneView.appearance(for: phoneTraitCollection).secondaryColor = .defaultLaneArrowSecondary
LaneView.appearance(for: phoneTraitCollection).primaryColorHighlighted = .defaultLaneArrowPrimaryHighlighted
LaneView.appearance(for: phoneTraitCollection).secondaryColorHighlighted = .defaultLaneArrowSecondaryHighlighted
LaneView.appearance(for: phoneTraitCollection, whenContainedInInstancesOf: [LanesView.self]).primaryColor = .defaultLaneArrowPrimary
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to set appearance for cases when LaneView is inside LanesView, because setting appearance for phoneTraitCollection covers this case.

LaneView.appearance(for: phoneTraitCollection, whenContainedInInstancesOf: [LanesView.self]).secondaryColor = .defaultLaneArrowSecondary
LaneView.appearance(for: phoneTraitCollection, whenContainedInInstancesOf: [LanesView.self]).primaryColorHighlighted = .defaultLaneArrowPrimaryHighlighted
LaneView.appearance(for: phoneTraitCollection, whenContainedInInstancesOf: [LanesView.self]).secondaryColorHighlighted = .defaultLaneArrowSecondaryHighlighted

LanesView.appearance(for: phoneTraitCollection).backgroundColor = #colorLiteral(red: 0.968627451, green: 0.968627451, blue: 0.968627451, alpha: 1)

Expand Down Expand Up @@ -355,12 +351,6 @@ open class DayStyle: Style {
SpeedLimitView.appearance(for: carPlayTraitCollection).textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
SpeedLimitView.appearance(for: carPlayTraitCollection).regulatoryBorderColor = #colorLiteral(red: 0.800, green: 0, blue: 0, alpha: 1)

LaneView.appearance(for: carPlayTraitCollection).primaryColor = .defaultLaneArrowPrimaryCarPlay
LaneView.appearance(for: carPlayTraitCollection).secondaryColor = .defaultLaneArrowSecondaryCarPlay

LaneView.appearance(for: carPlayTraitCollection).primaryColorHighlighted = .defaultLaneArrowPrimaryHighlighted
LaneView.appearance(for: carPlayTraitCollection).secondaryColorHighlighted = .defaultLaneArrowSecondaryHighlighted

ManeuverView.appearance(for: carPlayTraitCollection).backgroundColor = .clear
ManeuverView.appearance(for: carPlayTraitCollection).primaryColorHighlighted = .defaultTurnArrowPrimaryHighlighted
ManeuverView.appearance(for: carPlayTraitCollection).secondaryColorHighlighted = .defaultTurnArrowSecondaryHighlighted
Expand All @@ -369,34 +359,27 @@ open class DayStyle: Style {
// `UITraitCollection`, which contains both `UIUserInterfaceIdiom` and `UIUserInterfaceStyle`.
// If not, `UITraitCollection` will only contain `UIUserInterfaceIdiom`.
if #available(iOS 12.0, *) {
let carPlayTraitCollection = UITraitCollection(userInterfaceIdiom: .carPlay)

let carPlayLightTraitCollection = UITraitCollection(traitsFrom: [
carPlayTraitCollection,
UITraitCollection(userInterfaceStyle: .light)
])
setCarPlayInstructionsStyling(for: carPlayLightTraitCollection)
applyCarPlayStyling(for: carPlayLightTraitCollection)

let carPlayDarkTraitCollection = UITraitCollection(traitsFrom: [
carPlayTraitCollection,
UITraitCollection(userInterfaceStyle: .dark)
])
setCarPlayInstructionsStyling(for: carPlayDarkTraitCollection)
applyCarPlayStyling(for: carPlayDarkTraitCollection)
} else {
setDefaultCarPlayInstructionsStyling()
applyDefaultCarPlayStyling()
}
default:
break
}
}

@available(iOS 12.0, *)
func setCarPlayInstructionsStyling(for traitCollection: UITraitCollection?) {
guard let traitCollection = traitCollection,
traitCollection.userInterfaceIdiom == .carPlay else { return }

let carPlayTraitCollection = UITraitCollection(userInterfaceIdiom: .carPlay)

func applyCarPlayStyling(for traitCollection: UITraitCollection) {
// On CarPlay, `ExitView` and `GenericRouteShield` styling depends on `UIUserInterfaceStyle`,
// which was set on CarPlay external screen.
// In case if it was set to `UIUserInterfaceStyle.light` white color will be used, otherwise
Expand All @@ -405,51 +388,55 @@ open class DayStyle: Style {
// property of which returns incorrect value), this property has to be taken from callbacks
// similar to: `UITraitEnvironment.traitCollectionDidChange(_:)`, or by creating `UITraitCollection`
// directly.
let defaultInstructionColor: UIColor

let defaultLaneViewPrimaryColor: UIColor
let defaultLaneViewSecondaryColor: UIColor

let defaultLaneArrowPrimaryHighlightedColor: UIColor
let defaultLaneArrowSecondaryHighlightedColor: UIColor

switch traitCollection.userInterfaceStyle {
case .dark:
let defaultColor = UIColor.white
case .light, .unspecified:
defaultInstructionColor = UIColor.black

let carPlayDarkTraitCollection = UITraitCollection(traitsFrom: [
carPlayTraitCollection,
UITraitCollection(userInterfaceStyle: .dark)
])
defaultLaneViewPrimaryColor = .defaultLaneArrowPrimary
defaultLaneViewSecondaryColor = .defaultLaneArrowSecondary

ExitView.appearance(for: carPlayDarkTraitCollection).backgroundColor = .clear
ExitView.appearance(for: carPlayDarkTraitCollection).borderWidth = 1.0
ExitView.appearance(for: carPlayDarkTraitCollection).cornerRadius = 5.0
ExitView.appearance(for: carPlayDarkTraitCollection).foregroundColor = defaultColor
ExitView.appearance(for: carPlayDarkTraitCollection).borderColor = defaultColor

GenericRouteShield.appearance(for: carPlayDarkTraitCollection).backgroundColor = .clear
GenericRouteShield.appearance(for: carPlayDarkTraitCollection).borderWidth = 1.0
GenericRouteShield.appearance(for: carPlayDarkTraitCollection).cornerRadius = 5.0
GenericRouteShield.appearance(for: carPlayDarkTraitCollection).foregroundColor = defaultColor
GenericRouteShield.appearance(for: carPlayDarkTraitCollection).borderColor = defaultColor
case .light, .unspecified:
let defaultColor = UIColor.black
defaultLaneArrowPrimaryHighlightedColor = .defaultLaneArrowPrimaryHighlighted
defaultLaneArrowSecondaryHighlightedColor = .defaultLaneArrowSecondaryHighlighted
case .dark:
defaultInstructionColor = UIColor.white

let carPlayLightTraitCollection = UITraitCollection(traitsFrom: [
carPlayTraitCollection,
UITraitCollection(userInterfaceStyle: .light)
])
defaultLaneViewPrimaryColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
defaultLaneViewSecondaryColor = #colorLiteral(red: 0.4198532104, green: 0.4398920536, blue: 0.4437610507, alpha: 1)

ExitView.appearance(for: carPlayLightTraitCollection).backgroundColor = .clear
ExitView.appearance(for: carPlayLightTraitCollection).borderWidth = 1.0
ExitView.appearance(for: carPlayLightTraitCollection).cornerRadius = 5.0
ExitView.appearance(for: carPlayLightTraitCollection).foregroundColor = defaultColor
ExitView.appearance(for: carPlayLightTraitCollection).borderColor = defaultColor

GenericRouteShield.appearance(for: carPlayLightTraitCollection).backgroundColor = .clear
GenericRouteShield.appearance(for: carPlayLightTraitCollection).borderWidth = 1.0
GenericRouteShield.appearance(for: carPlayLightTraitCollection).cornerRadius = 5.0
GenericRouteShield.appearance(for: carPlayLightTraitCollection).foregroundColor = defaultColor
GenericRouteShield.appearance(for: carPlayLightTraitCollection).borderColor = defaultColor
defaultLaneArrowPrimaryHighlightedColor = .defaultLaneArrowPrimaryHighlighted
defaultLaneArrowSecondaryHighlightedColor = .defaultLaneArrowSecondaryHighlighted
@unknown default:
fatalError("Unknown userInterfaceStyle.")
}

ExitView.appearance(for: traitCollection).backgroundColor = .clear
ExitView.appearance(for: traitCollection).borderWidth = 1.0
ExitView.appearance(for: traitCollection).cornerRadius = 5.0
ExitView.appearance(for: traitCollection).foregroundColor = defaultInstructionColor
ExitView.appearance(for: traitCollection).borderColor = defaultInstructionColor

GenericRouteShield.appearance(for: traitCollection).backgroundColor = .clear
GenericRouteShield.appearance(for: traitCollection).borderWidth = 1.0
GenericRouteShield.appearance(for: traitCollection).cornerRadius = 5.0
GenericRouteShield.appearance(for: traitCollection).foregroundColor = defaultInstructionColor
GenericRouteShield.appearance(for: traitCollection).borderColor = defaultInstructionColor

LaneView.appearance(for: traitCollection).primaryColor = defaultLaneViewPrimaryColor
LaneView.appearance(for: traitCollection).secondaryColor = defaultLaneViewSecondaryColor

LaneView.appearance(for: traitCollection).primaryColorHighlighted = defaultLaneArrowPrimaryHighlightedColor
LaneView.appearance(for: traitCollection).secondaryColorHighlighted = defaultLaneArrowSecondaryHighlightedColor
}

func setDefaultCarPlayInstructionsStyling() {
func applyDefaultCarPlayStyling() {
let defaultColor = UIColor.black
let carPlayTraitCollection = UITraitCollection(userInterfaceIdiom: .carPlay)

Expand All @@ -458,5 +445,11 @@ open class DayStyle: Style {

GenericRouteShield.appearance(for: carPlayTraitCollection).foregroundColor = defaultColor
GenericRouteShield.appearance(for: carPlayTraitCollection).borderColor = defaultColor

LaneView.appearance(for: carPlayTraitCollection).primaryColor = .defaultLaneArrowPrimary
LaneView.appearance(for: carPlayTraitCollection).secondaryColor = .defaultLaneArrowSecondary

LaneView.appearance(for: carPlayTraitCollection).primaryColorHighlighted = .defaultLaneArrowPrimaryHighlighted
LaneView.appearance(for: carPlayTraitCollection).secondaryColorHighlighted = .defaultLaneArrowSecondaryHighlighted
}
}
59 changes: 49 additions & 10 deletions Sources/MapboxNavigation/LaneView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -336,24 +336,37 @@ extension ManeuverDirection {

/// :nodoc:
open class LaneView: UIView {
Comment on lines 337 to 338
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for documenting all the members of this class! Note that they still won’t show up in jazzy because the class itself is undocumented. I think that’s OK but just FYI.


/**
The direction or directions of travel that the lane is reserved for.
*/
var indications: LaneIndication {
didSet {
setNeedsDisplay()
}
}

/**
Denotes which of the `indications` is applicable to the current route when there is more than one.
*/
var maneuverDirection: ManeuverDirection? {
didSet {
setNeedsDisplay()
}
}

var isValid: Bool = false {
/**
Denotes whether or not the user can use this lane to continue along the current route.
*/
var isUsable: Bool = false {
didSet {
setNeedsDisplay()
}
}

/**
Indicates which side of the road cars and traffic flow.
*/
var drivingSide: DrivingSide = .right {
didSet {
setNeedsDisplay()
Expand All @@ -364,38 +377,60 @@ open class LaneView: UIView {
return bounds.size
}

/**
Color of the maneuver direction (applied only when `LaneView.isUsable` is set to `true`). In case if
`LaneView.showHighlightedColors` is set to `true` this value is not used, `LaneView.primaryColorHighlighted`
is used instead.
*/
@objc public dynamic var primaryColor: UIColor = .defaultLaneArrowPrimary {
didSet {
setNeedsDisplay()
}
}

/**
Color of the directions that the lane is reserved for (except the one that is applicable to the
current route). In case if `LaneView.showHighlightedColors` is set to `true` this value is not used,
`LaneView.secondaryColorHighlighted` is used instead.
*/
@objc public dynamic var secondaryColor: UIColor = .defaultLaneArrowSecondary {
didSet {
setNeedsDisplay()
}
}


/**
Highlighted color of the directions that the lane is reserved for (except the one that is
applicable to the current route).
*/
@objc public dynamic var primaryColorHighlighted: UIColor = .defaultLaneArrowPrimaryHighlighted {
didSet {
setNeedsDisplay()
}
}


/**
Highlighted color of the directions that the lane is reserved for (except the one that is applicable
to the current route).
*/
@objc public dynamic var secondaryColorHighlighted: UIColor = .defaultLaneArrowSecondaryHighlighted {
didSet {
setNeedsDisplay()
}
}


/**
Controls whether highighted colors (either `LaneView.primaryColorHighlighted` or
`LaneView.secondaryColorHighlighted`) should be used.
*/
public var showHighlightedColors: Bool = false {
didSet {
setNeedsDisplay()
}
}

var appropriatePrimaryColor: UIColor {
if isValid {
if isUsable {
return showHighlightedColors ? primaryColorHighlighted : primaryColor
} else {
return showHighlightedColors ? secondaryColorHighlighted : secondaryColor
Expand All @@ -408,12 +443,16 @@ open class LaneView: UIView {

static let defaultFrame: CGRect = CGRect(origin: .zero, size: 30.0)

convenience init(indications: LaneIndication, isUsable: Bool, direction: ManeuverDirection?) {
convenience init(indications: LaneIndication,
isUsable: Bool,
direction: ManeuverDirection?,
showHighlightedColors: Bool = false) {
self.init(frame: LaneView.defaultFrame)
backgroundColor = .clear
self.indications = indications
maneuverDirection = direction ?? ManeuverDirection(rawValue: indications.description)
isValid = isUsable
self.isUsable = isUsable
self.showHighlightedColors = showHighlightedColors
}

override init(frame: CGRect) {
Expand All @@ -422,9 +461,9 @@ open class LaneView: UIView {
commonInit()
}

@objc public required init?(coder aDecoder: NSCoder) {
@objc public required init?(coder decoder: NSCoder) {
indications = []
super.init(coder: aDecoder)
super.init(coder: decoder)
commonInit()
}

Expand All @@ -444,7 +483,7 @@ open class LaneView: UIView {
#endif

let resizing = LanesStyleKit.ResizingBehavior.aspectFit
let appropriateColor = isValid ? appropriatePrimaryColor : appropriateSecondaryColor
let appropriateColor = isUsable ? appropriatePrimaryColor : appropriateSecondaryColor
let size = CGSize(width: 32, height: 32)

let isFlipped = indications.dominantSide(maneuverDirection: maneuverDirection, drivingSide: drivingSide) == .left
Expand Down
2 changes: 1 addition & 1 deletion Sources/MapboxNavigation/LanesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ open class LanesView: UIView, NavigationComponent {
}
}

guard !subviews.isEmpty && subviews.contains(where: { $0.isValid }) else {
guard !subviews.isEmpty && subviews.contains(where: { $0.isUsable }) else {
hide(animated: animated,
duration: duration) { completed in
completion?(completed)
Expand Down
8 changes: 6 additions & 2 deletions Sources/MapboxNavigation/NavigationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -880,15 +880,19 @@ extension NavigationViewController: NavigationServiceDelegate {
imageColor = .black
}

if let image = instruction.primaryInstruction.maneuverImage(side: instruction.drivingSide, color: imageColor, size: CGSize(width: 72, height: 72)) {
if let image = instruction.primaryInstruction.maneuverImage(drivingSide: instruction.drivingSide,
color: imageColor,
size: CGSize(width: 72, height: 72)) {
// Bake in any transform required for left turn arrows etc.
let imageData = UIGraphicsImageRenderer(size: image.size).pngData { (context) in
image.draw(at: .zero)
}
let temporaryURL = FileManager.default.temporaryDirectory.appendingPathComponent("com.mapbox.navigation.notification-icon.png")
do {
try imageData.write(to: temporaryURL)
let iconAttachment = try UNNotificationAttachment(identifier: "maneuver", url: temporaryURL, options: [UNNotificationAttachmentOptionsTypeHintKey: kUTTypePNG])
let iconAttachment = try UNNotificationAttachment(identifier: "maneuver",
url: temporaryURL,
options: [UNNotificationAttachmentOptionsTypeHintKey: kUTTypePNG])
content.attachments = [iconAttachment]
} catch {
Log.error("Failed to create UNNotificationAttachment with error: \(error.localizedDescription).",
Expand Down