diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 1c37ee8ec..5d5274361 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -258,6 +258,7 @@ 67D6E0700A9C1E676F6231F8 /* Collections in Frameworks */ = {isa = PBXBuildFile; productRef = AD544C0FA48DFFB080920061 /* Collections */; }; 68184EF36396424FE19A727D /* MediaLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AFCE895ECFFA53FEE64D62B /* MediaLoader.swift */; }; 6832733838C57A7D3FE8FEB5 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 78A5A8DE1E2B09C978C7F3B0 /* KeychainAccess */; }; + 6860721DB3091BE08164C132 /* MapAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B48B7AD4908C5C374517B892 /* MapAssets.xcassets */; }; 68AC3C84E2B438036B174E30 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */; }; 69BCBB4FB2DC3D61A28D3FD8 /* TimelineStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */; }; 69C7B956B74BEC3DB88224EA /* NavigationSplitCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78913D6E120D46138E97C107 /* NavigationSplitCoordinatorTests.swift */; }; @@ -305,6 +306,7 @@ 7A71AEF419904209BB8C2833 /* UserAgentBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */; }; 7ABAB3A1D52B86FACF2F74CF /* MapTilerGeoCodingServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23B3FAD8B23C421BC0D1B1E /* MapTilerGeoCodingServiceProtocol.swift */; }; 7AEC56ADEFC5A7198A17412F /* InviteUsersScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADB35E2DB4EFE8E6F3959629 /* InviteUsersScreenUITests.swift */; }; + 7B5DAB915357BE596529BF25 /* MapTilerStaticMapProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20872C3887F835958CE2F1D0 /* MapTilerStaticMapProtocol.swift */; }; 7BB31E67648CF32D2AB5E502 /* RoomScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CE3C90E487B255B735D73C8 /* RoomScreenViewModel.swift */; }; 7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; }; 7C6376192F578E0BA801BFEC /* AnalyticsSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C64A14EE89928207E3B42B /* AnalyticsSettingsScreenModels.swift */; }; @@ -575,6 +577,7 @@ D55AF9B5B55FEED04771A461 /* RoomFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A008E57D52B07B78DFAD1BB /* RoomFlowCoordinator.swift */; }; D5C805F49B2C75DC3793E780 /* EmojiItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37A243E04B58DC6E41FDCD82 /* EmojiItem.swift */; }; D5EA4C6C80579279770D5804 /* ImageRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0A45283CF1DB96E583BECA6 /* ImageRoomTimelineView.swift */; }; + D6661A94DBD97658B2ADBD6A /* MapTilerStaticMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */; }; D7CDBAE82782BD0529DECB5F /* AttributedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52BD6ED18E2EB61E28C340AD /* AttributedString.swift */; }; D8359F67AF3A83516E9083C1 /* MockUserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4756C5A8C8649AD6C10C615 /* MockUserSession.swift */; }; D85D4FA590305180B4A41795 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB3073CCD77D906B330BC1D6 /* Tests.swift */; }; @@ -601,6 +604,7 @@ E27C4D1A1F8BB77CA790B403 /* InviteUsersScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */; }; E290C78E7F09F47FD2662986 /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = A40C19719687984FD9478FBE /* Task.swift */; }; E2DB696117BAEABAD5718023 /* MediaSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49B9785E3AD7D1C15A29F2F /* MediaSourceProxy.swift */; }; + E2DDA49BD62F03F180A42E30 /* MapLibreStaticMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 592A35163B0749C66BFD6186 /* MapLibreStaticMapView.swift */; }; E313BDD2B8813144139B2E00 /* UserDiscoveryServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0287793F11C480E242B03DF5 /* UserDiscoveryServiceTest.swift */; }; E3291AD16D7A5CB14781819C /* UserNotificationCenterProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D8149FDDA0315CDC553B4B /* UserNotificationCenterProtocol.swift */; }; E3CA565A4B9704F191B191F0 /* JoinedRoomSize+MemberCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF9AEA706926DD0DA2B954C /* JoinedRoomSize+MemberCount.swift */; }; @@ -801,6 +805,7 @@ 196004E7695FBA292A7944AF /* ScreenTrackerViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenTrackerViewModifier.swift; sourceTree = ""; }; 1A02406480C351B8C6E0682C /* MediaLoaderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaLoaderProtocol.swift; sourceTree = ""; }; 1A18F6CE4D694D21E4EA9B25 /* Strings+Untranslated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Strings+Untranslated.swift"; sourceTree = ""; }; + 1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerStaticMap.swift; sourceTree = ""; }; 1ABDE6F66532CBEB0E016F94 /* RoomProxyMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomProxyMock.swift; sourceTree = ""; }; 1B1EE0908B2BF9212436AD3E /* SessionVerificationScreenStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenStateMachine.swift; sourceTree = ""; }; 1B6E30BB748F3F480F077969 /* RoomMemberDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMemberDetailsScreenModels.swift; sourceTree = ""; }; @@ -814,6 +819,7 @@ 1F2529D434C750ED78ADF1ED /* UserAgentBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentBuilder.swift; sourceTree = ""; }; 1FD51B4D5173F7FC886F5360 /* NoticeRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineItemContent.swift; sourceTree = ""; }; 201305507D7DFD16E544563A /* EmojiLoaderProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiLoaderProtocol.swift; sourceTree = ""; }; + 20872C3887F835958CE2F1D0 /* MapTilerStaticMapProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapTilerStaticMapProtocol.swift; sourceTree = ""; }; 2141693488CE5446BB391964 /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = ""; }; 216F0DDC98F2A2C162D09C28 /* FileRoomTimelineItemContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileRoomTimelineItemContent.swift; sourceTree = ""; }; 218AB05B4E3889731959C5F1 /* EventBasedTimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventBasedTimelineItemProtocol.swift; sourceTree = ""; }; @@ -950,6 +956,7 @@ 57F95CADD0A5DBD76B990FCB /* ServiceLocator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceLocator.swift; sourceTree = ""; }; 584A61D9C459FAFEF038A7C0 /* Section.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Section.swift; sourceTree = ""; }; 58C2527813FDAE23E72A9063 /* AnalyticsSettingsScreenViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSettingsScreenViewModelTests.swift; sourceTree = ""; }; + 592A35163B0749C66BFD6186 /* MapLibreStaticMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLibreStaticMapView.swift; sourceTree = ""; }; 5AEA0B743847CFA5B3C38EE4 /* RoomMembersListScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenCoordinator.swift; sourceTree = ""; }; 5B8F0ED874DF8C9A51B0AB6F /* SettingsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreenCoordinator.swift; sourceTree = ""; }; 5C7C7CFA6B2A62A685FF6CE3 /* DeveloperOptionsScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeveloperOptionsScreenCoordinator.swift; sourceTree = ""; }; @@ -1161,6 +1168,7 @@ B3005886F00029F058DB62BE /* StartChatScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreenCoordinator.swift; sourceTree = ""; }; B383DCD3DCB19E00FD478A5F /* ConfirmationDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialog.swift; sourceTree = ""; }; B43456E73F8A2D52B69B9FB9 /* TemplateScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateScreenViewModel.swift; sourceTree = ""; }; + B48B7AD4908C5C374517B892 /* MapAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = MapAssets.xcassets; sourceTree = ""; }; B590BD4507D4F0A377FDE01A /* LoadableAvatarImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadableAvatarImage.swift; sourceTree = ""; }; B5B243E7818E5E9F6A4EDC7A /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = ""; }; B61C339A2FDDBD067FF6635C /* ConfettiScene.scn */ = {isa = PBXFileReference; path = ConfettiScene.scn; sourceTree = ""; }; @@ -2978,11 +2986,15 @@ isa = PBXGroup; children = ( AAD8234D0E9C9B12BF9F240B /* LocationAnnotation.swift */, + B48B7AD4908C5C374517B892 /* MapAssets.xcassets */, 622D09D4ECE759189009AEAF /* MapLibreMapView.swift */, B81B6170DB690013CEB646F4 /* MapLibreModels.swift */, + 592A35163B0749C66BFD6186 /* MapLibreStaticMapView.swift */, E062C1750EFC8627DE4CAB8E /* MapTilerAuthorization.swift */, 33720F7AD25E85E4A84669E8 /* MapTilerGeocoding.swift */, C23B3FAD8B23C421BC0D1B1E /* MapTilerGeoCodingServiceProtocol.swift */, + 1A4D29F2683F5772AC72406F /* MapTilerStaticMap.swift */, + 20872C3887F835958CE2F1D0 /* MapTilerStaticMapProtocol.swift */, B7AE92E7BFF71797BDE1D261 /* MapTilerStyleBuilder.swift */, 225EFCA26877E75CDFE7F48D /* MapTilerStyleBuilderProtocol.swift */, ); @@ -3572,6 +3584,7 @@ AB34401E4E1CAD5D2EC3072B /* LaunchScreen.storyboard in Resources */, 5F5488FBC9CFEB6F433D74A4 /* Localizable.strings in Resources */, 0EA6537A07E2DC882AEA5962 /* Localizable.stringsdict in Resources */, + 6860721DB3091BE08164C132 /* MapAssets.xcassets in Resources */, CE1694C7BB93C3311524EF28 /* Untranslated.strings in Resources */, 2797C9D9BA642370F1C85D78 /* Untranslated.stringsdict in Resources */, CCAA0671B46EAFD0BB528E2C /* apple_emojis_data.json in Resources */, @@ -4033,10 +4046,13 @@ B66757D0254843162595B25D /* MXLogger.swift in Sources */, C1D0AB8222D7BAFC9AF9C8C0 /* MapLibreMapView.swift in Sources */, C9BE065FA7D4E77E4C61CB69 /* MapLibreModels.swift in Sources */, + E2DDA49BD62F03F180A42E30 /* MapLibreStaticMapView.swift in Sources */, D181AC8FF236B7F91C0A8C28 /* MapTiler.swift in Sources */, FCDA202B246F75BA28E10C5F /* MapTilerAuthorization.swift in Sources */, 7ABAB3A1D52B86FACF2F74CF /* MapTilerGeoCodingServiceProtocol.swift in Sources */, 516534FC5C893D57F169D5A8 /* MapTilerGeocoding.swift in Sources */, + D6661A94DBD97658B2ADBD6A /* MapTilerStaticMap.swift in Sources */, + 7B5DAB915357BE596529BF25 /* MapTilerStaticMapProtocol.swift in Sources */, 14343C2F9AD2BFEA92CA28FF /* MapTilerStyleBuilder.swift in Sources */, BEA646DF302711A753F0D420 /* MapTilerStyleBuilderProtocol.swift in Sources */, 67C05C50AD734283374605E3 /* MatrixEntityRegex.swift in Sources */, diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index 5df090eea..cf65cff18 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -173,17 +173,13 @@ final class AppSettings { // MARK: - Maps - // maptiler dynamic map urls - let lightTileMapStyleURL = "https://api.maptiler.com/maps/9bc819c8-e627-474a-a348-ec144fe3d810/style.json" - let darkTileMapStyleURL = "https://api.maptiler.com/maps/dea61faf-292b-4774-9660-58fcef89a7f3/style.json" + // maptiler map urls + let lightTileMapStyleURL = "https://api.maptiler.com/maps/9bc819c8-e627-474a-a348-ec144fe3d810" + let darkTileMapStyleURL = "https://api.maptiler.com/maps/dea61faf-292b-4774-9660-58fcef89a7f3" // maptiler api key let mapTilerApiKey = "fU3vlMsMn4Jb6dnEIFsx" - // maptiler static map urls - let lightTileStaticMapStyleURL = "https://api.maptiler.com/maps/9bc819c8-e627-474a-a348-ec144fe3d810/{z}/{x}/{y}.png" - let darkTileStaticMapStyleURL = "https://api.maptiler.com/maps/dea61faf-292b-4774-9660-58fcef89a7f3/{z}/{x}/{y}.png" - // maptiler geocoding url let geocodingURLFormatString = "https://api.maptiler.com/geocoding/%f,%f.json" diff --git a/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/Contents.json b/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/mapBlurred.imageset/Contents.json b/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/mapBlurred.imageset/Contents.json new file mode 100644 index 000000000..966643e3e --- /dev/null +++ b/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/mapBlurred.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "filename" : "lightMapBlurred.pdf", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "DarkMapBlurred.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/mapBlurred.imageset/DarkMapBlurred.pdf b/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/mapBlurred.imageset/DarkMapBlurred.pdf new file mode 100644 index 000000000..670c5ea60 Binary files /dev/null and b/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/mapBlurred.imageset/DarkMapBlurred.pdf differ diff --git a/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/mapBlurred.imageset/lightMapBlurred.pdf b/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/mapBlurred.imageset/lightMapBlurred.pdf new file mode 100644 index 000000000..d3bef2c2d Binary files /dev/null and b/ElementX/Sources/Other/MapLibre/MapAssets.xcassets/mapBlurred.imageset/lightMapBlurred.pdf differ diff --git a/ElementX/Sources/Other/MapLibre/MapLibreStaticMapView.swift b/ElementX/Sources/Other/MapLibre/MapLibreStaticMapView.swift new file mode 100644 index 000000000..834715449 --- /dev/null +++ b/ElementX/Sources/Other/MapLibre/MapLibreStaticMapView.swift @@ -0,0 +1,115 @@ +// +// Copyright 2023 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import CoreLocation +import SwiftUI + +struct MapLibreStaticMapView: View { + private let coordinates: CLLocationCoordinate2D + private let zoomLevel: Double + private let mapTilerStatic: MapTilerStaticMapProtocol + private let pinAnnotationView: PinAnnotation + @Environment(\.colorScheme) private var colorScheme + @ScaledMetric private var height: CGFloat + @ScaledMetric private var width: CGFloat + @State private var attempt = 0 + + init(coordinates: CLLocationCoordinate2D, zoomLevel: Double, mapTilerStatic: MapTilerStaticMapProtocol, height: CGFloat, width: CGFloat, @ViewBuilder pinAnnotationView: () -> PinAnnotation) { + self.coordinates = coordinates + self.zoomLevel = zoomLevel + self.mapTilerStatic = mapTilerStatic + _height = .init(wrappedValue: height) + _width = .init(wrappedValue: width) + self.pinAnnotationView = pinAnnotationView() + } + + var body: some View { + if let url = mapTilerStatic.staticMapURL(for: colorScheme.mapStyle, coordinates: coordinates, zoomLevel: zoomLevel, size: .init(width: width, height: height)) { + AsyncImage(url: url) { phase in + switch phase { + case .empty: + Image("mapBlurred") + case .success(let image): + ZStack { + image + .resizable() + .aspectRatio(contentMode: .fill) + pinAnnotationView + } + case .failure: + errorView + @unknown default: + EmptyView() + } + } + .id(attempt) + .frame(width: width, height: height) + .clipped() + } else { + Image("mapBlurred") + } + } + + var errorView: some View { + Button { + attempt += 1 + } label: { + ZStack { + Image("mapBlurred") + VStack { + Image(systemName: "arrow.clockwise") + Text(L10n.actionStaticMapLoad) + } + } + } + } +} + +private extension ColorScheme { + var mapStyle: MapTilerStyle { + switch self { + case .light: + return .light + case .dark: + return .dark + @unknown default: + return .light + } + } +} + +struct MapLibreStaticMapView_Previews: PreviewProvider { + static var previews: some View { + MapLibreStaticMapView(coordinates: CLLocationCoordinate2D(), + zoomLevel: 15, + mapTilerStatic: MapTilerStaticMapMock(), + height: 150, width: 300) { + Image(systemName: "mappin.circle.fill") + .padding(.bottom, 35) + } + } +} + +private struct MapTilerStaticMapMock: MapTilerStaticMapProtocol { + func staticMapURL(for style: MapTilerStyle, coordinates: CLLocationCoordinate2D, zoomLevel: Double, size: CGSize) -> URL? { + switch style { + case .light: + return URL(string: "https://www.maptiler.com/img/cloud/home/map5.webp") + case .dark: + return URL(string: "https://www.maptiler.com/img/cloud/home/map6.webp") + } + } +} diff --git a/ElementX/Sources/Other/MapLibre/MapTilerStaticMap.swift b/ElementX/Sources/Other/MapLibre/MapTilerStaticMap.swift new file mode 100644 index 000000000..3a3906928 --- /dev/null +++ b/ElementX/Sources/Other/MapLibre/MapTilerStaticMap.swift @@ -0,0 +1,45 @@ +// +// Copyright 2023 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import CoreLocation + +struct MapTilerStaticMap: MapTilerStaticMapProtocol { + private let lightURL: String + private let darkURL: String + private let key: String + + init(key: String, lightURL: String, darkURL: String) { + self.lightURL = lightURL + self.darkURL = darkURL + self.key = key + } + + func staticMapURL(for style: MapTilerStyle, coordinates: CLLocationCoordinate2D, zoomLevel: Double, size: CGSize) -> URL? { + var path: String + switch style { + case .light: + path = lightURL + case .dark: + path = darkURL + } + + path.append(String(format: "/static/%f,%f,%f/%dx%d@2x.png", coordinates.longitude, coordinates.latitude, zoomLevel, Int(size.width), Int(size.height))) + + guard let url = URL(string: path) else { return nil } + let authorization = MapTilerAuthorization(key: key) + return authorization.authorizeURL(url) + } +} diff --git a/ElementX/Sources/Other/MapLibre/MapTilerStaticMapProtocol.swift b/ElementX/Sources/Other/MapLibre/MapTilerStaticMapProtocol.swift new file mode 100644 index 000000000..ad0010af8 --- /dev/null +++ b/ElementX/Sources/Other/MapLibre/MapTilerStaticMapProtocol.swift @@ -0,0 +1,21 @@ +// +// Copyright 2023 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import CoreLocation + +protocol MapTilerStaticMapProtocol { + func staticMapURL(for style: MapTilerStyle, coordinates: CLLocationCoordinate2D, zoomLevel: Double, size: CGSize) -> URL? +} diff --git a/ElementX/Sources/Other/MapLibre/MapTilerStyleBuilder.swift b/ElementX/Sources/Other/MapLibre/MapTilerStyleBuilder.swift index 760437794..a149fa37e 100644 --- a/ElementX/Sources/Other/MapLibre/MapTilerStyleBuilder.swift +++ b/ElementX/Sources/Other/MapLibre/MapTilerStyleBuilder.swift @@ -17,12 +17,18 @@ import Foundation struct MapTilerStyleBuilder: MapTilerStyleBuilderProtocol { - let lightURL: String - let darkURL: String - let key: String + private let lightURL: String + private let darkURL: String + private let key: String + + init(lightURL: String, darkURL: String, key: String) { + self.lightURL = lightURL + self.darkURL = darkURL + self.key = key + } func dynamicMapURL(for style: MapTilerStyle) -> URL? { - let path: String + var path: String switch style { case .light: path = lightURL @@ -30,6 +36,8 @@ struct MapTilerStyleBuilder: MapTilerStyleBuilderProtocol { path = darkURL } + path.append("/style.json") + guard let url = URL(string: path) else { return nil } let authorization = MapTilerAuthorization(key: key) return authorization.authorizeURL(url) diff --git a/changelog.d/1115.feature b/changelog.d/1115.feature new file mode 100644 index 000000000..c55db0ca0 --- /dev/null +++ b/changelog.d/1115.feature @@ -0,0 +1 @@ +Add static map url builder and static map UI component with placeholder and reload logic \ No newline at end of file