mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Add location's description in timeline (#1236)
* Refactor location URLs * Add description in LocationRoomTimelineView * Amend preview text * Cleanup code
This commit is contained in:
@@ -184,8 +184,8 @@ final class AppSettings {
|
|||||||
// MARK: - Maps
|
// MARK: - Maps
|
||||||
|
|
||||||
// maptiler map urls
|
// maptiler map urls
|
||||||
let lightTileMapStyleURL = "https://api.maptiler.com/maps/9bc819c8-e627-474a-a348-ec144fe3d810"
|
let lightTileMapStyleURL: URL = "https://api.maptiler.com/maps/9bc819c8-e627-474a-a348-ec144fe3d810"
|
||||||
let darkTileMapStyleURL = "https://api.maptiler.com/maps/dea61faf-292b-4774-9660-58fcef89a7f3"
|
let darkTileMapStyleURL: URL = "https://api.maptiler.com/maps/dea61faf-292b-4774-9660-58fcef89a7f3"
|
||||||
|
|
||||||
// maptiler api key
|
// maptiler api key
|
||||||
let mapTilerApiKey = "fU3vlMsMn4Jb6dnEIFsx"
|
let mapTilerApiKey = "fU3vlMsMn4Jb6dnEIFsx"
|
||||||
|
|||||||
@@ -17,28 +17,26 @@
|
|||||||
import CoreLocation
|
import CoreLocation
|
||||||
|
|
||||||
struct MapTilerStaticMap: MapTilerStaticMapProtocol {
|
struct MapTilerStaticMap: MapTilerStaticMapProtocol {
|
||||||
private let lightURL: String
|
private let lightURL: URL
|
||||||
private let darkURL: String
|
private let darkURL: URL
|
||||||
private let key: String
|
private let key: String
|
||||||
|
|
||||||
init(key: String, lightURL: String, darkURL: String) {
|
init(key: String, lightURL: URL, darkURL: URL) {
|
||||||
self.lightURL = lightURL
|
self.lightURL = lightURL
|
||||||
self.darkURL = darkURL
|
self.darkURL = darkURL
|
||||||
self.key = key
|
self.key = key
|
||||||
}
|
}
|
||||||
|
|
||||||
func staticMapURL(for style: MapTilerStyle, coordinates: CLLocationCoordinate2D, zoomLevel: Double, size: CGSize, attribution: MapTilerAttributionPlacement) -> URL? {
|
func staticMapURL(for style: MapTilerStyle, coordinates: CLLocationCoordinate2D, zoomLevel: Double, size: CGSize, attribution: MapTilerAttributionPlacement) -> URL? {
|
||||||
var path: String
|
var url: URL
|
||||||
switch style {
|
switch style {
|
||||||
case .light:
|
case .light:
|
||||||
path = lightURL
|
url = lightURL
|
||||||
case .dark:
|
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)))
|
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)
|
||||||
|
|
||||||
guard var url = URL(string: path) else { return nil }
|
|
||||||
url.append(queryItems: [.init(name: "attribution", value: attribution.rawValue)])
|
url.append(queryItems: [.init(name: "attribution", value: attribution.rawValue)])
|
||||||
let authorization = MapTilerAuthorization(key: key)
|
let authorization = MapTilerAuthorization(key: key)
|
||||||
return authorization.authorizeURL(url)
|
return authorization.authorizeURL(url)
|
||||||
|
|||||||
@@ -17,28 +17,26 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct MapTilerStyleBuilder: MapTilerStyleBuilderProtocol {
|
struct MapTilerStyleBuilder: MapTilerStyleBuilderProtocol {
|
||||||
private let lightURL: String
|
private let lightURL: URL
|
||||||
private let darkURL: String
|
private let darkURL: URL
|
||||||
private let key: String
|
private let key: String
|
||||||
|
|
||||||
init(lightURL: String, darkURL: String, key: String) {
|
init(lightURL: URL, darkURL: URL, key: String) {
|
||||||
self.lightURL = lightURL
|
self.lightURL = lightURL
|
||||||
self.darkURL = darkURL
|
self.darkURL = darkURL
|
||||||
self.key = key
|
self.key = key
|
||||||
}
|
}
|
||||||
|
|
||||||
func dynamicMapURL(for style: MapTilerStyle) -> URL? {
|
func dynamicMapURL(for style: MapTilerStyle) -> URL? {
|
||||||
var path: String
|
var url: URL
|
||||||
switch style {
|
switch style {
|
||||||
case .light:
|
case .light:
|
||||||
path = lightURL
|
url = lightURL
|
||||||
case .dark:
|
case .dark:
|
||||||
path = darkURL
|
url = darkURL
|
||||||
}
|
}
|
||||||
|
|
||||||
path.append("/style.json")
|
url.appendPathComponent("style.json", conformingTo: .json)
|
||||||
|
|
||||||
guard let url = URL(string: path) else { return nil }
|
|
||||||
let authorization = MapTilerAuthorization(key: key)
|
let authorization = MapTilerAuthorization(key: key)
|
||||||
return authorization.authorizeURL(url)
|
return authorization.authorizeURL(url)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,16 @@ enum TimelineStyle: String, CaseIterable, Codable {
|
|||||||
return EdgeInsets(top: 1, leading: 8, bottom: 1, trailing: 8)
|
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 {
|
enum TimelineGroupStyle: Hashable {
|
||||||
|
|||||||
@@ -23,16 +23,46 @@ struct LocationRoomTimelineView: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
TimelineStyler(timelineItem: timelineItem) {
|
TimelineStyler(timelineItem: timelineItem) {
|
||||||
if let geoURI = timelineItem.content.geoURI {
|
if let geoURI = timelineItem.content.geoURI {
|
||||||
MapLibreStaticMapView(geoURI: geoURI) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
LocationMarkerView()
|
descriptionView
|
||||||
|
.frame(maxWidth: mapAspectRatio * mapMaxHeight, alignment: .leading)
|
||||||
|
|
||||||
|
MapLibreStaticMapView(geoURI: geoURI) {
|
||||||
|
LocationMarkerView()
|
||||||
|
}
|
||||||
|
.frame(maxHeight: mapMaxHeight)
|
||||||
|
.aspectRatio(mapAspectRatio, contentMode: .fit)
|
||||||
}
|
}
|
||||||
.frame(maxHeight: 300)
|
.background(backgroundView)
|
||||||
.aspectRatio(3 / 2, contentMode: .fit)
|
|
||||||
} else {
|
} else {
|
||||||
FormattedBodyText(text: timelineItem.body)
|
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 {
|
private extension MapLibreStaticMapView {
|
||||||
@@ -53,6 +83,7 @@ struct LocationRoomTimelineView_Previews: PreviewProvider {
|
|||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
body
|
body
|
||||||
.environmentObject(viewModel.context)
|
.environmentObject(viewModel.context)
|
||||||
|
|
||||||
body
|
body
|
||||||
.environment(\.timelineStyle, .plain)
|
.environment(\.timelineStyle, .plain)
|
||||||
.environmentObject(viewModel.context)
|
.environmentObject(viewModel.context)
|
||||||
@@ -73,6 +104,6 @@ struct LocationRoomTimelineView_Previews: PreviewProvider {
|
|||||||
isEditable: false,
|
isEditable: false,
|
||||||
sender: .init(id: "Bob"),
|
sender: .init(id: "Bob"),
|
||||||
content: .init(body: "Fallback geo uri description",
|
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")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user