Skip to content

Commit 51886b0

Browse files
authored
Refactor the MapTiler configuration into a single place. (#3944)
* Refactor the MapTiler configuration into a single place. * Merge the MapAssets catalog into the normal one.
1 parent e0edafc commit 51886b0

31 files changed

+190
-220
lines changed

ElementX.xcodeproj/project.pbxproj

Lines changed: 12 additions & 36 deletions
Large diffs are not rendered by default.

ElementX/Sources/Application/AppSettings.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ final class AppSettings {
9797
copyrightURL: URL,
9898
acceptableUseURL: URL,
9999
privacyURL: URL,
100-
supportEmailAddress: String) {
100+
supportEmailAddress: String,
101+
mapTilerConfiguration: MapTilerConfiguration) {
101102
self.defaultHomeserverAddress = defaultHomeserverAddress
102103
self.oidcRedirectURL = oidcRedirectURL
103104
self.websiteURL = websiteURL
@@ -106,6 +107,7 @@ final class AppSettings {
106107
self.acceptableUseURL = acceptableUseURL
107108
self.privacyURL = privacyURL
108109
self.supportEmailAddress = supportEmailAddress
110+
self.mapTilerConfiguration = mapTilerConfiguration
109111
}
110112

111113
// MARK: - Application
@@ -290,10 +292,10 @@ final class AppSettings {
290292
// MARK: - Maps
291293

292294
// maptiler base url
293-
let mapTilerBaseURL: URL = "https://api.maptiler.com/maps"
294-
295-
// maptiler api key
296-
let mapTilerApiKey = Secrets.mapLibreAPIKey
295+
private(set) var mapTilerConfiguration = MapTilerConfiguration(baseURL: "https://api.maptiler.com/maps",
296+
apiKey: Secrets.mapLibreAPIKey,
297+
lightStyleID: "9bc819c8-e627-474a-a348-ec144fe3d810",
298+
darkStyleID: "dea61faf-292b-4774-9660-58fcef89a7f3")
297299

298300
// MARK: - Presence
299301

ElementX/Sources/FlowCoordinators/PinnedEventsTimelineFlowCoordinator.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
2121
private let timelineControllerFactory: TimelineControllerFactoryProtocol
2222
private let roomProxy: JoinedRoomProxyProtocol
2323
private let userIndicatorController: UserIndicatorControllerProtocol
24+
private let appSettings: AppSettings
2425
private let appMediator: AppMediatorProtocol
2526
private let emojiProvider: EmojiProviderProtocol
2627

@@ -36,13 +37,15 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
3637
timelineControllerFactory: TimelineControllerFactoryProtocol,
3738
roomProxy: JoinedRoomProxyProtocol,
3839
userIndicatorController: UserIndicatorControllerProtocol,
40+
appSettings: AppSettings,
3941
appMediator: AppMediatorProtocol,
4042
emojiProvider: EmojiProviderProtocol) {
4143
self.navigationStackCoordinator = navigationStackCoordinator
4244
self.userSession = userSession
4345
self.timelineControllerFactory = timelineControllerFactory
4446
self.roomProxy = roomProxy
4547
self.userIndicatorController = userIndicatorController
48+
self.appSettings = appSettings
4649
self.appMediator = appMediator
4750
self.emojiProvider = emojiProvider
4851
}
@@ -106,7 +109,9 @@ class PinnedEventsTimelineFlowCoordinator: FlowCoordinatorProtocol {
106109
private func presentMapNavigator(geoURI: GeoURI, description: String?) {
107110
let stackCoordinator = NavigationStackCoordinator()
108111

109-
let params = StaticLocationScreenCoordinatorParameters(interactionMode: .viewOnly(geoURI: geoURI, description: description), appMediator: appMediator)
112+
let params = StaticLocationScreenCoordinatorParameters(interactionMode: .viewOnly(geoURI: geoURI, description: description),
113+
mapURLBuilder: appSettings.mapTilerConfiguration,
114+
appMediator: appMediator)
110115
let coordinator = StaticLocationScreenCoordinator(parameters: params)
111116

112117
coordinator.actions.sink { [weak self] action in

ElementX/Sources/FlowCoordinators/RoomFlowCoordinator.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,9 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
10761076
private func presentMapNavigator(interactionMode: StaticLocationInteractionMode) {
10771077
let stackCoordinator = NavigationStackCoordinator()
10781078

1079-
let params = StaticLocationScreenCoordinatorParameters(interactionMode: interactionMode, appMediator: appMediator)
1079+
let params = StaticLocationScreenCoordinatorParameters(interactionMode: interactionMode,
1080+
mapURLBuilder: appSettings.mapTilerConfiguration,
1081+
appMediator: appMediator)
10801082
let coordinator = StaticLocationScreenCoordinator(parameters: params)
10811083

10821084
coordinator.actions.sink { [weak self] action in
@@ -1563,6 +1565,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
15631565
timelineControllerFactory: timelineControllerFactory,
15641566
roomProxy: roomProxy,
15651567
userIndicatorController: userIndicatorController,
1568+
appSettings: appSettings,
15661569
appMediator: appMediator,
15671570
emojiProvider: emojiProvider)
15681571

ElementX/Sources/Generated/Assets.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ internal enum Asset {
3737
internal static let stopRecording = ImageAsset(name: "images/stop-recording")
3838
internal static let launchBackground = ImageAsset(name: "images/launch-background")
3939
internal static let locationMarkerShape = ImageAsset(name: "images/location-marker-shape")
40+
internal static let mapBlurred = ImageAsset(name: "images/mapBlurred")
4041
internal static let mediaPause = ImageAsset(name: "images/media-pause")
4142
internal static let mediaPlay = ImageAsset(name: "images/media-play")
4243
internal static let notificationsPromptGraphic = ImageAsset(name: "images/notifications-prompt-graphic")

ElementX/Sources/Other/Extensions/MapTiler.swift

Lines changed: 0 additions & 14 deletions
This file was deleted.

ElementX/Sources/Other/MapLibre/MapAssets.xcassets/Contents.json

Lines changed: 0 additions & 6 deletions
This file was deleted.

ElementX/Sources/Other/MapLibre/MapLibreMapView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct MapLibreMapView: UIViewRepresentable {
3434

3535
@Environment(\.colorScheme) private var colorScheme
3636

37-
let builder: MapTilerStyleBuilderProtocol
37+
let mapURLBuilder: MapTilerURLBuilderProtocol
3838

3939
let options: Options
4040

@@ -64,7 +64,7 @@ struct MapLibreMapView: UIViewRepresentable {
6464
// Don't set the same value twice. Otherwise, if there is an error loading the map, a loop
6565
// is caused as the `error` binding being set, which triggers this update, which sets a
6666
// new URL, which causes another error, and so it goes on round and round in a circle.
67-
let dynamicMapURL = builder.dynamicMapURL(for: .init(colorScheme))
67+
let dynamicMapURL = mapURLBuilder.dynamicMapURL(for: .init(colorScheme))
6868
if mapView.styleURL != dynamicMapURL {
6969
mapView.styleURL = dynamicMapURL
7070
}
@@ -85,7 +85,7 @@ struct MapLibreMapView: UIViewRepresentable {
8585
}
8686

8787
private func makeMapView() -> MGLMapView {
88-
let mapView = MGLMapView(frame: .zero, styleURL: colorScheme == .dark ? builder.dynamicMapURL(for: .dark) : builder.dynamicMapURL(for: .light))
88+
let mapView = MGLMapView(frame: .zero, styleURL: mapURLBuilder.dynamicMapURL(for: colorScheme == .dark ? .dark : .light))
8989
mapView.logoViewPosition = .topLeft
9090
mapView.attributionButtonPosition = .topLeft
9191
mapView.attributionButtonMargins = .init(x: mapView.logoView.frame.maxX + 8, y: mapView.logoView.center.y / 2)

ElementX/Sources/Other/MapLibre/MapLibreModels.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ enum MapLibreError: Error {
2424
case failedLocatingUser
2525
}
2626

27+
/// The style to show a map in.
28+
///
29+
/// There can be any number of styles, we have defined one for light and another for dark.
30+
enum MapTilerStyle {
31+
case light
32+
case dark
33+
}
34+
2735
enum MapTilerAttributionPlacement: String {
2836
case bottomRight = "bottomright"
2937
case bottomLeft = "bottomleft"

ElementX/Sources/Other/MapLibre/MapLibreStaticMapView.swift

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import SwiftUI
1111
struct MapLibreStaticMapView<PinAnnotation: View>: View {
1212
private let coordinates: CLLocationCoordinate2D
1313
private let zoomLevel: Double
14-
private let mapTilerStatic: MapTilerStaticMapProtocol
14+
private let mapURLBuilder: MapTilerURLBuilderProtocol
1515
private let mapTilerAttributionPlacement: MapTilerAttributionPlacement
1616
private let mapSize: CGSize
1717
private let pinAnnotationView: PinAnnotation
@@ -22,24 +22,24 @@ struct MapLibreStaticMapView<PinAnnotation: View>: View {
2222
init(coordinates: CLLocationCoordinate2D,
2323
zoomLevel: Double,
2424
attributionPlacement: MapTilerAttributionPlacement,
25-
mapTilerStatic: MapTilerStaticMapProtocol,
25+
mapURLBuilder: MapTilerURLBuilderProtocol,
2626
mapSize: CGSize,
2727
@ViewBuilder pinAnnotationView: () -> PinAnnotation) {
2828
self.coordinates = coordinates
2929
self.zoomLevel = zoomLevel
30-
self.mapTilerStatic = mapTilerStatic
30+
self.mapURLBuilder = mapURLBuilder
3131
mapTilerAttributionPlacement = attributionPlacement
3232
self.mapSize = mapSize
3333
self.pinAnnotationView = pinAnnotationView()
3434
}
3535

3636
var body: some View {
3737
GeometryReader { geometry in
38-
if let url = mapTilerStatic.staticMapURL(for: colorScheme.mapStyle,
39-
coordinates: coordinates,
40-
zoomLevel: zoomLevel,
41-
size: mapSize, // temporary using a fixed size since the refresh doesn't work properly on the UITableView based timeline
42-
attribution: mapTilerAttributionPlacement) {
38+
if let url = mapURLBuilder.staticMapURL(for: colorScheme.mapStyle,
39+
coordinates: coordinates,
40+
zoomLevel: zoomLevel,
41+
size: mapSize, // temporary using a fixed size since the refresh doesn't work properly on the UITableView based timeline
42+
attribution: mapTilerAttributionPlacement) {
4343
AsyncImage(url: url) { phase in
4444
switch phase {
4545
case .empty:
@@ -66,7 +66,7 @@ struct MapLibreStaticMapView<PinAnnotation: View>: View {
6666
}
6767

6868
private var placeholderImage: some View {
69-
Image("mapBlurred")
69+
Image(asset: Asset.Images.mapBlurred)
7070
.resizable()
7171
.scaledToFill()
7272
}
@@ -104,15 +104,22 @@ struct MapLibreStaticMapView_Previews: PreviewProvider, TestablePreview {
104104
MapLibreStaticMapView(coordinates: CLLocationCoordinate2D(),
105105
zoomLevel: 15,
106106
attributionPlacement: .bottomLeft,
107-
mapTilerStatic: MapTilerStaticMapMock(), mapSize: .init(width: 300, height: 200)) {
107+
mapURLBuilder: MapTilerURLBuilderMock(),
108+
mapSize: .init(width: 300, height: 200)) {
108109
Image(systemName: "mappin.circle.fill")
109110
.padding(.bottom, 35)
110111
}
111112
}
112113
}
113114

114-
private struct MapTilerStaticMapMock: MapTilerStaticMapProtocol {
115-
func staticMapURL(for style: MapTilerStyle, coordinates: CLLocationCoordinate2D, zoomLevel: Double, size: CGSize, attribution: MapTilerAttributionPlacement) -> URL? {
115+
private struct MapTilerURLBuilderMock: MapTilerURLBuilderProtocol {
116+
func dynamicMapURL(for style: MapTilerStyle) -> URL? { nil }
117+
118+
func staticMapURL(for style: MapTilerStyle,
119+
coordinates: CLLocationCoordinate2D,
120+
zoomLevel: Double,
121+
size: CGSize,
122+
attribution: MapTilerAttributionPlacement) -> URL? {
116123
switch style {
117124
case .light:
118125
return URL(string: "https://www.maptiler.com/img/cloud/home/map5.webp")

ElementX/Sources/Other/MapLibre/MapTilerAuthorization.swift

Lines changed: 0 additions & 20 deletions
This file was deleted.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// Copyright 2023, 2024 New Vector Ltd.
3+
//
4+
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5+
// Please see LICENSE files in the repository root for full details.
6+
//
7+
8+
import CoreLocation
9+
10+
/// All of the configuration necessary to use MapTiler maps.
11+
///
12+
/// The style IDs need to be generated with the account that the API key belongs to. For more information read
13+
/// [FORKING.md](https://github.com/element-hq/element-x-ios/blob/develop/docs/FORKING.md#setup-the-location-sharing)
14+
struct MapTilerConfiguration {
15+
let baseURL: URL
16+
let apiKey: String
17+
/// A MapLibre style ID for a light-mode map.
18+
let lightStyleID: String
19+
/// A MapLibre style ID for a dark-mode map.
20+
let darkStyleID: String
21+
}
22+
23+
extension MapTilerConfiguration: MapTilerURLBuilderProtocol {
24+
func dynamicMapURL(for style: MapTilerStyle) -> URL? {
25+
var url = makeNewURL(for: style)
26+
url.appendPathComponent("style.json", conformingTo: .json)
27+
return url
28+
}
29+
30+
func staticMapURL(for style: MapTilerStyle,
31+
coordinates: CLLocationCoordinate2D,
32+
zoomLevel: Double,
33+
size: CGSize,
34+
attribution: MapTilerAttributionPlacement) -> URL? {
35+
var url = makeNewURL(for: style)
36+
url.appendPathComponent(String(format: "static/%f,%f,%f/%dx%d@2x.png",
37+
coordinates.longitude,
38+
coordinates.latitude,
39+
zoomLevel,
40+
Int(size.width),
41+
Int(size.height)),
42+
conformingTo: .png)
43+
url.append(queryItems: [.init(name: "attribution", value: attribution.rawValue)])
44+
return url
45+
}
46+
47+
// MARK: Private
48+
49+
private func makeNewURL(for style: MapTilerStyle) -> URL {
50+
var url: URL = baseURL
51+
url.appendPathComponent(styleID(for: style), conformingTo: .item)
52+
url.append(queryItems: [URLQueryItem(name: "key", value: apiKey)])
53+
return url
54+
}
55+
56+
private func styleID(for style: MapTilerStyle) -> String {
57+
switch style {
58+
case .light: lightStyleID
59+
case .dark: darkStyleID
60+
}
61+
}
62+
}

ElementX/Sources/Other/MapLibre/MapTilerStaticMap.swift

Lines changed: 0 additions & 27 deletions
This file was deleted.

ElementX/Sources/Other/MapLibre/MapTilerStyle.swift

Lines changed: 0 additions & 14 deletions
This file was deleted.

ElementX/Sources/Other/MapLibre/MapTilerStyleBuilder.swift

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)