mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
implement APIs for LLS observation
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
struct LiveLocationShareProxy: Hashable {
|
||||
let userID: String
|
||||
let geoURI: GeoURI?
|
||||
let timestamp: Date
|
||||
let timeoutDate: Date
|
||||
}
|
||||
|
||||
extension LiveLocationShareProxy {
|
||||
init(liveLocationShare: LiveLocationShare) {
|
||||
userID = liveLocationShare.userId
|
||||
if let geoURI = liveLocationShare.lastLocation?.location.geoUri {
|
||||
self.geoURI = GeoURI(string: geoURI)
|
||||
} else {
|
||||
geoURI = nil
|
||||
}
|
||||
timestamp = Date(timeIntervalSince1970: Double(liveLocationShare.startTs))
|
||||
timeoutDate = timestamp.addingTimeInterval(Double(liveLocationShare.timeout) / 1000)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
final class LiveLocationSharesService: LiveLocationSharesServiceProtocol {
|
||||
// periphery:ignore - required for instance retention in the rust codebase
|
||||
private let liveLocationShares: LiveLocationShares
|
||||
// periphery:ignore - required for instance retention in the rust codebase
|
||||
private var observationToken: TaskHandle?
|
||||
|
||||
private let liveLocationSharesSubject = PassthroughSubject<[LiveLocationShareProxy], Never>()
|
||||
var liveLocationSharesPublisher: AnyPublisher<[LiveLocationShareProxy], Never> {
|
||||
liveLocationSharesSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
private var previousLiveLocationShares: [LiveLocationShareProxy] = []
|
||||
|
||||
init(liveLocationShares: LiveLocationShares) {
|
||||
self.liveLocationShares = liveLocationShares
|
||||
observationToken = liveLocationShares
|
||||
.subscribe(listener: SDKListener { [weak self] updates in
|
||||
guard let self else { return }
|
||||
|
||||
MXLog.info("Received live location shares update")
|
||||
let updatedShares = handleLiveLocationShareUpdates(updates)
|
||||
liveLocationSharesSubject.send(updatedShares)
|
||||
})
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func handleLiveLocationShareUpdates(_ updates: [LiveLocationShareUpdate]) -> [LiveLocationShareProxy] {
|
||||
var shares = previousLiveLocationShares
|
||||
|
||||
for update in updates {
|
||||
switch update {
|
||||
case .append(let values):
|
||||
shares.append(contentsOf: values.map(LiveLocationShareProxy.init))
|
||||
case .clear:
|
||||
shares.removeAll()
|
||||
case .pushFront(let value):
|
||||
shares.insert(LiveLocationShareProxy(liveLocationShare: value), at: 0)
|
||||
case .pushBack(let value):
|
||||
shares.append(LiveLocationShareProxy(liveLocationShare: value))
|
||||
case .popFront:
|
||||
shares.removeFirst()
|
||||
case .popBack:
|
||||
shares.removeLast()
|
||||
case .insert(let index, let value):
|
||||
shares.insert(LiveLocationShareProxy(liveLocationShare: value), at: Int(index))
|
||||
case .set(let index, let value):
|
||||
shares[Int(index)] = LiveLocationShareProxy(liveLocationShare: value)
|
||||
case .remove(let index):
|
||||
shares.remove(at: Int(index))
|
||||
case .truncate(let length):
|
||||
shares.removeSubrange(Int(length)..<shares.count)
|
||||
case .reset(let values):
|
||||
shares = values.map(LiveLocationShareProxy.init)
|
||||
}
|
||||
}
|
||||
|
||||
previousLiveLocationShares = shares
|
||||
return shares
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
// sourcery: AutoMockable
|
||||
protocol LiveLocationSharesServiceProtocol {
|
||||
var liveLocationSharesPublisher: AnyPublisher<[LiveLocationShareProxy], Never> { get }
|
||||
}
|
||||
@@ -754,6 +754,10 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
||||
|
||||
// MARK: - Live Location
|
||||
|
||||
func getLiveLocationSharesService() async -> LiveLocationSharesServiceProtocol {
|
||||
await LiveLocationSharesService(liveLocationShares: room.liveLocationShares())
|
||||
}
|
||||
|
||||
func startLiveLocationShare(duration: Duration) async -> Result<Void, RoomProxyError> {
|
||||
do {
|
||||
try await room.startLiveLocationShare(durationMillis: UInt64(duration.seconds * 1000))
|
||||
|
||||
@@ -197,6 +197,8 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
|
||||
|
||||
// MARK: - Live Location
|
||||
|
||||
func getLiveLocationSharesService() async -> LiveLocationSharesServiceProtocol
|
||||
|
||||
func startLiveLocationShare(duration: Duration) async -> Result<Void, RoomProxyError>
|
||||
func sendLiveLocation(geoURI: GeoURI) async -> Result<Void, RoomProxyError>
|
||||
func stopLiveLocationShare() async -> Result<Void, RoomProxyError>
|
||||
|
||||
Reference in New Issue
Block a user