[ios] refactor search - use SearchQuery class instead of text+locale+isCategory

Signed-off-by: Kiryl Kaveryn <kirylkaveryn@gmail.com>
This commit is contained in:
Kiryl Kaveryn
2025-05-23 17:06:32 +04:00
committed by Konstantin Pastbin
parent 09171651ff
commit 96c24cf973
18 changed files with 145 additions and 122 deletions

View File

@@ -2,6 +2,8 @@
#import "MWMCarPlaySearchResultObject.h" #import "MWMCarPlaySearchResultObject.h"
#import "MWMSearch.h" #import "MWMSearch.h"
#import "SwiftBridge.h"
API_AVAILABLE(ios(12.0)) API_AVAILABLE(ios(12.0))
@interface MWMCarPlaySearchService ()<MWMSearchObserver> @interface MWMCarPlaySearchService ()<MWMSearchObserver>
@property(strong, nonatomic, nullable) void (^completionHandler)(NSArray<MWMCarPlaySearchResultObject *> *searchResults); @property(strong, nonatomic, nullable) void (^completionHandler)(NSArray<MWMCarPlaySearchResultObject *> *searchResults);
@@ -30,12 +32,14 @@ API_AVAILABLE(ios(12.0))
self.lastResults = @[]; self.lastResults = @[];
self.completionHandler = completionHandler; self.completionHandler = completionHandler;
/// @todo Didn't find pure category request in CarPlay. /// @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 { - (void)saveLastQuery {
if (self.lastQuery != nil && self.inputLocale != nil) { 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];
} }
} }

View File

@@ -5,6 +5,7 @@
@class MapViewController; @class MapViewController;
@class BottomTabBarViewController; @class BottomTabBarViewController;
@class TrackRecordingViewController; @class TrackRecordingViewController;
@class SearchQuery;
@protocol MWMFeatureHolder; @protocol MWMFeatureHolder;
@@ -45,8 +46,8 @@
#pragma mark - MWMSearchManager #pragma mark - MWMSearchManager
- (void)actionDownloadMaps:(MWMMapDownloaderMode)mode; - (void)actionDownloadMaps:(MWMMapDownloaderMode)mode;
- (BOOL)searchText:(NSString *)text forInputLocale:(NSString *)locale; - (BOOL)search:(SearchQuery *)query;
- (void)searchTextOnMap:(NSString *)text forInputLocale:(NSString *)locale; - (void)searchOnMap:(SearchQuery *)query;
#pragma mark - MWMFeatureHolder #pragma mark - MWMFeatureHolder

View File

@@ -104,19 +104,19 @@ NSString *const kMapToCategorySelectorSegue = @"MapToCategorySelectorSegue";
#pragma mark - MWMPlacePageViewManager #pragma mark - MWMPlacePageViewManager
- (void)searchTextOnMap:(NSString *)text forInputLocale:(NSString *)locale { - (void)searchOnMap:(SearchQuery *)query {
if (![self searchText:text forInputLocale:locale]) if (![self search:query])
return; return;
[self.searchManager startSearchingWithIsRouting:NO]; [self.searchManager startSearchingWithIsRouting:NO];
} }
- (BOOL)searchText:(NSString *)text forInputLocale:(NSString *)locale { - (BOOL)search:(SearchQuery *)query {
if (text.length == 0) if (query.text.length == 0)
return NO; return NO;
[self.searchManager startSearchingWithIsRouting:NO]; [self.searchManager startSearchingWithIsRouting:NO];
[self.searchManager searchText:text locale:locale isCategory:NO]; [self.searchManager searchText:query];
return YES; return YES;
} }

View File

