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

Visual Instruction Presentation Customization #1530

Merged
merged 8 commits into from
Jul 5, 2018

Conversation

JThramer
Copy link
Contributor

@JThramer JThramer commented Jun 29, 2018

Implements #1503.

  • Adding delegate method to customize attributed string that is computed by InstructionPresenter.

To-do:

  • Add tests
  • Add example

/cc @mapbox/navigation-ios

@@ -538,6 +538,10 @@ extension NavigationViewController: RouteMapViewControllerDelegate {
}
return roadName
}

@objc public func label(_ label: InstructionLabel, willPresent instruction: VisualInstruction, as presented: NSAttributedString) -> NSAttributedString? {
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious, why does NavigationViewController need to implement the delegate method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is just plumbing the delegate method through the view-controller hierarchy, just like we do here for a NavigationMapViewDelegate method or here for the same method (label(_:willPresent:as:)), being routed through RouteMapViewController.

It's not really accurate to say that the NavigationViewController is implementing the delegate method so much as it's merely passing the message onto its delegate.

@JThramer JThramer added ⚠️ DO NOT MERGE PR should not be merged! wip labels Jun 29, 2018
@JThramer
Copy link
Contributor Author

JThramer commented Jun 29, 2018

Demonstrative screenshot, where in the delegate method, I implemented logic to reverse the presented strings:
simulator screen shot - iphone 8 plus - 2018-06-28 at 15 38 55

- parameter presented: the formatted string that is provided by the instruction presenter
- returns: optionally, a customized NSAttributedString that will be presented instead of the default, or if nil, the default behavior will be used.
*/
@objc optional func label(_ label: InstructionLabel, willPresent instruction: VisualInstruction, as presented: NSAttributedString) -> NSAttributedString?
Copy link
Contributor

Choose a reason for hiding this comment

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

A delegate method’s first argument should always be the delegator. Is the delegator an InstructionLabel, or something else? Can it be either or two classes? That would be an antipattern in Cocoa.

Does this “will” method’s name make the implementation’s purpose clear enough? Is it clear that it’s an opportunity to override the presentation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To answer your first question, yes, the label is the delegator.

- parameter presented: the formatted string that is provided by the instruction presenter
- returns: optionally, a customized NSAttributedString that will be presented instead of the default, or if nil, the default behavior will be used.
*/
@objc optional func label(_ label: InstructionLabel, willPresent instruction: VisualInstruction, as presented: NSAttributedString) -> NSAttributedString?
Copy link
Contributor

Choose a reason for hiding this comment

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

The Objective-C signature of this method is currently -label:willPresent:as:. I think it should be -…:willPresentVisualInstruction:label:presentedAttributedString: or somesuch.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, right you are. Good catch. Will fix.

@JThramer JThramer added ✓ ready for review and removed ⚠️ DO NOT MERGE PR should not be merged! labels Jul 3, 2018
// Mark: VisualInstructionDelegate
extension ViewController: VisualInstructionDelegate {
func label(_ label: InstructionLabel, willPresent instruction: VisualInstruction, as presented: NSAttributedString) -> NSAttributedString? {
guard exampleMode == .customInstruction else { return nil }
Copy link
Contributor

Choose a reason for hiding this comment

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

With VoiceController(_:WillSpeak:Instruction:), returning nil omits the voice instruction. I'm guess that's not the case here? In reality, I can't really think of a use case where a developer would want to show nothing though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's kind of the idea. The utility of "I only want to override default behavior under specific circumstances" seems to outweigh the utility of "it's nice to say 'show nothing' via nil instead of NSAttributedString()". In this specific example you could also implement default behavior by returning presented, but I think we should get into the general habit of using a "returning nil means the delegate has no answer to the delegator, and thus default behavior should be used" pattern in our delegation, as otherwise you kind of force the developer to implement logic if they implement the optional delegate function. Not a super great pattern.

@bsudekum
Copy link
Contributor

bsudekum commented Jul 3, 2018

With #1514 coming down the line, can you think of anything that might make this play nicely with the lanes view? Maybe returning nil hides/omits the view? #1530 (comment)

@@ -69,6 +71,16 @@ class InstructionsBannerViewIntegrationTests: XCTestCase {

super.tearDown()
}

func testCustomVisualInstructionDelegate() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Also add a test for returning nil.

Copy link
Contributor Author

@JThramer JThramer Jul 3, 2018

Choose a reason for hiding this comment

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

  • Test for nil response


func testCustomVisualInstructionDelegate() {
let view = instructionsView()
view.instructionDelegate = TextReversingDelegate()
Copy link
Contributor

Choose a reason for hiding this comment

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

instructionDelegate will be deallocated immediately because it's weak. Keep a local ref to TextReversingDelegate(). (×2)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature request. topic: instructions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants