cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / ios / chrome / browser / translate / before_translate_infobar_controller.mm
blob7a872d9162f7a7ad9f9b244d28cf2fbbb0fefba9
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ios/chrome/browser/translate/before_translate_infobar_controller.h"
7 #import <UIKit/UIKit.h>
9 #include "base/logging.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/translate/core/browser/translate_infobar_delegate.h"
13 #include "grit/components_strings.h"
14 #include "ios/chrome/browser/translate/translate_infobar_tags.h"
15 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
16 #import "ios/public/provider/chrome/browser/ui/infobar_view_delegate.h"
17 #import "ios/public/provider/chrome/browser/ui/infobar_view_protocol.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/gfx/image/image.h"
21 namespace {
23 CGFloat kNavigationBarHeight = 44;
24 CGFloat kUIPickerHeight = 216;
25 CGFloat kUIPickerFontSize = 26;
26 NSTimeInterval kPickerAnimationDurationInSeconds = 0.2;
28 }  // namespace
30 // The class is a data source and delegate to the UIPickerView that contains the
31 // language list.
32 @interface LanguagePickerController
33     : UIViewController<UIPickerViewDataSource, UIPickerViewDelegate> {
34   __weak translate::TranslateInfoBarDelegate* _translateInfoBarDelegate;
35   NSInteger _initialRow;   // Displayed in bold font.
36   NSInteger _disabledRow;  // Grayed out.
38 @end
40 @implementation LanguagePickerController
42 - (instancetype)initWithDelegate:(translate::TranslateInfoBarDelegate*)
43                                      translateInfoBarDelegate
44                       initialRow:(NSInteger)initialRow
45                      disabledRow:(NSInteger)disabledRow {
46   if ((self = [super init])) {
47     _translateInfoBarDelegate = translateInfoBarDelegate;
48     _initialRow = initialRow;
49     _disabledRow = disabledRow;
50   }
51   return self;
54 #pragma mark -
55 #pragma mark UIPickerViewDataSource
57 - (NSInteger)pickerView:(UIPickerView*)pickerView
58     numberOfRowsInComponent:(NSInteger)component {
59   NSUInteger numRows = _translateInfoBarDelegate->num_languages();
60   return numRows;
63 - (NSInteger)numberOfComponentsInPickerView:(UIPickerView*)pickerView {
64   return 1;
67 #pragma mark -
68 #pragma mark UIPickerViewDelegate
70 - (UIView*)pickerView:(UIPickerView*)pickerView
71            viewForRow:(NSInteger)row
72          forComponent:(NSInteger)component
73           reusingView:(UIView*)view {
74   DCHECK_EQ(0, component);
75   UILabel* label = [view isKindOfClass:[UILabel class]]
76                        ? (UILabel*)view
77                        : [[[UILabel alloc] init] autorelease];
78   [label setText:base::SysUTF16ToNSString(
79                      _translateInfoBarDelegate->language_name_at(row))];
80   [label setTextAlignment:NSTextAlignmentCenter];
81   UIFont* font = [UIFont systemFontOfSize:kUIPickerFontSize];
82   BOOL enabled = YES;
83   if (row == _initialRow)
84     font = [UIFont boldSystemFontOfSize:kUIPickerFontSize];
85   else if (row == _disabledRow)
86     enabled = NO;
87   [label setFont:font];
88   [label setEnabled:enabled];
89   return label;
92 @end
94 @interface BeforeTranslateInfoBarController ()
96 // Action for any of the user defined buttons.
97 - (void)infoBarButtonDidPress:(id)sender;
98 // Action for any of the user defined links.
99 - (void)infobarLinkDidPress:(NSNumber*)tag;
100 // Action for the language selection "Done" button.
101 - (void)languageSelectionDone;
102 // Dismisses the language selection view.
103 - (void)dismissLanguageSelectionView;
104 // Changes the text on the view to match the language.
105 - (void)updateInfobarLabelOnView:(UIView<InfoBarViewProtocol>*)view;
107 @end
109 @implementation BeforeTranslateInfoBarController {
110   __weak translate::TranslateInfoBarDelegate* _translateInfoBarDelegate;
111   // A fullscreen view that catches all touch events and contains a UIPickerView
112   // and a UINavigationBar.
113   base::scoped_nsobject<UIView> _languageSelectionView;
114   // Stores whether the user is currently choosing in the UIPickerView the
115   // original language, or the target language.
116   NSUInteger _languageSelectionType;
117   // The language picker.
118   base::scoped_nsobject<UIPickerView> _languagePicker;
119   // Navigation bar associated with the picker with "Done" and "Cancel" buttons.
120   base::scoped_nsobject<UINavigationBar> _navigationBar;
121   // The controller of the languagePicker. Needs to be an ivar because
122   // |_languagePicker| does not retain it.
123   base::scoped_nsobject<LanguagePickerController> _languagePickerController;
126 #pragma mark -
127 #pragma mark InfoBarControllerProtocol
129 - (base::scoped_nsobject<UIView<InfoBarViewProtocol>>)
130     viewForDelegate:(infobars::InfoBarDelegate*)delegate
131               frame:(CGRect)frame {
132   base::scoped_nsobject<UIView<InfoBarViewProtocol>> infoBarView;
133   _translateInfoBarDelegate = delegate->AsTranslateInfoBarDelegate();
134   infoBarView.reset(
135       ios::GetChromeBrowserProvider()->CreateInfoBarView(frame, self.delegate));
136   // Icon
137   gfx::Image icon = _translateInfoBarDelegate->GetIcon();
138   if (!icon.IsEmpty())
139     [infoBarView addLeftIcon:icon.ToUIImage()];
141   // Main text.
142   [self updateInfobarLabelOnView:infoBarView];
144   // Close button.
145   [infoBarView addCloseButtonWithTag:TranslateInfoBarIOSTag::BEFORE_DENY
146                               target:self
147                               action:@selector(infoBarButtonDidPress:)];
148   // Other buttons.
149   NSString* buttonAccept = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_ACCEPT);
150   NSString* buttonDeny = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_DENY);
151   [infoBarView addButton1:buttonAccept
152                      tag1:TranslateInfoBarIOSTag::BEFORE_ACCEPT
153                   button2:buttonDeny
154                      tag2:TranslateInfoBarIOSTag::BEFORE_DENY
155                    target:self
156                    action:@selector(infoBarButtonDidPress:)];
157   return infoBarView;
160 - (void)updateInfobarLabelOnView:(UIView<InfoBarViewProtocol>*)view {
161   NSString* originalLanguage =
162       base::SysUTF16ToNSString(_translateInfoBarDelegate->language_name_at(
163           _translateInfoBarDelegate->original_language_index()));
164   NSString* targetLanguage =
165       base::SysUTF16ToNSString(_translateInfoBarDelegate->language_name_at(
166           _translateInfoBarDelegate->target_language_index()));
167   base::string16 originalLanguageWithLink =
168       base::SysNSStringToUTF16([[view class]
169           stringAsLink:originalLanguage
170                    tag:TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE]);
171   base::string16 targetLanguageWithLink = base::SysNSStringToUTF16([[view class]
172       stringAsLink:targetLanguage
173                tag:TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE]);
174   NSString* label =
175       l10n_util::GetNSStringF(IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE_IOS,
176                               originalLanguageWithLink, targetLanguageWithLink);
177   [view addLabel:label target:self action:@selector(infobarLinkDidPress:)];
180 - (void)languageSelectionDone {
181   size_t selectedRow = [_languagePicker selectedRowInComponent:0];
182   if (_languageSelectionType ==
183           TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE &&
184       selectedRow != _translateInfoBarDelegate->target_language_index()) {
185     _translateInfoBarDelegate->UpdateOriginalLanguageIndex(selectedRow);
186   }
187   if (_languageSelectionType ==
188           TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE &&
189       selectedRow != _translateInfoBarDelegate->original_language_index()) {
190     _translateInfoBarDelegate->UpdateTargetLanguageIndex(selectedRow);
191   }
192   [self updateInfobarLabelOnView:self.view];
193   [self dismissLanguageSelectionView];
196 - (void)dismissLanguageSelectionView {
197   DCHECK_EQ(_languagePicker == nil, _navigationBar == nil);
198   if (_languagePicker == nil)
199     return;
200   // Sets the picker's delegate and data source to nil, because the
201   // |_languagePickerController| may be destroyed before the picker is hidden,
202   // and even though the interactions with the picker are disabled, it might
203   // still be turning and requesting data from the data source or calling the
204   // delegate.
205   [_languagePicker setDataSource:nil];
206   [_languagePicker setDelegate:nil];
207   _languagePickerController.reset();
208   // Animate the picker away.
209   CGRect languagePickerFrame = [_languagePicker frame];
210   CGRect navigationBarFrame = [_navigationBar frame];
211   const CGFloat animationHeight =
212       languagePickerFrame.size.height + navigationBarFrame.size.height;
213   languagePickerFrame.origin.y += animationHeight;
214   navigationBarFrame.origin.y += animationHeight;
215   auto blockLanguagePicker(_languagePicker);
216   auto blockNavigationBar(_navigationBar);
217   _languagePicker.reset();
218   _navigationBar.reset();
219   void (^animations)(void) = ^{
220     blockLanguagePicker.get().frame = languagePickerFrame;
221     blockNavigationBar.get().frame = navigationBarFrame;
222   };
223   auto blockSelectionView(_languageSelectionView);
224   _languageSelectionView.reset();
225   void (^completion)(BOOL finished) = ^(BOOL finished) {
226     [blockSelectionView removeFromSuperview];
227   };
228   [UIView animateWithDuration:kPickerAnimationDurationInSeconds
229                    animations:animations
230                    completion:completion];
233 #pragma mark - Handling of User Events
235 - (void)infoBarButtonDidPress:(id)sender {
236   // This press might have occurred after the user has already pressed a button,
237   // in which case the view has been detached from the delegate and this press
238   // should be ignored.
239   if (!self.delegate) {
240     return;
241   }
242   if ([sender isKindOfClass:[UIButton class]]) {
243     NSUInteger buttonId = static_cast<UIButton*>(sender).tag;
244     DCHECK(buttonId == TranslateInfoBarIOSTag::BEFORE_ACCEPT ||
245            buttonId == TranslateInfoBarIOSTag::BEFORE_DENY);
246     self.delegate->InfoBarButtonDidPress(buttonId);
247   }
250 - (void)infobarLinkDidPress:(NSNumber*)tag {
251   DCHECK([tag isKindOfClass:[NSNumber class]]);
252   _languageSelectionType = [tag unsignedIntegerValue];
253   DCHECK(_languageSelectionType ==
254              TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE ||
255          _languageSelectionType ==
256              TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE);
257   if (_languagePicker != nil)
258     return;  // The UIPickerView is already up.
260   // Creates and adds the view containing the UIPickerView and the
261   // UINavigationBar.
262   UIView* parentView =
263       [[UIApplication sharedApplication] keyWindow].rootViewController.view;
264   // Convert the parent frame to handle device rotation.
265   CGRect parentFrame =
266       CGRectApplyAffineTransform([parentView frame], [parentView transform]);
267   const CGFloat totalPickerHeight = kUIPickerHeight + kNavigationBarHeight;
268   CGRect languageSelectionViewFrame =
269       CGRectMake(0, parentFrame.size.height - totalPickerHeight,
270                  parentFrame.size.width, totalPickerHeight);
271   _languageSelectionView.reset(
272       [[UIView alloc] initWithFrame:languageSelectionViewFrame]);
273   [_languageSelectionView
274       setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
275                           UIViewAutoresizingFlexibleTopMargin];
276   [parentView addSubview:_languageSelectionView];
278   // Creates the navigation bar and its buttons.
279   CGRect finalPickerFrame = CGRectMake(
280       0, [_languageSelectionView frame].size.height - kUIPickerHeight,
281       [_languageSelectionView frame].size.width, kUIPickerHeight);
282   CGRect finalNavigationBarFrame = CGRectMake(
283       0, 0, [_languageSelectionView frame].size.width, kNavigationBarHeight);
284   // The language picker animates from the bottom of the screen.
285   CGRect initialPickerFrame = finalPickerFrame;
286   initialPickerFrame.origin.y += totalPickerHeight;
287   CGRect initialNavigationBarFrame = finalNavigationBarFrame;
288   initialNavigationBarFrame.origin.y += totalPickerHeight;
290   _navigationBar.reset(
291       [[UINavigationBar alloc] initWithFrame:initialNavigationBarFrame]);
292   const UIViewAutoresizing resizingMask =
293       UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
294   [_navigationBar setAutoresizingMask:resizingMask];
295   base::scoped_nsobject<UIBarButtonItem> doneButton([[UIBarButtonItem alloc]
296       initWithBarButtonSystemItem:UIBarButtonSystemItemDone
297                            target:self
298                            action:@selector(languageSelectionDone)]);
299   base::scoped_nsobject<UIBarButtonItem> cancelButton([[UIBarButtonItem alloc]
300       initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
301                            target:self
302                            action:@selector(dismissLanguageSelectionView)]);
303   base::scoped_nsobject<UINavigationItem> item(
304       [[UINavigationItem alloc] initWithTitle:@""]);
305   [item setRightBarButtonItem:doneButton];
306   [item setLeftBarButtonItem:cancelButton];
307   [item setHidesBackButton:YES];
308   [_navigationBar pushNavigationItem:item animated:NO];
310   // Creates the PickerView and its controller.
311   NSInteger selectedRow;
312   NSInteger disabledRow;
313   if (_languageSelectionType ==
314       TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE) {
315     selectedRow = _translateInfoBarDelegate->original_language_index();
316     disabledRow = _translateInfoBarDelegate->target_language_index();
317   } else {
318     selectedRow = _translateInfoBarDelegate->target_language_index();
319     disabledRow = _translateInfoBarDelegate->original_language_index();
320   }
321   _languagePickerController.reset([[LanguagePickerController alloc]
322       initWithDelegate:_translateInfoBarDelegate
323             initialRow:selectedRow
324            disabledRow:disabledRow]);
325   _languagePicker.reset(
326       [[UIPickerView alloc] initWithFrame:initialPickerFrame]);
327   [_languagePicker setAutoresizingMask:resizingMask];
328   [_languagePicker setShowsSelectionIndicator:YES];
329   [_languagePicker setDataSource:_languagePickerController];
330   [_languagePicker setDelegate:_languagePickerController];
331   [_languagePicker setShowsSelectionIndicator:YES];
332   [_languagePicker setBackgroundColor:[self.view backgroundColor]];
333   [_languagePicker selectRow:selectedRow inComponent:0 animated:NO];
335   auto blockLanguagePicker(_languagePicker);
336   auto blockNavigationBar(_navigationBar);
337   [UIView animateWithDuration:kPickerAnimationDurationInSeconds
338                    animations:^{
339                      blockLanguagePicker.get().frame = finalPickerFrame;
340                      blockNavigationBar.get().frame = finalNavigationBarFrame;
341                    }];
343   // Add the subviews.
344   [_languageSelectionView addSubview:_languagePicker];
345   [_languageSelectionView addSubview:_navigationBar];
348 - (void)removeView {
349   [super removeView];
350   [self dismissLanguageSelectionView];
353 - (void)detachView {
354   [super detachView];
355   [self dismissLanguageSelectionView];
358 @end