Refactor and redesign Location Sharing Screen (#5155)

* refactored the static location screen to the location sharing screen

# Conflicts:
#	UnitTests/Sources/LocationSharingScreenViewModelTests.swift

# Conflicts:
#	ElementX.xcodeproj/project.pbxproj

* implemented a custom pin with an overlayable view

* implemented the render of the user when the location is sender instead of the pin type

* removed description and body they are not used at all.

* reimplemented single button for sharing this or user location + implemented an experimental way to update annotations

* removed unnecessary @Suite description

* implemented a way to display the alert on top of the sheet and added a spinner to the center user location button

* fixed alerts strings

* fixed a failing test

* improved preview tests
This commit is contained in:
Mauro
2026-03-06 12:51:16 +01:00
committed by GitHub
parent 0c79b5404d
commit bbbb2e9dee
85 changed files with 917 additions and 626 deletions
@@ -16,7 +16,7 @@ struct LocationRoomTimelineView: View {
TimelineStyler(timelineItem: timelineItem) {
mainContent
.accessibilityElement(children: .ignore)
.accessibilityLabel(accessibilityLabel)
.accessibilityLabel(L10n.commonSharedLocation)
.onTapGesture {
guard context.viewState.mapTilerConfiguration.isEnabled else { return }
context.send(viewAction: .mediaTapped(itemID: timelineItem.id))
@@ -27,41 +27,20 @@ struct LocationRoomTimelineView: View {
@ViewBuilder
private var mainContent: some View {
if let geoURI = timelineItem.content.geoURI {
VStack(alignment: .leading, spacing: 0) {
descriptionView
.frame(maxWidth: mapAspectRatio * mapMaxHeight, alignment: .leading)
MapLibreStaticMapView(geoURI: geoURI,
mapURLBuilder: context.viewState.mapTilerConfiguration,
mapSize: .init(width: mapAspectRatio * mapMaxHeight, height: mapMaxHeight)) {
LocationMarkerView()
}
.frame(maxHeight: mapMaxHeight)
.aspectRatio(mapAspectRatio, contentMode: .fit)
.clipped()
MapLibreStaticMapView(geoURI: geoURI,
mapURLBuilder: context.viewState.mapTilerConfiguration,
mapSize: .init(width: mapAspectRatio * mapMaxHeight, height: mapMaxHeight)) {
LocationMarkerView(userProfile: timelineItem.content.kind == .sender ? .init(sender: timelineItem.sender) : nil, mediaProvider: context.mediaProvider)
}
.frame(maxHeight: mapMaxHeight)
.aspectRatio(mapAspectRatio, contentMode: .fit)
.clipped()
} else {
FormattedBodyText(text: timelineItem.body, additionalWhitespacesCount: timelineItem.additionalWhitespaces())
}
}
// MARK: - Private
private var accessibilityLabel: String {
if let description = timelineItem.content.description {
return "\(L10n.commonSharedLocation), \(description)"
}
return L10n.commonSharedLocation
}
@ViewBuilder
private var descriptionView: some View {
if let description = timelineItem.content.description, !description.isEmpty {
FormattedBodyText(text: description)
.padding(8)
}
}
private let mapAspectRatio: Double = 3 / 2
private let mapMaxHeight: Double = 300
@@ -107,9 +86,9 @@ struct LocationRoomTimelineView_Previews: PreviewProvider, TestablePreview {
isOutgoing: false,
isEditable: false,
canBeRepliedTo: true,
sender: .init(id: "Bob"),
sender: .init(id: "@bob:matrix.org", displayName: "Bob", avatarURL: .mockMXCUserAvatar),
content: .init(body: "Fallback geo uri description",
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: "Location description description description description description description description description")))
geoURI: .init(latitude: 41.902782, longitude: 12.496366))))
LocationRoomTimelineView(timelineItem: .init(id: .randomEvent,
timestamp: .mock,
isOutgoing: false,
@@ -117,7 +96,8 @@ struct LocationRoomTimelineView_Previews: PreviewProvider, TestablePreview {
canBeRepliedTo: true,
sender: .init(id: "Bob"),
content: .init(body: "Fallback geo uri description",
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: "Location description description description description description description description description"),
geoURI: .init(latitude: 41.902782, longitude: 12.496366),
kind: .pin),
properties: .init(replyDetails: .loaded(sender: .init(id: "Someone"),
eventID: "123",
eventContent: .message(.text(.init(body: "The thread content goes 'ere.")))),