Open Live Locations map on tapping on the banner (#5477)

* Implemented opening the LLS on our own user when tapping on the banner

* added a test for moving the map as soon as the first update arrives.

* updated preview tests
This commit is contained in:
Mauro
2026-04-24 13:19:07 +02:00
committed by GitHub
parent 5d1132c75b
commit ef26796d98
12 changed files with 104 additions and 27 deletions
@@ -26,7 +26,7 @@ enum LocationSharingScreenViewModelAction {
enum LocationSharingInteractionMode: Hashable {
case picker
case viewStatic(StaticLocationData)
case viewLive(sender: TimelineItemSender, initialLiveLocationShare: LiveLocationShare)
case viewLive(sender: TimelineItemSender?, initialLiveLocationShare: LiveLocationShare?)
}
struct LocationSharingScreenViewState: BindableState {
@@ -43,13 +43,17 @@ struct LocationSharingScreenViewState: BindableState {
case .viewStatic(let locationData):
.init(sender: locationData.sender)
case .viewLive(let sender, _):
.init(sender: sender)
if let sender {
.init(sender: sender)
} else {
.init(userID: ownUserID)
}
case .picker:
.init(userID: ownUserID)
}
userProfiles = [initialProfile.userID: initialProfile]
if case .viewLive(_, let initialLiveLocationShare) = interactionMode {
if case .viewLive(_, let initialLiveLocationShare) = interactionMode, let initialLiveLocationShare {
liveLocationShares = [initialLiveLocationShare]
}
@@ -112,8 +116,12 @@ struct LocationSharingScreenViewState: BindableState {
case .viewStatic(let location):
.init(latitude: location.geoURI.latitude, longitude: location.geoURI.longitude)
case .viewLive(_, let initialLiveLocationShare):
.init(latitude: initialLiveLocationShare.geoURI?.latitude ?? 0,
longitude: initialLiveLocationShare.geoURI?.longitude ?? 0)
if let initialLiveLocationShare {
.init(latitude: initialLiveLocationShare.geoURI?.latitude ?? 0,
longitude: initialLiveLocationShare.geoURI?.longitude ?? 0)
} else {
.init(latitude: 49.843, longitude: 9.902056)
}
}
}
@@ -29,6 +29,7 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
private var authorizationStatusSubscription: AnyCancellable?
// periphery:ignore - keep alive to keep receiving updates.
private var liveLocationService: RoomLiveLocationServiceProtocol?
private var needsCenteringOnFirstLiveLocationUpdate = false
init(interactionMode: LocationSharingInteractionMode,
mapURLBuilder: MapTilerURLBuilderProtocol,
@@ -56,7 +57,10 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
updateUserProfiles(members: roomProxy.membersPublisher.value)
setupSubscriptions()
if case .viewLive = interactionMode {
if case .viewLive(_, let initialLiveLocation) = interactionMode {
if initialLiveLocation == nil {
needsCenteringOnFirstLiveLocationUpdate = true
}
Task { await setupLiveLocationSubscription() }
}
}
@@ -109,6 +113,7 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
.sink { [weak self] liveLocationsShares in
guard let self else { return }
MXLog.info("Received live location shares update: \(liveLocationsShares.count) share(s)")
let ownUserID = roomProxy.ownUserID
let isStoppingLiveLocation = state.isStoppingLiveLocation
state.liveLocationShares = liveLocationsShares
@@ -118,7 +123,15 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
if rhs.userID == ownUserID { return false }
return lhs.timestamp > rhs.timestamp
}
updateUserProfiles(members: roomProxy.membersPublisher.value)
if needsCenteringOnFirstLiveLocationUpdate,
let liveLocation = state.liveLocationShares.first,
let geoURI = liveLocation.geoURI {
needsCenteringOnFirstLiveLocationUpdate = false
context.send(viewAction: .setMapCenter(.init(latitude: geoURI.latitude, longitude: geoURI.longitude)))
}
}
.store(in: &cancellables)
}
@@ -147,7 +160,9 @@ class LocationSharingScreenViewModel: LocationSharingScreenViewModelType, Locati
state.userProfiles = [sender.userID: sender]
case .viewLive(let sender, _):
var userIDs = Set(state.liveLocationShares.map(\.userID))
userIDs.insert(sender.id)
if let senderID = sender?.id {
userIDs.insert(senderID)
}
state.userProfiles = userIDs.reduce(into: [:]) { dict, userID in
if let member = members.first(where: { $0.userID == userID }) {
dict[userID] = UserProfileProxy(member: member)