@@ -193,10 +193,11 @@ BOOL defaultOrientation(CGSize const &size) {
- (IBAction)searchButtonTouchUpInside:(MWMButton *)sender { - (IBAction)searchButtonTouchUpInside:(MWMButton *)sender {
auto const body = ^(NavigationSearchState state) { auto const body = ^(NavigationSearchState state) {
NSString *query = [kSearchButtonRequest.at(state) stringByAppendingString:@" "]; NSString * text = [kSearchButtonRequest.at(state) stringByAppendingString:@" "];
NSString *locale = [[AppInfo sharedInfo] languageId]; NSString * locale = [[AppInfo sharedInfo] languageId];
// Category request from navigation search wheel. // 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]; [self setSearchState:state animated:YES];
}; };

View File

@@ -36,7 +36,6 @@
- (void)openEditor; - (void)openEditor;
- (void)openBookmarkEditor; - (void)openBookmarkEditor;
- (void)openFullPlaceDescriptionWithHtml:(NSString *_Nonnull)htmlString; - (void)openFullPlaceDescriptionWithHtml:(NSString *_Nonnull)htmlString;
- (void)searchText:(NSString *_Nonnull)text;
- (void)openDrivingOptions; - (void)openDrivingOptions;
- (void)setPlacePageTopBound:(CGFloat)bound duration:(double)duration; - (void)setPlacePageTopBound:(CGFloat)bound duration:(double)duration;

View File

@@ -612,10 +612,6 @@ NSString *const kSettingsSegue = @"Map2Settings";
[self.navigationController pushViewController:descriptionViewController animated:YES]; [self.navigationController pushViewController:descriptionViewController animated:YES];
} }
- (void)searchText:(NSString *)text {
[self.controlsManager searchText:text forInputLocale:[[AppInfo sharedInfo] languageId]];
}
- (void)openDrivingOptions { - (void)openDrivingOptions {
UIStoryboard *sb = [UIStoryboard instance:MWMStoryboardDrivingOptions]; UIStoryboard *sb = [UIStoryboard instance:MWMStoryboardDrivingOptions];
UIViewController *vc = [sb instantiateInitialViewController]; UIViewController *vc = [sb instantiateInitialViewController];

View File

@@ -85,9 +85,10 @@ using namespace osm_auth_ios;
}); });
return; return;
} }
SearchQuery * query = [[SearchQuery alloc] init:[searchString stringByAppendingString:@" "]
[[MWMMapViewControlsManager manager] searchText:[searchString stringByAppendingString:@" "] locale:[MWMSettings spotlightLocaleLanguageId]
forInputLocale:[MWMSettings spotlightLocaleLanguageId]]; source:SearchTextSourceDeeplink];
[[MWMMapViewControlsManager manager] search:query];
} }
- (void)commonInit { - (void)commonInit {

View File

@@ -113,10 +113,11 @@
sd.onViewportChanged(kSearchInViewportZoom) sd.onViewportChanged(kSearchInViewportZoom)
} }
} }
let searchQuery = SearchQuery(sd.query, locale: sd.locale, source: .deeplink)
if (sd.isSearchOnMap) { if (sd.isSearchOnMap) {
MWMMapViewControlsManager.manager()?.searchText(onMap: sd.query, forInputLocale: sd.locale) MWMMapViewControlsManager.manager()?.search(onMap: searchQuery)
} else { } else {
MWMMapViewControlsManager.manager()?.searchText(sd.query, forInputLocale: sd.locale) MWMMapViewControlsManager.manager()?.search(searchQuery)
} }
return true return true
case .menu: case .menu:

View File

@@ -3,14 +3,22 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSUInteger, SearchTextSource) {
SearchTextSourceTypedText,
SearchTextSourceCategory,
SearchTextSourceSuggestion,
SearchTextSourceDeeplink
};
@class SearchResult; @class SearchResult;
@class SearchQuery;
@protocol SearchManager @protocol SearchManager
+ (void)addObserver:(id<MWMSearchObserver>)observer; + (void)addObserver:(id<MWMSearchObserver>)observer;
+ (void)removeObserver:(id<MWMSearchObserver>)observer; + (void)removeObserver:(id<MWMSearchObserver>)observer;
+ (void)saveQuery:(NSString *)query forInputLocale:(NSString *)inputLocale; + (void)saveQuery:(SearchQuery *)query;
+ (void)searchQuery:(NSString *)query forInputLocale:(NSString *)inputLocale withCategory:(BOOL)isCategory; + (void)searchQuery:(SearchQuery *)query;
+ (void)showResultAtIndex:(NSUInteger)index; + (void)showResultAtIndex:(NSUInteger)index;
+ (void)showEverywhereSearchResultsOnMap; + (void)showEverywhereSearchResultsOnMap;

View File

