Skip to content

Commit db55afa

Browse files
mapbox-github-ci-writer-5[bot]aleksproger
authored andcommitted
[Backport release/v0.19] Update Android indoor example (#9840)
Backport 9e1cb02532b1d5d56f7214bef053ec060da2b46b from #9819. cc @mapbox/maps-ios cc @mapbox/maps-android Co-authored-by: Aleksei Sapitskii <45671572+aleksproger@users.noreply.github.com> GitOrigin-RevId: d4fc030c0892307abcadd88b22f3c5305fb75afe
1 parent 5dcd913 commit db55afa

6 files changed

Lines changed: 88 additions & 34 deletions

File tree

Sources/Examples/All Examples/Lab/IndoorExample.swift

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,94 @@ import UIKit
44
// EXPERIMENTAL: Not intended for usage in current stata. Subject to change or deletion.
55
final class IndoorExample: UIViewController, ExampleProtocol {
66
private var mapView: MapView!
7-
// Set indoor style. Do not commit staging style URIs.
87
private var styleURI: String?
98
private var cancellables = Set<AnyCancelable>()
9+
private let styleTextField = UITextField()
10+
private let loadStyleButton = UIButton(type: .system)
1011

1112
override func viewDidLoad() {
1213
super.viewDidLoad()
1314

1415
let cameraOptions = CameraOptions(
15-
center: CLLocationCoordinate2D(latitude: 40.6441, longitude: -73.7824),
16+
center: CLLocationCoordinate2D(latitude: 35.5483, longitude: 139.7780),
1617
zoom: 16,
1718
bearing: 12,
1819
pitch: 60)
19-
let options = MapInitOptions(cameraOptions: cameraOptions)
2020

21+
let options = MapInitOptions(cameraOptions: cameraOptions)
2122
mapView = MapView(frame: view.bounds, mapInitOptions: options)
22-
mapView.mapboxMap.styleURI = StyleURI(rawValue: styleURI!)!
2323

24-
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
2524
mapView.ornaments.options.scaleBar.visibility = .visible
26-
// EXPERIMENTAL: Not intended for usage in current stata. Subject to change or deletion.
27-
mapView.mapboxMap.indoor.selectFloor(selectedFloorId: "b937e2aa3423453ab0552d9f")
28-
mapView.mapboxMap.indoor.onIndoorUpdated.sink { indoorState in
29-
print(indoorState)
25+
mapView.ornaments.options.indoorSelector.visibility = .visible
26+
27+
var puckConfiguration = Puck2DConfiguration.makeDefault(showBearing: true)
28+
puckConfiguration.pulsing = nil
29+
mapView.location.options.puckType = .puck2D(puckConfiguration)
30+
31+
mapView.location.onLocationChange.observeNext { [weak mapView] newLocation in
32+
guard let mapView, let location = newLocation.last else { return }
33+
mapView.mapboxMap.setCamera(to: .init(center: location.coordinate, zoom: 18))
3034
}.store(in: &cancellables)
3135

36+
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
37+
38+
mapView.mapboxMap.indoor.onIndoorUpdated.sink { indoorState in
39+
print("Selected floor id: \(indoorState.selectedFloorId)")
40+
}.store(in: &cancellables)
3241
view.addSubview(mapView)
42+
43+
setupStyleInputUI()
44+
}
45+
46+
private func setupStyleInputUI() {
47+
styleTextField.borderStyle = .roundedRect
48+
styleTextField.backgroundColor = .white
49+
styleTextField.autocapitalizationType = .none
50+
styleTextField.autocorrectionType = .no
51+
styleTextField.text = "mapbox://styles/mapbox/standard"
52+
styleTextField.placeholder = "Enter Style URI or JSON"
53+
styleTextField.translatesAutoresizingMaskIntoConstraints = false
54+
55+
loadStyleButton.setTitle("Load Style", for: .normal)
56+
loadStyleButton.backgroundColor = .systemBlue
57+
loadStyleButton.setTitleColor(.white, for: .normal)
58+
loadStyleButton.layer.cornerRadius = 5
59+
loadStyleButton.addTarget(self, action: #selector(loadStyleTapped), for: .touchUpInside)
60+
loadStyleButton.translatesAutoresizingMaskIntoConstraints = false
61+
62+
let stackView = UIStackView(arrangedSubviews: [styleTextField, loadStyleButton])
63+
stackView.axis = .horizontal
64+
stackView.spacing = 8
65+
stackView.translatesAutoresizingMaskIntoConstraints = false
66+
stackView.layoutMargins = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
67+
stackView.isLayoutMarginsRelativeArrangement = true
68+
stackView.backgroundColor = UIColor.white.withAlphaComponent(0.8)
69+
70+
view.addSubview(stackView)
71+
72+
NSLayoutConstraint.activate([
73+
stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
74+
stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
75+
stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
76+
loadStyleButton.widthAnchor.constraint(equalToConstant: 100)
77+
])
78+
}
79+
80+
@objc private func loadStyleTapped() {
81+
guard let text = styleTextField.text, !text.isEmpty else { return }
82+
loadStyle(from: text)
83+
styleTextField.resignFirstResponder()
84+
}
85+
86+
private func loadStyle(from text: String) {
87+
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
88+
if let url = URL(string: trimmed), url.scheme != nil {
89+
if let styleURI = StyleURI(rawValue: trimmed) {
90+
mapView.mapboxMap.styleURI = styleURI
91+
}
92+
} else {
93+
mapView.mapboxMap.styleJSON = trimmed
94+
}
3395
}
3496

3597
override func viewDidAppear(_ animated: Bool) {

Sources/MapboxMaps/Documentation.docc/API Catalogs/Indoor.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
- ``IndoorFloor``
88
- ``IndoorState``
99
- ``IndoorManager``
10+
- ``IndoorSelectorViewOptions``

Sources/MapboxMaps/Ornaments/IndoorSelectorView.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ final class IndoorSelectorView: UIView {
9595
}
9696

9797
private func updateVisibility() {
98-
guard isHidden != model.isHidden else { return }
99-
isHidden = model.isHidden
98+
let newOpacity: Float = model.isHidden ? 0 : 1
99+
guard layer.opacity != newOpacity else { return }
100+
layer.opacity = newOpacity
100101
if !isHidden {
101102
invalidateIntrinsicContentSize()
102103
collectionView.reloadData()
@@ -208,7 +209,7 @@ extension IndoorSelectorView {
208209

209210
isUserInteractionEnabled = true
210211
isExclusiveTouch = true
211-
isHidden = model.isHidden
212+
layer.opacity = model.isHidden ? 0 : 1
212213

213214
addSubview(containerView)
214215
containerView.addSubview(collectionView)

Sources/MapboxMaps/Ornaments/OrnamentOptions.swift

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ public struct OrnamentOptions: Equatable, Sendable {
3535
// MARK: - Indoor Selector
3636

3737
/// The ornament options for the map's indoor selector view.
38-
var indoorSelector: IndoorSelectorViewOptions
38+
@_spi(Experimental)
39+
@_documentation(visibility: public)
40+
public var indoorSelector: IndoorSelectorViewOptions
3941

4042
/// Initializes an `OrnamentOptions`.
4143
/// - Parameters:
@@ -272,33 +274,35 @@ public struct LogoViewOptions: Equatable, Sendable {
272274
}
273275

274276
/// Used to configure position, margin, and visibility for the map's indoor selector view.
275-
struct IndoorSelectorViewOptions: Equatable, Sendable {
277+
@_spi(Experimental)
278+
@_documentation(visibility: public)
279+
public struct IndoorSelectorViewOptions: Equatable, Sendable {
276280

277281
/// The position of the indoor selector view.
278282
///
279283
/// The default value for this property is `.topTrailing`.
280-
var position: OrnamentPosition
284+
public var position: OrnamentPosition
281285

282286
/// The margins of the indoor selector view.
283287
///
284288
/// The default value for this property is `CGPoint(x: 8.0, y: 0.0)`.
285-
var margins: CGPoint
289+
public var margins: CGPoint
286290

287291
/// The visibility of the indoor selector view.
288292
///
289293
/// The default value for this property is `.adaptive`. When set to `.adaptive`,
290294
/// the indoor selector is visible only when indoor floor data is available.
291-
var visibility: OrnamentVisibility
295+
public var visibility: OrnamentVisibility
292296

293297
/// Initializes an `IndoorSelectorViewOptions`.
294298
/// - Parameters:
295299
/// - position: The position of the indoor selector view.
296300
/// - margins: The margins of the indoor selector view.
297301
/// - visibility: The visibility of the indoor selector view.
298-
init(
302+
public init(
299303
position: OrnamentPosition = .topTrailing,
300304
margins: CGPoint = .init(x: 8.0, y: 0.0),
301-
visibility: OrnamentVisibility = .adaptive
305+
visibility: OrnamentVisibility = .hidden
302306
) {
303307
self.position = position
304308
self.margins = margins

Sources/MapboxMaps/Ornaments/OrnamentsManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ public final class OrnamentsManager {
266266
case .hidden:
267267
_indoorSelectorView.isHidden = true
268268
case .adaptive:
269-
break // Adaptive visibility is handled by the IndoorSelectorView itself based on floor data
269+
indoorSelectorView.isHidden = false // Handled by the IndoorSelectorView itself based on floor data and uses opacity
270270
}
271271
}
272272

Tests/MapboxMapsTests/Ornaments/OrnamentManagerTests.swift

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -303,20 +303,6 @@ final class OrnamentManagerTests: XCTestCase {
303303
XCTAssertTrue(indoorSelector.isHidden, "Indoor selector should be hidden initially when model has no floors")
304304
}
305305

306-
func testIndoorSelectorVisibility() throws {
307-
let mockModel = MockIndoorSelectorModel()
308-
let testIndoorSelector = IndoorSelectorView(model: mockModel)
309-
310-
view.addSubview(testIndoorSelector)
311-
312-
XCTAssertTrue(testIndoorSelector.isHidden, "Indoor selector should be hidden when no floors")
313-
314-
mockModel.isHidden = false
315-
mockModel.onVisibilityChanged?()
316-
317-
XCTAssertFalse(testIndoorSelector.isHidden, "Indoor selector should be visible when model is not hidden")
318-
}
319-
320306
func testIndoorSelectorIntrinsicContentSizeUpdates() throws {
321307
let mockModel = MockIndoorSelectorModel()
322308
let testIndoorSelector = IndoorSelectorView(model: mockModel)

0 commit comments

Comments
 (0)