Render the live location timeline item (#5209)

* created the data for the timeline item

# Conflicts:
#	ElementX/Sources/Other/Logging/Tracing.swift
#	ElementX/Sources/Services/Authentication/AuthenticationService.swift
#	ElementX/Sources/Services/Authentication/LinkNewDeviceService.swift

* Implemented the LLS timeline item

* updated preview tests

* pr and design suggestions

* previewscrollview is debug only
This commit is contained in:
Mauro
2026-03-24 10:34:00 +01:00
committed by GitHub
parent 610c296125
commit b8d337e4ce
51 changed files with 799 additions and 93 deletions
@@ -35,6 +35,13 @@ struct LocationSharingScreenViewState: BindableState {
self.showLiveLocationSharingButton = showLiveLocationSharingButton
self.ownUserID = ownUserID
userProfile = switch interactionMode {
case .viewStatic(let locationData):
.init(sender: locationData.sender)
case .picker:
.init(userID: ownUserID)
}
bindings.showsUserLocationMode = switch interactionMode {
case .picker: .showAndFollow
case .viewStatic: .show
@@ -45,6 +52,11 @@ struct LocationSharingScreenViewState: BindableState {
let mapURLBuilder: MapTilerURLBuilderProtocol
let showLiveLocationSharingButton: Bool
let ownUserID: String
var userProfile: UserProfileProxy
var isOwnUser: Bool {
userProfile.userID == ownUserID
}
var bindings = LocationSharingScreenBindings(showsUserLocationMode: .hide)
@@ -91,14 +103,12 @@ struct LocationSharingScreenViewState: BindableState {
}
}
var userProfile: UserProfileProxy?
var locationMarkerUserProfile: UserProfileProxy? {
var locationMarkerKind: LocationMarkerKind {
switch interactionMode {
case .picker:
isSharingUserLocation ? userProfile : nil
isSharingUserLocation ? .staticUser(userProfile) : .pin
case .viewStatic(let location):
location.kind == .sender ? userProfile : nil
location.kind == .sender ? .staticUser(userProfile) : .pin
}
}
}
@@ -160,3 +170,37 @@ extension AlertInfo where T == LocationSharingViewError {
}
}
}
enum LocationMarkerKind {
case pin
case staticUser(UserProfileProxy)
case liveUser(UserProfileProxy)
case placeholder
var id: String {
switch self {
case .pin, .placeholder:
UUID().uuidString
case .staticUser(let profile), .liveUser(let profile):
profile.userID
}
}
var displayName: String? {
switch self {
case .pin, .placeholder:
nil
case .staticUser(let profile), .liveUser(let profile):
profile.displayName
}
}
var userProfile: UserProfileProxy? {
switch self {
case .pin, .placeholder:
nil
case .staticUser(let profile), .liveUser(let profile):
profile
}
}
}
@@ -56,7 +56,7 @@ struct LocationSharingScreen: View {
.ignoresSafeArea(.all, edges: mapSafeAreaEdges)
if context.viewState.isLocationPickerMode {
LocationMarkerView(userProfile: context.viewState.locationMarkerUserProfile, mediaProvider: context.mediaProvider)
LocationMarkerView(kind: context.viewState.locationMarkerKind, mediaProvider: context.mediaProvider)
}
}
.overlay(alignment: .topTrailing) {
@@ -76,13 +76,13 @@ struct LocationSharingScreen: View {
private var mapOptions: MapLibreMapView.Options {
var annotations: [String: LocationAnnotation] = [:]
if !context.viewState.isLocationPickerMode {
let id = context.viewState.locationMarkerUserProfile?.userID ?? UUID().uuidString
let annotation = LocationAnnotation(id: id,
let kind = context.viewState.locationMarkerKind
let annotation = LocationAnnotation(id: kind.id,
coordinate: context.viewState.initialMapCenter,
anchorPoint: .bottomCenter) {
LocationMarkerView(userProfile: context.viewState.locationMarkerUserProfile, mediaProvider: context.mediaProvider)
LocationMarkerView(kind: kind, mediaProvider: context.mediaProvider)
}
annotations[id] = annotation
annotations[kind.id] = annotation
}
return .init(zoomLevel: context.viewState.zoomLevel,
@@ -129,7 +129,7 @@ struct LocationSharingScreen: View {
@ViewBuilder
private var shareSheet: some View {
let location = context.viewState.initialMapCenter
let senderName = context.viewState.locationMarkerUserProfile?.displayName ?? context.viewState.locationMarkerUserProfile?.userID
let senderName = context.viewState.locationMarkerKind.displayName ?? context.viewState.locationMarkerKind.userProfile?.userID
AppActivityView(activityItems: [ShareToMapsAppActivity.MapsAppType.apple.activityURL(for: location, senderName: senderName)],
applicationActivities: ShareToMapsAppActivity.MapsAppType.allCases.map { ShareToMapsAppActivity(type: $0, location: location, senderName: senderName) })
.ignoresSafeArea(edges: .bottom)
@@ -34,13 +34,12 @@ struct StaticLocationSheet: View {
.font(.compound.bodyLGSemibold)
.padding(.bottom, 25)
.padding(.top, 29)
if case let .viewStatic(location) = context.viewState.interactionMode,
let userProfile = context.viewState.userProfile {
if case let .viewStatic(location) = context.viewState.interactionMode {
Button {
context.showShareSheet = true
} label: {
UserLocationCell(profile: userProfile,
isOwnUser: userProfile.userID == context.viewState.ownUserID,
UserLocationCell(profile: context.viewState.userProfile,
isOwnUser: context.viewState.isOwnUser,
isUserLocation: location.kind == .sender,
timestamp: location.timestamp,
mediaProvider: context.mediaProvider)