blob: e7a085967f40b8326e9dabe2b66f9cbeef315888 [file] [log] [blame]
// Copyright 2017 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/popup/omnibox_popup_mediator.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#import "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h"
#include "components/omnibox/browser/autocomplete_input.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/autocomplete_result.h"
#import "ios/chrome/browser/ui/commands/browser_commands.h"
#import "ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.h"
#import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_presenter.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation OmniboxPopupMediator {
// Fetcher for Answers in Suggest images.
std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> _imageFetcher;
OmniboxPopupMediatorDelegate* _delegate; // weak
AutocompleteResult _currentResult;
}
@synthesize consumer = _consumer;
@synthesize hasResults = _hasResults;
@synthesize incognito = _incognito;
@synthesize open = _open;
@synthesize presenter = _presenter;
- (instancetype)initWithFetcher:
(std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper>)
imageFetcher
delegate:(OmniboxPopupMediatorDelegate*)delegate {
self = [super init];
if (self) {
DCHECK(delegate);
_delegate = delegate;
_imageFetcher = std::move(imageFetcher);
_open = NO;
}
return self;
}
- (void)updateMatches:(const AutocompleteResult&)result
withAnimation:(BOOL)animation {
_currentResult.Reset();
_currentResult.CopyFrom(result);
self.hasResults = !_currentResult.empty();
[self.consumer updateMatches:[self wrappedMatches] withAnimation:animation];
}
- (NSArray<id<AutocompleteSuggestion>>*)wrappedMatches {
NSMutableArray<id<AutocompleteSuggestion>>* wrappedMatches =
[[NSMutableArray alloc] init];
size_t size = _currentResult.size();
for (size_t i = 0; i < size; i++) {
const AutocompleteMatch& match =
((const AutocompleteResult&)_currentResult).match_at((NSUInteger)i);
AutocompleteMatchFormatter* formatter =
[AutocompleteMatchFormatter formatterWithMatch:match];
formatter.starred = _delegate->IsStarredMatch(match);
formatter.incognito = _incognito;
[wrappedMatches addObject:formatter];
}
return wrappedMatches;
}
- (void)updateWithResults:(const AutocompleteResult&)result {
if (!self.open && !result.empty()) {
// The popup is not currently open and there are results to display. Update
// and animate the cells
[self updateMatches:result withAnimation:YES];
} else {
// The popup is already displayed or there are no results to display. Update
// the cells without animating.
[self updateMatches:result withAnimation:NO];
}
self.open = !result.empty();
if (self.open) {
[self.presenter updateHeightAndAnimateAppearanceIfNecessary];
}
}
- (void)setTextAlignment:(NSTextAlignment)alignment {
[self.consumer setTextAlignment:alignment];
}
#pragma mark - AutocompleteResultConsumerDelegate
- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
didHighlightRow:(NSUInteger)row {
_delegate->OnMatchHighlighted(row);
}
- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
didSelectRow:(NSUInteger)row {
// OpenMatch() may close the popup, which will clear the result set and, by
// extension, |match| and its contents. So copy the relevant match out to
// make sure it stays alive until the call completes.
const AutocompleteMatch& match =
((const AutocompleteResult&)_currentResult).match_at(row);
_delegate->OnMatchSelected(match, row);
}
- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
didTapTrailingButtonForRow:(NSUInteger)row {
const AutocompleteMatch& match =
((const AutocompleteResult&)_currentResult).match_at(row);
if (match.has_tab_match) {
[self.dispatcher unfocusOmniboxAndSwitchToTabWithURL:match.destination_url];
} else {
if (AutocompleteMatch::IsSearchType(match.type)) {
base::RecordAction(
base::UserMetricsAction("MobileOmniboxRefineSuggestion.Search"));
} else {
base::RecordAction(
base::UserMetricsAction("MobileOmniboxRefineSuggestion.Url"));
}
_delegate->OnMatchSelectedForAppending(match);
}
}
- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
didSelectRowForDeletion:(NSUInteger)row {
const AutocompleteMatch& match =
((const AutocompleteResult&)_currentResult).match_at(row);
_delegate->OnMatchSelectedForDeletion(match);
}
- (void)autocompleteResultConsumerDidScroll:
(id<AutocompleteResultConsumer>)sender {
_delegate->OnScroll();
}
#pragma mark - ImageFetcher
- (void)fetchImage:(GURL)imageURL completion:(void (^)(UIImage*))completion {
image_fetcher::ImageDataFetcherBlock callback =
^(NSData* data, const image_fetcher::RequestMetadata& metadata) {
if (data) {
UIImage* image =
[UIImage imageWithData:data scale:[UIScreen mainScreen].scale];
completion(image);
} else {
completion(nil);
}
};
_imageFetcher->FetchImageDataWebpDecoded(imageURL, callback);
}
@end