98 lines
2.6 KiB
Swift
98 lines
2.6 KiB
Swift
|
|
@objcMembers
|
||
|
|
final class SearchQuery: NSObject {
|
||
|
|
let text: String
|
||
|
|
let locale: String
|
||
|
|
let source: SearchTextSource
|
||
|
|
|
||
|
|
init(_ text: String, locale: String? = nil, source: SearchTextSource) {
|
||
|
|
self.text = text
|
||
|
|
self.locale = locale ?? AppInfo.shared().languageId
|
||
|
|
self.source = source
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
enum SearchOnMap {
|
||
|
|
struct ViewModel: Equatable {
|
||
|
|
enum Content: Equatable {
|
||
|
|
case historyAndCategory
|
||
|
|
case results(SearchResults)
|
||
|
|
case noResults
|
||
|
|
case searching
|
||
|
|
}
|
||
|
|
|
||
|
|
var isTyping: Bool
|
||
|
|
var skipSuggestions: Bool
|
||
|
|
var searchingText: String?
|
||
|
|
var contentState: Content
|
||
|
|
var presentationStep: ModalPresentationStep
|
||
|
|
}
|
||
|
|
|
||
|
|
struct SearchResults: Equatable {
|
||
|
|
let results: [SearchResult]
|
||
|
|
let hasPartialMatch: Bool
|
||
|
|
let isEmpty: Bool
|
||
|
|
let count: Int
|
||
|
|
let suggestionsCount: Int
|
||
|
|
|
||
|
|
init(_ results: [SearchResult]) {
|
||
|
|
self.results = results
|
||
|
|
self.hasPartialMatch = !results.allSatisfy { $0.highlightRanges.isEmpty }
|
||
|
|
self.isEmpty = results.isEmpty
|
||
|
|
self.count = results.count
|
||
|
|
self.suggestionsCount = results.filter { $0.itemType == .suggestion }.count
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
enum Request {
|
||
|
|
case openSearch
|
||
|
|
case hideSearch
|
||
|
|
case closeSearch
|
||
|
|
case didStartDraggingSearch
|
||
|
|
case didStartDraggingMap
|
||
|
|
case didStartTyping
|
||
|
|
case didType(SearchQuery)
|
||
|
|
case didSelect(SearchQuery)
|
||
|
|
case didSelectResult(SearchResult, withQuery: SearchQuery)
|
||
|
|
case searchButtonDidTap(SearchQuery)
|
||
|
|
case clearButtonDidTap
|
||
|
|
case didSelectPlaceOnMap
|
||
|
|
case didDeselectPlaceOnMap
|
||
|
|
case didUpdatePresentationStep(ModalPresentationStep)
|
||
|
|
}
|
||
|
|
|
||
|
|
enum Response: Equatable {
|
||
|
|
case startSearching
|
||
|
|
case showOnTheMap
|
||
|
|
case setIsTyping(Bool)
|
||
|
|
case showHistoryAndCategory
|
||
|
|
case showResults(SearchResults, isSearchCompleted: Bool = false)
|
||
|
|
case selectQuery(SearchQuery)
|
||
|
|
case clearSearch
|
||
|
|
case setSearchScreenHidden(Bool)
|
||
|
|
case setSearchScreenCompact
|
||
|
|
case updatePresentationStep(ModalPresentationStep)
|
||
|
|
case close
|
||
|
|
case none
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
extension SearchOnMap.SearchResults {
|
||
|
|
static let empty = SearchOnMap.SearchResults([])
|
||
|
|
|
||
|
|
subscript(index: Int) -> SearchResult {
|
||
|
|
results[index]
|
||
|
|
}
|
||
|
|
|
||
|
|
mutating func skipSuggestions() {
|
||
|
|
self = SearchOnMap.SearchResults(results.filter { $0.itemType != .suggestion })
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
extension SearchOnMap.ViewModel {
|
||
|
|
static let initial = SearchOnMap.ViewModel(isTyping: false,
|
||
|
|
skipSuggestions: false,
|
||
|
|
searchingText: nil,
|
||
|
|
contentState: .historyAndCategory,
|
||
|
|
presentationStep: .fullScreen)
|
||
|
|
}
|