@@ -88,7 +88,7 @@ using Observers = NSHashTable<Observer>;
} }
- (void)searchInViewport { - (void)searchInViewport {
search::ViewportSearchParams params{ search::ViewportSearchParams params {
m_query, m_locale, {} /* default timeout */, m_isCategory, m_query, m_locale, {} /* default timeout */, m_isCategory,
// m_onStarted // m_onStarted
{}, {},
@@ -125,29 +125,29 @@ using Observers = NSHashTable<Observer>;
#pragma mark - Methods #pragma mark - Methods
+ (void)saveQuery:(NSString *)query forInputLocale:(NSString *)inputLocale { + (void)saveQuery:(SearchQuery *)query {
if (!query || query.length == 0) if (!query.text || query.text.length == 0)
return; return;
std::string locale = (!inputLocale || inputLocale.length == 0) std::string locale = (!query.locale || query.locale == 0)
? [MWMSearch manager]->m_locale ? [MWMSearch manager]->m_locale
: inputLocale.UTF8String; : query.locale.UTF8String;
std::string text = query.UTF8String; std::string text = query.text.UTF8String;
GetFramework().GetSearchAPI().SaveSearchQuery({std::move(locale), std::move(text)}); GetFramework().GetSearchAPI().SaveSearchQuery({std::move(locale), std::move(text)});
} }
+ (void)searchQuery:(NSString *)query forInputLocale:(NSString *)inputLocale withCategory:(BOOL)isCategory { + (void)searchQuery:(SearchQuery *)query {
if (!query) if (!query.text)
return; return;
MWMSearch *manager = [MWMSearch manager]; MWMSearch *manager = [MWMSearch manager];
if (inputLocale.length != 0) if (query.locale.length != 0)
manager->m_locale = inputLocale.UTF8String; manager->m_locale = query.locale.UTF8String;
// Pass input query as-is without any normalization (precomposedStringWithCompatibilityMapping). // Pass input query as-is without any normalization (precomposedStringWithCompatibilityMapping).
// Otherwise № -> No, and it's unexpectable for the search index. // Otherwise № -> No, and it's unexpectable for the search index.
manager->m_query = query.UTF8String; manager->m_query = query.text.UTF8String;
manager->m_isCategory = (isCategory == YES); manager->m_isCategory = (query.source == SearchTextSourceCategory);
manager.textChanged = YES; manager.textChanged = YES;
[manager update]; [manager update];

View File

@@ -41,12 +41,12 @@ final class SearchOnMapTests: XCTestCase {
func test_GivenInitialState_WhenSelectCategory_ThenUpdateSearchResultsAndShowMap() { func test_GivenInitialState_WhenSelectCategory_ThenUpdateSearchResultsAndShowMap() {
interactor.handle(.openSearch) interactor.handle(.openSearch)
let searchText = SearchOnMap.SearchText("category") let query = SearchQuery("category", source: .category)
interactor.handle(.didSelectText(searchText, isCategory: true)) interactor.handle(.didSelect(query))
XCTAssertEqual(view.viewModel.presentationStep, .halfScreen) XCTAssertEqual(view.viewModel.presentationStep, .halfScreen)
XCTAssertEqual(view.viewModel.contentState, .searching) XCTAssertEqual(view.viewModel.contentState, .searching)
XCTAssertEqual(view.viewModel.searchingText, searchText.text) XCTAssertEqual(view.viewModel.searchingText, query.text)
XCTAssertEqual(view.viewModel.isTyping, false) XCTAssertEqual(view.viewModel.isTyping, false)
let results = SearchResult.stubResults() let results = SearchResult.stubResults()
@@ -62,8 +62,8 @@ final class SearchOnMapTests: XCTestCase {
func test_GivenInitialState_WhenTypeText_ThenUpdateSearchResults() { func test_GivenInitialState_WhenTypeText_ThenUpdateSearchResults() {
interactor.handle(.openSearch) interactor.handle(.openSearch)
let searchText = SearchOnMap.SearchText("text") let query = SearchQuery("text", source: .typedText)
interactor.handle(.didType(searchText)) interactor.handle(.didType(query))
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
XCTAssertEqual(view.viewModel.contentState, .searching) XCTAssertEqual(view.viewModel.contentState, .searching)
@@ -83,8 +83,8 @@ final class SearchOnMapTests: XCTestCase {
func test_GivenInitialState_WhenTapSearch_ThenUpdateSearchResultsAndShowMap() { func test_GivenInitialState_WhenTapSearch_ThenUpdateSearchResultsAndShowMap() {
interactor.handle(.openSearch) interactor.handle(.openSearch)
let searchText = SearchOnMap.SearchText("text") let query = SearchQuery("text", source: .typedText)
interactor.handle(.didType(searchText)) interactor.handle(.didType(query))
let results = SearchResult.stubResults() let results = SearchResult.stubResults()
searchManager.results = results searchManager.results = results
@@ -94,7 +94,7 @@ final class SearchOnMapTests: XCTestCase {
XCTAssertEqual(view.viewModel.searchingText, nil) XCTAssertEqual(view.viewModel.searchingText, nil)
XCTAssertEqual(view.viewModel.isTyping, true) XCTAssertEqual(view.viewModel.isTyping, true)
interactor.handle(.searchButtonDidTap(searchText)) interactor.handle(.searchButtonDidTap(query))
XCTAssertEqual(currentState, .searching) XCTAssertEqual(currentState, .searching)
XCTAssertEqual(view.viewModel.presentationStep, .halfScreen) XCTAssertEqual(view.viewModel.presentationStep, .halfScreen)
@@ -123,13 +123,13 @@ final class SearchOnMapTests: XCTestCase {
interactor.handle(.openSearch) interactor.handle(.openSearch)
XCTAssertEqual(view.viewModel.isTyping, true) XCTAssertEqual(view.viewModel.isTyping, true)
let searchText = SearchOnMap.SearchText("text") let query = SearchQuery("text", source: .typedText)
interactor.handle(.didType(searchText)) interactor.handle(.didSelect(query))
let results = SearchResult.stubResults() let results = SearchResult.stubResults()
searchManager.results = results searchManager.results = results
interactor.handle(.didSelectResult(results[0], withSearchText: searchText)) interactor.handle(.didSelectResult(results[0], withQuery: query))
if isIPad { if isIPad {
XCTAssertEqual(currentState, .searching) XCTAssertEqual(currentState, .searching)
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
@@ -156,13 +156,13 @@ final class SearchOnMapTests: XCTestCase {
interactor.handle(.openSearch) interactor.handle(.openSearch)
XCTAssertEqual(view.viewModel.isTyping, true) XCTAssertEqual(view.viewModel.isTyping, true)
let searchText = SearchOnMap.SearchText("text") let query = SearchQuery("text", source: .typedText)
interactor.handle(.didType(searchText)) interactor.handle(.didSelect(query))
let results = SearchResult.stubResults() let results = SearchResult.stubResults()
searchManager.results = results searchManager.results = results
interactor.handle(.didSelectResult(results[0], withSearchText: searchText)) interactor.handle(.didSelectResult(results[0], withQuery: query))
if isIPad { if isIPad {
XCTAssertEqual(currentState, .searching) XCTAssertEqual(currentState, .searching)
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
@@ -187,8 +187,8 @@ final class SearchOnMapTests: XCTestCase {
func test_GivenSearchHasText_WhenClearSearch_ThenShowHistoryAndCategory() { func test_GivenSearchHasText_WhenClearSearch_ThenShowHistoryAndCategory() {
interactor.handle(.openSearch) interactor.handle(.openSearch)
let searchText = SearchOnMap.SearchText("text") let query = SearchQuery("text", source: .typedText)
interactor.handle(.didType(searchText)) interactor.handle(.didSelect(query))
interactor.handle(.clearButtonDidTap) interactor.handle(.clearButtonDidTap)
XCTAssertEqual(view.viewModel.presentationStep, .fullScreen) XCTAssertEqual(view.viewModel.presentationStep, .fullScreen)
@@ -200,8 +200,8 @@ final class SearchOnMapTests: XCTestCase {
func test_GivenSearchExecuted_WhenNoResults_ThenShowNoResults() { func test_GivenSearchExecuted_WhenNoResults_ThenShowNoResults() {
interactor.handle(.openSearch) interactor.handle(.openSearch)
let searchText = SearchOnMap.SearchText("text") let query = SearchQuery("text", source: .typedText)
interactor.handle(.didType(searchText)) interactor.handle(.didSelect(query))
searchManager.results = SearchOnMap.SearchResults([]) searchManager.results = SearchOnMap.SearchResults([])
interactor.onSearchCompleted() interactor.onSearchCompleted()
@@ -209,17 +209,33 @@ final class SearchOnMapTests: XCTestCase {
XCTAssertEqual(view.viewModel.contentState, .noResults) XCTAssertEqual(view.viewModel.contentState, .noResults)
} }
func test_GivenSearchIsActive_WhenSelectSuggestion_ThenSearchAgain() { func test_GivenSearchIsActive_WhenSelectSuggestion_ThenReplaceWithSuggestion() {
interactor.handle(.openSearch) interactor.handle(.openSearch)
let searchText = SearchOnMap.SearchText("old search") let query = SearchQuery("ca", source: .typedText)
interactor.handle(.didType(searchText)) interactor.handle(.didType(query))
let suggestion = SearchResult(titleText: "", type: .suggestion, suggestion: "suggestion") let result = SearchResult(titleText: "", type: .suggestion, suggestion: "cafe")
interactor.handle(.didSelectResult(suggestion, withSearchText: searchText)) interactor.handle(.didSelectResult(result, withQuery: query))
XCTAssertEqual(view.viewModel.searchingText, "suggestion") XCTAssertEqual(view.viewModel.searchingText, "cafe")
XCTAssertEqual(view.viewModel.contentState, .searching) 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) self.observers.removeListener(observer)
} }
static func saveQuery(_ query: String, forInputLocale inputLocale: String) {} static func save(_ query: SearchQuery) {}
static func searchQuery(_ query: String, forInputLocale inputLocale: String, withCategory isCategory: Bool) {} static func searchQuery(_ query: SearchQuery) {}
static func showResult(at index: UInt) {} static func showResult(at index: UInt) {}
static func showEverywhereSearchResultsOnMap() {} static func showEverywhereSearchResultsOnMap() {}
static func showViewportSearchResultsOnMap() {} static func showViewportSearchResultsOnMap() {}

View File

@@ -139,7 +139,7 @@ final class SearchOnMapHeaderView: UIView {
} }
} }
var searchText: SearchOnMap.SearchText { var searchQuery: SearchQuery {
SearchOnMap.SearchText(searchBar.text ?? "", locale: searchBar.textInputMode?.primaryLanguage) SearchQuery(searchBar.text ?? "", locale: searchBar.textInputMode?.primaryLanguage, source: .typedText)
} }
} }

View File

@@ -41,12 +41,12 @@ final class SearchOnMapInteractor: NSObject {
return processTypedText(searchText) return processTypedText(searchText)
case .clearButtonDidTap: case .clearButtonDidTap:
return processClearButtonDidTap() return processClearButtonDidTap()
case .didSelectText(let searchText, let isCategory): case .didSelect(let searchText):
return processSelectedText(searchText, isCategory: isCategory) return processSelectedText(searchText)
case .searchButtonDidTap(let searchText): case .searchButtonDidTap(let searchText):
return processSearchButtonDidTap(searchText) return processSearchButtonDidTap(searchText)
case .didSelectResult(let result, let searchText): case .didSelectResult(let result, let query):
return processSelectedResult(result, searchText: searchText) return processSelectedResult(result, query: query)
case .didSelectPlaceOnMap: case .didSelectPlaceOnMap:
return isIPad ? .none : .setSearchScreenHidden(true) return isIPad ? .none : .setSearchScreenHidden(true)
case .didDeselectPlaceOnMap: case .didDeselectPlaceOnMap:
@@ -66,38 +66,31 @@ final class SearchOnMapInteractor: NSObject {
return .clearSearch return .clearSearch
} }
private func processSearchButtonDidTap(_ searchText: SearchOnMap.SearchText) -> SearchOnMap.Response { private func processSearchButtonDidTap(_ query: SearchQuery) -> SearchOnMap.Response {
searchManager.saveQuery(searchText.text, searchManager.save(query)
forInputLocale: searchText.locale)
showResultsOnMap = true showResultsOnMap = true
searchManager.showEverywhereSearchResultsOnMap() searchManager.showEverywhereSearchResultsOnMap()
return .showOnTheMap return .showOnTheMap
} }
private func processTypedText(_ searchText: SearchOnMap.SearchText) -> SearchOnMap.Response { private func processTypedText(_ query: SearchQuery) -> SearchOnMap.Response {
isUpdatesDisabled = false isUpdatesDisabled = false
searchManager.searchQuery(searchText.text, searchManager.searchQuery(query)
forInputLocale: searchText.locale,
withCategory: false)
return .startSearching return .startSearching
} }
private func processSelectedText(_ searchText: SearchOnMap.SearchText, isCategory: Bool) -> SearchOnMap.Response { private func processSelectedText(_ query: SearchQuery) -> SearchOnMap.Response {
isUpdatesDisabled = false isUpdatesDisabled = false
searchManager.saveQuery(searchText.text, searchManager.save(query)
forInputLocale: searchText.locale) searchManager.searchQuery(query)
searchManager.searchQuery(searchText.text,
forInputLocale: searchText.locale,
withCategory: isCategory)
showResultsOnMap = true 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 { switch result.itemType {
case .regular: case .regular:
searchManager.saveQuery(searchText.text, searchManager.save(query)
forInputLocale:searchText.locale)
switch routingTooltipSearch { switch routingTooltipSearch {
case .none: case .none:
searchManager.showResult(at: result.index) searchManager.showResult(at: result.index)
@@ -120,10 +113,11 @@ final class SearchOnMapInteractor: NSObject {
} }
return isIPad ? .none : .setSearchScreenHidden(true) return isIPad ? .none : .setSearchScreenHidden(true)
case .suggestion: case .suggestion:
searchManager.searchQuery(result.suggestion, var suggestionQuery = SearchQuery(result.suggestion,
forInputLocale: searchText.locale, locale: query.locale,
withCategory: result.isPureSuggest) source: result.isPureSuggest ? .suggestion : .typedText)
return .selectText(result.suggestion) searchManager.searchQuery(suggestionQuery)
return .selectQuery(suggestionQuery)
@unknown default: @unknown default:
fatalError("Unsupported result type") fatalError("Unsupported result type")
} }

View File

@@ -61,9 +61,8 @@ final class SearchOnMapManager: NSObject {
interactor?.handle(.didStartDraggingMap) interactor?.handle(.didStartDraggingMap)
} }
func searchText(_ text: String, locale: String, isCategory: Bool) { func searchText(_ searchText: SearchQuery) {
let searchText = SearchOnMap.SearchText(text, locale: locale) interactor?.handle(.didSelect(searchText))
interactor?.handle(.didSelectText(searchText, isCategory: isCategory))
} }
func addObserver(_ observer: SearchOnMapManagerObserver) { func addObserver(_ observer: SearchOnMapManagerObserver) {

View File

@@ -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 { enum SearchOnMap {
struct ViewModel: Equatable { struct ViewModel: Equatable {
enum Content: 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 { enum Request {
case openSearch case openSearch
case hideSearch case hideSearch
@@ -47,10 +50,10 @@ enum SearchOnMap {
case didStartDraggingSearch case didStartDraggingSearch
case didStartDraggingMap case didStartDraggingMap
case didStartTyping case didStartTyping
case didType(SearchText) case didType(SearchQuery)
case didSelectText(SearchText, isCategory: Bool) case didSelect(SearchQuery)
case didSelectResult(SearchResult, withSearchText: SearchText) case didSelectResult(SearchResult, withQuery: SearchQuery)
case searchButtonDidTap(SearchText) case searchButtonDidTap(SearchQuery)
case clearButtonDidTap case clearButtonDidTap
case didSelectPlaceOnMap case didSelectPlaceOnMap
case didDeselectPlaceOnMap case didDeselectPlaceOnMap
@@ -63,7 +66,7 @@ enum SearchOnMap {
case setIsTyping(Bool) case setIsTyping(Bool)
case showHistoryAndCategory case showHistoryAndCategory
case showResults(SearchResults, isSearchCompleted: Bool = false) case showResults(SearchResults, isSearchCompleted: Bool = false)
case selectText(String?) case selectQuery(SearchQuery)
case clearSearch case clearSearch
case setSearchScreenHidden(Bool) case setSearchScreenHidden(Bool)
case setSearchScreenCompact case setSearchScreenCompact

View File

@@ -74,11 +74,11 @@ final class SearchOnMapPresenter {
searchResults.skipSuggestions() searchResults.skipSuggestions()
} }
viewModel.contentState = searchResults.isEmpty && isSearchCompleted ? .noResults : .results(searchResults) viewModel.contentState = searchResults.isEmpty && isSearchCompleted ? .noResults : .results(searchResults)
case .selectText(let text): case .selectQuery(let query):
viewModel.isTyping = false
viewModel.skipSuggestions = false viewModel.skipSuggestions = false
viewModel.searchingText = text viewModel.searchingText = query.text
viewModel.contentState = .searching viewModel.contentState = .searching
viewModel.isTyping = false
viewModel.presentationStep = isRouting ? .hidden : .halfScreen viewModel.presentationStep = isRouting ? .hidden : .halfScreen
case .clearSearch: case .clearSearch:
viewModel.searchingText = "" viewModel.searchingText = ""

View File

@@ -18,7 +18,6 @@ protocol ModallyPresentedViewController: AnyObject {
final class SearchOnMapViewController: UIViewController { final class SearchOnMapViewController: UIViewController {
typealias ViewModel = SearchOnMap.ViewModel typealias ViewModel = SearchOnMap.ViewModel
typealias Content = SearchOnMap.ViewModel.Content typealias Content = SearchOnMap.ViewModel.Content
typealias SearchText = SearchOnMap.SearchText
fileprivate enum Constants { fileprivate enum Constants {
static let estimatedRowHeight: CGFloat = 80 static let estimatedRowHeight: CGFloat = 80
@@ -417,7 +416,7 @@ extension SearchOnMapViewController: UITableViewDataSource {
extension SearchOnMapViewController: UITableViewDelegate { extension SearchOnMapViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let result = searchResults[indexPath.row] 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) tableView.deselectRow(at: indexPath, animated: true)
} }
@@ -437,12 +436,12 @@ extension SearchOnMapViewController: SearchOnMapHeaderViewDelegate {
interactor?.handle(.clearButtonDidTap) interactor?.handle(.clearButtonDidTap)
return 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) { func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
guard let searchText = searchBar.text, !searchText.isEmpty else { return } 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() { func cancelButtonDidTap() {
@@ -456,8 +455,8 @@ extension SearchOnMapViewController: SearchOnMapHeaderViewDelegate {
// MARK: - SearchTabViewControllerDelegate // MARK: - SearchTabViewControllerDelegate
extension SearchOnMapViewController: SearchTabViewControllerDelegate { extension SearchOnMapViewController: SearchTabViewControllerDelegate {
func searchTabController(_ viewController: SearchTabViewController, didSearch text: String, withCategory: Bool) { func searchTabController(_ viewController: SearchTabViewController, didSearch query: SearchQuery) {
interactor?.handle(.didSelectText(SearchText(text, locale: nil), isCategory: withCategory)) interactor?.handle(.didSelect(query))
} }
} }

View File

@@ -1,6 +1,6 @@
@objc(MWMSearchTabViewControllerDelegate) @objc(MWMSearchTabViewControllerDelegate)
protocol SearchTabViewControllerDelegate: SearchOnMapScrollViewDelegate { protocol SearchTabViewControllerDelegate: SearchOnMapScrollViewDelegate {
func searchTabController(_ viewController: SearchTabViewController, didSearch: String, withCategory: Bool) func searchTabController(_ viewController: SearchTabViewController, didSearch: SearchQuery)
} }
@objc(MWMSearchTabViewController) @objc(MWMSearchTabViewController)
@@ -9,7 +9,7 @@ final class SearchTabViewController: TabViewController {
case history = 0 case history = 0
case categories case categories
} }
private static let selectedIndexKey = "SearchTabViewController_selectedIndexKey" private static let selectedIndexKey = "SearchTabViewController_selectedIndexKey"
@objc weak var delegate: SearchTabViewControllerDelegate? @objc weak var delegate: SearchTabViewControllerDelegate?
@@ -72,14 +72,15 @@ extension SearchTabViewController: SearchOnMapScrollViewDelegate {
extension SearchTabViewController: SearchCategoriesViewControllerDelegate { extension SearchTabViewController: SearchCategoriesViewControllerDelegate {
func categoriesViewController(_ viewController: SearchCategoriesViewController, func categoriesViewController(_ viewController: SearchCategoriesViewController,
didSelect category: String) { didSelect category: String) {
let query = L(category) + " " let query = SearchQuery(L(category) + " ", source: .category)
delegate?.searchTabController(self, didSearch: query, withCategory: true) delegate?.searchTabController(self, didSearch: query)
} }
} }
extension SearchTabViewController: SearchHistoryViewControllerDelegate { extension SearchTabViewController: SearchHistoryViewControllerDelegate {
func searchHistoryViewController(_ viewController: SearchHistoryViewController, func searchHistoryViewController(_ viewController: SearchHistoryViewController,
didSelect query: String) { didSelect query: String) {
delegate?.searchTabController(self, didSearch: query, withCategory: false) let query = SearchQuery(query.trimmingCharacters(in: .whitespacesAndNewlines) + " ", source: .suggestion)
delegate?.searchTabController(self, didSearch: query)
} }
} }