diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index 0ba05ce7d..871c156b9 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -577,14 +577,19 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { // MARK: Room Directory Search private func presentRoomDirectorySearch() { - let coordinator = RoomDirectorySearchScreenCoordinator(parameters: .init(roomDirectorySearchProxy: userSession.clientProxy.roomDirectorySearchProxy(), + let coordinator = RoomDirectorySearchScreenCoordinator(parameters: .init(clientProxy: userSession.clientProxy, imageProvider: userSession.mediaProvider, userIndicatorController: ServiceLocator.shared.userIndicatorController)) coordinator.actionsPublisher.sink { [weak self] action in + guard let self else { return } + switch action { + case .joined(let roomID): + stateMachine.processEvent(.dismissedRoomDirectorySearchScreen) + handleAppRoute(.room(roomID: roomID), animated: true) case .dismiss: - self?.stateMachine.processEvent(.dismissedRoomDirectorySearchScreen(joinedRoomID: nil)) + stateMachine.processEvent(.dismissedRoomDirectorySearchScreen) } } .store(in: &cancellables) diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift index 9d1c6c9ed..ff950300d 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinatorStateMachine.swift @@ -86,7 +86,8 @@ class UserSessionFlowCoordinatorStateMachine { case dismissedLogoutConfirmationScreen case showRoomDirectorySearchScreen - case dismissedRoomDirectorySearchScreen(joinedRoomID: String?) + + case dismissedRoomDirectorySearchScreen } private let stateMachine: StateMachine @@ -144,10 +145,7 @@ class UserSessionFlowCoordinatorStateMachine { case (.roomList(let selectedRoomID), .showRoomDirectorySearchScreen): return .roomDirectorySearchScreen(selectedRoomID: selectedRoomID) - case (.roomDirectorySearchScreen(let selectedRoomID), .dismissedRoomDirectorySearchScreen(let joinedRoomID)): - if let joinedRoomID { - return .roomList(selectedRoomID: joinedRoomID) - } + case (.roomDirectorySearchScreen(let selectedRoomID), .dismissedRoomDirectorySearchScreen): return .roomList(selectedRoomID: selectedRoomID) default: diff --git a/ElementX/Sources/Mocks/ClientProxyMock.swift b/ElementX/Sources/Mocks/ClientProxyMock.swift index 37c52feb6..a35f62e1d 100644 --- a/ElementX/Sources/Mocks/ClientProxyMock.swift +++ b/ElementX/Sources/Mocks/ClientProxyMock.swift @@ -21,6 +21,7 @@ struct ClientProxyMockConfiguration { var userID: String = RoomMemberProxyMock.mockMe.userID var deviceID: String? var roomSummaryProvider: RoomSummaryProviderProtocol? = RoomSummaryProviderMock(.init()) + var roomDirectorySearchProxy: RoomDirectorySearchProxyProtocol? } extension ClientProxyMock { @@ -36,6 +37,8 @@ extension ClientProxyMock { alternateRoomSummaryProvider = RoomSummaryProviderMock(.init()) inviteSummaryProvider = RoomSummaryProviderMock(.init()) + roomDirectorySearchProxyReturnValue = configuration.roomDirectorySearchProxy + actionsPublisher = PassthroughSubject().eraseToAnyPublisher() loadingStatePublisher = CurrentValuePublisher(.notLoading) verificationStatePublisher = CurrentValuePublisher(.unknown) diff --git a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift index 197b726fa..80a75f317 100644 --- a/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift +++ b/ElementX/Sources/Mocks/Generated/GeneratedMocks.swift @@ -898,6 +898,27 @@ class ClientProxyMock: ClientProxyProtocol { return createRoomNameTopicIsRoomPrivateUserIDsAvatarURLReturnValue } } + //MARK: - joinRoom + + var joinRoomCallsCount = 0 + var joinRoomCalled: Bool { + return joinRoomCallsCount > 0 + } + var joinRoomReceivedRoomID: String? + var joinRoomReceivedInvocations: [String] = [] + var joinRoomReturnValue: Result! + var joinRoomClosure: ((String) async -> Result)? + + func joinRoom(_ roomID: String) async -> Result { + joinRoomCallsCount += 1 + joinRoomReceivedRoomID = roomID + joinRoomReceivedInvocations.append(roomID) + if let joinRoomClosure = joinRoomClosure { + return await joinRoomClosure(roomID) + } else { + return joinRoomReturnValue + } + } //MARK: - uploadMedia var uploadMediaCallsCount = 0 diff --git a/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenCoordinator.swift b/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenCoordinator.swift index e6f36fec8..eac60bf5a 100644 --- a/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenCoordinator.swift +++ b/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenCoordinator.swift @@ -18,12 +18,13 @@ import Combine import SwiftUI struct RoomDirectorySearchScreenCoordinatorParameters { - let roomDirectorySearchProxy: RoomDirectorySearchProxyProtocol + let clientProxy: ClientProxyProtocol let imageProvider: ImageProviderProtocol let userIndicatorController: UserIndicatorControllerProtocol } enum RoomDirectorySearchScreenCoordinatorAction { + case joined(roomID: String) case dismiss } @@ -31,22 +32,26 @@ final class RoomDirectorySearchScreenCoordinator: CoordinatorProtocol { private let viewModel: RoomDirectorySearchScreenViewModelProtocol private var cancellables = Set() - + private let actionsSubject: PassthroughSubject = .init() var actionsPublisher: AnyPublisher { actionsSubject.eraseToAnyPublisher() } init(parameters: RoomDirectorySearchScreenCoordinatorParameters) { - viewModel = RoomDirectorySearchScreenViewModel(roomDirectorySearch: parameters.roomDirectorySearchProxy, userIndicatorController: parameters.userIndicatorController, imageProvider: parameters.imageProvider) + viewModel = RoomDirectorySearchScreenViewModel(clientProxy: parameters.clientProxy, + userIndicatorController: parameters.userIndicatorController, + imageProvider: parameters.imageProvider) } func start() { viewModel.actionsPublisher.sink { [weak self] action in guard let self else { return } switch action { + case .joined(let roomID): + actionsSubject.send(.joined(roomID: roomID)) case .dismiss: - self.actionsSubject.send(.dismiss) + actionsSubject.send(.dismiss) } } .store(in: &cancellables) diff --git a/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenModels.swift b/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenModels.swift index 864b332ba..b3385bb51 100644 --- a/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenModels.swift +++ b/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenModels.swift @@ -17,11 +17,12 @@ import Foundation enum RoomDirectorySearchScreenViewModelAction { + case joined(roomID: String) case dismiss } struct RoomDirectorySearchScreenViewState: BindableState { - var searchResults: [RoomDirectorySearchResult] = [] + var rooms: [RoomDirectorySearchResult] = [] var isLoading = false var bindings = RoomDirectorySearchScreenViewStateBindings() @@ -35,4 +36,5 @@ struct RoomDirectorySearchScreenViewStateBindings { enum RoomDirectorySearchScreenViewAction { case dismiss case join(roomID: String) + case reachedBottom } diff --git a/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenViewModel.swift b/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenViewModel.swift index 2889cc249..5dd597f5f 100644 --- a/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomDirectorySearchScreen/RoomDirectorySearchScreenViewModel.swift @@ -20,24 +20,29 @@ import SwiftUI typealias RoomDirectorySearchScreenViewModelType = StateStoreViewModel class RoomDirectorySearchScreenViewModel: RoomDirectorySearchScreenViewModelType, RoomDirectorySearchScreenViewModelProtocol { - private let roomDirectorySearch: RoomDirectorySearchProxyProtocol + private let clientProxy: ClientProxyProtocol + private let roomDirectorySearchProxy: RoomDirectorySearchProxyProtocol private let userIndicatorController: UserIndicatorControllerProtocol private let actionsSubject: PassthroughSubject = .init() var actionsPublisher: AnyPublisher { actionsSubject.eraseToAnyPublisher() } - - init(roomDirectorySearch: RoomDirectorySearchProxyProtocol, + + init(clientProxy: ClientProxyProtocol, userIndicatorController: UserIndicatorControllerProtocol, imageProvider: ImageProviderProtocol) { - self.roomDirectorySearch = roomDirectorySearch + self.clientProxy = clientProxy + roomDirectorySearchProxy = clientProxy.roomDirectorySearchProxy() self.userIndicatorController = userIndicatorController + super.init(initialViewState: RoomDirectorySearchScreenViewState(), imageProvider: imageProvider) - roomDirectorySearch.resultsPublisher + state.rooms = roomDirectorySearchProxy.resultsPublisher.value + + roomDirectorySearchProxy.resultsPublisher .receive(on: DispatchQueue.main) - .weakAssign(to: \.state.searchResults, on: self) + .weakAssign(to: \.state.rooms, on: self) .store(in: &cancellables) context.$viewState.map(\.bindings.searchString) @@ -62,10 +67,30 @@ class RoomDirectorySearchScreenViewModel: RoomDirectorySearchScreenViewModelType actionsSubject.send(.dismiss) case .join(roomID: let roomID): joinRoom(roomID: roomID) + case .reachedBottom: + loadNextPage() } } - private func joinRoom(roomID: String) { } + // MARK: - Private + + private func joinRoom(roomID: String) { + showLoadingIndicator() + + Task { + defer { + hideLoadingIndicator() + } + + switch await clientProxy.joinRoom(roomID) { + case .success: + actionsSubject.send(.joined(roomID: roomID)) + case .failure(let error): + MXLog.error("Failed joining room with error: \(error)") + userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown)) + } + } + } private static let errorID = "roomDirectorySearchViewModelLoadingError" @@ -74,9 +99,10 @@ class RoomDirectorySearchScreenViewModel: RoomDirectorySearchScreenViewModelType return } + state.rooms = [] state.isLoading = true Task { - switch await roomDirectorySearch.search(query: query) { + switch await roomDirectorySearchProxy.search(query: query) { case .success: break case .failure: @@ -88,4 +114,25 @@ class RoomDirectorySearchScreenViewModel: RoomDirectorySearchScreenViewModelType state.isLoading = false } } + + private func loadNextPage() { + Task { + state.isLoading = true + let _ = await roomDirectorySearchProxy.nextPage() + state.isLoading = false + } + } + + private static let loadingIndicatorIdentifier = "\(RoomDirectorySearchScreenViewModel.self)-Loading" + + private func showLoadingIndicator() { + userIndicatorController.submitIndicator(.init(id: Self.loadingIndicatorIdentifier, + type: .modal, + title: L10n.commonLoading, + persistent: true)) + } + + private func hideLoadingIndicator() { + userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier) + } } diff --git a/ElementX/Sources/Screens/RoomDirectorySearchScreen/View/RoomDirectoryCell.swift b/ElementX/Sources/Screens/RoomDirectorySearchScreen/View/RoomDirectoryCell.swift index 0b2e5066c..1ecb25c30 100644 --- a/ElementX/Sources/Screens/RoomDirectorySearchScreen/View/RoomDirectoryCell.swift +++ b/ElementX/Sources/Screens/RoomDirectorySearchScreen/View/RoomDirectoryCell.swift @@ -20,6 +20,7 @@ import SwiftUI struct RoomDirectorySearchCell: View { let result: RoomDirectorySearchResult let imageProvider: ImageProviderProtocol? + let joinAction: () -> Void private var description: String? { if let topic = result.topic { @@ -36,9 +37,17 @@ struct RoomDirectorySearchCell: View { } var body: some View { - ListRow(label: .avatar(title: result.name ?? result.alias ?? result.id, - description: description, - icon: avatar), kind: .label) + if result.canBeJoined { + ListRow(label: .avatar(title: result.name ?? result.alias ?? result.id, + description: description, + icon: avatar), + details: .label(title: L10n.actionJoin, icon: EmptyView()), + kind: .navigationLink(action: joinAction)) + } else { + ListRow(label: .avatar(title: result.name ?? result.alias ?? result.id, + description: description, + icon: avatar), kind: .label) + } } private var avatar: some View { @@ -56,14 +65,69 @@ struct RoomDirectorySearchCell: View { struct RoomDirectorySearchCell_Previews: PreviewProvider, TestablePreview { static var previews: some View { List { - RoomDirectorySearchCell(result: .init(id: "!test_id_1:matrix.org", alias: "#test:example.com", name: "Test title", topic: "test description", avatarURL: nil, canBeJoined: false), imageProvider: MockMediaProvider()) - RoomDirectorySearchCell(result: .init(id: "!test_id_2:matrix.org", alias: "#test:example.com", name: nil, topic: "test description", avatarURL: nil, canBeJoined: false), imageProvider: MockMediaProvider()) - RoomDirectorySearchCell(result: .init(id: "!test_id_3:example.com", alias: "#test_no_topic:example.com", name: "Test title no topic", topic: nil, avatarURL: nil, canBeJoined: false), imageProvider: MockMediaProvider()) - RoomDirectorySearchCell(result: .init(id: "!test_id_4:example.com", alias: "#test_no_topic:example.com", name: nil, topic: nil, avatarURL: nil, canBeJoined: false), imageProvider: MockMediaProvider()) - RoomDirectorySearchCell(result: .init(id: "!test_id_5:example.com", alias: nil, name: "Test title no alias", topic: nil, avatarURL: nil, canBeJoined: false), imageProvider: MockMediaProvider()) - RoomDirectorySearchCell(result: .init(id: "!test_id_6:example.com", alias: nil, name: "Test title no alias", topic: "Topic", avatarURL: nil, canBeJoined: false), imageProvider: MockMediaProvider()) - RoomDirectorySearchCell(result: .init(id: "!test_id_7:example.com", alias: nil, name: nil, topic: "Topic", avatarURL: nil, canBeJoined: false), imageProvider: MockMediaProvider()) - RoomDirectorySearchCell(result: .init(id: "!test_id_8:example.com", alias: nil, name: nil, topic: nil, avatarURL: nil, canBeJoined: false), imageProvider: MockMediaProvider()) + RoomDirectorySearchCell(result: .init(id: "!test_id_1:matrix.org", + alias: "#test:example.com", + name: "Test title", + topic: "test description", + avatarURL: nil, + canBeJoined: false), + imageProvider: MockMediaProvider()) { } + + RoomDirectorySearchCell(result: .init(id: "!test_id_2:matrix.org", + alias: "#test:example.com", + name: nil, + topic: "test description", + avatarURL: nil, + canBeJoined: false), + imageProvider: MockMediaProvider()) { } + + RoomDirectorySearchCell(result: .init(id: "!test_id_3:example.com", + alias: "#test_no_topic:example.com", + name: "Test title no topic", + topic: nil, + avatarURL: nil, + canBeJoined: false), + imageProvider: MockMediaProvider()) { } + + RoomDirectorySearchCell(result: .init(id: "!test_id_4:example.com", + alias: "#test_no_topic:example.com", + name: nil, + topic: nil, + avatarURL: nil, + canBeJoined: false), + imageProvider: MockMediaProvider()) { } + + RoomDirectorySearchCell(result: .init(id: "!test_id_5:example.com", + alias: nil, + name: "Test title no alias", + topic: nil, + avatarURL: nil, + canBeJoined: false), + imageProvider: MockMediaProvider()) { } + + RoomDirectorySearchCell(result: .init(id: "!test_id_6:example.com", + alias: nil, + name: "Test title no alias", + topic: "Topic", + avatarURL: nil, + canBeJoined: false), + imageProvider: MockMediaProvider()) { } + + RoomDirectorySearchCell(result: .init(id: "!test_id_7:example.com", + alias: nil, + name: nil, + topic: "Topic", + avatarURL: nil, + canBeJoined: false), + imageProvider: MockMediaProvider()) { } + RoomDirectorySearchCell(result: .init(id: "!test_id_8:example.com", + + alias: nil, + name: nil, + topic: nil, + avatarURL: nil, + canBeJoined: false), + imageProvider: MockMediaProvider()) { } } } } diff --git a/ElementX/Sources/Screens/RoomDirectorySearchScreen/View/RoomDirectorySearchScreen.swift b/ElementX/Sources/Screens/RoomDirectorySearchScreen/View/RoomDirectorySearchScreen.swift index aa28919b4..a881ccfe6 100644 --- a/ElementX/Sources/Screens/RoomDirectorySearchScreen/View/RoomDirectorySearchScreen.swift +++ b/ElementX/Sources/Screens/RoomDirectorySearchScreen/View/RoomDirectorySearchScreen.swift @@ -24,8 +24,22 @@ struct RoomDirectorySearchScreen: View { NavigationStack { List { Section { - ForEach(context.viewState.searchResults) { - RoomDirectorySearchCell(result: $0, imageProvider: context.imageProvider) + ForEach(context.viewState.rooms) { room in + RoomDirectorySearchCell(result: room, imageProvider: context.imageProvider) { + context.send(viewAction: .join(roomID: room.id)) + } + } + } footer: { + VStack(spacing: 0) { + if context.viewState.isLoading { + ProgressView() + .frame(maxWidth: .infinity) + } + + emptyRectangle + .onAppear { + context.send(viewAction: .reachedBottom) + } } } } @@ -46,25 +60,39 @@ struct RoomDirectorySearchScreen: View { } } } + + // The greedy size of Rectangle can create an issue with the navigation bar when the search is highlighted, so is best to use a fixed frame instead of hidden() or EmptyView() + private var emptyRectangle: some View { + Rectangle() + .frame(width: 0, height: 0) + } } // MARK: - Previews struct RoomDirectorySearchScreenScreen_Previews: PreviewProvider, TestablePreview { - static let viewModel = RoomDirectorySearchScreenViewModel(roomDirectorySearch: RoomDirectorySearchProxyMock(configuration: .init(results: [.init(id: "test_1", - alias: "#test_1:example.com", - name: "Test 1", - topic: "Test description 1", - avatarURL: nil, - canBeJoined: true), - .init(id: "test_2", - alias: "#test_2:example.com", - name: "Test 2", - topic: "Test description 2", - avatarURL: URL.documentsDirectory, - canBeJoined: false)])), - userIndicatorController: UserIndicatorControllerMock(), - imageProvider: MockMediaProvider()) + static let viewModel: RoomDirectorySearchScreenViewModel = { + let results = [RoomDirectorySearchResult(id: "test_1", + alias: "#test_1:example.com", + name: "Test 1", + topic: "Test description 1", + avatarURL: nil, + canBeJoined: true), + RoomDirectorySearchResult(id: "test_2", + alias: "#test_2:example.com", + name: "Test 2", + topic: nil, + avatarURL: URL.documentsDirectory, + canBeJoined: false)] + + let roomDirectorySearchProxy = RoomDirectorySearchProxyMock(configuration: .init(results: results)) + + let clientProxy = ClientProxyMock(.init(roomDirectorySearchProxy: roomDirectorySearchProxy)) + + return RoomDirectorySearchScreenViewModel(clientProxy: clientProxy, + userIndicatorController: UserIndicatorControllerMock(), + imageProvider: MockMediaProvider()) + }() static var previews: some View { RoomDirectorySearchScreen(context: viewModel.context) diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index 7bc77a151..40c0e614c 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -342,6 +342,19 @@ class ClientProxy: ClientProxyProtocol { return await waitForRoomSummary(with: result, name: name) } + func joinRoom(_ roomID: String) async -> Result { + do { + let _ = try await client.joinRoomById(roomId: roomID) + + // Wait for the room to appear in the room lists to avoid issues downstream + let _ = await waitForRoomSummary(with: .success(roomID), name: nil, timeout: 30) + + return .success(()) + } catch { + return .failure(.failedJoiningRoom) + } + } + func uploadMedia(_ media: MediaInfo) async -> Result { guard let mimeType = media.mimeType else { return .failure(ClientProxyError.mediaFileError) } do { @@ -356,8 +369,7 @@ class ClientProxy: ClientProxyProtocol { } /// Await the room to be available in the room summary list - /// - Parameter result: the result of a room creation Task with the `roomID`. - private func waitForRoomSummary(with result: Result, name: String?) async -> Result { + private func waitForRoomSummary(with result: Result, name: String?, timeout: Int = 10) async -> Result { guard case .success(let roomID) = result else { return result } let runner = ExpiringTaskRunner { [weak self] in guard let roomLists = self?.roomSummaryProvider?.roomListPublisher.values else { @@ -373,8 +385,8 @@ class ClientProxy: ClientProxyProtocol { } } - // we want to ignore the timeout error, and return the .success case because the room it was properly created already, we are only waiting for it to appear - try? await runner.run(timeout: .seconds(10)) + // we want to ignore the timeout error, and return the .success case because the room was properly created/joined already, we are only waiting for it to appear + try? await runner.run(timeout: .seconds(timeout)) return result } diff --git a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift index 5d83de07f..7b40b9cc3 100644 --- a/ElementX/Sources/Services/Client/ClientProxyProtocol.swift +++ b/ElementX/Sources/Services/Client/ClientProxyProtocol.swift @@ -53,6 +53,7 @@ enum ClientProxyError: Error { case failedCheckingIsLastDevice(Error?) case failedIgnoringUser case failedUnignoringUser + case failedJoiningRoom } enum SlidingSyncConstants { @@ -126,6 +127,8 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol { func createRoom(name: String, topic: String?, isRoomPrivate: Bool, userIDs: [String], avatarURL: URL?) async -> Result + func joinRoom(_ roomID: String) async -> Result + func uploadMedia(_ media: MediaInfo) async -> Result func roomForIdentifier(_ identifier: String) async -> RoomProxyProtocol? diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPad-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPad-en-GB.1.png index d2966ffbf..14be22c8d 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPad-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPad-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b4b0603f35bb8a828beff63268191992fab0d83660e2a0c5175e98b62e7b0730 -size 108648 +oid sha256:f31e5f39b635c8e4d63934933aae0bf25c7ed33d6b0f3d0bb9105cd86f0a6898 +size 111743 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPad-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPad-pseudo.1.png index 73ddbd869..1292fbf97 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPad-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPad-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b8ce266191dfbc6e95a944ff0edc826d71cdf923f3eb0efb5e34215925fbcff -size 121551 +oid sha256:d3331568faafd4c05eb768f5bf4be9b119ebd87be1f8829f1c84465aaf2aea1f +size 126969 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPhone-15-en-GB.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPhone-15-en-GB.1.png index 364f8b397..cafc4181d 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPhone-15-en-GB.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPhone-15-en-GB.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:615968dc9a95fbdb89e1f9cb3fe8b44916c3af6e323cd92c2f4d5db4ddb1284d -size 64240 +oid sha256:2d79c4687de4aae775d00f1442ae37697967f8b7d449eb4730a838e16adfb7be +size 66836 diff --git a/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPhone-15-pseudo.1.png b/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPhone-15-pseudo.1.png index 213db2ed7..4233a86a5 100644 --- a/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPhone-15-pseudo.1.png +++ b/PreviewTests/__Snapshots__/PreviewTests/test_roomDirectorySearchScreenScreen-iPhone-15-pseudo.1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97564fa372abeae5d8968dfc37dc9daefc8ae2d2fd5e3d7749d10cf0da5e4815 -size 72907 +oid sha256:9cf8c4e574758e34a7e4dee7bf1fa4f9c414a37c6c0558073db9a2fd555e32dc +size 77410 diff --git a/changelog.d/2518.feature b/changelog.d/2518.feature new file mode 100644 index 000000000..a4892d6f2 --- /dev/null +++ b/changelog.d/2518.feature @@ -0,0 +1 @@ +Implement public room search list pagination and room joining \ No newline at end of file