diff --git a/ElementX/Sources/Application/AppSettings.swift b/ElementX/Sources/Application/AppSettings.swift index dbaab85b8..1e06304b0 100644 --- a/ElementX/Sources/Application/AppSettings.swift +++ b/ElementX/Sources/Application/AppSettings.swift @@ -184,8 +184,8 @@ final class AppSettings { // MARK: - Maps // 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" + let lightTileMapStyleURL: URL = "https://api.maptiler.com/maps/9bc819c8-e627-474a-a348-ec144fe3d810" + let darkTileMapStyleURL: URL = "https://api.maptiler.com/maps/dea61faf-292b-4774-9660-58fcef89a7f3" // maptiler api key let mapTilerApiKey = "fU3vlMsMn4Jb6dnEIFsx" diff --git a/ElementX/Sources/Other/MapLibre/MapTilerStaticMap.swift b/ElementX/Sources/Other/MapLibre/MapTilerStaticMap.swift index d06c916b9..3d96a9805 100644 --- a/ElementX/Sources/Other/MapLibre/MapTilerStaticMap.swift +++ b/ElementX/Sources/Other/MapLibre/MapTilerStaticMap.swift @@ -17,28 +17,26 @@ import CoreLocation struct MapTilerStaticMap: MapTilerStaticMapProtocol { - private let lightURL: String - private let darkURL: String + private let lightURL: URL + private let darkURL: URL private let key: String - init(key: String, lightURL: String, darkURL: String) { + init(key: String, lightURL: URL, darkURL: URL) { self.lightURL = lightURL self.darkURL = darkURL self.key = key } func staticMapURL(for style: MapTilerStyle, coordinates: CLLocationCoordinate2D, zoomLevel: Double, size: CGSize, attribution: MapTilerAttributionPlacement) -> URL? { - var path: String + var url: URL switch style { case .light: - path = lightURL + url = lightURL case .dark: - path = darkURL + url = 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 var url = URL(string: path) else { return nil } + + url.appendPathComponent(String(format: "static/%f,%f,%f/%dx%d@2x.png", coordinates.longitude, coordinates.latitude, zoomLevel, Int(size.width), Int(size.height)), conformingTo: .png) url.append(queryItems: [.init(name: "attribution", value: attribution.rawValue)]) let authorization = MapTilerAuthorization(key: key) return authorization.authorizeURL(url) diff --git a/ElementX/Sources/Other/MapLibre/MapTilerStyleBuilder.swift b/ElementX/Sources/Other/MapLibre/MapTilerStyleBuilder.swift index a149fa37e..82ed18d41 100644 --- a/ElementX/Sources/Other/MapLibre/MapTilerStyleBuilder.swift +++ b/ElementX/Sources/Other/MapLibre/MapTilerStyleBuilder.swift @@ -17,28 +17,26 @@ import Foundation struct MapTilerStyleBuilder: MapTilerStyleBuilderProtocol { - private let lightURL: String - private let darkURL: String + private let lightURL: URL + private let darkURL: URL private let key: String - init(lightURL: String, darkURL: String, key: String) { + init(lightURL: URL, darkURL: URL, key: String) { self.lightURL = lightURL self.darkURL = darkURL self.key = key } func dynamicMapURL(for style: MapTilerStyle) -> URL? { - var path: String + var url: URL switch style { case .light: - path = lightURL + url = lightURL case .dark: - path = darkURL + url = darkURL } - path.append("/style.json") - - guard let url = URL(string: path) else { return nil } + url.appendPathComponent("style.json", conformingTo: .json) let authorization = MapTilerAuthorization(key: key) return authorization.authorizeURL(url) } diff --git a/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineStyle.swift b/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineStyle.swift index 72c4e13ec..f5dc0711d 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineStyle.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Style/TimelineStyle.swift @@ -30,6 +30,16 @@ enum TimelineStyle: String, CaseIterable, Codable { return EdgeInsets(top: 1, leading: 8, bottom: 1, trailing: 8) } } + + /// Short hand for `self == .bubbles` + var isBubbles: Bool { + switch self { + case .plain: + return false + case .bubbles: + return true + } + } } enum TimelineGroupStyle: Hashable { diff --git a/ElementX/Sources/Screens/RoomScreen/View/Timeline/LocationRoomTimelineView.swift b/ElementX/Sources/Screens/RoomScreen/View/Timeline/LocationRoomTimelineView.swift index d3dbfd250..580b1ca1c 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Timeline/LocationRoomTimelineView.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Timeline/LocationRoomTimelineView.swift @@ -23,16 +23,46 @@ struct LocationRoomTimelineView: View { var body: some View { TimelineStyler(timelineItem: timelineItem) { if let geoURI = timelineItem.content.geoURI { - MapLibreStaticMapView(geoURI: geoURI) { - LocationMarkerView() + VStack(alignment: .leading, spacing: 0) { + descriptionView + .frame(maxWidth: mapAspectRatio * mapMaxHeight, alignment: .leading) + + MapLibreStaticMapView(geoURI: geoURI) { + LocationMarkerView() + } + .frame(maxHeight: mapMaxHeight) + .aspectRatio(mapAspectRatio, contentMode: .fit) } - .frame(maxHeight: 300) - .aspectRatio(3 / 2, contentMode: .fit) + .background(backgroundView) } else { FormattedBodyText(text: timelineItem.body) } } } + + // MARK: - Private + + @ViewBuilder + private var descriptionView: some View { + if let description = timelineItem.content.description, !description.isEmpty { + FormattedBodyText(text: description) + .padding(.vertical, 8) + .padding(.horizontal, timelineStyle.isBubbles ? 8 : 0) + } + } + + @ViewBuilder + private var backgroundView: some View { + switch timelineStyle { + case .bubbles: + timelineItem.isOutgoing ? Color.compound._bgBubbleOutgoing : Color.compound._bgBubbleIncoming + case .plain: + EmptyView() + } + } + + private let mapAspectRatio: Double = 3 / 2 + private let mapMaxHeight: Double = 300 } private extension MapLibreStaticMapView { @@ -53,6 +83,7 @@ struct LocationRoomTimelineView_Previews: PreviewProvider { static var previews: some View { body .environmentObject(viewModel.context) + body .environment(\.timelineStyle, .plain) .environmentObject(viewModel.context) @@ -73,6 +104,6 @@ struct LocationRoomTimelineView_Previews: PreviewProvider { isEditable: false, sender: .init(id: "Bob"), content: .init(body: "Fallback geo uri description", - geoURI: .init(latitude: 41.902782, longitude: 12.496366)))) + geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: "Location description description description description description description description description"))) } }