Skip to content

Commit

Permalink
FIX crashing EORVC
Browse files Browse the repository at this point in the history
FIXES #57 - by rewriting EORVC as programmatic VC rather than storyboard.
FIXES #62 - Omitted the "Rate this route" feedback while rewriting the EORVC.

Note this was cherry-picked, and no longer works due to change in #54
  • Loading branch information
michaelkirk committed Jun 27, 2024
1 parent 8164e6f commit 4fd6d77
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 519 deletions.
27 changes: 0 additions & 27 deletions MapboxCoreNavigation/EndOfRouteFeedback.swift

This file was deleted.

6 changes: 0 additions & 6 deletions MapboxNavigation/DayStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,6 @@ open class DayStyle: Style {
PrimaryLabel.appearance(whenContainedInInstancesOf: [InstructionsBannerView.self]).normalTextColor = #colorLiteral(red: 0.09803921569, green: 0.09803921569, blue: 0.09803921569, alpha: 1)
PrimaryLabel.appearance(whenContainedInInstancesOf: [StepInstructionsView.self]).normalTextColor = #colorLiteral(red: 0.09803921569, green: 0.09803921569, blue: 0.09803921569, alpha: 1)
ProgressBar.appearance().barColor = #colorLiteral(red: 0.149, green: 0.239, blue: 0.341, alpha: 1)
RatingControl.appearance().normalColor = #colorLiteral(red: 0.8508961797, green: 0.8510394692, blue: 0.850877285, alpha: 1)
RatingControl.appearance().selectedColor = #colorLiteral(red: 0.1205472574, green: 0.2422055006, blue: 0.3489340544, alpha: 1)
ReportButton.appearance().backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
ReportButton.appearance().textColor = tintColor!
ReportButton.appearance().textFont = UIFont.systemFont(ofSize: 15, weight: .medium).adjustedFont
Expand Down Expand Up @@ -189,8 +187,6 @@ open class NightStyle: DayStyle {
DistanceLabel.appearance(whenContainedInInstancesOf: [StepInstructionsView.self]).valueTextColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1)
DistanceRemainingLabel.appearance().normalTextColor = #colorLiteral(red: 0.7991961837, green: 0.8232284188, blue: 0.8481693864, alpha: 1)
EndOfRouteButton.appearance().textColor = .white
EndOfRouteCommentView.appearance().backgroundColor = #colorLiteral(red: 0.1875049942, green: 0.2981707989, blue: 0.4181857639, alpha: 1)
EndOfRouteCommentView.appearance().normalTextColor = .white
EndOfRouteContentView.appearance().backgroundColor = backgroundColor
EndOfRouteStaticLabel.appearance().alpha = 1.0
EndOfRouteStaticLabel.appearance().textColor = UIColor.white.withAlphaComponent(0.9)
Expand All @@ -216,8 +212,6 @@ open class NightStyle: DayStyle {
PrimaryLabel.appearance(whenContainedInInstancesOf: [InstructionsBannerView.self]).normalTextColor = #colorLiteral(red: 0.9996390939, green: 1, blue: 0.9997561574, alpha: 1)
PrimaryLabel.appearance(whenContainedInInstancesOf: [StepInstructionsView.self]).normalTextColor = #colorLiteral(red: 0.9996390939, green: 1, blue: 0.9997561574, alpha: 1)
ProgressBar.appearance().barColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1)
RatingControl.appearance().normalColor = #colorLiteral(red: 0.149668334, green: 0.1680230035, blue: 0.1472480238, alpha: 1)
RatingControl.appearance().selectedColor = #colorLiteral(red: 0.9803059896, green: 0.9978019022, blue: 1, alpha: 1)
ReportButton.appearance().backgroundColor = backgroundColor
ReportButton.appearance().textColor = #colorLiteral(red: 0.9842069745, green: 0.9843751788, blue: 0.9841964841, alpha: 1)
ResumeButton.appearance().backgroundColor = backgroundColor
Expand Down
219 changes: 78 additions & 141 deletions MapboxNavigation/EndOfRouteViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,43 +23,60 @@ open class EndOfRouteTitleLabel: StylableLabel {}
@objc(MBEndOfRouteStaticLabel)
open class EndOfRouteStaticLabel: StylableLabel {}

/// :nodoc:
@objc(MBEndOfRouteCommentView)
open class EndOfRouteCommentView: StylableTextView {}

/// :nodoc:
@objc(MBEndOfRouteButton)
open class EndOfRouteButton: StylableButton {}

@objc(MBEndOfRouteViewController)
class EndOfRouteViewController: UIViewController {
// MARK: - IBOutlets

@IBOutlet var labelContainer: UIView!
@IBOutlet var staticYouHaveArrived: EndOfRouteStaticLabel!
@IBOutlet var primary: UILabel!
@IBOutlet var endNavigationButton: UIButton!
@IBOutlet var stars: RatingControl!
@IBOutlet var commentView: UITextView!
@IBOutlet var commentViewContainer: UIView!
@IBOutlet var showCommentView: NSLayoutConstraint!
@IBOutlet var hideCommentView: NSLayoutConstraint!
@IBOutlet var ratingCommentsSpacing: NSLayoutConstraint!

// MARK: - Properties

lazy var placeholder: String = NSLocalizedString("END_OF_ROUTE_TITLE", bundle: .mapboxNavigation, value: "How can we improve?", comment: "Comment Placeholder Text")
lazy var endNavigation: String = NSLocalizedString("END_NAVIGATION", bundle: .mapboxNavigation, value: "End Navigation", comment: "End Navigation Button Text")

typealias DismissHandler = (Int, String?) -> Void
var dismissHandler: DismissHandler?
var comment: String?
var rating: Int = 0 {
didSet {
self.rating == 0 ? self.hideComments() : self.showComments()
}
}

lazy var column: UIStackView = {
let spacerView = UIView()
spacerView.setContentHuggingPriority(.defaultLow, for: .vertical)
spacerView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
let column = UIStackView(arrangedSubviews: [self.staticYouHaveArrived, self.primaryLabel, spacerView, self.endNavigationButton])
column.axis = .vertical
column.alignment = .center
column.spacing = 8
column.translatesAutoresizingMaskIntoConstraints = false
return column
}()

lazy var staticYouHaveArrived: EndOfRouteStaticLabel = {
let label = EndOfRouteStaticLabel()
label.text = self.endOfRouteArrivedText
return label
}()

lazy var primaryLabel: EndOfRouteTitleLabel = {
let label = EndOfRouteTitleLabel()
label.numberOfLines = 3
label.adjustsFontSizeToFitWidth = true
return label
}()

lazy var endNavigationButton: EndOfRouteButton = {
let button = EndOfRouteButton(type: .system)
button.setTitle(self.endNavigationText, for: .normal)
button.addTarget(self, action: #selector(self.endNavigationPressed(_:)), for: .touchUpInside)
return button
}()

lazy var endOfRouteArrivedText: String = NSLocalizedString("END_OF_ROUTE_ARRIVED", bundle: .mapboxNavigation, value: "You have arrived", comment: "Title used for arrival")
lazy var endNavigationText: String = NSLocalizedString("END_NAVIGATION", bundle: .mapboxNavigation, value: "End Navigation", comment: "End Navigation Button Text")

let dismissHandler: () -> Void
init(dismissHandler: @escaping () -> Void) {
self.dismissHandler = dismissHandler
super.init(nibName: nil, bundle: nil)
}

@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

open var destination: Waypoint? {
didSet {
guard isViewLoaded else { return }
Expand All @@ -69,137 +86,57 @@ class EndOfRouteViewController: UIViewController {

// MARK: - Lifecycle Methods

override func viewDidLoad() {
super.viewDidLoad()
self.clearInterface()
self.stars.didChangeRating = { [weak self] new in self?.rating = new }
self.setPlaceholderText()
self.styleCommentView()
self.commentViewContainer.alpha = 0.0 // setting initial hidden state
override func loadView() {
self.view = EndOfRouteContentView()
self.view.addSubview(self.column)
self.activateLayoutConstraints()
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillDisappear(animated)
view.roundCorners([.topLeft, .topRight])
super.viewWillAppear(animated)
preferredContentSize.height = self.height(for: .normal)
self.updateInterface()
}

// MARK: - IBActions
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// roundCorners needs to be called whenever the bounds change
view.roundCorners([.topLeft, .topRight])
}

@IBAction func endNavigationPressed(_ sender: Any) {
self.dismissView()
// MARK: - Actions

@objc func endNavigationPressed(_ sender: Any) {
self.dismissHandler()
}

// MARK: - Private Functions

private func styleCommentView() {
self.commentView.layer.cornerRadius = 6.0
self.commentView.layer.borderColor = UIColor.lightGray.cgColor
self.commentView.layer.borderWidth = 1.0
self.commentView.textContainerInset = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
}

fileprivate func dismissView() {
let dismissal: () -> Void = { self.dismissHandler?(self.rating, self.comment) }
guard self.commentView.isFirstResponder else { return _ = dismissal() }
self.commentView.resignFirstResponder()
let fireTime = DispatchTime.now() + 0.3 // Not ideal, but works for now
DispatchQueue.main.asyncAfter(deadline: fireTime, execute: dismissal)
}

private func showComments(animated: Bool = true) {
self.showCommentView.isActive = true
self.hideCommentView.isActive = false
self.ratingCommentsSpacing.constant = ConstraintSpacing.closer.rawValue
preferredContentSize.height = self.height(for: .commentShowing)

let animate = {
self.view.layoutIfNeeded()
self.commentViewContainer.alpha = 1.0
self.labelContainer.alpha = 0.0
}

let completion: (Bool) -> Void = { _ in self.labelContainer.isHidden = true }
let noAnimate = { animate(); completion(true) }
if animated {
UIView.animate(withDuration: 0.3, animations: animate, completion: nil)
} else {
noAnimate()
}
}

private func hideComments(animated: Bool = true) {
self.labelContainer.isHidden = false
self.showCommentView.isActive = false
self.hideCommentView.isActive = true
self.ratingCommentsSpacing.constant = ConstraintSpacing.further.rawValue
preferredContentSize.height = self.height(for: .normal)

let animate = {
self.view.layoutIfNeeded()
self.commentViewContainer.alpha = 0.0
self.labelContainer.alpha = 1.0
}

let completion: (Bool) -> Void = { _ in self.commentViewContainer.isHidden = true }
let noAnimation = { animate(); completion(true) }
if animated {
UIView.animate(withDuration: 0.3, animations: animate, completion: nil)
} else { noAnimation() }
}

private func height(for height: ContainerHeight) -> CGFloat {
let window = UIApplication.shared.keyWindow
let bottomMargin = window!.safeAreaInsets.bottom
return height.rawValue + bottomMargin
}

private func updateInterface() {
guard let name = destination?.name?.nonEmptyString else { return self.styleForUnnamedDestination() }
self.primary.text = name
}

private func clearInterface() {
self.primary.text = nil
self.stars.rating = 0
}

private func styleForUnnamedDestination() {
self.staticYouHaveArrived.alpha = 0.0
self.primary.text = NSLocalizedString("END_OF_ROUTE_ARRIVED", bundle: .mapboxNavigation, value: "You have arrived", comment: "Title used for arrival")
}

private func setPlaceholderText() {
self.commentView.text = self.placeholder
}
}

// MARK: - UITextViewDelegate

extension EndOfRouteViewController: UITextViewDelegate {
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
guard text.count == 1, text.rangeOfCharacter(from: CharacterSet.newlines) != nil else { return true }
textView.resignFirstResponder()
return false
}

func textViewDidChange(_ textView: UITextView) {
self.comment = textView.text // Bind data model
}

func textViewDidBeginEditing(_ textView: UITextView) {
if textView.text == self.placeholder {
textView.text = nil
textView.alpha = 1.0
}
textView.becomeFirstResponder()
}

func textViewDidEndEditing(_ textView: UITextView) {
if (textView.text?.isEmpty ?? true) == true {
textView.text = self.placeholder
textView.alpha = 0.9
guard let name = destination?.name?.nonEmptyString else {
self.staticYouHaveArrived.alpha = 0.0
self.primaryLabel.text = self.endOfRouteArrivedText
return
}
self.staticYouHaveArrived.alpha = 1.0
self.primaryLabel.text = name
}

private func activateLayoutConstraints() {
NSLayoutConstraint.activate([
self.column.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
self.column.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -8),
self.column.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
self.column.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
self.endNavigationButton.heightAnchor.constraint(equalToConstant: 60),
self.endNavigationButton.leadingAnchor.constraint(equalTo: self.column.leadingAnchor),
self.endNavigationButton.trailingAnchor.constraint(equalTo: self.column.trailingAnchor)
])
}
}
Loading

0 comments on commit 4fd6d77

Please sign in to comment.