OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "ios/chrome/browser/translate/before_translate_infobar_controller.h" |
| 6 |
| 7 #import <UIKit/UIKit.h> |
| 8 |
| 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" |
| 20 |
| 21 namespace { |
| 22 |
| 23 CGFloat kNavigationBarHeight = 44; |
| 24 CGFloat kUIPickerHeight = 216; |
| 25 CGFloat kUIPickerFontSize = 26; |
| 26 NSTimeInterval kPickerAnimationDurationInSeconds = 0.2; |
| 27 |
| 28 } // namespace |
| 29 |
| 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. |
| 37 } |
| 38 @end |
| 39 |
| 40 @implementation LanguagePickerController |
| 41 |
| 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; |
| 52 } |
| 53 |
| 54 #pragma mark - |
| 55 #pragma mark UIPickerViewDataSource |
| 56 |
| 57 - (NSInteger)pickerView:(UIPickerView*)pickerView |
| 58 numberOfRowsInComponent:(NSInteger)component { |
| 59 NSUInteger numRows = translateInfoBarDelegate_->num_languages(); |
| 60 return numRows; |
| 61 } |
| 62 |
| 63 - (NSInteger)numberOfComponentsInPickerView:(UIPickerView*)pickerView { |
| 64 return 1; |
| 65 } |
| 66 |
| 67 #pragma mark - |
| 68 #pragma mark UIPickerViewDelegate |
| 69 |
| 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; |
| 90 } |
| 91 |
| 92 @end |
| 93 |
| 94 @interface BeforeTranslateInfoBarController () |
| 95 |
| 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 |
| 105 @end |
| 106 |
| 107 @implementation BeforeTranslateInfoBarController { |
| 108 __weak translate::TranslateInfoBarDelegate* translateInfoBarDelegate_; |
| 109 // A fullscreen view that catches all touch events and contains a UIPickerView |
| 110 // and a UINavigationBar. |
| 111 base::scoped_nsobject<UIView> languageSelectionView_; |
| 112 // Stores whether the user is currently choosing in the UIPickerView the |
| 113 // original language, or the target language. |
| 114 NSUInteger languageSelectionType_; |
| 115 // The language picker. |
| 116 base::scoped_nsobject<UIPickerView> languagePicker_; |
| 117 // Navigation bar associated with the picker with "Done" and "Cancel" buttons. |
| 118 base::scoped_nsobject<UINavigationBar> navigationBar_; |
| 119 // The controller of the languagePicker. Needs to be an ivar because |
| 120 // |languagePicker_| does not retain it. |
| 121 base::scoped_nsobject<LanguagePickerController> languagePickerController_; |
| 122 } |
| 123 |
| 124 #pragma mark - |
| 125 #pragma mark InfoBarControllerProtocol |
| 126 |
| 127 - (void)layoutForDelegate:(infobars::InfoBarDelegate*)delegate |
| 128 frame:(CGRect)frame { |
| 129 translateInfoBarDelegate_ = delegate->AsTranslateInfoBarDelegate(); |
| 130 infobars::InfoBarDelegate* infoBarDelegate = |
| 131 static_cast<infobars::InfoBarDelegate*>(translateInfoBarDelegate_); |
| 132 DCHECK(!infoBarView_); |
| 133 infoBarView_.reset([ios::GetChromeBrowserProvider()->CreateInfoBarView() |
| 134 initWithFrame:frame |
| 135 delegate:delegate_ |
| 136 isWarning:infoBarDelegate->GetInfoBarType() == |
| 137 infobars::InfoBarDelegate::WARNING_TYPE]); |
| 138 // Icon |
| 139 gfx::Image icon = translateInfoBarDelegate_->GetIcon(); |
| 140 if (!icon.IsEmpty()) |
| 141 [infoBarView_ addLeftIcon:icon.ToUIImage()]; |
| 142 |
| 143 // Main text. |
| 144 [self updateInfobarLabel]; |
| 145 |
| 146 // Close button. |
| 147 [infoBarView_ addCloseButtonWithTag:TranslateInfoBarIOSTag::BEFORE_DENY |
| 148 target:self |
| 149 action:@selector(infoBarButtonDidPress:)]; |
| 150 // Other buttons. |
| 151 NSString* buttonAccept = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_ACCEPT); |
| 152 NSString* buttonDeny = l10n_util::GetNSString(IDS_TRANSLATE_INFOBAR_DENY); |
| 153 [infoBarView_ addButton1:buttonAccept |
| 154 tag1:TranslateInfoBarIOSTag::BEFORE_ACCEPT |
| 155 button2:buttonDeny |
| 156 tag2:TranslateInfoBarIOSTag::BEFORE_DENY |
| 157 target:self |
| 158 action:@selector(infoBarButtonDidPress:)]; |
| 159 } |
| 160 |
| 161 - (void)updateInfobarLabel { |
| 162 NSString* originalLanguage = |
| 163 base::SysUTF16ToNSString(translateInfoBarDelegate_->language_name_at( |
| 164 translateInfoBarDelegate_->original_language_index())); |
| 165 NSString* targetLanguage = |
| 166 base::SysUTF16ToNSString(translateInfoBarDelegate_->language_name_at( |
| 167 translateInfoBarDelegate_->target_language_index())); |
| 168 base::string16 originalLanguageWithLink = |
| 169 base::SysNSStringToUTF16([[infoBarView_ class] |
| 170 stringAsLink:originalLanguage |
| 171 tag:TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE]); |
| 172 base::string16 targetLanguageWithLink = |
| 173 base::SysNSStringToUTF16([[infoBarView_ class] |
| 174 stringAsLink:targetLanguage |
| 175 tag:TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE]); |
| 176 NSString* label = |
| 177 l10n_util::GetNSStringF(IDS_TRANSLATE_INFOBAR_BEFORE_MESSAGE_IOS, |
| 178 originalLanguageWithLink, targetLanguageWithLink); |
| 179 [infoBarView_ addLabel:label |
| 180 target:self |
| 181 action:@selector(infobarLinkDidPress:)]; |
| 182 } |
| 183 |
| 184 - (void)languageSelectionDone { |
| 185 size_t selectedRow = [languagePicker_ selectedRowInComponent:0]; |
| 186 if (languageSelectionType_ == |
| 187 TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE && |
| 188 selectedRow != translateInfoBarDelegate_->target_language_index()) { |
| 189 translateInfoBarDelegate_->UpdateOriginalLanguageIndex(selectedRow); |
| 190 } |
| 191 if (languageSelectionType_ == |
| 192 TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE && |
| 193 selectedRow != translateInfoBarDelegate_->original_language_index()) { |
| 194 translateInfoBarDelegate_->UpdateTargetLanguageIndex(selectedRow); |
| 195 } |
| 196 [self updateInfobarLabel]; |
| 197 [self dismissLanguageSelectionView]; |
| 198 } |
| 199 |
| 200 - (void)dismissLanguageSelectionView { |
| 201 DCHECK_EQ(languagePicker_ == nil, navigationBar_ == nil); |
| 202 if (languagePicker_ == nil) |
| 203 return; |
| 204 // Sets the picker's delegate and data source to nil, because the |
| 205 // |languagePickerController_| may be destroyed before the picker is hidden, |
| 206 // and even though the interactions with the picker are disabled, it might |
| 207 // still be turning and requesting data from the data source or calling the |
| 208 // delegate. |
| 209 [languagePicker_ setDataSource:nil]; |
| 210 [languagePicker_ setDelegate:nil]; |
| 211 languagePickerController_.reset(); |
| 212 // Animate the picker away. |
| 213 CGRect languagePickerFrame = [languagePicker_ frame]; |
| 214 CGRect navigationBarFrame = [navigationBar_ frame]; |
| 215 const CGFloat animationHeight = |
| 216 languagePickerFrame.size.height + navigationBarFrame.size.height; |
| 217 languagePickerFrame.origin.y += animationHeight; |
| 218 navigationBarFrame.origin.y += animationHeight; |
| 219 UIView* blockLanguagePicker = languagePicker_.get(); |
| 220 UIView* blockNavigationBar = navigationBar_.get(); |
| 221 void (^animations)(void) = ^{ |
| 222 blockLanguagePicker.frame = languagePickerFrame; |
| 223 blockNavigationBar.frame = navigationBarFrame; |
| 224 }; |
| 225 languagePicker_.reset(); |
| 226 navigationBar_.reset(); |
| 227 void (^completion)(BOOL finished) = ^(BOOL finished) { |
| 228 [languageSelectionView_ removeFromSuperview]; |
| 229 languageSelectionView_.reset(); |
| 230 }; |
| 231 [UIView animateWithDuration:kPickerAnimationDurationInSeconds |
| 232 animations:animations |
| 233 completion:completion]; |
| 234 } |
| 235 |
| 236 #pragma mark - Handling of User Events |
| 237 |
| 238 - (void)infoBarButtonDidPress:(id)sender { |
| 239 // This press might have occurred after the user has already pressed a button, |
| 240 // in which case the view has been detached from the delegate and this press |
| 241 // should be ignored. |
| 242 if (!delegate_) { |
| 243 return; |
| 244 } |
| 245 if ([sender isKindOfClass:[UIButton class]]) { |
| 246 NSUInteger buttonId = static_cast<UIButton*>(sender).tag; |
| 247 DCHECK(buttonId == TranslateInfoBarIOSTag::BEFORE_ACCEPT || |
| 248 buttonId == TranslateInfoBarIOSTag::BEFORE_DENY); |
| 249 delegate_->InfoBarButtonDidPress(buttonId); |
| 250 } |
| 251 } |
| 252 |
| 253 - (void)infobarLinkDidPress:(NSNumber*)tag { |
| 254 DCHECK([tag isKindOfClass:[NSNumber class]]); |
| 255 languageSelectionType_ = [tag unsignedIntegerValue]; |
| 256 DCHECK(languageSelectionType_ == |
| 257 TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE || |
| 258 languageSelectionType_ == |
| 259 TranslateInfoBarIOSTag::BEFORE_TARGET_LANGUAGE); |
| 260 if (languagePicker_ != nil) |
| 261 return; // The UIPickerView is already up. |
| 262 |
| 263 // Creates and adds the view containing the UIPickerView and the |
| 264 // UINavigationBar. |
| 265 UIView* parentView = |
| 266 [[UIApplication sharedApplication] keyWindow].rootViewController.view; |
| 267 // Convert the parent frame to handle device rotation. |
| 268 CGRect parentFrame = |
| 269 CGRectApplyAffineTransform([parentView frame], [parentView transform]); |
| 270 const CGFloat totalPickerHeight = kUIPickerHeight + kNavigationBarHeight; |
| 271 CGRect languageSelectionViewFrame = |
| 272 CGRectMake(0, parentFrame.size.height - totalPickerHeight, |
| 273 parentFrame.size.width, totalPickerHeight); |
| 274 languageSelectionView_.reset( |
| 275 [[UIView alloc] initWithFrame:languageSelectionViewFrame]); |
| 276 [languageSelectionView_ |
| 277 setAutoresizingMask:UIViewAutoresizingFlexibleWidth | |
| 278 UIViewAutoresizingFlexibleTopMargin]; |
| 279 [parentView addSubview:languageSelectionView_]; |
| 280 |
| 281 // Creates the navigation bar and its buttons. |
| 282 CGRect finalPickerFrame = CGRectMake( |
| 283 0, [languageSelectionView_ frame].size.height - kUIPickerHeight, |
| 284 [languageSelectionView_ frame].size.width, kUIPickerHeight); |
| 285 CGRect finalNavigationBarFrame = CGRectMake( |
| 286 0, 0, [languageSelectionView_ frame].size.width, kNavigationBarHeight); |
| 287 // The language picker animates from the bottom of the screen. |
| 288 CGRect initialPickerFrame = finalPickerFrame; |
| 289 initialPickerFrame.origin.y += totalPickerHeight; |
| 290 CGRect initialNavigationBarFrame = finalNavigationBarFrame; |
| 291 initialNavigationBarFrame.origin.y += totalPickerHeight; |
| 292 |
| 293 navigationBar_.reset( |
| 294 [[UINavigationBar alloc] initWithFrame:initialNavigationBarFrame]); |
| 295 const UIViewAutoresizing resizingMask = |
| 296 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; |
| 297 [navigationBar_ setAutoresizingMask:resizingMask]; |
| 298 base::scoped_nsobject<UIBarButtonItem> doneButton([[UIBarButtonItem alloc] |
| 299 initWithBarButtonSystemItem:UIBarButtonSystemItemDone |
| 300 target:self |
| 301 action:@selector(languageSelectionDone)]); |
| 302 base::scoped_nsobject<UIBarButtonItem> cancelButton([[UIBarButtonItem alloc] |
| 303 initWithBarButtonSystemItem:UIBarButtonSystemItemCancel |
| 304 target:self |
| 305 action:@selector(dismissLanguageSelectionView)]); |
| 306 base::scoped_nsobject<UINavigationItem> item( |
| 307 [[UINavigationItem alloc] initWithTitle:nil]); |
| 308 [item setRightBarButtonItem:doneButton]; |
| 309 [item setLeftBarButtonItem:cancelButton]; |
| 310 [item setHidesBackButton:YES]; |
| 311 [navigationBar_ pushNavigationItem:item animated:NO]; |
| 312 |
| 313 // Creates the PickerView and its controller. |
| 314 NSInteger selectedRow; |
| 315 NSInteger disabledRow; |
| 316 if (languageSelectionType_ == |
| 317 TranslateInfoBarIOSTag::BEFORE_SOURCE_LANGUAGE) { |
| 318 selectedRow = translateInfoBarDelegate_->original_language_index(); |
| 319 disabledRow = translateInfoBarDelegate_->target_language_index(); |
| 320 } else { |
| 321 selectedRow = translateInfoBarDelegate_->target_language_index(); |
| 322 disabledRow = translateInfoBarDelegate_->original_language_index(); |
| 323 } |
| 324 languagePickerController_.reset([[LanguagePickerController alloc] |
| 325 initWithDelegate:translateInfoBarDelegate_ |
| 326 initialRow:selectedRow |
| 327 disabledRow:disabledRow]); |
| 328 languagePicker_.reset( |
| 329 [[UIPickerView alloc] initWithFrame:initialPickerFrame]); |
| 330 [languagePicker_ setAutoresizingMask:resizingMask]; |
| 331 [languagePicker_ setShowsSelectionIndicator:YES]; |
| 332 [languagePicker_ setDataSource:languagePickerController_]; |
| 333 [languagePicker_ setDelegate:languagePickerController_]; |
| 334 [languagePicker_ setShowsSelectionIndicator:YES]; |
| 335 [languagePicker_ setBackgroundColor:[infoBarView_ backgroundColor]]; |
| 336 [languagePicker_ selectRow:selectedRow inComponent:0 animated:NO]; |
| 337 |
| 338 [UIView animateWithDuration:kPickerAnimationDurationInSeconds |
| 339 animations:^{ |
| 340 languagePicker_.get().frame = finalPickerFrame; |
| 341 navigationBar_.get().frame = finalNavigationBarFrame; |
| 342 }]; |
| 343 |
| 344 // Add the subviews. |
| 345 [languageSelectionView_ addSubview:languagePicker_]; |
| 346 [languageSelectionView_ addSubview:navigationBar_]; |
| 347 } |
| 348 |
| 349 - (void)removeView { |
| 350 [super removeView]; |
| 351 [self dismissLanguageSelectionView]; |
| 352 } |
| 353 |
| 354 - (void)detachView { |
| 355 [super detachView]; |
| 356 [self dismissLanguageSelectionView]; |
| 357 } |
| 358 |
| 359 @end |
OLD | NEW |