blob: 1dfcdbf1697257f01acfb2d1950eec1d52bbf64a [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/omnibox/omnibox_coordinator.h"
#include "base/logging.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/strings/sys_string_conversions.h"
#include "components/omnibox/browser/omnibox_edit_model.h"
#include "components/omnibox/common/omnibox_focus_state.h"
#include "components/strings/grit/components_strings.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
#import "ios/chrome/browser/search_engines/template_url_service_factory.h"
#import "ios/chrome/browser/ui/commands/load_query_commands.h"
#import "ios/chrome/browser/ui/location_bar/location_bar_constants.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_mediator.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
#import "ios/chrome/browser/ui/omnibox/omnibox_util.h"
#include "ios/chrome/browser/ui/omnibox/omnibox_view_controller.h"
#include "ios/chrome/browser/ui/omnibox/omnibox_view_ios.h"
#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.h"
#include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h"
#import "ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_delegate.h"
#import "ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.h"
#import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface OmniboxCoordinator () <OmniboxViewControllerDelegate>
// Object taking care of adding the accessory views to the keyboard.
@property(nonatomic, strong)
ToolbarAssistiveKeyboardDelegateImpl* keyboardDelegate;
// View controller managed by this coordinator.
@property(nonatomic, strong) OmniboxViewController* viewController;
// The mediator for the omnibox.
@property(nonatomic, strong) OmniboxMediator* mediator;
@end
@implementation OmniboxCoordinator {
// TODO(crbug.com/818636): use a slimmer subclass of OmniboxView,
// OmniboxPopupViewSuggestionsDelegate instead of OmniboxViewIOS.
std::unique_ptr<OmniboxViewIOS> _editView;
}
@synthesize editController = _editController;
@synthesize browserState = _browserState;
@synthesize keyboardDelegate = _keyboardDelegate;
@synthesize dispatcher = _dispatcher;
@synthesize viewController = _viewController;
@synthesize mediator = _mediator;
#pragma mark - public
- (void)start {
BOOL isIncognito = self.browserState->IsOffTheRecord();
self.viewController =
[[OmniboxViewController alloc] initWithIncognito:isIncognito];
self.viewController.defaultLeadingImage =
GetOmniboxSuggestionIcon(DEFAULT_FAVICON);
self.viewController.dispatcher =
static_cast<id<BrowserCommands, LoadQueryCommands, OmniboxFocuser>>(
self.dispatcher);
self.viewController.delegate = self;
self.mediator = [[OmniboxMediator alloc] init];
self.mediator.templateURLService =
ios::TemplateURLServiceFactory::GetForBrowserState(self.browserState);
self.mediator.faviconLoader =
IOSChromeFaviconLoaderFactory::GetForBrowserState(self.browserState);
self.mediator.consumer = self.viewController;
DCHECK(self.editController);
id<OmniboxFocuser> focuser = static_cast<id<OmniboxFocuser>>(self.dispatcher);
_editView = std::make_unique<OmniboxViewIOS>(
self.textField, self.editController, self.mediator, self.browserState,
focuser);
// Configure the textfield.
self.textField.suggestionCommandsEndpoint =
static_cast<id<OmniboxSuggestionCommands>>(self.dispatcher);
self.keyboardDelegate = [[ToolbarAssistiveKeyboardDelegateImpl alloc] init];
self.keyboardDelegate.dispatcher =
static_cast<id<ApplicationCommands, BrowserCommands>>(self.dispatcher);
self.keyboardDelegate.omniboxTextField = self.textField;
ConfigureAssistiveKeyboardViews(self.textField, kDotComTLD,
self.keyboardDelegate);
}
- (void)stop {
_editView.reset();
self.editController = nil;
self.viewController = nil;
self.mediator = nil;
[NSNotificationCenter.defaultCenter removeObserver:self];
}
- (void)updateOmniboxState {
_editView->UpdateAppearance();
}
- (void)setNextFocusSourceAsSearchButton {
OmniboxEditModel* model = _editView->model();
model->set_focus_source(OmniboxFocusSource::SEARCH_BUTTON);
}
- (BOOL)isOmniboxFirstResponder {
return [self.textField isFirstResponder];
}
- (void)focusOmnibox {
if (![self.textField isFirstResponder]) {
base::RecordAction(base::UserMetricsAction("MobileOmniboxFocused"));
[self.textField becomeFirstResponder];
}
}
- (void)endEditing {
[self.textField resignFirstResponder];
_editView->EndEditing();
}
- (void)insertTextToOmnibox:(NSString*)text {
[self.textField insertTextWhileEditing:text];
// The call to |setText| shouldn't be needed, but without it the "Go" button
// of the keyboard is disabled.
[self.textField setText:text];
// Notify the accessibility system to start reading the new contents of the
// Omnibox.
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,
self.textField);
}
- (OmniboxPopupCoordinator*)createPopupCoordinator:
(id<OmniboxPopupPresenterDelegate>)presenterDelegate {
std::unique_ptr<OmniboxPopupViewIOS> popupView =
std::make_unique<OmniboxPopupViewIOS>(_editView->model(),
_editView.get());
_editView->model()->set_popup_model(popupView->model());
_editView->SetPopupProvider(popupView.get());
OmniboxPopupCoordinator* coordinator =
[[OmniboxPopupCoordinator alloc] initWithPopupView:std::move(popupView)];
coordinator.browserState = self.browserState;
coordinator.presenterDelegate = presenterDelegate;
return coordinator;
}
- (UIViewController*)managedViewController {
return self.viewController;
}
- (id<LocationBarOffsetProvider>)offsetProvider {
return self.viewController;
}
- (id<EditViewAnimatee>)animatee {
return self.viewController;
}
#pragma mark - OmniboxViewControllerDelegate
- (void)omniboxViewControllerTextInputModeDidChange:
(OmniboxViewController*)omniboxViewController {
_editView->UpdatePopupAppearance();
}
#pragma mark - private
// Convenience accessor.
- (OmniboxTextFieldIOS*)textField {
return self.viewController.textField;
}
@end