Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: ios/chrome/browser/ui/settings/password_details_collection_view_controller.mm

Issue 2719023005: Provide Copy button for username in password settings (Closed)
Patch Set: Fix format string Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "ios/chrome/browser/ui/settings/password_details_collection_view_control ler.h" 5 #import "ios/chrome/browser/ui/settings/password_details_collection_view_control ler.h"
6 6
7 #include "base/mac/foundation_util.h" 7 #include "base/mac/foundation_util.h"
8 #include "base/strings/sys_string_conversions.h" 8 #include "base/strings/sys_string_conversions.h"
9 #include "components/autofill/core/common/password_form.h" 9 #include "components/autofill/core/common/password_form.h"
10 #include "components/password_manager/core/browser/affiliation_utils.h" 10 #include "components/password_manager/core/browser/affiliation_utils.h"
(...skipping 21 matching lines...) Expand all
32 namespace { 32 namespace {
33 33
34 typedef NS_ENUM(NSInteger, SectionIdentifier) { 34 typedef NS_ENUM(NSInteger, SectionIdentifier) {
35 SectionIdentifierUsername = kSectionIdentifierEnumZero, 35 SectionIdentifierUsername = kSectionIdentifierEnumZero,
36 SectionIdentifierPassword, 36 SectionIdentifierPassword,
37 }; 37 };
38 38
39 typedef NS_ENUM(NSInteger, ItemType) { 39 typedef NS_ENUM(NSInteger, ItemType) {
40 ItemTypeHeader = kItemTypeEnumZero, 40 ItemTypeHeader = kItemTypeEnumZero,
41 ItemTypeUsername, 41 ItemTypeUsername,
42 ItemTypeCopyUsername,
42 ItemTypePassword, 43 ItemTypePassword,
43 ItemTypeShowHide, 44 ItemTypeShowHide,
44 ItemTypeCopy, 45 ItemTypeCopyPassword,
45 ItemTypeDelete, 46 ItemTypeDelete,
46 }; 47 };
47 48
48 } // namespace 49 } // namespace
49 50
50 @interface PasswordDetailsCollectionViewController () { 51 @interface PasswordDetailsCollectionViewController () {
51 // The username to which the saved password belongs. 52 // The username to which the saved password belongs.
52 NSString* _username; 53 NSString* _username;
53 // The saved password. 54 // The saved password.
54 NSString* _password; 55 NSString* _password;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME); 126 l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME);
126 usernameHeader.textColor = [[MDCPalette greyPalette] tint500]; 127 usernameHeader.textColor = [[MDCPalette greyPalette] tint500];
127 [model setHeader:usernameHeader 128 [model setHeader:usernameHeader
128 forSectionWithIdentifier:SectionIdentifierUsername]; 129 forSectionWithIdentifier:SectionIdentifierUsername];
129 PasswordDetailsItem* usernameItem = 130 PasswordDetailsItem* usernameItem =
130 [[PasswordDetailsItem alloc] initWithType:ItemTypeUsername]; 131 [[PasswordDetailsItem alloc] initWithType:ItemTypeUsername];
131 usernameItem.text = _username; 132 usernameItem.text = _username;
132 usernameItem.showingText = YES; 133 usernameItem.showingText = YES;
133 [model addItem:usernameItem 134 [model addItem:usernameItem
134 toSectionWithIdentifier:SectionIdentifierUsername]; 135 toSectionWithIdentifier:SectionIdentifierUsername];
136 [model addItem:[self usernameCopyButtonItem]
137 toSectionWithIdentifier:SectionIdentifierUsername];
135 138
136 [model addSectionWithIdentifier:SectionIdentifierPassword]; 139 [model addSectionWithIdentifier:SectionIdentifierPassword];
137 CollectionViewTextItem* passwordHeader = 140 CollectionViewTextItem* passwordHeader =
138 [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader]; 141 [[CollectionViewTextItem alloc] initWithType:ItemTypeHeader];
139 passwordHeader.text = 142 passwordHeader.text =
140 l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD); 143 l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD);
141 passwordHeader.textColor = [[MDCPalette greyPalette] tint500]; 144 passwordHeader.textColor = [[MDCPalette greyPalette] tint500];
142 [model setHeader:passwordHeader 145 [model setHeader:passwordHeader
143 forSectionWithIdentifier:SectionIdentifierPassword]; 146 forSectionWithIdentifier:SectionIdentifierPassword];
144 _passwordItem = [[PasswordDetailsItem alloc] initWithType:ItemTypePassword]; 147 _passwordItem = [[PasswordDetailsItem alloc] initWithType:ItemTypePassword];
(...skipping 11 matching lines...) Expand all
156 [model addItem:[self deletePasswordButtonItem] 159 [model addItem:[self deletePasswordButtonItem]
157 toSectionWithIdentifier:SectionIdentifierPassword]; 160 toSectionWithIdentifier:SectionIdentifierPassword];
158 } 161 }
159 162
160 - (void)dealloc { 163 - (void)dealloc {
161 [[NSNotificationCenter defaultCenter] removeObserver:self]; 164 [[NSNotificationCenter defaultCenter] removeObserver:self];
162 } 165 }
163 166
164 #pragma mark - Items 167 #pragma mark - Items
165 168
166 - (CollectionViewItem*)passwordCopyButtonItem { 169 - (CollectionViewItem*)usernameCopyButtonItem {
167 CollectionViewTextItem* item = 170 CollectionViewTextItem* item =
168 [[CollectionViewTextItem alloc] initWithType:ItemTypeCopy]; 171 [[CollectionViewTextItem alloc] initWithType:ItemTypeCopyUsername];
169 item.text = l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_COPY_BUTTON); 172 item.text = l10n_util::GetNSString(IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON);
170 item.textColor = [[MDCPalette cr_bluePalette] tint500]; 173 item.textColor = [[MDCPalette cr_bluePalette] tint500];
174 // Accessibility label adds the header to the text, so that accessibility
175 // users do not have to rely on the visual grouping to understand which part
176 // of the credential is being copied.
177 item.accessibilityLabel =
178 [NSString stringWithFormat:@"%@: %@",
179 l10n_util::GetNSString(
180 IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME),
181 l10n_util::GetNSString(
182 IDS_IOS_SETTINGS_USERNAME_COPY_BUTTON)];
171 item.accessibilityTraits |= UIAccessibilityTraitButton; 183 item.accessibilityTraits |= UIAccessibilityTraitButton;
172 return item; 184 return item;
173 } 185 }
186
187 - (CollectionViewItem*)passwordCopyButtonItem {
188 CollectionViewTextItem* item =
189 [[CollectionViewTextItem alloc] initWithType:ItemTypeCopyPassword];
190 item.text = l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_COPY_BUTTON);
191 item.textColor = [[MDCPalette cr_bluePalette] tint500];
192 // Accessibility label adds the header to the text, so that accessibility
193 // users do not have to rely on the visual grouping to understand which part
194 // of the credential is being copied.
195 item.accessibilityLabel =
196 [NSString stringWithFormat:@"%@: %@",
197 l10n_util::GetNSString(
198 IDS_IOS_SHOW_PASSWORD_VIEW_PASSWORD),
199 l10n_util::GetNSString(
200 IDS_IOS_SETTINGS_PASSWORD_COPY_BUTTON)];
201 item.accessibilityTraits |= UIAccessibilityTraitButton;
202 return item;
203 }
174 204
175 - (CollectionViewItem*)showHidePasswordButtonItem { 205 - (CollectionViewItem*)showHidePasswordButtonItem {
176 CollectionViewTextItem* item = 206 CollectionViewTextItem* item =
177 [[CollectionViewTextItem alloc] initWithType:ItemTypeShowHide]; 207 [[CollectionViewTextItem alloc] initWithType:ItemTypeShowHide];
178 item.text = [self showHideButtonText]; 208 item.text = [self showHideButtonText];
179 item.textColor = [[MDCPalette cr_bluePalette] tint500]; 209 item.textColor = [[MDCPalette cr_bluePalette] tint500];
180 item.accessibilityTraits |= UIAccessibilityTraitButton; 210 item.accessibilityTraits |= UIAccessibilityTraitButton;
181 return item; 211 return item;
182 } 212 }
183 213
184 - (CollectionViewItem*)deletePasswordButtonItem { 214 - (CollectionViewItem*)deletePasswordButtonItem {
185 CollectionViewTextItem* item = 215 CollectionViewTextItem* item =
186 [[CollectionViewTextItem alloc] initWithType:ItemTypeDelete]; 216 [[CollectionViewTextItem alloc] initWithType:ItemTypeDelete];
187 item.text = l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON); 217 item.text = l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_DELETE_BUTTON);
188 item.textColor = [[MDCPalette cr_redPalette] tint500]; 218 item.textColor = [[MDCPalette cr_redPalette] tint500];
189 item.accessibilityTraits |= UIAccessibilityTraitButton; 219 item.accessibilityTraits |= UIAccessibilityTraitButton;
190 return item; 220 return item;
191 } 221 }
192 222
193 #pragma mark - Actions 223 #pragma mark - Actions
194 224
225 - (void)copyUsername {
226 UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
227 generalPasteboard.string = _username;
228 [self showCopyResultToast:l10n_util::GetNSString(
229 IDS_IOS_SETTINGS_USERNAME_WAS_COPIED_MESSAGE)];
230 }
231
195 - (NSString*)showHideButtonText { 232 - (NSString*)showHideButtonText {
196 if (_plainTextPasswordShown) { 233 if (_plainTextPasswordShown) {
197 return l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_HIDE_BUTTON); 234 return l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_HIDE_BUTTON);
198 } 235 }
199 return l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_SHOW_BUTTON); 236 return l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_SHOW_BUTTON);
200 } 237 }
201 238
202 // Changes the text on the Show/Hide button appropriately according to 239 // Changes the text on the Show/Hide button appropriately according to
203 // |_plainTextPasswordShown|. 240 // |_plainTextPasswordShown|.
204 - (void)toggleShowHideButton { 241 - (void)toggleShowHideButton {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 } 292 }
256 293
257 - (void)copyPassword { 294 - (void)copyPassword {
258 // If the password is displayed in plain text, there is no need to 295 // If the password is displayed in plain text, there is no need to
259 // re-authenticate the user when copying the password because they are already 296 // re-authenticate the user when copying the password because they are already
260 // granted access to it. 297 // granted access to it.
261 if (_plainTextPasswordShown) { 298 if (_plainTextPasswordShown) {
262 UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard]; 299 UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
263 generalPasteboard.string = _password; 300 generalPasteboard.string = _password;
264 TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess); 301 TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess);
265 [self showCopyPasswordResultToast: 302 [self
266 l10n_util::GetNSString( 303 showCopyResultToast:l10n_util::GetNSString(
267 IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE)]; 304 IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE)];
268 } else if ([_weakReauthenticationModule canAttemptReauth]) { 305 } else if ([_weakReauthenticationModule canAttemptReauth]) {
269 __weak PasswordDetailsCollectionViewController* weakSelf = self; 306 __weak PasswordDetailsCollectionViewController* weakSelf = self;
270 void (^copyPasswordHandler)(BOOL) = ^(BOOL success) { 307 void (^copyPasswordHandler)(BOOL) = ^(BOOL success) {
271 PasswordDetailsCollectionViewController* strongSelf = weakSelf; 308 PasswordDetailsCollectionViewController* strongSelf = weakSelf;
272 if (!strongSelf) 309 if (!strongSelf)
273 return; 310 return;
274 if (success) { 311 if (success) {
275 UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard]; 312 UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
276 generalPasteboard.string = strongSelf->_password; 313 generalPasteboard.string = strongSelf->_password;
277 TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess); 314 TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeSuccess);
278 [strongSelf showCopyPasswordResultToast: 315 [strongSelf showCopyResultToast:
279 l10n_util::GetNSString( 316 l10n_util::GetNSString(
280 IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE)]; 317 IDS_IOS_SETTINGS_PASSWORD_WAS_COPIED_MESSAGE)];
281 } else { 318 } else {
282 TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeError); 319 TriggerHapticFeedbackForNotification(UINotificationFeedbackTypeError);
283 [strongSelf showCopyPasswordResultToast: 320 [strongSelf showCopyResultToast:
284 l10n_util::GetNSString( 321 l10n_util::GetNSString(
285 IDS_IOS_SETTINGS_PASSWORD_WAS_NOT_COPIED_MESSAGE)]; 322 IDS_IOS_SETTINGS_PASSWORD_WAS_NOT_COPIED_MESSAGE)];
286 } 323 }
287 }; 324 };
288 [_weakReauthenticationModule 325 [_weakReauthenticationModule
289 attemptReauthWithLocalizedReason: 326 attemptReauthWithLocalizedReason:
290 l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_COPY) 327 l10n_util::GetNSString(IDS_IOS_SETTINGS_PASSWORD_REAUTH_REASON_COPY)
291 handler:copyPasswordHandler]; 328 handler:copyPasswordHandler];
292 } 329 }
293 } 330 }
294 331
295 - (void)showCopyPasswordResultToast:(NSString*)message { 332 - (void)showCopyResultToast:(NSString*)message {
296 // TODO(crbug.com/159166): Route this through some delegate API to be able 333 // TODO(crbug.com/159166): Route this through some delegate API to be able
297 // to mock it in the unittest, and avoid having an EGTest just for that? 334 // to mock it in the unittest, and avoid having an EGTest just for that?
298 MDCSnackbarMessage* copyPasswordResultMessage = 335 MDCSnackbarMessage* copyPasswordResultMessage =
299 [MDCSnackbarMessage messageWithText:message]; 336 [MDCSnackbarMessage messageWithText:message];
300 [MDCSnackbarManager showMessage:copyPasswordResultMessage]; 337 [MDCSnackbarManager showMessage:copyPasswordResultMessage];
301 } 338 }
302 339
303 - (void)deletePassword { 340 - (void)deletePassword {
304 [_weakDelegate deletePassword:_passwordForm]; 341 [_weakDelegate deletePassword:_passwordForm];
305 } 342 }
306 343
307 #pragma mark - UICollectionViewDelegate 344 #pragma mark - UICollectionViewDelegate
308 345
309 - (void)collectionView:(UICollectionView*)collectionView 346 - (void)collectionView:(UICollectionView*)collectionView
310 didSelectItemAtIndexPath:(NSIndexPath*)indexPath { 347 didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
311 [super collectionView:collectionView didSelectItemAtIndexPath:indexPath]; 348 [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
312 NSInteger itemType = 349 NSInteger itemType =
313 [self.collectionViewModel itemTypeForIndexPath:indexPath]; 350 [self.collectionViewModel itemTypeForIndexPath:indexPath];
314 switch (itemType) { 351 switch (itemType) {
352 case ItemTypeCopyUsername:
353 [self copyUsername];
354 break;
315 case ItemTypeShowHide: 355 case ItemTypeShowHide:
316 if (_plainTextPasswordShown) { 356 if (_plainTextPasswordShown) {
317 [self hidePassword]; 357 [self hidePassword];
318 } else { 358 } else {
319 [self showPassword]; 359 [self showPassword];
320 } 360 }
321 break; 361 break;
322 case ItemTypeCopy: 362 case ItemTypeCopyPassword:
323 [self copyPassword]; 363 [self copyPassword];
324 break; 364 break;
325 case ItemTypeDelete: 365 case ItemTypeDelete:
326 [self deletePassword]; 366 [self deletePassword];
327 break; 367 break;
328 default: 368 default:
329 break; 369 break;
330 } 370 }
331 } 371 }
332 372
(...skipping 15 matching lines...) Expand all
348 } 388 }
349 389
350 #pragma mark - ForTesting 390 #pragma mark - ForTesting
351 391
352 - (void)setReauthenticationModule: 392 - (void)setReauthenticationModule:
353 (id<ReauthenticationProtocol>)reauthenticationModule { 393 (id<ReauthenticationProtocol>)reauthenticationModule {
354 _weakReauthenticationModule = reauthenticationModule; 394 _weakReauthenticationModule = reauthenticationModule;
355 } 395 }
356 396
357 @end 397 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698