diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift index b6361c47b..a71bdac83 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift @@ -47,6 +47,7 @@ enum HomeScreenViewAction { case skipSessionVerification case updateVisibleItemRange(range: Range, isScrolling: Bool) case selectInvites + case updatedSearchQuery } enum HomeScreenRoomListMode: CustomStringConvertible { @@ -84,11 +85,7 @@ struct HomeScreenViewState: BindableState { return placeholderRooms } - if bindings.searchQuery.isEmpty { - return rooms - } - - return rooms.filter { $0.name.localizedStandardContains(bindings.searchQuery) } + return rooms } var bindings = HomeScreenViewStateBindings() diff --git a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift index 9840f249f..71b0e27f5 100644 --- a/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift +++ b/ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift @@ -187,6 +187,8 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol callback?(.presentStartChatScreen) case .selectInvites: callback?(.presentInvitesScreen) + case .updatedSearchQuery: + roomSummaryProvider?.updateFilterPattern(state.bindings.searchQuery) } } diff --git a/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift b/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift index 6e33c9577..d27975d12 100644 --- a/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift +++ b/ElementX/Sources/Screens/HomeScreen/View/HomeScreen.swift @@ -79,8 +79,9 @@ struct HomeScreen: View { .onReceive(scrollViewAdapter.isScrolling) { _ in updateVisibleRange() } - .onChange(of: context.searchQuery) { searchQuery in - guard searchQuery.isEmpty else { return } + .onChange(of: context.searchQuery) { _ in + context.send(viewAction: .updatedSearchQuery) + // Dispatch allows the view to update after changing the query DispatchQueue.main.async { updateVisibleRange() } } diff --git a/ElementX/Sources/Services/Room/RoomSummary/MockRoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/MockRoomSummaryProvider.swift index 1a07170a8..525a23701 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/MockRoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/MockRoomSummaryProvider.swift @@ -45,6 +45,8 @@ class MockRoomSummaryProvider: RoomSummaryProviderProtocol { func setRoomList(_ roomList: RoomList) { } func updateVisibleRange(_ range: Range) { } + + func updateFilterPattern(_ pattern: String?) { } } extension Array where Element == RoomSummary { diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift index ddd5339ad..87df65917 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift @@ -28,6 +28,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { private var roomList: RoomListProtocol? private var cancellables = Set() + private var listUpdatesSubscriptionResult: RoomListEntriesWithDynamicFilterResult? private var listUpdatesTaskHandle: TaskHandle? private var stateUpdatesTaskHandle: TaskHandle? @@ -73,21 +74,17 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { self.roomList = roomList do { - let listUpdatesSubscriptionResult = roomList.entries(listener: RoomListEntriesListenerProxy { [weak self] updates in + listUpdatesSubscriptionResult = roomList.entriesWithDynamicFilter(listener: RoomListEntriesListenerProxy { [weak self] updates in guard let self else { return } MXLog.info("\(name): Received list update") diffsPublisher.send(updates) }) - - listUpdatesTaskHandle = listUpdatesSubscriptionResult.entriesStream - - rooms = listUpdatesSubscriptionResult.entries.map { roomListEntry in - buildSummaryForRoomListEntry(roomListEntry) - } - // Manually call it here as the didSet doesn't work from constructors - roomListSubject.send(rooms) + listUpdatesTaskHandle = listUpdatesSubscriptionResult?.entriesStream + // Forces the listener above to be called with the current state + updateFilterPattern(nil) + let stateUpdatesSubscriptionResult = try roomList.loadingState(listener: RoomListStateObserver { [weak self] state in guard let self else { return } MXLog.info("\(name): Received state update: \(state)") @@ -113,6 +110,15 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { } } + func updateFilterPattern(_ pattern: String?) { + guard let pattern, !pattern.isEmpty else { + _ = listUpdatesSubscriptionResult?.dynamicFilter.set(kind: .all) + return + } + + _ = listUpdatesSubscriptionResult?.dynamicFilter.set(kind: .fuzzyMatchRoomName(pattern: pattern.lowercased())) + } + // MARK: - Private fileprivate func updateRoomsWithDiffs(_ diffs: [RoomListEntriesUpdate]) { diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProviderProtocol.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProviderProtocol.swift index a804163fd..545bd2fdd 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProviderProtocol.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProviderProtocol.swift @@ -99,4 +99,6 @@ protocol RoomSummaryProviderProtocol { func setRoomList(_ roomList: RoomList) func updateVisibleRange(_ range: Range) + + func updateFilterPattern(_ pattern: String?) } diff --git a/changelog.d/pr-1483.feature b/changelog.d/pr-1483.feature new file mode 100644 index 000000000..f457e4115 --- /dev/null +++ b/changelog.d/pr-1483.feature @@ -0,0 +1 @@ +Allow fuzzy searching for room list rooms \ No newline at end of file