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 support for non-HTML attribution #1163

Merged
merged 10 commits into from
Mar 8, 2022
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Mapbox welcomes participation and contributions from everyone.
* Restore cancellation of animations on single tap. ([#1166](https://github.com/mapbox/mapbox-maps-ios/pull/1166))
* Fix issue where invalid locations could be emitted when setting a custom location provider. ([#1172](https://github.com/mapbox/mapbox-maps-ios/pull/1172))
* Fix crash in Puck2D when location accuracy authorization is reduced. ([#1173](https://github.com/mapbox/mapbox-maps-ios/pull/1173))
* Fix an issue where plain text source attribution was not populated in attribution dialog.([1163](https://github.com/mapbox/mapbox-maps-ios/pull/1163))

## 10.4.0-beta.1 - February 23, 2022

Expand Down
15 changes: 12 additions & 3 deletions Sources/MapboxMaps/Foundation/MapView+Attribution.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@_implementationOnly import MapboxCommon_Private
import UIKit

@available(iOSApplicationExtension, unavailable)
extension MapView: AttributionDialogManagerDelegate {
Expand All @@ -7,9 +8,17 @@ extension MapView: AttributionDialogManagerDelegate {
}

func attributionDialogManager(_ attributionDialogManager: AttributionDialogManager, didTriggerActionFor attribution: Attribution) {
let url: URL = attribution.isFeedbackURL ? mapboxFeedbackURL() : attribution.url
Log.debug(forMessage: "Open url: \(url))", category: "Attribution")
UIApplication.shared.open(url)
switch attribution.kind {
case .actionable(let url):
Log.debug(forMessage: "Open url: \(url))", category: "Attribution")
UIApplication.shared.open(url)
case .feedback:
let url = mapboxFeedbackURL()
Log.debug(forMessage: "Open url: \(url))", category: "Attribution")
UIApplication.shared.open(url)
case .nonActionable:
break
}
}

internal func mapboxFeedbackURL() -> URL {
Expand Down
52 changes: 29 additions & 23 deletions Sources/MapboxMaps/Style/Attribution.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,28 @@ internal struct Attribution: Hashable {
case none
}

static let OSM = "OpenStreetMap"
static let OSMAbbr = "OSM"
static let telemetrySettings = "Telemetry Settings"
static let aboutMapsURL = URL(string: "https://www.mapbox.com/about/maps")!
static let aboutTelemetryURL = URL(string: "https://www.mapbox.com/telemetry")!
enum Kind: Hashable {
case feedback
case actionable(URL)
case nonActionable
}

// Feedback URLs
private static let improveMapURLs = [
"https://www.mapbox.com/feedback/",
"https://www.mapbox.com/map-feedback/",
"https://apps.mapbox.com/feedback/"
]

var title: String
var url: URL
var kind: Kind

var titleAbbreviation: String {
return title == Self.OSM ? Self.OSMAbbr : title
return title == "OpenStreetMap" ? "OSM" : title
}

func snapshotTitle(for style: Style) -> String? {
guard !isFeedbackURL else {
guard kind != .feedback else {
return nil
}

Expand All @@ -38,19 +45,19 @@ internal struct Attribution: Hashable {
}
}

// Feedback URLs as fallback
static let improveMapURLs = [
"https://www.mapbox.com/feedback/",
"https://www.mapbox.com/map-feedback/",
"https://apps.mapbox.com/feedback/"
]
internal init(title: String, url: URL?) {
self.title = title

var isFeedbackURL: Bool {
return title.lowercased() == "improve this map" ||
Self.improveMapURLs.contains(url.absoluteString)
}
guard let url = url else {
self.kind = .nonActionable
return
}

let isFeedback = title.lowercased() == "improve this map" ||
Self.improveMapURLs.contains(url.absoluteString)

static let font = UIFont.systemFont(ofSize: UIFont.smallSystemFontSize)
self.kind = isFeedback ? .feedback : .actionable(url)
}

/// Return a combined text for attributions, intended for use with Snapshotters
/// (via AttributionView)
Expand All @@ -69,7 +76,7 @@ internal struct Attribution: Hashable {
let attributionText = "© \(titleArray.joined(separator: " / "))"

let attributes: [NSAttributedString.Key: Any] = [
.font: font,
.font: UIFont.systemFont(ofSize: UIFont.smallSystemFontSize),
.foregroundColor: UIColor(white: 0.2, alpha: 1.0),
]

Expand Down Expand Up @@ -104,8 +111,7 @@ internal struct Attribution: Hashable {
attributedString.enumerateAttribute(.link,
in: NSRange(location: 0, length: attributedString.length),
options: []) { (value: Any?, range: NSRange, _: UnsafeMutablePointer<ObjCBool>) in
guard let url = value as? URL,
range.location != NSNotFound else {
guard range.location != NSNotFound else {
return
}

Expand All @@ -116,7 +122,7 @@ internal struct Attribution: Hashable {
return
}

let attribution = Attribution(title: trimmedString, url: url)
let attribution = Attribution(title: trimmedString, url: value as? URL)

// Disallow duplicates.
if !attributions.contains(attribution) {
Expand Down
16 changes: 12 additions & 4 deletions Sources/MapboxMaps/Style/AttributionDialogManager.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import UIKit
internal protocol AttributionDataSource: AnyObject {
func attributions() -> [Attribution]
}
Expand Down Expand Up @@ -131,11 +132,18 @@ extension AttributionDialogManager: InfoButtonOrnamentDelegate {
let bundle = Bundle.mapboxMaps

if let attributions = dataSource?.attributions() {
for attribution in attributions {
let action = UIAlertAction(title: attribution.title, style: .default) { _ in
self.delegate?.attributionDialogManager(self, didTriggerActionFor: attribution)

// Non actionable single item gets displayed as alert's message
if attributions.count == 1, let attribution = attributions.first, attribution.kind == .nonActionable {
alert.message = attribution.title
} else {
for attribution in attributions {
let action = UIAlertAction(title: attribution.title, style: .default) { _ in
self.delegate?.attributionDialogManager(self, didTriggerActionFor: attribution)
}
macdrevx marked this conversation as resolved.
Show resolved Hide resolved
action.isEnabled = attribution.kind != .nonActionable
alert.addAction(action)
}
alert.addAction(action)
}
}

Expand Down
50 changes: 0 additions & 50 deletions Tests/MapboxMapsTests/Snapshot/AttributionTests.swift

This file was deleted.

Loading