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:TranslateInfoBarIos::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:TranslateInfoBarIos::BEFORE_ACCEPT | |
155 button2:buttonDeny | |
156 tag2:TranslateInfoBarIos::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:TranslateInfoBarIos::BEFORE_SOURCE_LANGUAGE]); | |
172 base::string16 targetLanguageWithLink = | |
173 base::SysNSStringToUTF16([[infoBarView_ class] | |
174 stringAsLink:targetLanguage | |
175 tag:TranslateInfoBarIos::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_ == TranslateInfoBarIos::BEFORE_SOURCE_LANGUAGE && | |
187 selectedRow != translateInfoBarDelegate_->target_language_index()) { | |
188 translateInfoBarDelegate_->UpdateOriginalLanguageIndex(selectedRow); | |
189 } | |
190 if (languageSelectionType_ == TranslateInfoBarIos::BEFORE_TARGET_LANGUAGE && | |
191 selectedRow != translateInfoBarDelegate_->original_language_index()) { | |
192 translateInfoBarDelegate_->UpdateTargetLanguageIndex(selectedRow); | |
193 } | |
194 // TODO(translate): Update the position of the infobar. | |
sdefresne
2015/01/08 09:22:33
nit: is this still relevant? is there a tracking b
| |
195 [self updateInfobarLabel]; | |
196 [self dismissLanguageSelectionView]; | |
197 } | |
198 | |
199 - (void)dismissLanguageSelectionView { | |
200 DCHECK_EQ(languagePicker_ == nil, navigationBar_ == nil); | |
201 if (languagePicker_ == nil) | |
202 return; | |
203 // Sets the picker's delegate and data source to nil, because the | |
204 // |languagePickerController_| may be destroyed before the picker is hidden, | |
205 // and even though the interactions with the picker are disabled, it might | |
206 // still be turning and requesting data from the data source or calling the | |
207 // delegate. | |
208 [languagePicker_ setDataSource:nil]; | |
209 [languagePicker_ setDelegate:nil]; | |
210 languagePickerController_.reset(); | |
211 // Animate the picker away. | |
212 CGRect languagePickerFrame = [languagePicker_ frame]; | |
213 CGRect navigationBarFrame = [navigationBar_ frame]; | |
214 const CGFloat animationHeight = | |
215 languagePickerFrame.size.height + navigationBarFrame.size.height; | |
216 languagePickerFrame.origin.y += animationHeight; | |
217 navigationBarFrame.origin.y += animationHeight; | |
218 UIView* blockLanguagePicker = languagePicker_.get(); | |
219 UIView* blockNavigationBar = navigationBar_.get(); | |
220 languagePicker_.reset(); | |
sdefresne
2015/01/08 09:22:33
I'm afraid that this may lead to blockLanguagePick
droger
2015/01/08 11:57:33
Right.
I think it's not a problem in practice beca
| |
221 navigationBar_.reset(); | |
222 void (^animations)(void) = ^{ | |
223 blockLanguagePicker.frame = languagePickerFrame; | |
224 blockNavigationBar.frame = navigationBarFrame; | |
225 }; | |
226 void (^completion)(BOOL finished) = ^(BOOL finished) { | |
227 [languageSelectionView_ removeFromSuperview]; | |
sdefresne
2015/01/08 09:22:33
animations block goes to great length to avoid kee
droger
2015/01/08 11:57:33
I would rather not change this one as part of upst
| |
228 languageSelectionView_.reset(); | |
229 }; | |
230 [UIView animateWithDuration:kPickerAnimationDurationInSeconds | |
231 animations:animations | |
232 completion:completion]; | |
233 } | |
234 | |
235 #pragma mark - Handling of User Events | |
236 | |
237 - (void)infoBarButtonDidPress:(id)sender { | |
238 // This press might have occurred after the user has already pressed a button, | |
239 // in which case the view has been detached from the delegate and this press | |
240 // should be ignored. | |
241 if (!delegate_) { | |
242 return; | |
243 } | |
244 if ([sender isKindOfClass:[UIButton class]]) { | |
245 NSUInteger buttonId = static_cast<UIButton*>(sender).tag; | |
246 DCHECK(buttonId == TranslateInfoBarIos::BEFORE_ACCEPT || | |
247 buttonId == TranslateInfoBarIos::BEFORE_DENY); | |
248 delegate_->InfoBarButtonDidPress(buttonId); | |
249 } | |
250 } | |
251 | |
252 - (void)infobarLinkDidPress:(NSNumber*)tag { | |
253 DCHECK([tag isKindOfClass:[NSNumber class]]); | |
254 languageSelectionType_ = [tag unsignedIntegerValue]; | |
255 DCHECK(languageSelectionType_ == | |
256 TranslateInfoBarIos::BEFORE_SOURCE_LANGUAGE || | |
257 languageSelectionType_ == TranslateInfoBarIos::BEFORE_TARGET_LANGUAGE); | |
258 if (languagePicker_ != nil) | |
259 return; // The UIPickerView is already up. | |
260 | |
261 // Creates and adds the view containing the UIPickerView and the | |
262 // UINavigationBar. | |
263 UIView* parentView = | |
264 [[UIApplication sharedApplication] keyWindow].rootViewController.view; | |
265 // Convert the parent frame to handle device rotation. | |
266 CGRect parentFrame = | |
267 CGRectApplyAffineTransform([parentView frame], [parentView transform]); | |
268 const CGFloat totalPickerHeight = kUIPickerHeight + kNavigationBarHeight; | |
269 CGRect languageSelectionViewFrame = | |
270 CGRectMake(0, parentFrame.size.height - totalPickerHeight, | |
271 parentFrame.size.width, totalPickerHeight); | |
272 languageSelectionView_.reset( | |
273 [[UIView alloc] initWithFrame:languageSelectionViewFrame]); | |
274 [languageSelectionView_ | |
275 setAutoresizingMask:UIViewAutoresizingFlexibleWidth | | |
276 UIViewAutoresizingFlexibleTopMargin]; | |
277 [parentView addSubview:languageSelectionView_]; | |
278 | |
279 // Creates the navigation bar and its buttons. | |
280 CGRect finalPickerFrame = CGRectMake( | |
281 0, [languageSelectionView_ frame].size.height - kUIPickerHeight, | |
282 [languageSelectionView_ frame].size.width, kUIPickerHeight); | |
283 CGRect finalNavigationBarFrame = CGRectMake( | |
284 0, 0, [languageSelectionView_ frame].size.width, kNavigationBarHeight); | |
285 // The language picker animates from the bottom of the screen. | |
286 CGRect initialPickerFrame = finalPickerFrame; | |
287 initialPickerFrame.origin.y += totalPickerHeight; | |
288 CGRect initialNavigationBarFrame = finalNavigationBarFrame; | |
289 initialNavigationBarFrame.origin.y += totalPickerHeight; | |
290 | |
291 navigationBar_.reset( | |
292 [[UINavigationBar alloc] initWithFrame:initialNavigationBarFrame]); | |
293 const UIViewAutoresizing resizingMask = | |
294 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; | |
295 [navigationBar_ setAutoresizingMask:resizingMask]; | |
296 base::scoped_nsobject<UIBarButtonItem> doneButton([[UIBarButtonItem alloc] | |
297 initWithBarButtonSystemItem:UIBarButtonSystemItemDone | |
298 target:self | |
299 action:@selector(languageSelectionDone)]); | |
300 base::scoped_nsobject<UIBarButtonItem> cancelButton([[UIBarButtonItem alloc] | |
301 initWithBarButtonSystemItem:UIBarButtonSystemItemCancel | |
302 target:self | |
303 action:@selector(dismissLanguageSelectionView)]); | |
304 base::scoped_nsobject<UINavigationItem> item( | |
305 [[UINavigationItem alloc] initWithTitle:nil]); | |
306 [item setRightBarButtonItem:doneButton]; | |
307 [item setLeftBarButtonItem:cancelButton]; | |
308 [item setHidesBackButton:YES]; | |
309 [navigationBar_ pushNavigationItem:item animated:NO]; | |
310 | |
311 // Creates the PickerView and its controller. | |
312 NSInteger selectedRow; | |
313 NSInteger disabledRow; | |
314 if (languageSelectionType_ == TranslateInfoBarIos::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:[infoBarView_ backgroundColor]]; | |
333 [languagePicker_ selectRow:selectedRow inComponent:0 animated:NO]; | |
334 | |
335 [UIView animateWithDuration:kPickerAnimationDurationInSeconds | |
336 animations:^{ | |
337 languagePicker_.get().frame = finalPickerFrame; | |
338 navigationBar_.get().frame = finalNavigationBarFrame; | |
339 }]; | |
340 | |
341 // Add the subviews. | |
342 [languageSelectionView_ addSubview:languagePicker_]; | |
343 [languageSelectionView_ addSubview:navigationBar_]; | |
344 } | |
345 | |
346 - (void)removeView { | |
347 [super removeView]; | |
348 [self dismissLanguageSelectionView]; | |
349 } | |
350 | |
351 - (void)detachView { | |
352 [super detachView]; | |
353 [self dismissLanguageSelectionView]; | |
354 } | |
355 | |
356 @end | |
OLD | NEW |