From eec2facab16d1d97271f03bf8150266715e549f2 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 1 Sep 2026 17:08:00 +0100 Subject: [PATCH] Add a Mentions room list filter (#5885) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a Mentions room list filter Adds a new filter chip to the room list that shows only rooms with unread mentions, using the new mentions room list filter from the Rust SDK (matrix-org/matrix-rust-sdk branch matthew/mentions-filter). The SDK version needs bumping to a release that includes the new filter kind before this can build against the released components. Co-Authored-By: Claude Fable 5 * Order the room list filters by expected usage Move Favourites ahead of People and Rooms so the more commonly used filters (Unreads, Mentions, Favourites) sit first in the chip row — Rooms and Invites are used rarely enough that it's fine for them to wrap off the side. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Uk8aPxHn3BHCe52L226jdG * update the SDK and use the appropriate rust filter types * preview tests + app settings flag for mentions --------- Co-authored-by: Claude Fable 5 Co-authored-by: Mauro Romito --- .../Sources/Generated/SDKGeneratedMocks.swift | 419 ++++++++++++++---- ElementX.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 6 +- .../en-US.lproj/Localizable.strings | 2 + .../en.lproj/Localizable.strings | 2 + .../Application/Settings/AppSettings.swift | 3 + ElementX/Sources/Generated/Strings.swift | 4 + .../View/Filters/RoomListFilterModels.swift | 17 +- .../RoomListFiltersEmptyStateView.swift | 2 + .../DeveloperOptionsScreenModels.swift | 1 + .../View/DeveloperOptionsScreen.swift | 4 + .../Services/Client/ClientFactory.swift | 2 + .../Sources/Services/Client/ClientProxy.swift | 5 - .../Services/Room/JoinedRoomProxy.swift | 2 +- .../RoomSummary/RoomSummaryProvider.swift | 2 +- .../homeScreen.Loaded-iPad-en-GB.png | 4 +- .../homeScreen.Loaded-iPad-pseudo.png | 4 +- .../homeScreen.Loaded-iPhone-en-GB.png | 4 +- .../homeScreen.Loaded-iPhone-pseudo.png | 4 +- ...ListFiltersEmptyStateView.iPad-en-GB-0.png | 4 +- ...istFiltersEmptyStateView.iPad-pseudo-0.png | 4 +- ...stFiltersEmptyStateView.iPhone-en-GB-0.png | 4 +- ...tFiltersEmptyStateView.iPhone-pseudo-0.png | 4 +- .../roomListFiltersView.iPad-en-GB-0.png | 4 +- .../roomListFiltersView.iPad-pseudo-0.png | 4 +- .../roomListFiltersView.iPhone-en-GB-0.png | 4 +- .../roomListFiltersView.iPhone-pseudo-0.png | 4 +- .../Sources/RoomListFiltersStateTests.swift | 38 +- project.yml | 2 +- 29 files changed, 440 insertions(+), 121 deletions(-) diff --git a/Components/SDKMocks/Sources/Generated/SDKGeneratedMocks.swift b/Components/SDKMocks/Sources/Generated/SDKGeneratedMocks.swift index f01fdd0a2..46afc5778 100644 --- a/Components/SDKMocks/Sources/Generated/SDKGeneratedMocks.swift +++ b/Components/SDKMocks/Sources/Generated/SDKGeneratedMocks.swift @@ -741,24 +741,6 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable { await enableAllSendQueuesEnableClosure?(enable) } - //MARK: - enableAutomaticBackpagination - - private let enableAutomaticBackpaginationCallsCountLock = NSLock() - private var enableAutomaticBackpaginationUnderlyingCallsCount = 0 - open var enableAutomaticBackpaginationCallsCount: Int { - get { enableAutomaticBackpaginationCallsCountLock.withLock { enableAutomaticBackpaginationUnderlyingCallsCount } } - set { enableAutomaticBackpaginationCallsCountLock.withLock { enableAutomaticBackpaginationUnderlyingCallsCount = newValue } } - } - open var enableAutomaticBackpaginationCalled: Bool { - return enableAutomaticBackpaginationCallsCount > 0 - } - open var enableAutomaticBackpaginationClosure: (() -> Void)? - - open override func enableAutomaticBackpagination() { - enableAutomaticBackpaginationCallsCountLock.withLock { enableAutomaticBackpaginationUnderlyingCallsCount += 1 } - enableAutomaticBackpaginationClosure?() - } - //MARK: - enableAutomaticCallStatus private let enableAutomaticCallStatusEnabledCallsCountLock = NSLock() @@ -1582,6 +1564,53 @@ open class ClientSDKMock: MatrixRustSDK.Client, @unchecked Sendable { } } + //MARK: - getUrlPreview + + open var getUrlPreviewUrlTsThrowableError: Error? + private let getUrlPreviewUrlTsCallsCountLock = NSLock() + private var getUrlPreviewUrlTsUnderlyingCallsCount = 0 + open var getUrlPreviewUrlTsCallsCount: Int { + get { getUrlPreviewUrlTsCallsCountLock.withLock { getUrlPreviewUrlTsUnderlyingCallsCount } } + set { getUrlPreviewUrlTsCallsCountLock.withLock { getUrlPreviewUrlTsUnderlyingCallsCount = newValue } } + } + open var getUrlPreviewUrlTsCalled: Bool { + return getUrlPreviewUrlTsCallsCount > 0 + } + private let getUrlPreviewUrlTsReceivedArgumentsLock = NSLock() + private var getUrlPreviewUrlTsUnderlyingReceivedArguments: (url: String, ts: UInt64?)? + open var getUrlPreviewUrlTsReceivedArguments: (url: String, ts: UInt64?)? { + get { getUrlPreviewUrlTsReceivedArgumentsLock.withLock { getUrlPreviewUrlTsUnderlyingReceivedArguments } } + set { getUrlPreviewUrlTsReceivedArgumentsLock.withLock { getUrlPreviewUrlTsUnderlyingReceivedArguments = newValue } } + } + private let getUrlPreviewUrlTsReceivedInvocationsLock = NSLock() + private var getUrlPreviewUrlTsUnderlyingReceivedInvocations: [(url: String, ts: UInt64?)] = [] + open var getUrlPreviewUrlTsReceivedInvocations: [(url: String, ts: UInt64?)] { + get { getUrlPreviewUrlTsReceivedInvocationsLock.withLock { getUrlPreviewUrlTsUnderlyingReceivedInvocations } } + set { getUrlPreviewUrlTsReceivedInvocationsLock.withLock { getUrlPreviewUrlTsUnderlyingReceivedInvocations = newValue } } + } + + private let getUrlPreviewUrlTsReturnValueLock = NSLock() + open var getUrlPreviewUrlTsUnderlyingReturnValue: String? + open var getUrlPreviewUrlTsReturnValue: String? { + get { getUrlPreviewUrlTsReturnValueLock.withLock { getUrlPreviewUrlTsUnderlyingReturnValue } } + set { getUrlPreviewUrlTsReturnValueLock.withLock { getUrlPreviewUrlTsUnderlyingReturnValue = newValue } } + } + open var getUrlPreviewUrlTsClosure: ((String, UInt64?) async throws -> String?)? + + open override func getUrlPreview(url: String, ts: UInt64?) async throws -> String? { + if let error = getUrlPreviewUrlTsThrowableError { + throw error + } + getUrlPreviewUrlTsCallsCountLock.withLock { getUrlPreviewUrlTsUnderlyingCallsCount += 1 } + getUrlPreviewUrlTsReceivedArguments = (url: url, ts: ts) + getUrlPreviewUrlTsReceivedInvocationsLock.withLock { getUrlPreviewUrlTsUnderlyingReceivedInvocations.append((url: url, ts: ts)) } + if let getUrlPreviewUrlTsClosure = getUrlPreviewUrlTsClosure { + return try await getUrlPreviewUrlTsClosure(url, ts) + } else { + return getUrlPreviewUrlTsReturnValue + } + } + //MARK: - homeserver private let homeserverCallsCountLock = NSLock() @@ -4916,6 +4945,49 @@ open class ClientBuilderSDKMock: MatrixRustSDK.ClientBuilder, @unchecked Sendabl } } + //MARK: - enableAutomaticBackPagination + + private let enableAutomaticBackPaginationEnableAutomaticBackPaginationCallsCountLock = NSLock() + private var enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingCallsCount = 0 + open var enableAutomaticBackPaginationEnableAutomaticBackPaginationCallsCount: Int { + get { enableAutomaticBackPaginationEnableAutomaticBackPaginationCallsCountLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingCallsCount } } + set { enableAutomaticBackPaginationEnableAutomaticBackPaginationCallsCountLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingCallsCount = newValue } } + } + open var enableAutomaticBackPaginationEnableAutomaticBackPaginationCalled: Bool { + return enableAutomaticBackPaginationEnableAutomaticBackPaginationCallsCount > 0 + } + private let enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedEnableAutomaticBackPaginationLock = NSLock() + private var enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReceivedEnableAutomaticBackPagination: Bool? + open var enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedEnableAutomaticBackPagination: Bool? { + get { enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedEnableAutomaticBackPaginationLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReceivedEnableAutomaticBackPagination } } + set { enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedEnableAutomaticBackPaginationLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReceivedEnableAutomaticBackPagination = newValue } } + } + private let enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedInvocationsLock = NSLock() + private var enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReceivedInvocations: [Bool] = [] + open var enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedInvocations: [Bool] { + get { enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedInvocationsLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReceivedInvocations } } + set { enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedInvocationsLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReceivedInvocations = newValue } } + } + + private let enableAutomaticBackPaginationEnableAutomaticBackPaginationReturnValueLock = NSLock() + open var enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReturnValue: ClientBuilder! + open var enableAutomaticBackPaginationEnableAutomaticBackPaginationReturnValue: ClientBuilder! { + get { enableAutomaticBackPaginationEnableAutomaticBackPaginationReturnValueLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReturnValue } } + set { enableAutomaticBackPaginationEnableAutomaticBackPaginationReturnValueLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReturnValue = newValue } } + } + open var enableAutomaticBackPaginationEnableAutomaticBackPaginationClosure: ((Bool) -> ClientBuilder)? + + open override func enableAutomaticBackPagination(enableAutomaticBackPagination: Bool) -> ClientBuilder { + enableAutomaticBackPaginationEnableAutomaticBackPaginationCallsCountLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingCallsCount += 1 } + enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedEnableAutomaticBackPagination = enableAutomaticBackPagination + enableAutomaticBackPaginationEnableAutomaticBackPaginationReceivedInvocationsLock.withLock { enableAutomaticBackPaginationEnableAutomaticBackPaginationUnderlyingReceivedInvocations.append(enableAutomaticBackPagination) } + if let enableAutomaticBackPaginationEnableAutomaticBackPaginationClosure = enableAutomaticBackPaginationEnableAutomaticBackPaginationClosure { + return enableAutomaticBackPaginationEnableAutomaticBackPaginationClosure(enableAutomaticBackPagination) + } else { + return enableAutomaticBackPaginationEnableAutomaticBackPaginationReturnValue + } + } + //MARK: - enableShareHistoryOnInvite private let enableShareHistoryOnInviteEnableShareHistoryOnInviteCallsCountLock = NSLock() @@ -9445,6 +9517,72 @@ open class RoomSDKMock: MatrixRustSDK.Room, @unchecked Sendable { } fileprivate var underlyingHandle: UInt64! + //MARK: - activeHumanMemberIds + + open var activeHumanMemberIdsThrowableError: Error? + private let activeHumanMemberIdsCallsCountLock = NSLock() + private var activeHumanMemberIdsUnderlyingCallsCount = 0 + open var activeHumanMemberIdsCallsCount: Int { + get { activeHumanMemberIdsCallsCountLock.withLock { activeHumanMemberIdsUnderlyingCallsCount } } + set { activeHumanMemberIdsCallsCountLock.withLock { activeHumanMemberIdsUnderlyingCallsCount = newValue } } + } + open var activeHumanMemberIdsCalled: Bool { + return activeHumanMemberIdsCallsCount > 0 + } + + private let activeHumanMemberIdsReturnValueLock = NSLock() + open var activeHumanMemberIdsUnderlyingReturnValue: [String]! + open var activeHumanMemberIdsReturnValue: [String]! { + get { activeHumanMemberIdsReturnValueLock.withLock { activeHumanMemberIdsUnderlyingReturnValue } } + set { activeHumanMemberIdsReturnValueLock.withLock { activeHumanMemberIdsUnderlyingReturnValue = newValue } } + } + open var activeHumanMemberIdsClosure: (() async throws -> [String])? + + open override func activeHumanMemberIds() async throws -> [String] { + if let error = activeHumanMemberIdsThrowableError { + throw error + } + activeHumanMemberIdsCallsCountLock.withLock { activeHumanMemberIdsUnderlyingCallsCount += 1 } + if let activeHumanMemberIdsClosure = activeHumanMemberIdsClosure { + return try await activeHumanMemberIdsClosure() + } else { + return activeHumanMemberIdsReturnValue + } + } + + //MARK: - activeHumanMemberIdsNoSync + + open var activeHumanMemberIdsNoSyncThrowableError: Error? + private let activeHumanMemberIdsNoSyncCallsCountLock = NSLock() + private var activeHumanMemberIdsNoSyncUnderlyingCallsCount = 0 + open var activeHumanMemberIdsNoSyncCallsCount: Int { + get { activeHumanMemberIdsNoSyncCallsCountLock.withLock { activeHumanMemberIdsNoSyncUnderlyingCallsCount } } + set { activeHumanMemberIdsNoSyncCallsCountLock.withLock { activeHumanMemberIdsNoSyncUnderlyingCallsCount = newValue } } + } + open var activeHumanMemberIdsNoSyncCalled: Bool { + return activeHumanMemberIdsNoSyncCallsCount > 0 + } + + private let activeHumanMemberIdsNoSyncReturnValueLock = NSLock() + open var activeHumanMemberIdsNoSyncUnderlyingReturnValue: [String]! + open var activeHumanMemberIdsNoSyncReturnValue: [String]! { + get { activeHumanMemberIdsNoSyncReturnValueLock.withLock { activeHumanMemberIdsNoSyncUnderlyingReturnValue } } + set { activeHumanMemberIdsNoSyncReturnValueLock.withLock { activeHumanMemberIdsNoSyncUnderlyingReturnValue = newValue } } + } + open var activeHumanMemberIdsNoSyncClosure: (() async throws -> [String])? + + open override func activeHumanMemberIdsNoSync() async throws -> [String] { + if let error = activeHumanMemberIdsNoSyncThrowableError { + throw error + } + activeHumanMemberIdsNoSyncCallsCountLock.withLock { activeHumanMemberIdsNoSyncUnderlyingCallsCount += 1 } + if let activeHumanMemberIdsNoSyncClosure = activeHumanMemberIdsNoSyncClosure { + return try await activeHumanMemberIdsNoSyncClosure() + } else { + return activeHumanMemberIdsNoSyncReturnValue + } + } + //MARK: - activeMembersCount private let activeMembersCountCallsCountLock = NSLock() @@ -13594,6 +13732,78 @@ open class RoomListServiceSDKMock: MatrixRustSDK.RoomListService, @unchecked Sen } } + //MARK: - removeRoomSubscriptions + + open var removeRoomSubscriptionsRoomIdsThrowableError: Error? + private let removeRoomSubscriptionsRoomIdsCallsCountLock = NSLock() + private var removeRoomSubscriptionsRoomIdsUnderlyingCallsCount = 0 + open var removeRoomSubscriptionsRoomIdsCallsCount: Int { + get { removeRoomSubscriptionsRoomIdsCallsCountLock.withLock { removeRoomSubscriptionsRoomIdsUnderlyingCallsCount } } + set { removeRoomSubscriptionsRoomIdsCallsCountLock.withLock { removeRoomSubscriptionsRoomIdsUnderlyingCallsCount = newValue } } + } + open var removeRoomSubscriptionsRoomIdsCalled: Bool { + return removeRoomSubscriptionsRoomIdsCallsCount > 0 + } + private let removeRoomSubscriptionsRoomIdsReceivedRoomIdsLock = NSLock() + private var removeRoomSubscriptionsRoomIdsUnderlyingReceivedRoomIds: [String]? + open var removeRoomSubscriptionsRoomIdsReceivedRoomIds: [String]? { + get { removeRoomSubscriptionsRoomIdsReceivedRoomIdsLock.withLock { removeRoomSubscriptionsRoomIdsUnderlyingReceivedRoomIds } } + set { removeRoomSubscriptionsRoomIdsReceivedRoomIdsLock.withLock { removeRoomSubscriptionsRoomIdsUnderlyingReceivedRoomIds = newValue } } + } + private let removeRoomSubscriptionsRoomIdsReceivedInvocationsLock = NSLock() + private var removeRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations: [[String]] = [] + open var removeRoomSubscriptionsRoomIdsReceivedInvocations: [[String]] { + get { removeRoomSubscriptionsRoomIdsReceivedInvocationsLock.withLock { removeRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations } } + set { removeRoomSubscriptionsRoomIdsReceivedInvocationsLock.withLock { removeRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations = newValue } } + } + open var removeRoomSubscriptionsRoomIdsClosure: (([String]) throws -> Void)? + + open override func removeRoomSubscriptions(roomIds: [String]) throws { + if let error = removeRoomSubscriptionsRoomIdsThrowableError { + throw error + } + removeRoomSubscriptionsRoomIdsCallsCountLock.withLock { removeRoomSubscriptionsRoomIdsUnderlyingCallsCount += 1 } + removeRoomSubscriptionsRoomIdsReceivedRoomIds = roomIds + removeRoomSubscriptionsRoomIdsReceivedInvocationsLock.withLock { removeRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations.append(roomIds) } + try removeRoomSubscriptionsRoomIdsClosure?(roomIds) + } + + //MARK: - resetAndAddRoomSubscriptions + + open var resetAndAddRoomSubscriptionsRoomIdsThrowableError: Error? + private let resetAndAddRoomSubscriptionsRoomIdsCallsCountLock = NSLock() + private var resetAndAddRoomSubscriptionsRoomIdsUnderlyingCallsCount = 0 + open var resetAndAddRoomSubscriptionsRoomIdsCallsCount: Int { + get { resetAndAddRoomSubscriptionsRoomIdsCallsCountLock.withLock { resetAndAddRoomSubscriptionsRoomIdsUnderlyingCallsCount } } + set { resetAndAddRoomSubscriptionsRoomIdsCallsCountLock.withLock { resetAndAddRoomSubscriptionsRoomIdsUnderlyingCallsCount = newValue } } + } + open var resetAndAddRoomSubscriptionsRoomIdsCalled: Bool { + return resetAndAddRoomSubscriptionsRoomIdsCallsCount > 0 + } + private let resetAndAddRoomSubscriptionsRoomIdsReceivedRoomIdsLock = NSLock() + private var resetAndAddRoomSubscriptionsRoomIdsUnderlyingReceivedRoomIds: [String]? + open var resetAndAddRoomSubscriptionsRoomIdsReceivedRoomIds: [String]? { + get { resetAndAddRoomSubscriptionsRoomIdsReceivedRoomIdsLock.withLock { resetAndAddRoomSubscriptionsRoomIdsUnderlyingReceivedRoomIds } } + set { resetAndAddRoomSubscriptionsRoomIdsReceivedRoomIdsLock.withLock { resetAndAddRoomSubscriptionsRoomIdsUnderlyingReceivedRoomIds = newValue } } + } + private let resetAndAddRoomSubscriptionsRoomIdsReceivedInvocationsLock = NSLock() + private var resetAndAddRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations: [[String]] = [] + open var resetAndAddRoomSubscriptionsRoomIdsReceivedInvocations: [[String]] { + get { resetAndAddRoomSubscriptionsRoomIdsReceivedInvocationsLock.withLock { resetAndAddRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations } } + set { resetAndAddRoomSubscriptionsRoomIdsReceivedInvocationsLock.withLock { resetAndAddRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations = newValue } } + } + open var resetAndAddRoomSubscriptionsRoomIdsClosure: (([String]) async throws -> Void)? + + open override func resetAndAddRoomSubscriptions(roomIds: [String]) async throws { + if let error = resetAndAddRoomSubscriptionsRoomIdsThrowableError { + throw error + } + resetAndAddRoomSubscriptionsRoomIdsCallsCountLock.withLock { resetAndAddRoomSubscriptionsRoomIdsUnderlyingCallsCount += 1 } + resetAndAddRoomSubscriptionsRoomIdsReceivedRoomIds = roomIds + resetAndAddRoomSubscriptionsRoomIdsReceivedInvocationsLock.withLock { resetAndAddRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations.append(roomIds) } + try await resetAndAddRoomSubscriptionsRoomIdsClosure?(roomIds) + } + //MARK: - room open var roomRoomIdThrowableError: Error? @@ -13641,6 +13851,42 @@ open class RoomListServiceSDKMock: MatrixRustSDK.RoomListService, @unchecked Sen } } + //MARK: - setRoomSubscriptions + + open var setRoomSubscriptionsRoomIdsThrowableError: Error? + private let setRoomSubscriptionsRoomIdsCallsCountLock = NSLock() + private var setRoomSubscriptionsRoomIdsUnderlyingCallsCount = 0 + open var setRoomSubscriptionsRoomIdsCallsCount: Int { + get { setRoomSubscriptionsRoomIdsCallsCountLock.withLock { setRoomSubscriptionsRoomIdsUnderlyingCallsCount } } + set { setRoomSubscriptionsRoomIdsCallsCountLock.withLock { setRoomSubscriptionsRoomIdsUnderlyingCallsCount = newValue } } + } + open var setRoomSubscriptionsRoomIdsCalled: Bool { + return setRoomSubscriptionsRoomIdsCallsCount > 0 + } + private let setRoomSubscriptionsRoomIdsReceivedRoomIdsLock = NSLock() + private var setRoomSubscriptionsRoomIdsUnderlyingReceivedRoomIds: [String]? + open var setRoomSubscriptionsRoomIdsReceivedRoomIds: [String]? { + get { setRoomSubscriptionsRoomIdsReceivedRoomIdsLock.withLock { setRoomSubscriptionsRoomIdsUnderlyingReceivedRoomIds } } + set { setRoomSubscriptionsRoomIdsReceivedRoomIdsLock.withLock { setRoomSubscriptionsRoomIdsUnderlyingReceivedRoomIds = newValue } } + } + private let setRoomSubscriptionsRoomIdsReceivedInvocationsLock = NSLock() + private var setRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations: [[String]] = [] + open var setRoomSubscriptionsRoomIdsReceivedInvocations: [[String]] { + get { setRoomSubscriptionsRoomIdsReceivedInvocationsLock.withLock { setRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations } } + set { setRoomSubscriptionsRoomIdsReceivedInvocationsLock.withLock { setRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations = newValue } } + } + open var setRoomSubscriptionsRoomIdsClosure: (([String]) async throws -> Void)? + + open override func setRoomSubscriptions(roomIds: [String]) async throws { + if let error = setRoomSubscriptionsRoomIdsThrowableError { + throw error + } + setRoomSubscriptionsRoomIdsCallsCountLock.withLock { setRoomSubscriptionsRoomIdsUnderlyingCallsCount += 1 } + setRoomSubscriptionsRoomIdsReceivedRoomIds = roomIds + setRoomSubscriptionsRoomIdsReceivedInvocationsLock.withLock { setRoomSubscriptionsRoomIdsUnderlyingReceivedInvocations.append(roomIds) } + try await setRoomSubscriptionsRoomIdsClosure?(roomIds) + } + //MARK: - state private let stateListenerCallsCountLock = NSLock() @@ -13684,42 +13930,6 @@ open class RoomListServiceSDKMock: MatrixRustSDK.RoomListService, @unchecked Sen } } - //MARK: - subscribeToRooms - - open var subscribeToRoomsRoomIdsThrowableError: Error? - private let subscribeToRoomsRoomIdsCallsCountLock = NSLock() - private var subscribeToRoomsRoomIdsUnderlyingCallsCount = 0 - open var subscribeToRoomsRoomIdsCallsCount: Int { - get { subscribeToRoomsRoomIdsCallsCountLock.withLock { subscribeToRoomsRoomIdsUnderlyingCallsCount } } - set { subscribeToRoomsRoomIdsCallsCountLock.withLock { subscribeToRoomsRoomIdsUnderlyingCallsCount = newValue } } - } - open var subscribeToRoomsRoomIdsCalled: Bool { - return subscribeToRoomsRoomIdsCallsCount > 0 - } - private let subscribeToRoomsRoomIdsReceivedRoomIdsLock = NSLock() - private var subscribeToRoomsRoomIdsUnderlyingReceivedRoomIds: [String]? - open var subscribeToRoomsRoomIdsReceivedRoomIds: [String]? { - get { subscribeToRoomsRoomIdsReceivedRoomIdsLock.withLock { subscribeToRoomsRoomIdsUnderlyingReceivedRoomIds } } - set { subscribeToRoomsRoomIdsReceivedRoomIdsLock.withLock { subscribeToRoomsRoomIdsUnderlyingReceivedRoomIds = newValue } } - } - private let subscribeToRoomsRoomIdsReceivedInvocationsLock = NSLock() - private var subscribeToRoomsRoomIdsUnderlyingReceivedInvocations: [[String]] = [] - open var subscribeToRoomsRoomIdsReceivedInvocations: [[String]] { - get { subscribeToRoomsRoomIdsReceivedInvocationsLock.withLock { subscribeToRoomsRoomIdsUnderlyingReceivedInvocations } } - set { subscribeToRoomsRoomIdsReceivedInvocationsLock.withLock { subscribeToRoomsRoomIdsUnderlyingReceivedInvocations = newValue } } - } - open var subscribeToRoomsRoomIdsClosure: (([String]) async throws -> Void)? - - open override func subscribeToRooms(roomIds: [String]) async throws { - if let error = subscribeToRoomsRoomIdsThrowableError { - throw error - } - subscribeToRoomsRoomIdsCallsCountLock.withLock { subscribeToRoomsRoomIdsUnderlyingCallsCount += 1 } - subscribeToRoomsRoomIdsReceivedRoomIds = roomIds - subscribeToRoomsRoomIdsReceivedInvocationsLock.withLock { subscribeToRoomsRoomIdsUnderlyingReceivedInvocations.append(roomIds) } - try await subscribeToRoomsRoomIdsClosure?(roomIds) - } - //MARK: - syncIndicator private let syncIndicatorDelayBeforeShowingInMsDelayBeforeHidingInMsListenerCallsCountLock = NSLock() @@ -15230,34 +15440,48 @@ open class SendHandleSDKMock: MatrixRustSDK.SendHandle, @unchecked Sendable { //MARK: - abort - open var abortThrowableError: Error? - private let abortCallsCountLock = NSLock() - private var abortUnderlyingCallsCount = 0 - open var abortCallsCount: Int { - get { abortCallsCountLock.withLock { abortUnderlyingCallsCount } } - set { abortCallsCountLock.withLock { abortUnderlyingCallsCount = newValue } } + open var abortReasonThrowableError: Error? + private let abortReasonCallsCountLock = NSLock() + private var abortReasonUnderlyingCallsCount = 0 + open var abortReasonCallsCount: Int { + get { abortReasonCallsCountLock.withLock { abortReasonUnderlyingCallsCount } } + set { abortReasonCallsCountLock.withLock { abortReasonUnderlyingCallsCount = newValue } } } - open var abortCalled: Bool { - return abortCallsCount > 0 + open var abortReasonCalled: Bool { + return abortReasonCallsCount > 0 + } + private let abortReasonReceivedReasonLock = NSLock() + private var abortReasonUnderlyingReceivedReason: String? + open var abortReasonReceivedReason: String? { + get { abortReasonReceivedReasonLock.withLock { abortReasonUnderlyingReceivedReason } } + set { abortReasonReceivedReasonLock.withLock { abortReasonUnderlyingReceivedReason = newValue } } + } + private let abortReasonReceivedInvocationsLock = NSLock() + private var abortReasonUnderlyingReceivedInvocations: [String?] = [] + open var abortReasonReceivedInvocations: [String?] { + get { abortReasonReceivedInvocationsLock.withLock { abortReasonUnderlyingReceivedInvocations } } + set { abortReasonReceivedInvocationsLock.withLock { abortReasonUnderlyingReceivedInvocations = newValue } } } - private let abortReturnValueLock = NSLock() - open var abortUnderlyingReturnValue: Bool! - open var abortReturnValue: Bool! { - get { abortReturnValueLock.withLock { abortUnderlyingReturnValue } } - set { abortReturnValueLock.withLock { abortUnderlyingReturnValue = newValue } } + private let abortReasonReturnValueLock = NSLock() + open var abortReasonUnderlyingReturnValue: Bool! + open var abortReasonReturnValue: Bool! { + get { abortReasonReturnValueLock.withLock { abortReasonUnderlyingReturnValue } } + set { abortReasonReturnValueLock.withLock { abortReasonUnderlyingReturnValue = newValue } } } - open var abortClosure: (() async throws -> Bool)? + open var abortReasonClosure: ((String?) async throws -> Bool)? - open override func abort() async throws -> Bool { - if let error = abortThrowableError { + open override func abort(reason: String? = nil) async throws -> Bool { + if let error = abortReasonThrowableError { throw error } - abortCallsCountLock.withLock { abortUnderlyingCallsCount += 1 } - if let abortClosure = abortClosure { - return try await abortClosure() + abortReasonCallsCountLock.withLock { abortReasonUnderlyingCallsCount += 1 } + abortReasonReceivedReason = reason + abortReasonReceivedInvocationsLock.withLock { abortReasonUnderlyingReceivedInvocations.append(reason) } + if let abortReasonClosure = abortReasonClosure { + return try await abortReasonClosure(reason) } else { - return abortReturnValue + return abortReasonReturnValue } } @@ -17674,6 +17898,53 @@ open class TimelineSDKMock: MatrixRustSDK.Timeline, @unchecked Sendable { try await editEventOrTransactionIdNewContentClosure?(eventOrTransactionId, newContent) } + //MARK: - editRevisions + + open var editRevisionsEventIdThrowableError: Error? + private let editRevisionsEventIdCallsCountLock = NSLock() + private var editRevisionsEventIdUnderlyingCallsCount = 0 + open var editRevisionsEventIdCallsCount: Int { + get { editRevisionsEventIdCallsCountLock.withLock { editRevisionsEventIdUnderlyingCallsCount } } + set { editRevisionsEventIdCallsCountLock.withLock { editRevisionsEventIdUnderlyingCallsCount = newValue } } + } + open var editRevisionsEventIdCalled: Bool { + return editRevisionsEventIdCallsCount > 0 + } + private let editRevisionsEventIdReceivedEventIdLock = NSLock() + private var editRevisionsEventIdUnderlyingReceivedEventId: String? + open var editRevisionsEventIdReceivedEventId: String? { + get { editRevisionsEventIdReceivedEventIdLock.withLock { editRevisionsEventIdUnderlyingReceivedEventId } } + set { editRevisionsEventIdReceivedEventIdLock.withLock { editRevisionsEventIdUnderlyingReceivedEventId = newValue } } + } + private let editRevisionsEventIdReceivedInvocationsLock = NSLock() + private var editRevisionsEventIdUnderlyingReceivedInvocations: [String] = [] + open var editRevisionsEventIdReceivedInvocations: [String] { + get { editRevisionsEventIdReceivedInvocationsLock.withLock { editRevisionsEventIdUnderlyingReceivedInvocations } } + set { editRevisionsEventIdReceivedInvocationsLock.withLock { editRevisionsEventIdUnderlyingReceivedInvocations = newValue } } + } + + private let editRevisionsEventIdReturnValueLock = NSLock() + open var editRevisionsEventIdUnderlyingReturnValue: [EditRevisionRecord]! + open var editRevisionsEventIdReturnValue: [EditRevisionRecord]! { + get { editRevisionsEventIdReturnValueLock.withLock { editRevisionsEventIdUnderlyingReturnValue } } + set { editRevisionsEventIdReturnValueLock.withLock { editRevisionsEventIdUnderlyingReturnValue = newValue } } + } + open var editRevisionsEventIdClosure: ((String) async throws -> [EditRevisionRecord])? + + open override func editRevisions(eventId: String) async throws -> [EditRevisionRecord] { + if let error = editRevisionsEventIdThrowableError { + throw error + } + editRevisionsEventIdCallsCountLock.withLock { editRevisionsEventIdUnderlyingCallsCount += 1 } + editRevisionsEventIdReceivedEventId = eventId + editRevisionsEventIdReceivedInvocationsLock.withLock { editRevisionsEventIdUnderlyingReceivedInvocations.append(eventId) } + if let editRevisionsEventIdClosure = editRevisionsEventIdClosure { + return try await editRevisionsEventIdClosure(eventId) + } else { + return editRevisionsEventIdReturnValue + } + } + //MARK: - endPoll open var endPollPollStartEventIdTextThrowableError: Error? diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index 015799a9d..977f24ae5 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -10813,7 +10813,7 @@ repositoryURL = "https://github.com/element-hq/matrix-rust-components-swift"; requirement = { kind = exactVersion; - version = 26.08.27; + version = 26.09.01; }; }; 701C7BEF8F70F7A83E852DCC /* XCRemoteSwiftPackageReference "GZIP" */ = { diff --git a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 21818ba9b..77804fdca 100644 --- a/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "20b091ffed1191ab205d228b4682ceec9698235e1d8eb82e9aba1703fc8e9f05", + "originHash" : "bcdaa8f9cef68194f84e2cedfc8f5b970018b430090e70cabca834140c3573a5", "pins" : [ { "identity" : "compound-design-tokens", @@ -167,8 +167,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/element-hq/matrix-rust-components-swift", "state" : { - "revision" : "13503ceebfa90f7cc3c0c5de6392fcc73d993570", - "version" : "26.8.27" + "revision" : "5aba7a6306b02e79157831e8e352a9a959003e5b", + "version" : "26.9.1" } }, { diff --git a/ElementX/Resources/Localizations/en-US.lproj/Localizable.strings b/ElementX/Resources/Localizations/en-US.lproj/Localizable.strings index ce0ef486e..c3047fd13 100644 --- a/ElementX/Resources/Localizations/en-US.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en-US.lproj/Localizable.strings @@ -1432,6 +1432,8 @@ "screen_roomlist_filter_invites_empty_state_title" = "You don't have any pending invites."; "screen_roomlist_filter_low_priority" = "Low Priority"; "screen_roomlist_filter_low_priority_empty_state_title" = "You don’t have any low priority chats yet"; +"screen_roomlist_filter_mention" = "Mention"; +"screen_roomlist_filter_mention_empty_state_title" = "You don’t have any unread mentions"; "screen_roomlist_filter_mixed_empty_state_subtitle" = "You can deselect filters in order to see your other chats"; "screen_roomlist_filter_mixed_empty_state_title" = "You don’t have chats for this selection"; "screen_roomlist_filter_people" = "People"; diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index 9dcb159c0..f866d381f 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -1432,6 +1432,8 @@ "screen_roomlist_filter_invites_empty_state_title" = "You don't have any pending invites."; "screen_roomlist_filter_low_priority" = "Low Priority"; "screen_roomlist_filter_low_priority_empty_state_title" = "You don’t have any low priority chats yet"; +"screen_roomlist_filter_mention" = "Mention"; +"screen_roomlist_filter_mention_empty_state_title" = "You don’t have any unread mentions"; "screen_roomlist_filter_mixed_empty_state_subtitle" = "You can deselect filters in order to see your other chats"; "screen_roomlist_filter_mixed_empty_state_title" = "You don’t have chats for this selection"; "screen_roomlist_filter_people" = "People"; diff --git a/ElementX/Sources/Application/Settings/AppSettings.swift b/ElementX/Sources/Application/Settings/AppSettings.swift index 90984ac7d..a2f2cd342 100644 --- a/ElementX/Sources/Application/Settings/AppSettings.swift +++ b/ElementX/Sources/Application/Settings/AppSettings.swift @@ -407,6 +407,9 @@ final nonisolated class AppSettings: @unchecked Sendable { @UserPreference(defaultValue: false) var lowPriorityFilterEnabled: Bool + @UserPreference(defaultValue: false) + var mentionsFilterEnabled: Bool + /// Configuration to enable only signed device isolation mode for crypto. In this mode only devices signed by their owner will be considered in e2ee rooms. @UserPreference(defaultValue: false) var enableOnlySignedDeviceIsolationMode: Bool diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index 0aad2b644..4bcb3b248 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -3339,6 +3339,10 @@ internal nonisolated enum L10n { internal static var screenRoomlistFilterLowPriority: String { return L10n.tr("Localizable", "screen_roomlist_filter_low_priority") } /// You don’t have any low priority chats yet internal static var screenRoomlistFilterLowPriorityEmptyStateTitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_low_priority_empty_state_title") } + /// Mention + internal static var screenRoomlistFilterMention: String { return L10n.tr("Localizable", "screen_roomlist_filter_mention") } + /// You don’t have any unread mentions + internal static var screenRoomlistFilterMentionEmptyStateTitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_mention_empty_state_title") } /// You can deselect filters in order to see your other chats internal static var screenRoomlistFilterMixedEmptyStateSubtitle: String { return L10n.tr("Localizable", "screen_roomlist_filter_mixed_empty_state_subtitle") } /// You don’t have chats for this selection diff --git a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFilterModels.swift b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFilterModels.swift index 4f44b5ca9..9d9ea9f80 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFilterModels.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFilterModels.swift @@ -17,9 +17,10 @@ enum RoomListFilter: Int, CaseIterable, Identifiable { } case unreads + case mentions + case favourites case people case rooms - case favourites case invites case lowPriority @@ -35,6 +36,8 @@ enum RoomListFilter: Int, CaseIterable, Identifiable { return L10n.screenRoomlistFilterRooms case .unreads: return L10n.screenRoomlistFilterUnreads + case .mentions: + return L10n.screenRoomlistFilterMention case .favourites: return L10n.screenRoomlistFilterFavourites case .invites: @@ -52,10 +55,12 @@ enum RoomListFilter: Int, CaseIterable, Identifiable { return [.people, .invites] case .unreads: return [.invites] + case .mentions: + return [.invites] case .favourites: return [.invites, .lowPriority] case .invites: - return [.rooms, .people, .unreads, .favourites, .lowPriority] + return [.rooms, .people, .unreads, .mentions, .favourites, .lowPriority] case .lowPriority: return [.favourites, .invites] } @@ -68,7 +73,9 @@ enum RoomListFilter: Int, CaseIterable, Identifiable { case .rooms: return .all(filters: [.category(expect: .group), .joined]) case .unreads: - return .all(filters: [.unread, .joined]) + return .all(filters: [.readReceipts(expect: .notifications), .joined]) + case .mentions: + return .all(filters: [.readReceipts(expect: .mentions), .joined]) case .favourites: return .all(filters: [.favourite, .joined]) case .invites: @@ -96,6 +103,10 @@ struct RoomListFiltersState { availableFilters.remove(.lowPriority) } + if !appSettings.mentionsFilterEnabled { + availableFilters.remove(.mentions) + } + for filter in activeFilters { availableFilters.remove(filter) filter.incompatibleFilters.forEach { availableFilters.remove($0) } diff --git a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift index 38ba08b01..4d7a78d72 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/Filters/RoomListFiltersEmptyStateView.swift @@ -16,6 +16,8 @@ struct RoomListFiltersEmptyStateView: View { switch state.activeFilters[0] { case .unreads: return L10n.screenRoomlistFilterUnreadsEmptyStateTitle + case .mentions: + return L10n.screenRoomlistFilterMentionEmptyStateTitle case .people: return L10n.screenRoomlistFilterPeopleEmptyStateTitle case .rooms: diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift index 60e452cbc..6cfd3f5bf 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/DeveloperOptionsScreenModels.swift @@ -63,6 +63,7 @@ protocol DeveloperOptionsProtocol: AnyObject { var fuzzyRoomListSearchEnabled: Bool { get set } var lowPriorityFilterEnabled: Bool { get set } + var mentionsFilterEnabled: Bool { get set } var knockingEnabled: Bool { get set } var linkPreviewsEnabled: Bool { get set } diff --git a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift index af3b0c8ad..7928c5eb3 100644 --- a/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift +++ b/ElementX/Sources/Screens/Settings/DeveloperOptionsScreen/View/DeveloperOptionsScreen.swift @@ -75,6 +75,10 @@ struct DeveloperOptionsScreen: View { Text("Low priority filter") } + Toggle(isOn: $context.mentionsFilterEnabled) { + Text("Mentions filter") + } + Toggle(isOn: $context.automaticBackPaginationEnabled) { Text("Automatic back pagination") Text("Requires app reboot") diff --git a/ElementX/Sources/Services/Client/ClientFactory.swift b/ElementX/Sources/Services/Client/ClientFactory.swift index 6e08766de..ecc8155e5 100644 --- a/ElementX/Sources/Services/Client/ClientFactory.swift +++ b/ElementX/Sources/Services/Client/ClientFactory.swift @@ -26,6 +26,7 @@ nonisolated struct ClientFactory: ClientFactoryProtocol { appHooks: appHooks, enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode, threadsEnabled: appSettings.threadsEnabled) + .enableAutomaticBackPagination(enableAutomaticBackPagination: appSettings.automaticBackPaginationEnabled) .sqliteStore(config: .init(dataPath: sessionDirectories.dataPath, cachePath: sessionDirectories.cachePath) .passphrase(passphrase: passphrase)) .serverNameOrHomeserverUrl(serverNameOrUrl: homeserverAddress) @@ -63,6 +64,7 @@ nonisolated struct ClientFactory: ClientFactoryProtocol { appHooks: appHooks, enableOnlySignedDeviceIsolationMode: appSettings.enableOnlySignedDeviceIsolationMode, threadsEnabled: appSettings.threadsEnabled) + .enableAutomaticBackPagination(enableAutomaticBackPagination: appSettings.automaticBackPaginationEnabled) .sqliteStore(config: .init(dataPath: credentials.restorationToken.sessionDirectories.dataPath, cachePath: credentials.restorationToken.sessionDirectories.cachePath) .passphrase(passphrase: credentials.restorationToken.passphrase)) diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index fbf7251f5..0a33d1401 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -214,11 +214,6 @@ class ClientProxy: ClientProxyProtocol { userProfileSubject = .init(UserProfile(userID: (try? client.userId()) ?? "")) - if appSettings.automaticBackPaginationEnabled { - // Must be called before creating the sync service, timelines etc. - client.enableAutomaticBackpagination() - } - mediaLoader = MediaLoader(client: client) // Route media downloads through a content scanner when one has been configured for the server, diff --git a/ElementX/Sources/Services/Room/JoinedRoomProxy.swift b/ElementX/Sources/Services/Room/JoinedRoomProxy.swift index 114045b7a..60de9d80a 100644 --- a/ElementX/Sources/Services/Room/JoinedRoomProxy.swift +++ b/ElementX/Sources/Services/Room/JoinedRoomProxy.swift @@ -114,7 +114,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol { subscribedForUpdates = true do { - try await roomListService.subscribeToRooms(roomIds: [id]) + try await roomListService.setRoomSubscriptions(roomIds: [id]) } catch { MXLog.error("Failed subscribing to room with error: \(error)") } diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift index b7f79c504..646b6b198 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift @@ -246,7 +246,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { Task { [weak self] in do { - try await self?.roomListService.subscribeToRooms(roomIds: roomIDs) + try await self?.roomListService.setRoomSubscriptions(roomIds: roomIDs) } catch { MXLog.error("Failed subscribing to rooms with error: \(error)") } diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPad-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPad-en-GB.png index a9a371721..5dbccec65 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPad-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPad-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:58137b15f53694ca640c21b2b6c148a4a79fb87dd9f73c72e6ebfadbbdd59350 -size 287230 +oid sha256:c02bce898b1b152d033925056fbc6988aa26586e51c72a197f451a8fee6d6165 +size 287212 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPad-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPad-pseudo.png index 91aeb7a7e..dafc3afb3 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPad-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPad-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a7c68d341aaab43644e0a19c7b945330e30ebb9f792a68cef9e6e5356a65fefe -size 297881 +oid sha256:d6d245a8f330678b0cce10db60408839e0f6a7bbf3e8d0f1e4c4413311485b79 +size 297921 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPhone-en-GB.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPhone-en-GB.png index 3001029c5..0730416ab 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPhone-en-GB.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPhone-en-GB.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:699086a1955139e3dde58d790fbde8c9b7786e9733bb8633cd285caae3e945a2 -size 203524 +oid sha256:21900e354eb87dacdb3eb86c8ea6cc89ca3ca5440360d72857027d3a42f75b7d +size 203557 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPhone-pseudo.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPhone-pseudo.png index 5e87711a9..44da87703 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPhone-pseudo.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/homeScreen.Loaded-iPhone-pseudo.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:683c200b9610218b12e1c55678181190b6b2172f9973997be68641dc013f4745 -size 209725 +oid sha256:9618c5743c9f49ea3f59238f9a8aef209275461954be2ab7faa8d6caadf4da3f +size 209937 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPad-en-GB-0.png index f03e7b301..dadecafe3 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPad-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPad-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fce400b18722256d7c24622726c553318fc6266dddf90361d6f77e03296e0e38 -size 188015 +oid sha256:9222c9c7b7e7a1b943caf556e1a52c8a06a8529c8af5e19346ccb27c46f3ffbe +size 212590 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPad-pseudo-0.png index 7e5dc282d..284fcb454 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPad-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPad-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:48ab58418ad2831c39a906d0abe1242f23e5582af3da801b4d2188964daeb640 -size 237078 +oid sha256:f0f65d8af54ba61434507f3680b7da6b6749b435f4e64b97c3d33c058b7788ec +size 264744 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPhone-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPhone-en-GB-0.png index 540a5d2eb..d1d5f7725 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPhone-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPhone-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a896bccdb2ee452b4e067e8d8e5dc8b78007e3c3904ba20293a58c1b7461f4b8 -size 173467 +oid sha256:87d818e2f3cb66ab8022b559f863f040dabe6372c5c70c016afd3309c2c66f40 +size 196609 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPhone-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPhone-pseudo-0.png index 286a5b453..42ddd551c 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPhone-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersEmptyStateView.iPhone-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:29e265bc02c1114e2a97d4eb8f42ecaec66b69556f9da2de95580acd3074f8a8 -size 323381 +oid sha256:f29790007f2d377d44008be11626a30bcfed2395e868d1e9ba7c154faebccd8d +size 364929 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPad-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPad-en-GB-0.png index 9bc0d159b..627eea5cc 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPad-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPad-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69e544e36a969d194f839cd14ec2a078a867f29c47e986ce620b0405c1ab10c2 -size 76539 +oid sha256:6db2ba7dce6ca9adfda2b1f04c9a8a1c1ac620e10f63a150512f7f5bb1e9d408 +size 76512 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPad-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPad-pseudo-0.png index 2bf1a01b4..6bc8be6a0 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPad-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPad-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f5ec5862b009b4409dc23dc5c1dbb1c65582c13d290ee144197520aad16fdcf -size 81060 +oid sha256:483efa6ea441734da0ec36655ed95f368622f5327e62f380f8256267fb6966fa +size 81098 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPhone-en-GB-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPhone-en-GB-0.png index f698438d4..59dd359b9 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPhone-en-GB-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPhone-en-GB-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e6b424f570806806839c4f113547012198c56b8773e82bc099bbef1b3434f241 -size 35515 +oid sha256:df640a03c091cdddb5faff742a029368b8877f00aa99e2b495e600bddb174345 +size 35357 diff --git a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPhone-pseudo-0.png b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPhone-pseudo-0.png index e2c698012..461828cf8 100644 --- a/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPhone-pseudo-0.png +++ b/PreviewTests/Sources/__Snapshots__/PreviewTests/roomListFiltersView.iPhone-pseudo-0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:703f9cde60567f6d6da656ec73a1715bf9030ba322aa9b9c61fa56e188e6df2e -size 35567 +oid sha256:8e43f0fbdc85743cc981bad603fc472340ecc89ce5b1f47b8d539f0e4b705c27 +size 35866 diff --git a/UnitTests/Sources/RoomListFiltersStateTests.swift b/UnitTests/Sources/RoomListFiltersStateTests.swift index 9aea35b46..875ae0c50 100644 --- a/UnitTests/Sources/RoomListFiltersStateTests.swift +++ b/UnitTests/Sources/RoomListFiltersStateTests.swift @@ -13,7 +13,8 @@ import Testing final class RoomListFiltersStateTests { var appSettings: AppSettings var state: RoomListFiltersState - let allCasesWithoutLowPriority = RoomListFilter.allCases.filter { $0 != .lowPriority } + /// The filters that aren't hidden behind a feature flag. + let defaultFilters = RoomListFilter.allCases.filter { $0 != .mentions && $0 != .lowPriority } init() { appSettings = AppSettings.volatile() @@ -24,7 +25,7 @@ final class RoomListFiltersStateTests { func initialState() { #expect(!state.isFiltering) #expect(state.activeFilters == []) - #expect(state.availableFilters == allCasesWithoutLowPriority) + #expect(state.availableFilters == defaultFilters) } @Test @@ -32,11 +33,11 @@ final class RoomListFiltersStateTests { state.activateFilter(.unreads) #expect(state.isFiltering) #expect(state.activeFilters == [.unreads]) - #expect(state.availableFilters == [.people, .rooms, .favourites]) + #expect(state.availableFilters == [.favourites, .people, .rooms]) state.deactivateFilter(.unreads) #expect(!state.isFiltering) #expect(state.activeFilters == []) - #expect(state.availableFilters == allCasesWithoutLowPriority) + #expect(state.availableFilters == defaultFilters) } @Test @@ -49,7 +50,7 @@ final class RoomListFiltersStateTests { state.deactivateFilter(.people) #expect(!state.isFiltering) #expect(state.activeFilters == []) - #expect(state.availableFilters == allCasesWithoutLowPriority) + #expect(state.availableFilters == defaultFilters) state.activateFilter(.rooms) #expect(state.isFiltering) @@ -87,7 +88,7 @@ final class RoomListFiltersStateTests { state.clearFilters() #expect(!state.isFiltering) #expect(state.activeFilters == []) - #expect(state.availableFilters == allCasesWithoutLowPriority) + #expect(state.availableFilters == defaultFilters) } @Test @@ -98,7 +99,7 @@ final class RoomListFiltersStateTests { state.deactivateFilter(.favourites) #expect(state.activeFilters == []) - #expect(state.availableFilters == allCasesWithoutLowPriority) + #expect(state.availableFilters == defaultFilters) state.activateFilter(.rooms) #expect(state.activeFilters == [.rooms]) @@ -121,17 +122,38 @@ final class RoomListFiltersStateTests { enableLowPriorityFeature() #expect(!state.isFiltering) #expect(state.activeFilters == []) - #expect(state.availableFilters == RoomListFilter.allCases) + #expect(state.availableFilters == defaultFilters + [.lowPriority]) state.activateFilter(.lowPriority) #expect(state.activeFilters == [.lowPriority]) #expect(state.availableFilters == [.unreads, .people, .rooms]) } + // MARK: Mentions feature flag + + /// Don't forget to add .mentions into the mix above when enabling the feature. + @Test + func withMentionsFeature() { + enableMentionsFeature() + #expect(!state.isFiltering) + #expect(state.activeFilters == []) + #expect(state.availableFilters == [.unreads, .mentions, .favourites, .people, .rooms, .invites]) + + state.activateFilter(.mentions) + #expect(state.isFiltering) + #expect(state.activeFilters == [.mentions]) + #expect(state.availableFilters == [.unreads, .favourites, .people, .rooms]) + } + // MARK: - Helpers private func enableLowPriorityFeature() { appSettings.lowPriorityFilterEnabled = true state = RoomListFiltersState(appSettings: appSettings) } + + private func enableMentionsFeature() { + appSettings.mentionsFilterEnabled = true + state = RoomListFiltersState(appSettings: appSettings) + } } diff --git a/project.yml b/project.yml index 7c0a000d1..5ce740dfd 100644 --- a/project.yml +++ b/project.yml @@ -74,7 +74,7 @@ packages: # Element/Matrix dependencies MatrixRustSDK: url: https://github.com/element-hq/matrix-rust-components-swift - exactVersion: 26.08.27 + exactVersion: 26.09.01 # path: ../matrix-rust-sdk Compound: path: compound-ios