implement APIs for LLS observation
This commit is contained in:
@@ -572,6 +572,7 @@
|
||||
6298AB0906DDD3525CD78C6B /* KZFileWatchers in Frameworks */ = {isa = PBXBuildFile; productRef = 81DB3AB6CE996AB3954F4F03 /* KZFileWatchers */; };
|
||||
62A7FC3A0191BC7181AA432B /* AudioRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 907FA4DE17DEA1A3738EFB83 /* AudioRecorder.swift */; };
|
||||
62C5876C4254C58C2086F0DE /* HomeScreenContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3B4B58B79A6FA250B24A1EC /* HomeScreenContent.swift */; };
|
||||
633400018E07D2DC7175B16E /* LiveLocationShareProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA12A7F5EF5C6D0B992869ED /* LiveLocationShareProxy.swift */; };
|
||||
633501761094E09DFBEBFFAD /* CopyTextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B682FE2C44C5E163E7023B05 /* CopyTextButton.swift */; };
|
||||
63780F9DA06573E38A471ECA /* GenericCallLinkWidgetDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C202C1C7E330F124981A31 /* GenericCallLinkWidgetDriver.swift */; };
|
||||
6386EA3C898AD1A4BC1DC8A5 /* TimelineMediaPreviewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FD40B92FCF20165658296AD /* TimelineMediaPreviewModifier.swift */; };
|
||||
@@ -739,6 +740,7 @@
|
||||
7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = C024C151639C4E1B91FCC68B /* ElementXAttributeScope.swift */; };
|
||||
7C545FFEC9930F7247352593 /* SecurityAndPrivacyScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 978092B01BEAB39F2C4389AE /* SecurityAndPrivacyScreenViewModel.swift */; };
|
||||
7C6376192F578E0BA801BFEC /* AnalyticsSettingsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C64A14EE89928207E3B42B /* AnalyticsSettingsScreenModels.swift */; };
|
||||
7C9A62022717060DFC1878D7 /* LiveLocationSharesServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2C9C6EFC19EBB79E35806ED /* LiveLocationSharesServiceProtocol.swift */; };
|
||||
7C9BDF1FC7BD46C4676536AB /* AuthenticationStartScreenBackgroundImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682BC7BAF0EFEF512A8C5140 /* AuthenticationStartScreenBackgroundImage.swift */; };
|
||||
7CD16990BA843BE9ED639129 /* ImageRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFE4453AB0B34C203447162 /* ImageRoomTimelineItem.swift */; };
|
||||
7D249465ED00988EEEC14E05 /* JoinedRoomProxyMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 867DC9530C42F7B5176BE465 /* JoinedRoomProxyMock.swift */; };
|
||||
@@ -1181,6 +1183,7 @@
|
||||
C8E1E4E06B7C7A3A8246FC9B /* MediaEventsTimelineScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8512B82404B1751D0BCC82D2 /* MediaEventsTimelineScreenCoordinator.swift */; };
|
||||
C900127318820AD04D6C90B8 /* LabsScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E43D8784B0054C048060FEB /* LabsScreenModels.swift */; };
|
||||
C915347779B3C7FDD073A87A /* AVMetadataMachineReadableCodeObjectExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93E1FF0DFBB3768F79FDBF6D /* AVMetadataMachineReadableCodeObjectExtensionsTest.swift */; };
|
||||
C9169AB88A0953C0B3D8601B /* LiveLocationSharesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89EE3CE58040FD2DF63DC23 /* LiveLocationSharesService.swift */; };
|
||||
C960BACE42A9D8C535E8CB34 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1912062B53CE95E6F700DA60 /* Pagination.swift */; };
|
||||
C969A62F3D9F14318481A33B /* KnockedRoomProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 858DA81F2ACF484B7CAD6AE4 /* KnockedRoomProxy.swift */; };
|
||||
C97325EFDCCEE457432A9E82 /* MessageText.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E0B4A34E69BD2132BEC521 /* MessageText.swift */; };
|
||||
@@ -1475,6 +1478,7 @@
|
||||
FA2BBAE9FC5E2E9F960C0980 /* NavigationCoordinators.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F28602AC7AC881AED37EBA /* NavigationCoordinators.swift */; };
|
||||
FA53FA227FFBE469AFF32F71 /* TimelineControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C585CE1F721A2770C70D47 /* TimelineControllerProtocol.swift */; };
|
||||
FA5A7E32B1920FCB4EEDC1BA /* RoomDetailsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6493AC9979CEB1410302BFE3 /* RoomDetailsScreenCoordinator.swift */; };
|
||||
FA5FD4910EA871ACCED8D47B /* LiveLocationSharesMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4609B3576A5E612A95352EC1 /* LiveLocationSharesMock.swift */; };
|
||||
FA71CD334F2D2289BEF0D749 /* SecureBackupRecoveryKeyScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A2FCA3D0F239B9E911B966B /* SecureBackupRecoveryKeyScreen.swift */; };
|
||||
FA9C427FFB11B1AA2DCC5602 /* RoomProxyProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47111410B6E659A697D472B5 /* RoomProxyProtocol.swift */; };
|
||||
FB0A9D06FC9122E37992D962 /* LayoutDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14D83B2B7CD5501A0089EFC /* LayoutDirection.swift */; };
|
||||
@@ -1998,6 +2002,7 @@
|
||||
45A4B934BA41D6C255900265 /* preview_video.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = preview_video.jpg; sourceTree = "<group>"; };
|
||||
45CDF9A107BFE6C79B58D6B5 /* RoomMembersListScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMembersListScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
45D8149FDDA0315CDC553B4B /* UserNotificationCenterProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationCenterProtocol.swift; sourceTree = "<group>"; };
|
||||
4609B3576A5E612A95352EC1 /* LiveLocationSharesMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveLocationSharesMock.swift; sourceTree = "<group>"; };
|
||||
4629710C0337ADD9C8909542 /* ka */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ka; path = ka.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
466C71A0FED9BFF287613C82 /* RoomDetailsScreenModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDetailsScreenModels.swift; sourceTree = "<group>"; };
|
||||
467498BEA681758BE2F80826 /* TimelineMediaPreviewDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewDetailsView.swift; sourceTree = "<group>"; };
|
||||
@@ -2538,6 +2543,7 @@
|
||||
A9E6065FC6BC4A1B4C629E08 /* TimelineItemMenuActionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemMenuActionProvider.swift; sourceTree = "<group>"; };
|
||||
A9E88667D393612FD5D84718 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/SAS.strings; sourceTree = "<group>"; };
|
||||
A9FAFE1C2149E6AC8156ED2B /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = "<group>"; };
|
||||
AA12A7F5EF5C6D0B992869ED /* LiveLocationShareProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveLocationShareProxy.swift; sourceTree = "<group>"; };
|
||||
AA19C32BD97F45847724E09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Untranslated.strings; sourceTree = "<group>"; };
|
||||
AAC9344689121887B74877AF /* UnitTests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AACE9B8E1A4AE79A7E2914F6 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
@@ -2717,6 +2723,7 @@
|
||||
C75FE3F524B575D53787868C /* TimelineMediaPreviewRedactConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMediaPreviewRedactConfirmationView.swift; sourceTree = "<group>"; };
|
||||
C7661EFFCAA307A97D71132A /* HomeScreenRoomList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeScreenRoomList.swift; sourceTree = "<group>"; };
|
||||
C830A64609CBD152F06E0457 /* NotificationConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationConstants.swift; sourceTree = "<group>"; };
|
||||
C89EE3CE58040FD2DF63DC23 /* LiveLocationSharesService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveLocationSharesService.swift; sourceTree = "<group>"; };
|
||||
C90514BE9B8ACCBCF0AD2489 /* ComposerToolbarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerToolbarViewModel.swift; sourceTree = "<group>"; };
|
||||
C95ADE8D9527523572532219 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = hu; path = hu.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
C97F8963B14EB0AF3940DDBF /* NotificationSettingsEditScreenRoomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsEditScreenRoomCell.swift; sourceTree = "<group>"; };
|
||||
@@ -2956,6 +2963,7 @@
|
||||
F229480685F30BCB96C439EC /* AdvancedSettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsScreen.swift; sourceTree = "<group>"; };
|
||||
F276F31C1AEC19E52B951B62 /* SendInviteConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendInviteConfirmationView.swift; sourceTree = "<group>"; };
|
||||
F2B94F1B0B5D9D42B15AA6E8 /* ChatsTabFlowCoordinatorStateMachine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsTabFlowCoordinatorStateMachine.swift; sourceTree = "<group>"; };
|
||||
F2C9C6EFC19EBB79E35806ED /* LiveLocationSharesServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveLocationSharesServiceProtocol.swift; sourceTree = "<group>"; };
|
||||
F2DC502B1A566E99969D34DD /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
F2E4EF80DFB8FE7C4469B15D /* RoomDirectorySearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomDirectorySearchScreen.swift; sourceTree = "<group>"; };
|
||||
F3082001D373607455CB08A1 /* QRCodeErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeErrorView.swift; sourceTree = "<group>"; };
|
||||
@@ -3748,6 +3756,7 @@
|
||||
7F957320D0EB7D7B4E30C79D /* KnockRequestProxyMock.swift */,
|
||||
BA257D747DD7E6FFA5C2BE2D /* LinkNewDeviceServiceMock.swift */,
|
||||
0B5DF0E888F66652F8C4CEC5 /* LiveLocationManagerMock.swift */,
|
||||
4609B3576A5E612A95352EC1 /* LiveLocationSharesMock.swift */,
|
||||
6F65E4BB9E82EB8373207CF8 /* MediaProviderMock.swift */,
|
||||
8DA1E8F287680C8ED25EDBAC /* NetworkMonitorMock.swift */,
|
||||
840182D7A61402D5947DE094 /* NotificationItemProxyMock.swift */,
|
||||
@@ -5468,6 +5477,9 @@
|
||||
DA46D6DD4B4AB17E1D45092E /* CLLocationManagerProtocol.swift */,
|
||||
D17F49E39CC38DAB7B305701 /* LiveLocationManager.swift */,
|
||||
33752AE856E93CE62412B7A1 /* LiveLocationManagerProtocol.swift */,
|
||||
AA12A7F5EF5C6D0B992869ED /* LiveLocationShareProxy.swift */,
|
||||
C89EE3CE58040FD2DF63DC23 /* LiveLocationSharesService.swift */,
|
||||
F2C9C6EFC19EBB79E35806ED /* LiveLocationSharesServiceProtocol.swift */,
|
||||
);
|
||||
path = Location;
|
||||
sourceTree = "<group>";
|
||||
@@ -8407,6 +8419,10 @@
|
||||
CD077E14FAADC444C5A80068 /* LiveLocationManagerProtocol.swift in Sources */,
|
||||
C8D0AC22E03F652118A2BB73 /* LiveLocationRoomTimelineItem.swift in Sources */,
|
||||
F7977C53B2B1D73030C69761 /* LiveLocationRoomTimelineView.swift in Sources */,
|
||||
633400018E07D2DC7175B16E /* LiveLocationShareProxy.swift in Sources */,
|
||||
FA5FD4910EA871ACCED8D47B /* LiveLocationSharesMock.swift in Sources */,
|
||||
C9169AB88A0953C0B3D8601B /* LiveLocationSharesService.swift in Sources */,
|
||||
7C9A62022717060DFC1878D7 /* LiveLocationSharesServiceProtocol.swift in Sources */,
|
||||
9223E5F2A2CE0AFFDFF0AFFB /* LiveLocationSharingBannerView.swift in Sources */,
|
||||
6E47D126DD7585E8F8237CE7 /* LoadableAvatarImage.swift in Sources */,
|
||||
D9F80CE61BF8FF627FDB0543 /* LoadableImage.swift in Sources */,
|
||||
|
||||
@@ -10414,6 +10414,70 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol, @unchecked Sendable {
|
||||
return clearDraftThreadRootEventIDReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - getLiveLocationSharesService
|
||||
|
||||
var getLiveLocationSharesServiceUnderlyingCallsCount = 0
|
||||
var getLiveLocationSharesServiceCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return getLiveLocationSharesServiceUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = getLiveLocationSharesServiceUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
getLiveLocationSharesServiceUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
getLiveLocationSharesServiceUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var getLiveLocationSharesServiceCalled: Bool {
|
||||
return getLiveLocationSharesServiceCallsCount > 0
|
||||
}
|
||||
|
||||
var getLiveLocationSharesServiceUnderlyingReturnValue: LiveLocationSharesServiceProtocol!
|
||||
var getLiveLocationSharesServiceReturnValue: LiveLocationSharesServiceProtocol! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return getLiveLocationSharesServiceUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: LiveLocationSharesServiceProtocol? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = getLiveLocationSharesServiceUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
getLiveLocationSharesServiceUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
getLiveLocationSharesServiceUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var getLiveLocationSharesServiceClosure: (() async -> LiveLocationSharesServiceProtocol)?
|
||||
|
||||
func getLiveLocationSharesService() async -> LiveLocationSharesServiceProtocol {
|
||||
getLiveLocationSharesServiceCallsCount += 1
|
||||
if let getLiveLocationSharesServiceClosure = getLiveLocationSharesServiceClosure {
|
||||
return await getLiveLocationSharesServiceClosure()
|
||||
} else {
|
||||
return getLiveLocationSharesServiceReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - startLiveLocationShare
|
||||
|
||||
var startLiveLocationShareDurationUnderlyingCallsCount = 0
|
||||
@@ -11904,6 +11968,14 @@ class LiveLocationManagerMock: LiveLocationManagerProtocol, @unchecked Sendable
|
||||
await stopLiveLocationRoomIDClosure?(roomID)
|
||||
}
|
||||
}
|
||||
class LiveLocationSharesServiceMock: LiveLocationSharesServiceProtocol, @unchecked Sendable {
|
||||
var liveLocationSharesPublisher: AnyPublisher<[LiveLocationShareProxy], Never> {
|
||||
get { return underlyingLiveLocationSharesPublisher }
|
||||
set(value) { underlyingLiveLocationSharesPublisher = value }
|
||||
}
|
||||
var underlyingLiveLocationSharesPublisher: AnyPublisher<[LiveLocationShareProxy], Never>!
|
||||
|
||||
}
|
||||
class MediaLoaderMock: MediaLoaderProtocol, @unchecked Sendable {
|
||||
|
||||
//MARK: - loadMediaContentForSource
|
||||
|
||||
@@ -68,6 +68,8 @@ extension JoinedRoomProxyMock {
|
||||
typingMembersPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
|
||||
identityStatusChangesPublisher = CurrentValueSubject([]).asCurrentValuePublisher()
|
||||
|
||||
getLiveLocationSharesServiceReturnValue = LiveLocationSharesServiceMock(.init())
|
||||
|
||||
updateMembersClosure = { }
|
||||
setNameClosure = { _ in .success(()) }
|
||||
setTopicClosure = { _ in .success(()) }
|
||||
|
||||
20
ElementX/Sources/Mocks/LiveLocationSharesMock.swift
Normal file
20
ElementX/Sources/Mocks/LiveLocationSharesMock.swift
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
struct LiveLocationSharesServiceMockConfiguration {
|
||||
var shares: [LiveLocationShareProxy] = []
|
||||
}
|
||||
|
||||
extension LiveLocationSharesServiceMock {
|
||||
convenience init(_ configuration: LiveLocationSharesServiceMockConfiguration = .init()) {
|
||||
self.init()
|
||||
liveLocationSharesPublisher = CurrentValueSubject(configuration.shares).eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
@@ -197,6 +197,12 @@ extension SDKListener: KnockRequestsListener where T == [KnockRequest] {
|
||||
}
|
||||
}
|
||||
|
||||
extension SDKListener: LiveLocationShareListener where T == [LiveLocationShareUpdate] {
|
||||
func onUpdate(updates: [LiveLocationShareUpdate]) {
|
||||
onUpdateClosure(updates)
|
||||
}
|
||||
}
|
||||
|
||||
extension SDKListener: ThreadListEntriesListener where T == [ThreadListUpdate] {
|
||||
func onUpdate(diff: [ThreadListUpdate]) {
|
||||
onUpdateClosure(diff)
|
||||
|
||||
@@ -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