blob: d94714a07a148003534307db86593230ada38982 [file] [log] [blame]
// Copyright 2013 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.
#include "ios/chrome/browser/translate/before_translate_infobar_controller.h"
#include <stddef.h>
#import <UIKit/UIKit.h>
#include "base/logging.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/strings/grit/components_strings.h"
#include "components/translate/core/browser/translate_infobar_delegate.h"
#include "ios/chrome/browser/translate/translate_infobar_tags.h"
#import "ios/chrome/browser/ui/infobars/infobar_view.h"
#import "ios/chrome/browser/ui/infobars/infobar_view_delegate.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
CGFloat kNavigationBarHeight = 44;
CGFloat kUIPickerHeight = 216;
CGFloat kUIPickerFontSize = 26;
NSTimeInterval kPickerAnimationDurationInSeconds = 0.2;
} // namespace
// The class is a data source and delegate to the UIPickerView that contains the
// language list.
@interface LanguagePickerController
: UIViewController<UIPickerViewDataSource, UIPickerViewDelegate> {
translate::TranslateInfoBarDelegate* _translateInfoBarDelegate; // weak
NSInteger _initialRow; // Displayed in bold font.
NSInteger _disabledRow; // Grayed out.
}
@end
@implementation LanguagePickerController
- (instancetype)initWithDelegate:(translate::TranslateInfoBarDelegate*)
translateInfoBarDelegate
initialRow:(NSInteger)initialRow
disabledRow:(NSInteger)disabledRow {
if ((self = [super init])) {
_translateInfoBarDelegate = translateInfoBarDelegate;
_initialRow = initialRow;
_disabledRow = disabledRow;
}
return self;
}
#pragma mark -
#pragma mark UIPickerViewDataSource
- (NSInteger)pickerView:(UIPickerView*)pickerView
numberOfRowsInComponent:(NSInteger)component {
NSUInteger numRows = _translateInfoBarDelegate->num_languages();
return numRows;
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView*)pickerView {
return 1;
}
#pragma mark -
#pragma mark UIPickerViewDelegate
- (UIView*)pickerView:(UIPickerView*)pickerView
viewForRow:(NSInteger)row
forComponent:(NSInteger)component
reusingView:(UIView*)view {
DCHECK_EQ(0, component);
UILabel* label = [view isKindOfClass:[UILabel class]]
? (UILabel*)view
: [[UILabel alloc] init];
[label setText:base::SysUTF16ToNSString(
_translateInfoBarDelegate->language_name_at(row))];
[label setTextAlignment:NSTextAlignmentCenter];
UIFont* font = [UIFont systemFontOfSize:kUIPickerFontSize];
BOOL enabled = YES;
if (row == _initialRow)
font = [UIFont boldSystemFontOfSize:kUIPickerFontSize];
else if (row == _disabledRow)
enabled = NO;
[label setFont:font];
[label setEnabled:enabled];
return label;
}
@end
@interface BeforeTranslateInfoBarController ()
// Action for any of the user defined buttons.
- (void)infoBarButtonDidPress:(id)sender;
// Action for any of the user defined links.
- (void)infobarLinkDidPress:(NSUInteger)tag;
// Action for the language selection "Done" button.
- (void)languageSelectionDone;
// Dismisses the language selection view.
- (void)dismissLanguageSelectionView;
// Changes the text on the view to match the language.
- (void)updateInfobarLabelOnView:(InfoBarView*)view;
@end
@implementation BeforeTranslateInfoBarController {
translate::TranslateInfoBarDelegate* _translateInfoBarDelegate; // weak
// A fullscreen view that catches all touch events and contains a UIPickerView
// and a UINavigationBar.
UIView* _languageSelectionView;
// Stores whether the user is currently choosing in the UIPickerView the
// original language, or the target language.
NSUInteger _languageSelectionType;
// The language picker.
UIPickerView* _languagePicker;
// Navigation bar associated with the picker with "Done" and "Cancel" buttons.
UINavigationBar* _navigationBar;
// The controller of the languagePicker. Needs to be an ivar because
// |_languagePicker| does not retain it.
LanguagePickerController* _languagePickerController;
}
#pragma mark -
#pragma mark InfoBarControllerProtocol
- (InfoBarView*)viewForDelegate:(infobars::InfoBarDelegate*)delegate
frame:(CGRect)frame {
InfoBarView* infoBarView;
_translateInfoBarDelegate = delegate->AsTranslateInfoBarDelegate();
infoBarView =
[[InfoBarView alloc] initWithFrame:frame delegate:self.delegate];
// Icon
gfx::Image icon = _translateInfoBarDelegate->GetIcon();
if (!icon.IsEmpty())
[infoBarView addLeftIcon:icon.ToUIImage()];
// Main text.
[self updateInfobarLabelOnView:infoBarView];
// Close button.
[infoBarView addCloseButtonWithTag:TranslateInfoBarIOSTag::BEFORE_DENY
target:self
action:@selector(infoBarButtonDidPress:)];
// Other buttons.
NSString* buttonAccept = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_ACCEPT);
NSString* buttonDeny = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_DENY);
[infoBarView addButton1:buttonAccept
tag1:TranslateInfoBarIOSTag::BEFORE_ACCEPT
button2:buttonDeny
tag2:TranslateInfoBarIOSTag::BEFORE_DENY
target:self
action:@selector(infoBarButtonDidPress:)];
return infoBarView;
}
- (void)updateInfobarLabelOnView:(InfoBarView*)view {
NSString* originalLanguage = base::SysUTF16ToNSString(
_translateInfoBarDelegate->original_language_name());
NSString* targetLanguage = base::SysUTF16ToNSString(
_translateInfoBarDelegate->target_language_name());
base::string16 originalLanguageWithLink =
base::SysNSStringToUTF16([[view class]
stringAsLink:originalLanguage
tag:TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE]);
base::string16 targetLanguageWithLink = base::SysNSStringToUTF16([[view class]
stringAsLink:targetLanguage
tag:TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE]);
NSString* label =
l10n_util::GetNSStringF(IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE_IOS,
originalLanguageWithLink, targetLanguageWithLink);
__weak BeforeTranslateInfoBarController* weakSelf = self;
[view addLabel:label
action:^(NSUInteger tag) {
[weakSelf infobarLinkDidPress:tag];
}];
}
- (void)languageSelectionDone {
size_t selectedRow = [_languagePicker selectedRowInComponent:0];
std::string lang = _translateInfoBarDelegate->language_code_at(selectedRow);
if (_languageSelectionType ==
TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE &&
lang != _translateInfoBarDelegate->target_language_code()) {
_translateInfoBarDelegate->UpdateOriginalLanguage(lang);
}
if (_languageSelectionType ==
TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE &&
lang != _translateInfoBarDelegate->original_language_code()) {
_translateInfoBarDelegate->UpdateTargetLanguage(lang);
}
[self updateInfobarLabelOnView:self.view];
[self dismissLanguageSelectionView];
}
- (void)dismissLanguageSelectionView {
DCHECK_EQ(_languagePicker == nil, _navigationBar == nil);
if (_languagePicker == nil)
return;
// Sets the picker's delegate and data source to nil, because the
// |_languagePickerController| may be destroyed before the picker is hidden,
// and even though the interactions with the picker are disabled, it might
// still be turning and requesting data from the data source or calling the
// delegate.
[_languagePicker setDataSource:nil];
[_languagePicker setDelegate:nil];
_languagePickerController = nil;
// Animate the picker away.
CGRect languagePickerFrame = [_languagePicker frame];
CGRect navigationBarFrame = [_navigationBar frame];
const CGFloat animationHeight =
languagePickerFrame.size.height + navigationBarFrame.size.height;
languagePickerFrame.origin.y += animationHeight;
navigationBarFrame.origin.y += animationHeight;
UIPickerView* blockLanguagePicker = _languagePicker;
UINavigationBar* blockNavigationBar = _navigationBar;
_languagePicker = nil;
_navigationBar = nil;
void (^animations)(void) = ^{
blockLanguagePicker.frame = languagePickerFrame;
blockNavigationBar.frame = navigationBarFrame;
};
UIView* blockSelectionView = _languageSelectionView;
_languageSelectionView = nil;
void (^completion)(BOOL finished) = ^(BOOL finished) {
[blockSelectionView removeFromSuperview];
};
[UIView animateWithDuration:kPickerAnimationDurationInSeconds
animations:animations
completion:completion];
}
#pragma mark - Handling of User Events
- (void)infoBarButtonDidPress:(id)sender {
// This press might have occurred after the user has already pressed a button,
// in which case the view has been detached from the delegate and this press
// should be ignored.
if (!self.delegate) {
return;
}
if ([sender isKindOfClass:[UIButton class]]) {
NSUInteger buttonId = static_cast<UIButton*>(sender).tag;
DCHECK(buttonId == TranslateInfoBarIOSTag::BEFORE_ACCEPT ||
buttonId == TranslateInfoBarIOSTag::BEFORE_DENY);
self.delegate->InfoBarButtonDidPress(buttonId);
}
}
- (void)infobarLinkDidPress:(NSUInteger)tag {
_languageSelectionType = tag;
DCHECK(_languageSelectionType ==
TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE ||
_languageSelectionType ==
TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE);
if (_languagePicker != nil)
return; // The UIPickerView is already up.
// Creates and adds the view containing the UIPickerView and the
// UINavigationBar.
UIView* parentView =
[[UIApplication sharedApplication] keyWindow].rootViewController.view;
// Convert the parent frame to handle device rotation.
CGRect parentFrame =
CGRectApplyAffineTransform([parentView frame], [parentView transform]);
const CGFloat totalPickerHeight = kUIPickerHeight + kNavigationBarHeight;
CGRect languageSelectionViewFrame =
CGRectMake(0, parentFrame.size.height - totalPickerHeight,
parentFrame.size.width, totalPickerHeight);
_languageSelectionView =
[[UIView alloc] initWithFrame:languageSelectionViewFrame];
[_languageSelectionView
setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleTopMargin];
[parentView addSubview:_languageSelectionView];
// Creates the navigation bar and its buttons.
CGRect finalPickerFrame = CGRectMake(
0, [_languageSelectionView frame].size.height - kUIPickerHeight,
[_languageSelectionView frame].size.width, kUIPickerHeight);
CGRect finalNavigationBarFrame = CGRectMake(
0, 0, [_languageSelectionView frame].size.width, kNavigationBarHeight);
// The language picker animates from the bottom of the screen.
CGRect initialPickerFrame = finalPickerFrame;
initialPickerFrame.origin.y += totalPickerHeight;
CGRect initialNavigationBarFrame = finalNavigationBarFrame;
initialNavigationBarFrame.origin.y += totalPickerHeight;
_navigationBar =
[[UINavigationBar alloc] initWithFrame:initialNavigationBarFrame];
const UIViewAutoresizing resizingMask =
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
[_navigationBar setAutoresizingMask:resizingMask];
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:@selector(languageSelectionDone)];
UIBarButtonItem* cancelButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:@selector(dismissLanguageSelectionView)];
UINavigationItem* item = [[UINavigationItem alloc] initWithTitle:@""];
[item setRightBarButtonItem:doneButton];
[item setLeftBarButtonItem:cancelButton];
[item setHidesBackButton:YES];
[_navigationBar pushNavigationItem:item animated:NO];
// Creates the PickerView and its controller.
NSInteger selectedRow;
NSInteger disabledRow;
NSInteger originalLanguageIndex = -1;
NSInteger targetLanguageIndex = -1;
for (size_t i = 0; i < _translateInfoBarDelegate->num_languages(); ++i) {
if (_translateInfoBarDelegate->language_code_at(i) ==
_translateInfoBarDelegate->original_language_code()) {
originalLanguageIndex = i;
}
if (_translateInfoBarDelegate->language_code_at(i) ==
_translateInfoBarDelegate->target_language_code()) {
targetLanguageIndex = i;
}
}
DCHECK_GT(originalLanguageIndex, -1);
DCHECK_GT(targetLanguageIndex, -1);
if (_languageSelectionType ==
TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE) {
selectedRow = originalLanguageIndex;
disabledRow = targetLanguageIndex;
} else {
selectedRow = targetLanguageIndex;
disabledRow = originalLanguageIndex;
}
_languagePickerController = [[LanguagePickerController alloc]
initWithDelegate:_translateInfoBarDelegate
initialRow:selectedRow
disabledRow:disabledRow];
_languagePicker = [[UIPickerView alloc] initWithFrame:initialPickerFrame];
[_languagePicker setAutoresizingMask:resizingMask];
[_languagePicker setShowsSelectionIndicator:YES];
[_languagePicker setDataSource:_languagePickerController];
[_languagePicker setDelegate:_languagePickerController];
[_languagePicker setShowsSelectionIndicator:YES];
[_languagePicker setBackgroundColor:[self.view backgroundColor]];
[_languagePicker selectRow:selectedRow inComponent:0 animated:NO];
UIPickerView* blockLanguagePicker = _languagePicker;
UINavigationBar* blockNavigationBar = _navigationBar;
[UIView animateWithDuration:kPickerAnimationDurationInSeconds
animations:^{
blockLanguagePicker.frame = finalPickerFrame;
blockNavigationBar.frame = finalNavigationBarFrame;
}];
// Add the subviews.
[_languageSelectionView addSubview:_languagePicker];
[_languageSelectionView addSubview:_navigationBar];
}
- (void)removeView {
[super removeView];
[self dismissLanguageSelectionView];
}
- (void)detachView {
[super detachView];
[self dismissLanguageSelectionView];
}
@end