mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 20:09:04 +00:00
Only record query breadcrumbs when the search is submitted
Queries were previously stored whenever a result was selected, which meant half-typed queries ended up in the history. Now a query is only recorded when the user submits the search field, while selecting a result only records the room.
This commit is contained in:
@@ -48,6 +48,7 @@ struct SearchScreenViewStateBindings {
|
|||||||
|
|
||||||
enum SearchScreenViewAction {
|
enum SearchScreenViewAction {
|
||||||
case appeared
|
case appeared
|
||||||
|
case submitQuery
|
||||||
case selectRoom(roomID: String)
|
case selectRoom(roomID: String)
|
||||||
case selectMessage(roomID: String, eventID: String)
|
case selectMessage(roomID: String, eventID: String)
|
||||||
case reachedTop
|
case reachedTop
|
||||||
|
|||||||
@@ -138,11 +138,14 @@ class SearchScreenViewModel: SearchScreenViewModelType, SearchScreenViewModelPro
|
|||||||
// The provider is shared, so other consumers may have changed its filter while we were off-screen.
|
// The provider is shared, so other consumers may have changed its filter while we were off-screen.
|
||||||
// Re-apply ours on every appearance to keep the displayed results in sync with the query.
|
// Re-apply ours on every appearance to keep the displayed results in sync with the query.
|
||||||
updateFilter(for: state.bindings.searchQuery, forced: true)
|
updateFilter(for: state.bindings.searchQuery, forced: true)
|
||||||
|
case .submitQuery:
|
||||||
|
guard !state.bindings.searchQuery.isEmpty else { return }
|
||||||
|
recordBreadcrumb(.query(state.bindings.searchQuery))
|
||||||
case .selectRoom(let roomID):
|
case .selectRoom(let roomID):
|
||||||
recordBreadcrumbs(roomID: roomID)
|
recordBreadcrumb(.room(roomID: roomID))
|
||||||
actionsSubject.send(.presentRoom(roomID: roomID, eventID: nil))
|
actionsSubject.send(.presentRoom(roomID: roomID, eventID: nil))
|
||||||
case .selectMessage(let roomID, let eventID):
|
case .selectMessage(let roomID, let eventID):
|
||||||
recordBreadcrumbs(roomID: roomID)
|
recordBreadcrumb(.room(roomID: roomID))
|
||||||
actionsSubject.send(.presentRoom(roomID: roomID, eventID: eventID))
|
actionsSubject.send(.presentRoom(roomID: roomID, eventID: eventID))
|
||||||
case .reachedTop:
|
case .reachedTop:
|
||||||
if state.bindings.searchMode == .rooms {
|
if state.bindings.searchMode == .rooms {
|
||||||
@@ -210,16 +213,11 @@ class SearchScreenViewModel: SearchScreenViewModelType, SearchScreenViewModelPro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores the query that led to the selected result, along with the room it belongs to.
|
/// Moves the breadcrumb to the top of the history, adding it if needed.
|
||||||
private func recordBreadcrumbs(roomID: String) {
|
private func recordBreadcrumb(_ breadcrumb: SearchBreadcrumb) {
|
||||||
let searchQuery = state.bindings.searchQuery
|
|
||||||
let newBreadcrumbs: [SearchBreadcrumb] = searchQuery.isEmpty ? [.room(roomID: roomID)] : [.query(searchQuery), .room(roomID: roomID)]
|
|
||||||
|
|
||||||
var breadcrumbs = userSettings.searchBreadcrumbs
|
var breadcrumbs = userSettings.searchBreadcrumbs
|
||||||
for breadcrumb in newBreadcrumbs {
|
breadcrumbs.removeAll { $0 == breadcrumb }
|
||||||
breadcrumbs.removeAll { $0 == breadcrumb }
|
breadcrumbs.insert(breadcrumb, at: 0)
|
||||||
breadcrumbs.insert(breadcrumb, at: 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
userSettings.searchBreadcrumbs = Array(breadcrumbs.prefix(Self.maximumBreadcrumbCount))
|
userSettings.searchBreadcrumbs = Array(breadcrumbs.prefix(Self.maximumBreadcrumbCount))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ struct SearchScreen: View {
|
|||||||
.scrollDismissesKeyboard(.immediately)
|
.scrollDismissesKeyboard(.immediately)
|
||||||
.background(tabShortcuts)
|
.background(tabShortcuts)
|
||||||
.onSubmit(of: .search) {
|
.onSubmit(of: .search) {
|
||||||
|
context.send(viewAction: .submitQuery)
|
||||||
// A software keyboard's submit/search button just dismisses; only a hardware return selects.
|
// A software keyboard's submit/search button just dismisses; only a hardware return selects.
|
||||||
if isHardwareKeyboardConnected, selectedID != nil {
|
if isHardwareKeyboardConnected, selectedID != nil {
|
||||||
selectCurrent()
|
selectCurrent()
|
||||||
|
|||||||
@@ -127,16 +127,26 @@ struct SearchScreenViewModelTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
func selectionRecordsBreadcrumbs() {
|
func selectionRecordsBreadcrumbs() {
|
||||||
|
// Typing alone doesn't record the query, only submitting it does.
|
||||||
context.searchQuery = "Second"
|
context.searchQuery = "Second"
|
||||||
context.send(viewAction: .selectRoom(roomID: "2"))
|
context.send(viewAction: .selectRoom(roomID: "2"))
|
||||||
|
|
||||||
#expect(userSettings.searchBreadcrumbs == [.room(roomID: "2"), .query("Second")])
|
#expect(userSettings.searchBreadcrumbs == [.room(roomID: "2")])
|
||||||
|
|
||||||
|
context.send(viewAction: .submitQuery)
|
||||||
|
|
||||||
|
#expect(userSettings.searchBreadcrumbs == [.query("Second"), .room(roomID: "2")])
|
||||||
|
|
||||||
// Selecting the same room again from the empty state only bumps it back to the top.
|
// Selecting the same room again from the empty state only bumps it back to the top.
|
||||||
context.searchQuery = ""
|
context.searchQuery = ""
|
||||||
context.send(viewAction: .selectRoom(roomID: "2"))
|
context.send(viewAction: .selectRoom(roomID: "2"))
|
||||||
|
|
||||||
#expect(userSettings.searchBreadcrumbs == [.room(roomID: "2"), .query("Second")])
|
#expect(userSettings.searchBreadcrumbs == [.room(roomID: "2"), .query("Second")])
|
||||||
|
|
||||||
|
// Submitting an empty query records nothing.
|
||||||
|
context.send(viewAction: .submitQuery)
|
||||||
|
|
||||||
|
#expect(userSettings.searchBreadcrumbs == [.room(roomID: "2"), .query("Second")])
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user