diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 0c0eeca75a..f2a7da2e4b 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -1122,7 +1122,6 @@ E3CA565A4B9704F191B191F0 /* JoinedRoomSize+MemberCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF9AEA706926DD0DA2B954C /* JoinedRoomSize+MemberCount.swift */; }; E3E1E255DC8CB34BD8573E0D /* UserIndicatorControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A12D3B1BCF920880CA8BBB6B /* UserIndicatorControllerProtocol.swift */; }; E3EBC3BF7CE3960B41757BAA /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7310D8DFE01AF45F0689C3AA /* Publisher.swift */; }; - E45C9FA22BC13B477FD3B4AC /* EmojiDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D99730313BEBF08CDE81EE3 /* EmojiDetection.swift */; }; E468CC731C3F4D678499E52F /* LAContextMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BA5A62DA4B543827FF82354 /* LAContextMock.swift */; }; E481C8FDCB6C089963C95344 /* DeviceKit in Frameworks */ = {isa = PBXBuildFile; productRef = BC01130651CB23340B899032 /* DeviceKit */; }; E49F74BD93230BDEFFE5EA51 /* RoomNotificationSettingsScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58D295F0081084F38DB20893 /* RoomNotificationSettingsScreenViewModelTests.swift */; }; @@ -1216,7 +1215,6 @@ F66BBBE51B258BBB0B918C68 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = C79D91A7F9F378CECEF64B5A /* MatrixRustSDK */; }; F66BCCC825D6CA51724A94D0 /* MediaPlayerProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8A1F98AE670377B20679FF5 /* MediaPlayerProvider.swift */; }; F6767F17D538578B370DD805 /* TimelineItemBubbleBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE739A6836E86E3780748477 /* TimelineItemBubbleBackground.swift */; }; - F697284B9B5F2C00CFEA3B12 /* EmojiDetectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58E93D91DE3288010390DEE /* EmojiDetectionTests.swift */; }; F6BF52CB027393EE03CEC523 /* TimelineMediaPreviewViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1F000589F2CEE6B03ECFAB /* TimelineMediaPreviewViewModelTests.swift */; }; F6DFA23885980118AD7359C5 /* NotificationSettingsScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2389732B0E115A999A069083 /* NotificationSettingsScreenCoordinator.swift */; }; F6F49E37272AD7397CD29A01 /* HomeScreenViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505208F28007C0FEC14E1FF0 /* HomeScreenViewModelTests.swift */; }; @@ -1797,7 +1795,6 @@ 5CEEAE1BFAACD6C96B6DB731 /* PHGPostHogProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHGPostHogProtocol.swift; sourceTree = ""; }; 5D26A086A8278D39B5756D6F /* project.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = project.yml; sourceTree = ""; }; 5D53754227CEBD06358956D7 /* PinnedEventsTimelineScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineScreenCoordinator.swift; sourceTree = ""; }; - 5D99730313BEBF08CDE81EE3 /* EmojiDetection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiDetection.swift; sourceTree = ""; }; 5DE8D25D6A91030175D52A20 /* RoomTimelineItemProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineItemProperties.swift; sourceTree = ""; }; 5E33FD32BBC44D703C7AE4F9 /* TextBasedRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextBasedRoomTimelineItem.swift; sourceTree = ""; }; 5E75948AA1FE1D1A7809931F /* AuthenticationServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceProtocol.swift; sourceTree = ""; }; @@ -2115,7 +2112,6 @@ A436057DBEA1A23CA8CB1FD7 /* UIFont+AttributedStringBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIFont+AttributedStringBuilder.h"; sourceTree = ""; }; A443FAE2EE820A5790C35C8D /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/Localizable.strings; sourceTree = ""; }; A54AAF72E821B4084B7E4298 /* PinnedEventsTimelineFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinnedEventsTimelineFlowCoordinator.swift; sourceTree = ""; }; - A58E93D91DE3288010390DEE /* EmojiDetectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiDetectionTests.swift; sourceTree = ""; }; A6702BC84D3CC2421D78CD4E /* WebRegistrationScreenViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRegistrationScreenViewModel.swift; sourceTree = ""; }; A69869844D2B6F5BD9AABF85 /* OIDCConfigurationProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCConfigurationProxy.swift; sourceTree = ""; }; A6B19D10B102956066AF117B /* PollOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollOptionView.swift; sourceTree = ""; }; @@ -4186,7 +4182,6 @@ D77F75B3E9F99864048A422A /* DeactivateAccountScreenViewModelTests.swift */, 6D0A27607AB09784C8501B5C /* DeveloperOptionsScreenViewModelTests.swift */, 906451FB8CF27C628152BF7A /* EditRoomAddressScreenViewModelTests.swift */, - A58E93D91DE3288010390DEE /* EmojiDetectionTests.swift */, 099F2D36C141D845A445B1E6 /* EmojiProviderTests.swift */, 84B7A28A6606D58D1E38C55A /* ExpiringTaskRunnerTests.swift */, 1A7ED2EF5BDBAD2A7DBC4636 /* GeoURITests.swift */, @@ -5259,7 +5254,6 @@ AE52983FAFB4E0998C00EE8A /* CancellableTask.swift */, 127A57D053CE8C87B5EFB089 /* Consumable.swift */, 127C8472672A5BA09EF1ACF8 /* CurrentValuePublisher.swift */, - 5D99730313BEBF08CDE81EE3 /* EmojiDetection.swift */, 7B25F959A434BB9923A3223F /* ExpiringTaskRunner.swift */, 6A580295A56B55A856CC4084 /* InfoPlistReader.swift */, 6AD1A853D605C2146B0DC028 /* MatrixEntityRegex.swift */, @@ -6657,7 +6651,6 @@ 80F6C8EFCA4564B67F0D34B0 /* DeactivateAccountScreenViewModelTests.swift in Sources */, 864C69CF951BF36D25BE0C03 /* DeveloperOptionsScreenViewModelTests.swift in Sources */, EDB6915EC953BB2A44AA608E /* EditRoomAddressScreenViewModelTests.swift in Sources */, - F697284B9B5F2C00CFEA3B12 /* EmojiDetectionTests.swift in Sources */, 25618589E0DE0F1E95FC7B5C /* EmojiProviderTests.swift in Sources */, 71B62C48B8079D49F3FBC845 /* ExpiringTaskRunnerTests.swift in Sources */, 07756D532EFE33DD1FA258E5 /* GeoURITests.swift in Sources */, @@ -7003,7 +6996,6 @@ 370AF5BFCD4384DD455479B6 /* ElementCallWidgetDriverProtocol.swift in Sources */, 3F997171C3C79A45E92BF9EF /* ElementWellKnown.swift in Sources */, 7C1A7B594B2F8143F0DD0005 /* ElementXAttributeScope.swift in Sources */, - E45C9FA22BC13B477FD3B4AC /* EmojiDetection.swift in Sources */, 3A08584ECDD4A4541DBF21F8 /* EmojiLoaderProtocol.swift in Sources */, 340D39DB87F3800D53A6A621 /* EmojiPickerScreen.swift in Sources */, C1910A16BDF131FECA77BE22 /* EmojiPickerScreenCoordinator.swift in Sources */, @@ -8508,7 +8500,7 @@ repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = 25.01.22; + version = 25.01.27; }; }; 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 796bd41d72..00efa6ad1c 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -149,8 +149,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/element-hq/matrix-rust-components-swift", "state" : { - "revision" : "0851aa6271d6aee77612f87638a5e30e45b3a7f8", - "version" : "25.1.22" + "revision" : "58ce51362ec8b01279a5090f9d7d8c1de4b5b0f3", + "version" : "25.1.27" } }, { diff --git a/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift index 631e2f1e38..b5908100d2 100644 --- a/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/SDKGeneratedMocks.swift @@ -8088,6 +8088,71 @@ open class LazyTimelineItemProviderSDKMock: MatrixRustSDK.LazyTimelineItemProvid fileprivate var pointer: UnsafeMutableRawPointer! + //MARK: - containsOnlyEmojis + + var containsOnlyEmojisUnderlyingCallsCount = 0 + open var containsOnlyEmojisCallsCount: Int { + get { + if Thread.isMainThread { + return containsOnlyEmojisUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = containsOnlyEmojisUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + containsOnlyEmojisUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + containsOnlyEmojisUnderlyingCallsCount = newValue + } + } + } + } + open var containsOnlyEmojisCalled: Bool { + return containsOnlyEmojisCallsCount > 0 + } + + var containsOnlyEmojisUnderlyingReturnValue: Bool! + open var containsOnlyEmojisReturnValue: Bool! { + get { + if Thread.isMainThread { + return containsOnlyEmojisUnderlyingReturnValue + } else { + var returnValue: Bool? = nil + DispatchQueue.main.sync { + returnValue = containsOnlyEmojisUnderlyingReturnValue + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + containsOnlyEmojisUnderlyingReturnValue = newValue + } else { + DispatchQueue.main.sync { + containsOnlyEmojisUnderlyingReturnValue = newValue + } + } + } + } + open var containsOnlyEmojisClosure: (() -> Bool)? + + open override func containsOnlyEmojis() -> Bool { + containsOnlyEmojisCallsCount += 1 + if let containsOnlyEmojisClosure = containsOnlyEmojisClosure { + return containsOnlyEmojisClosure() + } else { + return containsOnlyEmojisReturnValue + } + } + //MARK: - debugInfo var debugInfoUnderlyingCallsCount = 0 @@ -13988,6 +14053,52 @@ open class RoomSDKMock: MatrixRustSDK.Room, @unchecked Sendable { try await sendCallNotificationIfNeededClosure?() } + //MARK: - sendLiveLocation + + open var sendLiveLocationGeoUriThrowableError: Error? + var sendLiveLocationGeoUriUnderlyingCallsCount = 0 + open var sendLiveLocationGeoUriCallsCount: Int { + get { + if Thread.isMainThread { + return sendLiveLocationGeoUriUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = sendLiveLocationGeoUriUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + sendLiveLocationGeoUriUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + sendLiveLocationGeoUriUnderlyingCallsCount = newValue + } + } + } + } + open var sendLiveLocationGeoUriCalled: Bool { + return sendLiveLocationGeoUriCallsCount > 0 + } + open var sendLiveLocationGeoUriReceivedGeoUri: String? + open var sendLiveLocationGeoUriReceivedInvocations: [String] = [] + open var sendLiveLocationGeoUriClosure: ((String) async throws -> Void)? + + open override func sendLiveLocation(geoUri: String) async throws { + if let error = sendLiveLocationGeoUriThrowableError { + throw error + } + sendLiveLocationGeoUriCallsCount += 1 + sendLiveLocationGeoUriReceivedGeoUri = geoUri + DispatchQueue.main.async { + self.sendLiveLocationGeoUriReceivedInvocations.append(geoUri) + } + try await sendLiveLocationGeoUriClosure?(geoUri) + } + //MARK: - sendRaw open var sendRawEventTypeContentThrowableError: Error? @@ -14264,6 +14375,92 @@ open class RoomSDKMock: MatrixRustSDK.Room, @unchecked Sendable { try await setUnreadFlagNewValueClosure?(newValue) } + //MARK: - startLiveLocationShare + + open var startLiveLocationShareDurationMillisThrowableError: Error? + var startLiveLocationShareDurationMillisUnderlyingCallsCount = 0 + open var startLiveLocationShareDurationMillisCallsCount: Int { + get { + if Thread.isMainThread { + return startLiveLocationShareDurationMillisUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = startLiveLocationShareDurationMillisUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + startLiveLocationShareDurationMillisUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + startLiveLocationShareDurationMillisUnderlyingCallsCount = newValue + } + } + } + } + open var startLiveLocationShareDurationMillisCalled: Bool { + return startLiveLocationShareDurationMillisCallsCount > 0 + } + open var startLiveLocationShareDurationMillisReceivedDurationMillis: UInt64? + open var startLiveLocationShareDurationMillisReceivedInvocations: [UInt64] = [] + open var startLiveLocationShareDurationMillisClosure: ((UInt64) async throws -> Void)? + + open override func startLiveLocationShare(durationMillis: UInt64) async throws { + if let error = startLiveLocationShareDurationMillisThrowableError { + throw error + } + startLiveLocationShareDurationMillisCallsCount += 1 + startLiveLocationShareDurationMillisReceivedDurationMillis = durationMillis + DispatchQueue.main.async { + self.startLiveLocationShareDurationMillisReceivedInvocations.append(durationMillis) + } + try await startLiveLocationShareDurationMillisClosure?(durationMillis) + } + + //MARK: - stopLiveLocationShare + + open var stopLiveLocationShareThrowableError: Error? + var stopLiveLocationShareUnderlyingCallsCount = 0 + open var stopLiveLocationShareCallsCount: Int { + get { + if Thread.isMainThread { + return stopLiveLocationShareUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = stopLiveLocationShareUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + stopLiveLocationShareUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + stopLiveLocationShareUnderlyingCallsCount = newValue + } + } + } + } + open var stopLiveLocationShareCalled: Bool { + return stopLiveLocationShareCallsCount > 0 + } + open var stopLiveLocationShareClosure: (() async throws -> Void)? + + open override func stopLiveLocationShare() async throws { + if let error = stopLiveLocationShareThrowableError { + throw error + } + stopLiveLocationShareCallsCount += 1 + try await stopLiveLocationShareClosure?() + } + //MARK: - subscribeToIdentityStatusChanges var subscribeToIdentityStatusChangesListenerUnderlyingCallsCount = 0 @@ -14410,6 +14607,77 @@ open class RoomSDKMock: MatrixRustSDK.Room, @unchecked Sendable { } } + //MARK: - subscribeToLiveLocationShares + + var subscribeToLiveLocationSharesListenerUnderlyingCallsCount = 0 + open var subscribeToLiveLocationSharesListenerCallsCount: Int { + get { + if Thread.isMainThread { + return subscribeToLiveLocationSharesListenerUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = subscribeToLiveLocationSharesListenerUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + subscribeToLiveLocationSharesListenerUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + subscribeToLiveLocationSharesListenerUnderlyingCallsCount = newValue + } + } + } + } + open var subscribeToLiveLocationSharesListenerCalled: Bool { + return subscribeToLiveLocationSharesListenerCallsCount > 0 + } + open var subscribeToLiveLocationSharesListenerReceivedListener: LiveLocationShareListener? + open var subscribeToLiveLocationSharesListenerReceivedInvocations: [LiveLocationShareListener] = [] + + var subscribeToLiveLocationSharesListenerUnderlyingReturnValue: TaskHandle! + open var subscribeToLiveLocationSharesListenerReturnValue: TaskHandle! { + get { + if Thread.isMainThread { + return subscribeToLiveLocationSharesListenerUnderlyingReturnValue + } else { + var returnValue: TaskHandle? = nil + DispatchQueue.main.sync { + returnValue = subscribeToLiveLocationSharesListenerUnderlyingReturnValue + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + subscribeToLiveLocationSharesListenerUnderlyingReturnValue = newValue + } else { + DispatchQueue.main.sync { + subscribeToLiveLocationSharesListenerUnderlyingReturnValue = newValue + } + } + } + } + open var subscribeToLiveLocationSharesListenerClosure: ((LiveLocationShareListener) -> TaskHandle)? + + open override func subscribeToLiveLocationShares(listener: LiveLocationShareListener) -> TaskHandle { + subscribeToLiveLocationSharesListenerCallsCount += 1 + subscribeToLiveLocationSharesListenerReceivedListener = listener + DispatchQueue.main.async { + self.subscribeToLiveLocationSharesListenerReceivedInvocations.append(listener) + } + if let subscribeToLiveLocationSharesListenerClosure = subscribeToLiveLocationSharesListenerClosure { + return subscribeToLiveLocationSharesListenerClosure(listener) + } else { + return subscribeToLiveLocationSharesListenerReturnValue + } + } + //MARK: - subscribeToRoomInfoUpdates var subscribeToRoomInfoUpdatesListenerUnderlyingCallsCount = 0 @@ -19713,81 +19981,6 @@ open class TimelineSDKMock: MatrixRustSDK.Timeline, @unchecked Sendable { await fetchMembersClosure?() } - //MARK: - focusedPaginateForwards - - open var focusedPaginateForwardsNumEventsThrowableError: Error? - var focusedPaginateForwardsNumEventsUnderlyingCallsCount = 0 - open var focusedPaginateForwardsNumEventsCallsCount: Int { - get { - if Thread.isMainThread { - return focusedPaginateForwardsNumEventsUnderlyingCallsCount - } else { - var returnValue: Int? = nil - DispatchQueue.main.sync { - returnValue = focusedPaginateForwardsNumEventsUnderlyingCallsCount - } - - return returnValue! - } - } - set { - if Thread.isMainThread { - focusedPaginateForwardsNumEventsUnderlyingCallsCount = newValue - } else { - DispatchQueue.main.sync { - focusedPaginateForwardsNumEventsUnderlyingCallsCount = newValue - } - } - } - } - open var focusedPaginateForwardsNumEventsCalled: Bool { - return focusedPaginateForwardsNumEventsCallsCount > 0 - } - open var focusedPaginateForwardsNumEventsReceivedNumEvents: UInt16? - open var focusedPaginateForwardsNumEventsReceivedInvocations: [UInt16] = [] - - var focusedPaginateForwardsNumEventsUnderlyingReturnValue: Bool! - open var focusedPaginateForwardsNumEventsReturnValue: Bool! { - get { - if Thread.isMainThread { - return focusedPaginateForwardsNumEventsUnderlyingReturnValue - } else { - var returnValue: Bool? = nil - DispatchQueue.main.sync { - returnValue = focusedPaginateForwardsNumEventsUnderlyingReturnValue - } - - return returnValue! - } - } - set { - if Thread.isMainThread { - focusedPaginateForwardsNumEventsUnderlyingReturnValue = newValue - } else { - DispatchQueue.main.sync { - focusedPaginateForwardsNumEventsUnderlyingReturnValue = newValue - } - } - } - } - open var focusedPaginateForwardsNumEventsClosure: ((UInt16) async throws -> Bool)? - - open override func focusedPaginateForwards(numEvents: UInt16) async throws -> Bool { - if let error = focusedPaginateForwardsNumEventsThrowableError { - throw error - } - focusedPaginateForwardsNumEventsCallsCount += 1 - focusedPaginateForwardsNumEventsReceivedNumEvents = numEvents - DispatchQueue.main.async { - self.focusedPaginateForwardsNumEventsReceivedInvocations.append(numEvents) - } - if let focusedPaginateForwardsNumEventsClosure = focusedPaginateForwardsNumEventsClosure { - return try await focusedPaginateForwardsNumEventsClosure(numEvents) - } else { - return focusedPaginateForwardsNumEventsReturnValue - } - } - //MARK: - getEventTimelineItemByEventId open var getEventTimelineItemByEventIdEventIdThrowableError: Error? @@ -20059,6 +20252,81 @@ open class TimelineSDKMock: MatrixRustSDK.Timeline, @unchecked Sendable { } } + //MARK: - paginateForwards + + open var paginateForwardsNumEventsThrowableError: Error? + var paginateForwardsNumEventsUnderlyingCallsCount = 0 + open var paginateForwardsNumEventsCallsCount: Int { + get { + if Thread.isMainThread { + return paginateForwardsNumEventsUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = paginateForwardsNumEventsUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + paginateForwardsNumEventsUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + paginateForwardsNumEventsUnderlyingCallsCount = newValue + } + } + } + } + open var paginateForwardsNumEventsCalled: Bool { + return paginateForwardsNumEventsCallsCount > 0 + } + open var paginateForwardsNumEventsReceivedNumEvents: UInt16? + open var paginateForwardsNumEventsReceivedInvocations: [UInt16] = [] + + var paginateForwardsNumEventsUnderlyingReturnValue: Bool! + open var paginateForwardsNumEventsReturnValue: Bool! { + get { + if Thread.isMainThread { + return paginateForwardsNumEventsUnderlyingReturnValue + } else { + var returnValue: Bool? = nil + DispatchQueue.main.sync { + returnValue = paginateForwardsNumEventsUnderlyingReturnValue + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + paginateForwardsNumEventsUnderlyingReturnValue = newValue + } else { + DispatchQueue.main.sync { + paginateForwardsNumEventsUnderlyingReturnValue = newValue + } + } + } + } + open var paginateForwardsNumEventsClosure: ((UInt16) async throws -> Bool)? + + open override func paginateForwards(numEvents: UInt16) async throws -> Bool { + if let error = paginateForwardsNumEventsThrowableError { + throw error + } + paginateForwardsNumEventsCallsCount += 1 + paginateForwardsNumEventsReceivedNumEvents = numEvents + DispatchQueue.main.async { + self.paginateForwardsNumEventsReceivedInvocations.append(numEvents) + } + if let paginateForwardsNumEventsClosure = paginateForwardsNumEventsClosure { + return try await paginateForwardsNumEventsClosure(numEvents) + } else { + return paginateForwardsNumEventsReturnValue + } + } + //MARK: - pinEvent open var pinEventEventIdThrowableError: Error? diff --git a/ElementX/Sources/Other/EmojiDetection.swift b/ElementX/Sources/Other/EmojiDetection.swift deleted file mode 100644 index fd9d5e66be..0000000000 --- a/ElementX/Sources/Other/EmojiDetection.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright 2023, 2024 New Vector 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 - -// Taken from https://gist.github.com/krummler/879e1ce942893db3104783d1d0e67b34 -extension Character { - /// A simple emoji is one scalar and presented to the user as an Emoji - var isSimpleEmoji: Bool { - unicodeScalars.count == 1 && unicodeScalars.first?.properties.isEmojiPresentation ?? false - } - - /// Checks if the scalars will be merged into and emoji - var isCombinedIntoEmoji: Bool { - unicodeScalars.count > 1 && - unicodeScalars.contains { $0.properties.isJoinControl || $0.properties.isVariationSelector } - } - - var isEmoji: Bool { - isSimpleEmoji || isCombinedIntoEmoji - } -} - -extension String { - var containsOnlyEmoji: Bool { - !isEmpty && !contains { !$0.isEmoji } - } -} diff --git a/ElementX/Sources/Other/Extensions/ClientBuilder.swift b/ElementX/Sources/Other/Extensions/ClientBuilder.swift index 08ea5aaba8..2cce00e9ea 100644 --- a/ElementX/Sources/Other/Extensions/ClientBuilder.swift +++ b/ElementX/Sources/Other/Extensions/ClientBuilder.swift @@ -44,7 +44,7 @@ extension ClientBuilder { .roomDecryptionTrustRequirement(trustRequirement: .crossSignedOrLegacy) } else { builder = builder - .roomKeyRecipientStrategy(strategy: .deviceBasedStrategy(onlyAllowTrustedDevices: false, errorOnVerifiedUserProblem: true)) + .roomKeyRecipientStrategy(strategy: .errorOnVerifiedUserProblem) .roomDecryptionTrustRequirement(trustRequirement: .untrusted) } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/AudioRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/AudioRoomTimelineView.swift index e2d97ef844..c538a5b806 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/AudioRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/AudioRoomTimelineView.swift @@ -19,6 +19,7 @@ struct AudioRoomTimelineView: View { caption: timelineItem.content.caption, formattedCaption: timelineItem.content.formattedCaption, additionalWhitespaces: timelineItem.additionalWhitespaces(), + shouldBoost: timelineItem.shouldBoost, isAudioFile: true) { context?.send(viewAction: .mediaTapped(itemID: timelineItem.id)) } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift index 787ec724d9..45063ec589 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FileRoomTimelineView.swift @@ -18,7 +18,8 @@ struct FileRoomTimelineView: View { fileSize: timelineItem.content.fileSize, caption: timelineItem.content.caption, formattedCaption: timelineItem.content.formattedCaption, - additionalWhitespaces: timelineItem.additionalWhitespaces()) { + additionalWhitespaces: timelineItem.additionalWhitespaces(), + shouldBoost: timelineItem.shouldBoost) { context?.send(viewAction: .mediaTapped(itemID: timelineItem.id)) } .accessibilityLabel(L10n.commonFile) @@ -34,6 +35,7 @@ struct MediaFileRoomTimelineContent: View { let caption: String? let formattedCaption: AttributedString? let additionalWhitespaces: Int + var shouldBoost = false var isAudioFile = false var onMediaTap: (() -> Void)? @@ -55,10 +57,12 @@ struct MediaFileRoomTimelineContent: View { if let formattedCaption { FormattedBodyText(attributedString: formattedCaption, - additionalWhitespacesCount: additionalWhitespaces) + additionalWhitespacesCount: additionalWhitespaces, + boostFontSize: shouldBoost) } else if let caption { FormattedBodyText(text: caption, - additionalWhitespacesCount: additionalWhitespaces) + additionalWhitespacesCount: additionalWhitespaces, + boostFontSize: shouldBoost) } } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift index 80236b2259..458ae7f611 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/FormattedBodyText.swift @@ -12,7 +12,7 @@ struct FormattedBodyText: View { private let attributedString: AttributedString private let additionalWhitespacesCount: Int - private let boostEmojiSize: Bool + private let boostFontSize: Bool private let defaultAttributesContainer: AttributeContainer = { var container = AttributeContainer() @@ -35,9 +35,7 @@ struct FormattedBodyText: View { let string = String(attributedString.characters) - if boostEmojiSize, - string.containsOnlyEmoji, - let range = adjustedAttributedString.range(of: string) { + if boostFontSize, let range = adjustedAttributedString.range(of: string) { adjustedAttributedString[range].font = UIFont.systemFont(ofSize: 48.0) } @@ -46,16 +44,16 @@ struct FormattedBodyText: View { init(attributedString: AttributedString, additionalWhitespacesCount: Int = 0, - boostEmojiSize: Bool = false) { + boostFontSize: Bool = false) { self.attributedString = attributedString self.additionalWhitespacesCount = additionalWhitespacesCount - self.boostEmojiSize = boostEmojiSize + self.boostFontSize = boostFontSize } - init(text: String, additionalWhitespacesCount: Int = 0, boostEmojiSize: Bool = false) { + init(text: String, additionalWhitespacesCount: Int = 0, boostFontSize: Bool = false) { self.init(attributedString: AttributedString(text), additionalWhitespacesCount: additionalWhitespacesCount, - boostEmojiSize: boostEmojiSize) + boostFontSize: boostFontSize) } // These is needed to create the slightly off inlined timestamp effect @@ -199,7 +197,7 @@ struct FormattedBodyText_Previews: PreviewProvider, TestablePreview { FormattedBodyText(text: "Some plain text that's not an attributed component. This one is really long.") .bubbleBackground() - FormattedBodyText(text: "❤ī¸", boostEmojiSize: true) + FormattedBodyText(text: "❤ī¸", boostFontSize: true) .bubbleBackground() } .padding() diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ImageRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ImageRoomTimelineView.swift index 78417de77e..af5bf1f7a5 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ImageRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/ImageRoomTimelineView.swift @@ -30,11 +30,11 @@ struct ImageRoomTimelineView: View { if let attributedCaption = timelineItem.content.formattedCaption { FormattedBodyText(attributedString: attributedCaption, additionalWhitespacesCount: timelineItem.additionalWhitespaces(), - boostEmojiSize: true) + boostFontSize: timelineItem.shouldBoost) } else if let caption = timelineItem.content.caption { FormattedBodyText(text: caption, additionalWhitespacesCount: timelineItem.additionalWhitespaces(), - boostEmojiSize: true) + boostFontSize: timelineItem.shouldBoost) } } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift index 818f922ca2..746071d958 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/TextRoomTimelineView.swift @@ -16,11 +16,11 @@ struct TextRoomTimelineView: View, TextBasedRoomTimelineViewProtocol { if let attributedString = timelineItem.content.formattedBody { FormattedBodyText(attributedString: attributedString, additionalWhitespacesCount: timelineItem.additionalWhitespaces(), - boostEmojiSize: true) + boostFontSize: timelineItem.shouldBoost) } else { FormattedBodyText(text: timelineItem.body, additionalWhitespacesCount: timelineItem.additionalWhitespaces(), - boostEmojiSize: true) + boostFontSize: timelineItem.shouldBoost) } } } diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/VideoRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/VideoRoomTimelineView.swift index bfd4066f5c..0bda39aba1 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/VideoRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/VideoRoomTimelineView.swift @@ -31,11 +31,11 @@ struct VideoRoomTimelineView: View { if let attributedCaption = timelineItem.content.formattedCaption { FormattedBodyText(attributedString: attributedCaption, additionalWhitespacesCount: timelineItem.additionalWhitespaces(), - boostEmojiSize: true) + boostFontSize: timelineItem.shouldBoost) } else if let caption = timelineItem.content.caption { FormattedBodyText(text: caption, additionalWhitespacesCount: timelineItem.additionalWhitespaces(), - boostEmojiSize: true) + boostFontSize: timelineItem.shouldBoost) } } } diff --git a/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift b/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift index dfb5f94274..0a82a7e4f1 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItemProxy.swift @@ -137,6 +137,8 @@ class EventTimelineItemProxy { lazy var sendHandle = item.lazyProvider.getSendHandle() + lazy var shouldBoost = item.lazyProvider.containsOnlyEmojis() + lazy var readReceipts = item.readReceipts } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/AudioRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/AudioRoomTimelineItem.swift index 575e49bcfd..037f41515a 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/AudioRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/AudioRoomTimelineItem.swift @@ -14,6 +14,8 @@ struct AudioRoomTimelineItem: EventBasedMessageTimelineItemProtocol, Equatable { let isEditable: Bool let canBeRepliedTo: Bool let isThreaded: Bool + var shouldBoost = false + let sender: TimelineItemSender let content: AudioRoomTimelineItemContent diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/FileRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/FileRoomTimelineItem.swift index 11d89ac8ee..289d156465 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/FileRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/FileRoomTimelineItem.swift @@ -14,8 +14,8 @@ struct FileRoomTimelineItem: EventBasedMessageTimelineItemProtocol, Equatable { let isOutgoing: Bool let isEditable: Bool let canBeRepliedTo: Bool - let isThreaded: Bool + var shouldBoost = false let sender: TimelineItemSender diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/ImageRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/ImageRoomTimelineItem.swift index 0e338fed96..0afcdf44d0 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/ImageRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/ImageRoomTimelineItem.swift @@ -15,6 +15,7 @@ struct ImageRoomTimelineItem: EventBasedMessageTimelineItemProtocol, Equatable { let isEditable: Bool let canBeRepliedTo: Bool let isThreaded: Bool + var shouldBoost = false let sender: TimelineItemSender diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/TextRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/TextRoomTimelineItem.swift index 119e6864cc..ecc020a7c7 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/TextRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/TextRoomTimelineItem.swift @@ -14,8 +14,8 @@ struct TextRoomTimelineItem: TextBasedRoomTimelineItem, Equatable { let isOutgoing: Bool let isEditable: Bool let canBeRepliedTo: Bool - let isThreaded: Bool + var shouldBoost = false let sender: TimelineItemSender diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/VideoRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/VideoRoomTimelineItem.swift index 51f5ba845d..b7044c110b 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/VideoRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/VideoRoomTimelineItem.swift @@ -15,6 +15,7 @@ struct VideoRoomTimelineItem: EventBasedMessageTimelineItemProtocol, Equatable { let isEditable: Bool let canBeRepliedTo: Bool let isThreaded: Bool + var shouldBoost = false let sender: TimelineItemSender diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift index 2b1c51cd90..e4368abe00 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/RoomTimelineItemFactory.swift @@ -205,6 +205,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol { isEditable: eventItemProxy.isEditable, canBeRepliedTo: eventItemProxy.canBeRepliedTo, isThreaded: messageContent.threadRoot != nil, + shouldBoost: eventItemProxy.shouldBoost, sender: eventItemProxy.sender, content: buildTextTimelineItemContent(textMessageContent), replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo), @@ -225,6 +226,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol { isEditable: eventItemProxy.isEditable, canBeRepliedTo: eventItemProxy.canBeRepliedTo, isThreaded: messageContent.threadRoot != nil, + shouldBoost: eventItemProxy.shouldBoost, sender: eventItemProxy.sender, content: buildImageTimelineItemContent(imageMessageContent), replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo), @@ -245,6 +247,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol { isEditable: eventItemProxy.isEditable, canBeRepliedTo: eventItemProxy.canBeRepliedTo, isThreaded: messageContent.threadRoot != nil, + shouldBoost: eventItemProxy.shouldBoost, sender: eventItemProxy.sender, content: buildVideoTimelineItemContent(videoMessageContent), replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo), @@ -265,6 +268,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol { isEditable: eventItemProxy.isEditable, canBeRepliedTo: eventItemProxy.canBeRepliedTo, isThreaded: messageContent.threadRoot != nil, + shouldBoost: eventItemProxy.shouldBoost, sender: eventItemProxy.sender, content: buildAudioTimelineItemContent(audioMessageContent), replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo), @@ -305,6 +309,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol { isEditable: eventItemProxy.isEditable, canBeRepliedTo: eventItemProxy.canBeRepliedTo, isThreaded: messageContent.threadRoot != nil, + shouldBoost: eventItemProxy.shouldBoost, sender: eventItemProxy.sender, content: buildFileTimelineItemContent(fileMessageContent), replyDetails: buildReplyToDetailsFromDetailsIfAvailable(details: messageContent.inReplyTo), diff --git a/ElementX/Sources/Services/Timeline/TimelineProxy.swift b/ElementX/Sources/Services/Timeline/TimelineProxy.swift index 0513bad4f8..0ce0f65885 100644 --- a/ElementX/Sources/Services/Timeline/TimelineProxy.swift +++ b/ElementX/Sources/Services/Timeline/TimelineProxy.swift @@ -142,7 +142,7 @@ final class TimelineProxy: TimelineProxyProtocol { do { let timelineEndReached = switch direction { case .backwards: try await timeline.paginateBackwards(numEvents: requestSize) - case .forwards: try await timeline.focusedPaginateForwards(numEvents: requestSize) + case .forwards: try await timeline.paginateForwards(numEvents: requestSize) } MXLog.info("Finished paginating \(direction.rawValue)") diff --git a/UnitTests/Sources/EmojiDetectionTests.swift b/UnitTests/Sources/EmojiDetectionTests.swift deleted file mode 100644 index 50dc801a11..0000000000 --- a/UnitTests/Sources/EmojiDetectionTests.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright 2023, 2024 New Vector Ltd. -// -// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial -// Please see LICENSE files in the repository root for full details. -// - -import XCTest - -@testable import ElementX - -class EmojiDetectionTests: XCTestCase { - func testEmojiDetection() { - XCTAssertTrue("👨‍👩‍đŸ‘Ļ".containsOnlyEmoji) - XCTAssertTrue("1ī¸âƒŖ".containsOnlyEmoji) - XCTAssertTrue("🚀".containsOnlyEmoji) - XCTAssertTrue("đŸ‘ŗ🏾‍♂ī¸".containsOnlyEmoji) - XCTAssertTrue("đŸĒŠ".containsOnlyEmoji) - - XCTAssertTrue("👨‍👩‍đŸ‘Ļ1ī¸âƒŖ🚀đŸ‘ŗ🏾‍♂ī¸đŸĒŠ".containsOnlyEmoji) - - XCTAssertFalse(" 👨‍👩‍đŸ‘Ļ".containsOnlyEmoji) - XCTAssertFalse(" 👨‍👩‍đŸ‘Ļ ".containsOnlyEmoji) - XCTAssertFalse("👨‍👩‍đŸ‘Ļ ".containsOnlyEmoji) - XCTAssertFalse("Ciao 👨‍👩‍đŸ‘Ļ peeps".containsOnlyEmoji) - - XCTAssertFalse("0".containsOnlyEmoji) - XCTAssertFalse("1".containsOnlyEmoji) - XCTAssertFalse("5".containsOnlyEmoji) - XCTAssertFalse("000".containsOnlyEmoji) - - XCTAssertTrue("👍".containsOnlyEmoji) - XCTAssertTrue("đŸĢąđŸŧ‍đŸĢ˛đŸž".containsOnlyEmoji) - XCTAssertFalse("🙂 ".containsOnlyEmoji) - XCTAssertFalse("Hello 👋".containsOnlyEmoji) - XCTAssertFalse("Thanks".containsOnlyEmoji) - - XCTAssertFalse("0*".containsOnlyEmoji) - } -} diff --git a/project.yml b/project.yml index a56dc18706..87d0619075 100644 --- a/project.yml +++ b/project.yml @@ -61,7 +61,7 @@ packages: # Element/Matrix dependencies MatrixRustSDK: url: https://github.com/element-hq/matrix-rust-components-swift - exactVersion: 25.01.22 + exactVersion: 25.01.27 # path: ../matrix-rust-sdk Compound: url: https://github.com/element-hq/compound-ios