diff --git a/iphone/Maps/Classes/CarPlay/MWMCarPlaySearchService.mm b/iphone/Maps/Classes/CarPlay/MWMCarPlaySearchService.mm index b8b4f83aa..f80f76f66 100644 --- a/iphone/Maps/Classes/CarPlay/MWMCarPlaySearchService.mm +++ b/iphone/Maps/Classes/CarPlay/MWMCarPlaySearchService.mm @@ -2,6 +2,8 @@ #import "MWMCarPlaySearchResultObject.h" #import "MWMSearch.h" +#import "SwiftBridge.h" + API_AVAILABLE(ios(12.0)) @interface MWMCarPlaySearchService () @property(strong, nonatomic, nullable) void (^completionHandler)(NSArray *searchResults); @@ -30,12 +32,14 @@ API_AVAILABLE(ios(12.0)) self.lastResults = @[]; self.completionHandler = completionHandler; /// @todo Didn't find pure category request in CarPlay. - [MWMSearch searchQuery:text forInputLocale:inputLocale withCategory:NO]; + SearchQuery * query = [[SearchQuery alloc] init:text locale:inputLocale source:SearchTextSourceTypedText]; + [MWMSearch searchQuery:query]; } - (void)saveLastQuery { if (self.lastQuery != nil && self.inputLocale != nil) { - [MWMSearch saveQuery:self.lastQuery forInputLocale:self.inputLocale]; + SearchQuery * query = [[SearchQuery alloc] init:self.lastQuery locale:self.inputLocale source:SearchTextSourceTypedText]; + [MWMSearch saveQuery:query]; } } diff --git a/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.h b/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.h index b57d9bef9..7ddbbd89f 100644 --- a/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.h +++ b/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.h @@ -5,6 +5,7 @@ @class MapViewController; @class BottomTabBarViewController; @class TrackRecordingViewController; +@class SearchQuery; @protocol MWMFeatureHolder; @@ -45,8 +46,8 @@ #pragma mark - MWMSearchManager - (void)actionDownloadMaps:(MWMMapDownloaderMode)mode; -- (BOOL)searchText:(NSString *)text forInputLocale:(NSString *)locale; -- (void)searchTextOnMap:(NSString *)text forInputLocale:(NSString *)locale; +- (BOOL)search:(SearchQuery *)query; +- (void)searchOnMap:(SearchQuery *)query; #pragma mark - MWMFeatureHolder diff --git a/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.mm b/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.mm index 8357f5e63..dc2360f9e 100644 --- a/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.mm +++ b/iphone/Maps/Classes/CustomViews/MapViewControls/MWMMapViewControlsManager.mm @@ -104,19 +104,19 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue"; #pragma mark - MWMPlacePageViewManager -- (void)searchTextOnMap:(NSString *)text forInputLocale:(NSString *)locale { - if (![self searchText:text forInputLocale:locale]) +- (void)searchOnMap:(SearchQuery *)query { + if (![self search:query]) return; [self.searchManager startSearchingWithIsRouting:NO]; } -- (BOOL)searchText:(NSString *)text forInputLocale:(NSString *)locale { - if (text.length == 0) +- (BOOL)search:(SearchQuery *)query { + if (query.text.length == 0) return NO; [self.searchManager startSearchingWithIsRouting:NO]; - [self.searchManager searchText:text locale:locale isCategory:NO]; + [self.searchManager searchText:query]; return YES; } diff --git a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/MWMNavigationInfoView.mm b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/MWMNavigationInfoView.mm index 34acbed97..613e2ca35 100644 --- a/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/MWMNavigationInfoView.mm +++ b/iphone/Maps/Classes/CustomViews/NavigationDashboard/Views/MWMNavigationInfoView.mm @@ -193,10 +193,11 @@ BOOL defaultOrientation(CGSize const &size) { - (IBAction)searchButtonTouchUpInside:(MWMButton *)sender { auto const body = ^(NavigationSearchState state) { - NSString *query = [kSearchButtonRequest.at(state) stringByAppendingString:@" "]; - NSString *locale = [[AppInfo sharedInfo] languageId]; + NSString * text = [kSearchButtonRequest.at(state) stringByAppendingString:@" "]; + NSString * locale = [[AppInfo sharedInfo] languageId]; // Category request from navigation search wheel. - [MWMSearch searchQuery:query forInputLocale:locale withCategory:YES]; + SearchQuery * query = [[SearchQuery alloc] init:text locale:locale source:SearchTextSourceCategory]; + [MWMSearch searchQuery:query]; [self setSearchState:state animated:YES]; }; diff --git a/iphone/Maps/Classes/MapViewController.h b/iphone/Maps/Classes/MapViewController.h index 492642107..465137125 100644 --- a/iphone/Maps/Classes/MapViewController.h +++ b/iphone/Maps/Classes/MapViewController.h @@ -36,7 +36,6 @@ - (void)openEditor; - (void)openBookmarkEditor; - (void)openFullPlaceDescriptionWithHtml:(NSString *_Nonnull)htmlString; -- (void)searchText:(NSString *_Nonnull)text; - (void)openDrivingOptions; - (void)setPlacePageTopBound:(CGFloat)bound duration:(double)duration; diff --git a/iphone/Maps/Classes/MapViewController.mm b/iphone/Maps/Classes/MapViewController.mm index d54f920f1..24b0d3aad 100644 --- a/iphone/Maps/Classes/MapViewController.mm +++ b/iphone/Maps/Classes/MapViewController.mm @@ -612,10 +612,6 @@ NSString *const kSettingsSegue = @"Map2Settings"; [self.navigationController pushViewController:descriptionViewController animated:YES]; } -- (void)searchText:(NSString *)text { - [self.controlsManager searchText:text forInputLocale:[[AppInfo sharedInfo] languageId]]; -} - - (void)openDrivingOptions { UIStoryboard *sb = [UIStoryboard instance:MWMStoryboardDrivingOptions]; UIViewController *vc = [sb instantiateInitialViewController]; diff --git a/iphone/Maps/Classes/MapsAppDelegate.mm b/iphone/Maps/Classes/MapsAppDelegate.mm index 3e5a7b7bb..b77459f75 100644 --- a/iphone/Maps/Classes/MapsAppDelegate.mm +++ b/iphone/Maps/Classes/MapsAppDelegate.mm @@ -85,9 +85,10 @@ using namespace osm_auth_ios; }); return; } - - [[MWMMapViewControlsManager manager] searchText:[searchString stringByAppendingString:@" "] - forInputLocale:[MWMSettings spotlightLocaleLanguageId]]; + SearchQuery * query = [[SearchQuery alloc] init:[searchString stringByAppendingString:@" "] + locale:[MWMSettings spotlightLocaleLanguageId] + source:SearchTextSourceDeeplink]; + [[MWMMapViewControlsManager manager] search:query]; } - (void)commonInit { diff --git a/iphone/Maps/Core/DeepLink/DeepLinkHandler.swift b/iphone/Maps/Core/DeepLink/DeepLinkHandler.swift index 0c8649065..d094cc681 100644 --- a/iphone/Maps/Core/DeepLink/DeepLinkHandler.swift +++ b/iphone/Maps/Core/DeepLink/DeepLinkHandler.swift @@ -113,10 +113,11 @@ sd.onViewportChanged(kSearchInViewportZoom) } } + let searchQuery = SearchQuery(sd.query, locale: sd.locale, source: .deeplink) if (sd.isSearchOnMap) { - MWMMapViewControlsManager.manager()?.searchText(onMap: sd.query, forInputLocale: sd.locale) + MWMMapViewControlsManager.manager()?.search(onMap: searchQuery) } else { - MWMMapViewControlsManager.manager()?.searchText(sd.query, forInputLocale: sd.locale) + MWMMapViewControlsManager.manager()?.search(searchQuery) } return true case .menu: diff --git a/iphone/Maps/Core/Search/MWMSearch.h b/iphone/Maps/Core/Search/MWMSearch.h index 86422f89a..40d75784e 100644 --- a/iphone/Maps/Core/Search/MWMSearch.h +++ b/iphone/Maps/Core/Search/MWMSearch.h @@ -3,14 +3,22 @@ NS_ASSUME_NONNULL_BEGIN +typedef NS_ENUM(NSUInteger, SearchTextSource) { + SearchTextSourceTypedText, + SearchTextSourceCategory, + SearchTextSourceSuggestion, + SearchTextSourceDeeplink +}; + @class SearchResult; +@class SearchQuery; @protocol SearchManager + (void)addObserver:(id)observer; + (void)removeObserver:(id)observer; -+ (void)saveQuery:(NSString *)query forInputLocale:(NSString *)inputLocale; -+ (void)searchQuery:(NSString *)query forInputLocale:(NSString *)inputLocale withCategory:(BOOL)isCategory; ++ (void)saveQuery:(SearchQuery *)query; ++ (void)searchQuery:(SearchQuery *)query; + (void)showResultAtIndex:(NSUInteger)index; + (void)showEverywhereSearchResultsOnMap; diff --git a/iphone/Maps/Core/Search/MWMSearch.mm b/iphone/Maps/Core/Search/MWMSearch.mm index 2689c90a9..d26ced3a9 100644 --- a/iphone/Maps/Core/Search/MWMSearch.mm +++ b/iphone/Maps/Core/Search/MWMSearch.mm @@ -88,7 +88,7 @@ using Observers = NSHashTable; } - (void)searchInViewport { - search::ViewportSearchParams params{ + search::ViewportSearchParams params { m_query, m_locale, {} /* default timeout */, m_isCategory, // m_onStarted {}, @@ -125,29 +125,29 @@ using Observers = NSHashTable; #pragma mark - Methods -+ (void)saveQuery:(NSString *)query forInputLocale:(NSString *)inputLocale { - if (!query || query.length == 0) ++ (void)saveQuery:(SearchQuery *)query { + if (!query.text || query.text.length == 0) return; - std::string locale = (!inputLocale || inputLocale.length == 0) + std::string locale = (!query.locale || query.locale == 0) ? [MWMSearch manager]->m_locale - : inputLocale.UTF8String; - std::string text = query.UTF8String; + : query.locale.UTF8String; + std::string text = query.text.UTF8String; GetFramework().GetSearchAPI().SaveSearchQuery({std::move(locale), std::move(text)}); } -+ (void)searchQuery:(NSString *)query forInputLocale:(NSString *)inputLocale withCategory:(BOOL)isCategory { - if (!query) ++ (void)searchQuery:(SearchQuery *)query { + if (!query.text) return; MWMSearch *manager = [MWMSearch manager]; - if (inputLocale.length != 0) - manager->m_locale = inputLocale.UTF8String; + if (query.locale.length != 0) + manager->m_locale = query.locale.UTF8String; // Pass input query as-is without any normalization (precomposedStringWithCompatibilityMapping). // Otherwise № -> No, and it's unexpectable for the search index. - manager->m_query = query.UTF8String; - manager->m_isCategory = (isCategory == YES); + manager->m_query = query.text.UTF8String; + manager->m_isCategory = (query.source == SearchTextSourceCategory); manager.textChanged = YES; [manager update]; diff --git a/iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift b/iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift index b8f3423ef..3ceeae861 100644 --- a/iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift +++ b/iphone/Maps/Tests/UI/SearchOnMapTests/SearchOnMapTests.swift @@ -41,12 +41,12 @@ final class SearchOnMapTests: XCTestCase { func test_GivenInitialState_WhenSelectCategory_ThenUpdateSearchResultsAndShowMap() { interactor.handle(.openSearch) - let searchText = SearchOnMap.SearchText("category") - interactor.handle(.didSelectText(searchText, isCategory: true)) + let query = SearchQuery("category", source: .category) + interactor.handle(.didSelect(query)) XCTAssertEqual(view.viewModel.presentationStep, .halfScreen) XCTAssertEqual(view.viewModel.contentState, .searching) - XCTAssertEqual(view.viewModel.searchingText, searchText.text) + XCTAssertEqual(view.viewModel.searchingText, query.text) XCTAssertEqual(view.viewModel.isTyping, false) let results = SearchResult.stubResults() @@ -62,8 +62,8 @@ final class SearchOnMapTests: XCTestCase { func test_GivenInitialState_WhenTypeText_ThenUpdateSearchResults() { interactor.handle(.openSearch) - let searchText = SearchOnMap.SearchText("text") - interactor.handle(.didType(searchText)) + let query = SearchQuery("text", source: .typedText) + interactor.handle(.didType(query)) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) XCTAssertEqual(view.viewModel.contentState, .searching) @@ -83,8 +83,8 @@ final class SearchOnMapTests: XCTestCase { func test_GivenInitialState_WhenTapSearch_ThenUpdateSearchResultsAndShowMap() { interactor.handle(.openSearch) - let searchText = SearchOnMap.SearchText("text") - interactor.handle(.didType(searchText)) + let query = SearchQuery("text", source: .typedText) + interactor.handle(.didType(query)) let results = SearchResult.stubResults() searchManager.results = results @@ -94,7 +94,7 @@ final class SearchOnMapTests: XCTestCase { XCTAssertEqual(view.viewModel.searchingText, nil) XCTAssertEqual(view.viewModel.isTyping, true) - interactor.handle(.searchButtonDidTap(searchText)) + interactor.handle(.searchButtonDidTap(query)) XCTAssertEqual(currentState, .searching) XCTAssertEqual(view.viewModel.presentationStep, .halfScreen) @@ -123,13 +123,13 @@ final class SearchOnMapTests: XCTestCase { interactor.handle(.openSearch) XCTAssertEqual(view.viewModel.isTyping, true) - let searchText = SearchOnMap.SearchText("text") - interactor.handle(.didType(searchText)) + let query = SearchQuery("text", source: .typedText) + interactor.handle(.didSelect(query)) let results = SearchResult.stubResults() searchManager.results = results - interactor.handle(.didSelectResult(results[0], withSearchText: searchText)) + interactor.handle(.didSelectResult(results[0], withQuery: query)) if isIPad { XCTAssertEqual(currentState, .searching) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) @@ -156,13 +156,13 @@ final class SearchOnMapTests: XCTestCase { interactor.handle(.openSearch) XCTAssertEqual(view.viewModel.isTyping, true) - let searchText = SearchOnMap.SearchText("text") - interactor.handle(.didType(searchText)) + let query = SearchQuery("text", source: .typedText) + interactor.handle(.didSelect(query)) let results = SearchResult.stubResults() searchManager.results = results - interactor.handle(.didSelectResult(results[0], withSearchText: searchText)) + interactor.handle(.didSelectResult(results[0], withQuery: query)) if isIPad { XCTAssertEqual(currentState, .searching) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) @@ -187,8 +187,8 @@ final class SearchOnMapTests: XCTestCase { func test_GivenSearchHasText_WhenClearSearch_ThenShowHistoryAndCategory() { interactor.handle(.openSearch) - let searchText = SearchOnMap.SearchText("text") - interactor.handle(.didType(searchText)) + let query = SearchQuery("text", source: .typedText) + interactor.handle(.didSelect(query)) interactor.handle(.clearButtonDidTap) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) @@ -200,8 +200,8 @@ final class SearchOnMapTests: XCTestCase { func test_GivenSearchExecuted_WhenNoResults_ThenShowNoResults() { interactor.handle(.openSearch) - let searchText = SearchOnMap.SearchText("text") - interactor.handle(.didType(searchText)) + let query = SearchQuery("text", source: .typedText) + interactor.handle(.didSelect(query)) searchManager.results = SearchOnMap.SearchResults([]) interactor.onSearchCompleted() @@ -209,17 +209,33 @@ final class SearchOnMapTests: XCTestCase { XCTAssertEqual(view.viewModel.contentState, .noResults) } - func test_GivenSearchIsActive_WhenSelectSuggestion_ThenSearchAgain() { + func test_GivenSearchIsActive_WhenSelectSuggestion_ThenReplaceWithSuggestion() { interactor.handle(.openSearch) - let searchText = SearchOnMap.SearchText("old search") - interactor.handle(.didType(searchText)) + let query = SearchQuery("ca", source: .typedText) + interactor.handle(.didType(query)) - let suggestion = SearchResult(titleText: "", type: .suggestion, suggestion: "suggestion") - interactor.handle(.didSelectResult(suggestion, withSearchText: searchText)) + let result = SearchResult(titleText: "", type: .suggestion, suggestion: "cafe") + interactor.handle(.didSelectResult(result, withQuery: query)) - XCTAssertEqual(view.viewModel.searchingText, "suggestion") + XCTAssertEqual(view.viewModel.searchingText, "cafe") XCTAssertEqual(view.viewModel.contentState, .searching) + XCTAssertEqual(view.viewModel.isTyping, false) + } + + func test_GivenSearchIsActive_WhenPasteDeeplink_ThenShowResult() { + interactor.handle(.openSearch) + + let query = SearchQuery("om://search?cll=42.0,44.0&query=Toilet", source: .deeplink) + interactor.handle(.didSelect(query)) + + let result = SearchResult(titleText: "some result", type: .regular, suggestion: "") + let results = SearchOnMap.SearchResults([result]) + searchManager.results = results + interactor.onSearchCompleted() + + XCTAssertEqual(view.viewModel.contentState, .results(results)) + XCTAssertEqual(view.viewModel.isTyping, false) // No typing when deeplink is used } } @@ -255,8 +271,8 @@ private class SearchManagerMock: SearchManager { self.observers.removeListener(observer) } - static func saveQuery(_ query: String, forInputLocale inputLocale: String) {} - static func searchQuery(_ query: String, forInputLocale inputLocale: String, withCategory isCategory: Bool) {} + static func save(_ query: SearchQuery) {} + static func searchQuery(_ query: SearchQuery) {} static func showResult(at index: UInt) {} static func showEverywhereSearchResultsOnMap() {} static func showViewportSearchResultsOnMap() {} diff --git a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapHeaderView.swift b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapHeaderView.swift index 9809d82cf..46c931c70 100644 --- a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapHeaderView.swift +++ b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapHeaderView.swift @@ -139,7 +139,7 @@ final class SearchOnMapHeaderView: UIView { } } - var searchText: SearchOnMap.SearchText { - SearchOnMap.SearchText(searchBar.text ?? "", locale: searchBar.textInputMode?.primaryLanguage) + var searchQuery: SearchQuery { + SearchQuery(searchBar.text ?? "", locale: searchBar.textInputMode?.primaryLanguage, source: .typedText) } } diff --git a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift index fc6499f4c..d77f9ced6 100644 --- a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift +++ b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapInteractor.swift @@ -41,12 +41,12 @@ final class SearchOnMapInteractor: NSObject { return processTypedText(searchText) case .clearButtonDidTap: return processClearButtonDidTap() - case .didSelectText(let searchText, let isCategory): - return processSelectedText(searchText, isCategory: isCategory) + case .didSelect(let searchText): + return processSelectedText(searchText) case .searchButtonDidTap(let searchText): return processSearchButtonDidTap(searchText) - case .didSelectResult(let result, let searchText): - return processSelectedResult(result, searchText: searchText) + case .didSelectResult(let result, let query): + return processSelectedResult(result, query: query) case .didSelectPlaceOnMap: return isIPad ? .none : .setSearchScreenHidden(true) case .didDeselectPlaceOnMap: @@ -66,38 +66,31 @@ final class SearchOnMapInteractor: NSObject { return .clearSearch } - private func processSearchButtonDidTap(_ searchText: SearchOnMap.SearchText) -> SearchOnMap.Response { - searchManager.saveQuery(searchText.text, - forInputLocale: searchText.locale) + private func processSearchButtonDidTap(_ query: SearchQuery) -> SearchOnMap.Response { + searchManager.save(query) showResultsOnMap = true searchManager.showEverywhereSearchResultsOnMap() return .showOnTheMap } - private func processTypedText(_ searchText: SearchOnMap.SearchText) -> SearchOnMap.Response { + private func processTypedText(_ query: SearchQuery) -> SearchOnMap.Response { isUpdatesDisabled = false - searchManager.searchQuery(searchText.text, - forInputLocale: searchText.locale, - withCategory: false) + searchManager.searchQuery(query) return .startSearching } - private func processSelectedText(_ searchText: SearchOnMap.SearchText, isCategory: Bool) -> SearchOnMap.Response { + private func processSelectedText(_ query: SearchQuery) -> SearchOnMap.Response { isUpdatesDisabled = false - searchManager.saveQuery(searchText.text, - forInputLocale: searchText.locale) - searchManager.searchQuery(searchText.text, - forInputLocale: searchText.locale, - withCategory: isCategory) + searchManager.save(query) + searchManager.searchQuery(query) showResultsOnMap = true - return .selectText(searchText.text) + return .selectQuery(query) } - private func processSelectedResult(_ result: SearchResult, searchText: SearchOnMap.SearchText) -> SearchOnMap.Response { + private func processSelectedResult(_ result: SearchResult, query: SearchQuery) -> SearchOnMap.Response { switch result.itemType { case .regular: - searchManager.saveQuery(searchText.text, - forInputLocale:searchText.locale) + searchManager.save(query) switch routingTooltipSearch { case .none: searchManager.showResult(at: result.index) @@ -120,10 +113,11 @@ final class SearchOnMapInteractor: NSObject { } return isIPad ? .none : .setSearchScreenHidden(true) case .suggestion: - searchManager.searchQuery(result.suggestion, - forInputLocale: searchText.locale, - withCategory: result.isPureSuggest) - return .selectText(result.suggestion) + var suggestionQuery = SearchQuery(result.suggestion, + locale: query.locale, + source: result.isPureSuggest ? .suggestion : .typedText) + searchManager.searchQuery(suggestionQuery) + return .selectQuery(suggestionQuery) @unknown default: fatalError("Unsupported result type") } diff --git a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapManager.swift b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapManager.swift index c1291d266..51bf331db 100644 --- a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapManager.swift +++ b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapManager.swift @@ -61,9 +61,8 @@ final class SearchOnMapManager: NSObject { interactor?.handle(.didStartDraggingMap) } - func searchText(_ text: String, locale: String, isCategory: Bool) { - let searchText = SearchOnMap.SearchText(text, locale: locale) - interactor?.handle(.didSelectText(searchText, isCategory: isCategory)) + func searchText(_ searchText: SearchQuery) { + interactor?.handle(.didSelect(searchText)) } func addObserver(_ observer: SearchOnMapManagerObserver) { diff --git a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapModels.swift b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapModels.swift index 2634571f8..2442a8e3a 100644 --- a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapModels.swift +++ b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapModels.swift @@ -1,3 +1,16 @@ +@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 { @@ -30,16 +43,6 @@ enum SearchOnMap { } } - struct SearchText { - let text: String - let locale: String - - init(_ text: String, locale: String? = nil) { - self.text = text - self.locale = locale ?? AppInfo.shared().languageId - } - } - enum Request { case openSearch case hideSearch @@ -47,10 +50,10 @@ enum SearchOnMap { case didStartDraggingSearch case didStartDraggingMap case didStartTyping - case didType(SearchText) - case didSelectText(SearchText, isCategory: Bool) - case didSelectResult(SearchResult, withSearchText: SearchText) - case searchButtonDidTap(SearchText) + case didType(SearchQuery) + case didSelect(SearchQuery) + case didSelectResult(SearchResult, withQuery: SearchQuery) + case searchButtonDidTap(SearchQuery) case clearButtonDidTap case didSelectPlaceOnMap case didDeselectPlaceOnMap @@ -63,7 +66,7 @@ enum SearchOnMap { case setIsTyping(Bool) case showHistoryAndCategory case showResults(SearchResults, isSearchCompleted: Bool = false) - case selectText(String?) + case selectQuery(SearchQuery) case clearSearch case setSearchScreenHidden(Bool) case setSearchScreenCompact diff --git a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapPresenter.swift b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapPresenter.swift index 74c669f5c..6ce14565e 100644 --- a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapPresenter.swift +++ b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapPresenter.swift @@ -74,11 +74,11 @@ final class SearchOnMapPresenter { searchResults.skipSuggestions() } viewModel.contentState = searchResults.isEmpty && isSearchCompleted ? .noResults : .results(searchResults) - case .selectText(let text): - viewModel.isTyping = false + case .selectQuery(let query): viewModel.skipSuggestions = false - viewModel.searchingText = text + viewModel.searchingText = query.text viewModel.contentState = .searching + viewModel.isTyping = false viewModel.presentationStep = isRouting ? .hidden : .halfScreen case .clearSearch: viewModel.searchingText = "" diff --git a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapViewController.swift b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapViewController.swift index 7bb0d416a..8c7cc57a2 100644 --- a/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapViewController.swift +++ b/iphone/Maps/UI/Search/SearchOnMap/SearchOnMapViewController.swift @@ -18,7 +18,6 @@ protocol ModallyPresentedViewController: AnyObject { final class SearchOnMapViewController: UIViewController { typealias ViewModel = SearchOnMap.ViewModel typealias Content = SearchOnMap.ViewModel.Content - typealias SearchText = SearchOnMap.SearchText fileprivate enum Constants { static let estimatedRowHeight: CGFloat = 80 @@ -417,7 +416,7 @@ extension SearchOnMapViewController: UITableViewDataSource { extension SearchOnMapViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let result = searchResults[indexPath.row] - interactor?.handle(.didSelectResult(result, withSearchText: headerView.searchText)) + interactor?.handle(.didSelectResult(result, withQuery: headerView.searchQuery)) tableView.deselectRow(at: indexPath, animated: true) } @@ -437,12 +436,12 @@ extension SearchOnMapViewController: SearchOnMapHeaderViewDelegate { interactor?.handle(.clearButtonDidTap) return } - interactor?.handle(.didType(SearchText(searchText, locale: searchBar.textInputMode?.primaryLanguage))) + interactor?.handle(.didType(SearchQuery(searchText, locale: searchBar.textInputMode?.primaryLanguage, source: .typedText))) } func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { guard let searchText = searchBar.text, !searchText.isEmpty else { return } - interactor?.handle(.searchButtonDidTap(SearchText(searchText, locale: searchBar.textInputMode?.primaryLanguage))) + interactor?.handle(.searchButtonDidTap(SearchQuery(searchText, locale: searchBar.textInputMode?.primaryLanguage, source: .typedText))) } func cancelButtonDidTap() { @@ -456,8 +455,8 @@ extension SearchOnMapViewController: SearchOnMapHeaderViewDelegate { // MARK: - SearchTabViewControllerDelegate extension SearchOnMapViewController: SearchTabViewControllerDelegate { - func searchTabController(_ viewController: SearchTabViewController, didSearch text: String, withCategory: Bool) { - interactor?.handle(.didSelectText(SearchText(text, locale: nil), isCategory: withCategory)) + func searchTabController(_ viewController: SearchTabViewController, didSearch query: SearchQuery) { + interactor?.handle(.didSelect(query)) } } diff --git a/iphone/Maps/UI/Search/Tabs/SearchTabViewController.swift b/iphone/Maps/UI/Search/Tabs/SearchTabViewController.swift index 2dfe98f80..9660879aa 100644 --- a/iphone/Maps/UI/Search/Tabs/SearchTabViewController.swift +++ b/iphone/Maps/UI/Search/Tabs/SearchTabViewController.swift @@ -1,6 +1,6 @@ @objc(MWMSearchTabViewControllerDelegate) protocol SearchTabViewControllerDelegate: SearchOnMapScrollViewDelegate { - func searchTabController(_ viewController: SearchTabViewController, didSearch: String, withCategory: Bool) + func searchTabController(_ viewController: SearchTabViewController, didSearch: SearchQuery) } @objc(MWMSearchTabViewController) @@ -9,7 +9,7 @@ final class SearchTabViewController: TabViewController { case history = 0 case categories } - + private static let selectedIndexKey = "SearchTabViewController_selectedIndexKey" @objc weak var delegate: SearchTabViewControllerDelegate? @@ -72,14 +72,15 @@ extension SearchTabViewController: SearchOnMapScrollViewDelegate { extension SearchTabViewController: SearchCategoriesViewControllerDelegate { func categoriesViewController(_ viewController: SearchCategoriesViewController, didSelect category: String) { - let query = L(category) + " " - delegate?.searchTabController(self, didSearch: query, withCategory: true) + let query = SearchQuery(L(category) + " ", source: .category) + delegate?.searchTabController(self, didSearch: query) } } extension SearchTabViewController: SearchHistoryViewControllerDelegate { func searchHistoryViewController(_ viewController: SearchHistoryViewController, - didSelect query: String) { - delegate?.searchTabController(self, didSearch: query, withCategory: false) + didSelect query: String) { + let query = SearchQuery(query.trimmingCharacters(in: .whitespacesAndNewlines) + " ", source: .suggestion) + delegate?.searchTabController(self, didSearch: query) } }