diff --git a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift index 16f99c1af..589f6fdc8 100644 --- a/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift +++ b/ElementX/Sources/FlowCoordinators/UserSessionFlowCoordinator.swift @@ -339,6 +339,8 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol { handleAppRoute(.room(roomID: roomID, via: []), animated: true) } case .cancel: + // The search screen is also dismissed when leaving the tab, ignore it in that case. + guard navigationTabCoordinator.selectedTab == .search else { return } // Return to the tab the user came from, but never back into search. navigationTabCoordinator.selectedTab = navigationTabCoordinator.previousTab == .search ? .chats : navigationTabCoordinator.previousTab ?? .chats } diff --git a/ElementX/Sources/Screens/SearchScreen/View/SearchScreen.swift b/ElementX/Sources/Screens/SearchScreen/View/SearchScreen.swift index 2c353dcd1..9b4d08740 100644 --- a/ElementX/Sources/Screens/SearchScreen/View/SearchScreen.swift +++ b/ElementX/Sources/Screens/SearchScreen/View/SearchScreen.swift @@ -79,6 +79,9 @@ struct SearchScreen: View { messagesList } } + + // Dismissing the search field (the tab bar's close button) leaves the tab. + SearchDismissalObserver { context.send(viewAction: .cancel) } } .frame(maxHeight: .infinity, alignment: .top) .background(Color.compound.bgCanvasDefault) @@ -99,7 +102,7 @@ struct SearchScreen: View { moveDown: { moveSelection(backwards: false) }, cancel: { context.send(viewAction: .cancel) }) // The TabView calls onAppear/onDisappear each time the search tab is selected/deselected, - // so the query is cleared and the selection resets on every switch. + // so the field re-focuses, the query is cleared and the selection resets on every switch. .onAppear { context.send(viewAction: .appeared) isSearchFieldFocused = true @@ -324,6 +327,23 @@ private struct SearchScreenRoomCell: View { } } +/// Reports the search field being dismissed, which `isSearching` only exposes to the searchable view's children. +private struct SearchDismissalObserver: View { + @Environment(\.isSearching) private var isSearching + + let action: () -> Void + + var body: some View { + Color.clear + .frame(width: 0, height: 0) + .onChange(of: isSearching) { _, isSearching in + if !isSearching { + action() + } + } + } +} + private struct SearchScreenRoomCellButtonStyle: ButtonStyle { let isSelected: Bool