Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #import "chrome/browser/ui/cocoa/passwords/credential_item_view.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/i18n/rtl.h" | |
| 10 #include "base/mac/foundation_util.h" | |
| 11 #include "base/strings/sys_string_conversions.h" | |
| 12 #include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h" | |
| 13 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h" | |
| 14 #include "grit/theme_resources.h" | |
| 15 #include "ui/base/resource/resource_bundle.h" | |
| 16 #include "ui/gfx/image/image_skia.h" | |
| 17 #include "ui/gfx/image/image_skia_util_mac.h" | |
| 18 | |
| 19 namespace { | |
| 20 const CGFloat kVerticalPaddingBetweenCredentials = 10.0f; | |
| 21 const CGFloat kHorizontalPaddingBetweenAvatarAndLabels = 10.0f; | |
| 22 const CGFloat kVerticalPaddingBetweenLabels = 2.0f; | |
| 23 } // namespace | |
| 24 | |
| 25 // Custom button cell that draws nothing. | |
| 26 @interface CredentialItemViewCell : NSButtonCell | |
|
groby-ooo-7-16
2015/02/19 17:01:33
Are you sure you need an NSButton at all? :)
dconnelly
2015/02/20 15:36:06
Replaced all this handling and ListView stuff with
| |
| 27 @end | |
| 28 | |
| 29 @implementation CredentialItemViewCell | |
| 30 - (void)drawWithFrame:(CGRect)frame inView:(NSView*)view { | |
| 31 // Do nothing. | |
| 32 } | |
| 33 @end | |
| 34 | |
| 35 @interface CredentialItemView() | |
| 36 - (void)click:(id)sender; | |
| 37 @end | |
| 38 | |
| 39 @implementation CredentialItemView | |
| 40 | |
| 41 - (id)initWithPasswordForm:(const autofill::PasswordForm&)passwordForm | |
| 42 credentialType:(password_manager::CredentialType)credentialType | |
| 43 delegate:(id<CredentialItemDelegate>)delegate { | |
| 44 if ((self = [super init])) { | |
| 45 passwordForm_ = passwordForm; | |
| 46 credentialType_ = credentialType; | |
| 47 delegate_ = delegate; | |
| 48 | |
| 49 // Forward clicks to the delegate. | |
| 50 [self setTarget:self]; | |
| 51 [self setAction:@selector(click:)]; | |
| 52 | |
| 53 // ----------------------------------------------- | |
| 54 // | | John Q. Facebooker | | |
| 55 // | icon | john@somewhere.com | | |
| 56 // ----------------------------------------------- | |
| 57 | |
| 58 // Create the views. | |
| 59 | |
| 60 avatarView_.reset([[NSImageView alloc] initWithFrame:CGRectZero]); | |
|
groby-ooo-7-16
2015/02/19 17:01:33
I vaguely recall the profile switcher does similar
dconnelly
2015/02/20 15:36:06
The profile switchers I see on trunk Chromium and
| |
| 61 [avatarView_ setWantsLayer:YES]; | |
| 62 [[avatarView_ layer] setCornerRadius:kAvatarImageSize / 2.0f]; | |
| 63 [[avatarView_ layer] setMasksToBounds:YES]; | |
| 64 [self addSubview:avatarView_]; | |
| 65 | |
| 66 if (!passwordForm_.display_name.empty()) { | |
| 67 nameLabel_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]); | |
| 68 [self addSubview:nameLabel_]; | |
| 69 [nameLabel_ setBezeled:NO]; | |
| 70 [nameLabel_ setDrawsBackground:NO]; | |
| 71 [nameLabel_ setEditable:NO]; | |
| 72 [nameLabel_ setSelectable:NO]; | |
| 73 [nameLabel_ | |
| 74 setStringValue:base::SysUTF16ToNSString(passwordForm_.display_name)]; | |
| 75 [nameLabel_ setAlignment:base::i18n::IsRTL() ? NSRightTextAlignment | |
| 76 : NSLeftTextAlignment]; | |
| 77 [nameLabel_ sizeToFit]; | |
| 78 } | |
| 79 | |
| 80 usernameLabel_.reset([[NSTextField alloc] initWithFrame:NSZeroRect]); | |
| 81 [self addSubview:usernameLabel_]; | |
| 82 [usernameLabel_ setBezeled:NO]; | |
| 83 [usernameLabel_ setDrawsBackground:NO]; | |
| 84 [usernameLabel_ setEditable:NO]; | |
| 85 [usernameLabel_ setSelectable:NO]; | |
| 86 [usernameLabel_ | |
| 87 setStringValue:base::SysUTF16ToNSString(passwordForm_.username_value)]; | |
| 88 [usernameLabel_ setAlignment:base::i18n::IsRTL() ? NSRightTextAlignment | |
| 89 : NSLeftTextAlignment]; | |
| 90 [usernameLabel_ sizeToFit]; | |
| 91 | |
| 92 // Compute the heights and widths of everything, as the layout depends on | |
| 93 // these measurements. | |
| 94 const CGFloat labelsHeight = CGRectGetHeight([nameLabel_ frame]) + | |
| 95 CGRectGetHeight([usernameLabel_ frame]) + | |
| 96 kVerticalPaddingBetweenLabels; | |
| 97 const CGFloat height = std::max(labelsHeight, CGFloat(kAvatarImageSize)); | |
| 98 const CGFloat width = kAvatarImageSize + | |
| 99 kHorizontalPaddingBetweenAvatarAndLabels + | |
| 100 std::max(CGRectGetWidth([nameLabel_ frame]), | |
| 101 CGRectGetWidth([usernameLabel_ frame])); | |
| 102 self.frame = CGRectMake(0, 0, width, height); | |
| 103 | |
| 104 // Lay out the views (RTL reverses the order horizontally). | |
| 105 | |
| 106 const CGFloat avatarX = base::i18n::IsRTL() ? width - kAvatarImageSize : 0; | |
| 107 const CGFloat avatarY = | |
| 108 (kAvatarImageSize > height) ? 0 : (height - kAvatarImageSize) / 2.0f; | |
| 109 [avatarView_ setFrame:CGRectMake(avatarX, avatarY, kAvatarImageSize, | |
| 110 kAvatarImageSize)]; | |
| 111 | |
| 112 const CGFloat nameX = base::i18n::IsRTL() | |
| 113 ? NSMinX([avatarView_ frame]) - | |
| 114 kHorizontalPaddingBetweenAvatarAndLabels - | |
| 115 CGRectGetWidth([nameLabel_ frame]) | |
| 116 : NSMaxX([avatarView_ frame]) + | |
| 117 kHorizontalPaddingBetweenAvatarAndLabels; | |
| 118 const CGFloat nameLabelY = | |
| 119 (labelsHeight > height) ? 0 : (height - labelsHeight) / 2.0f; | |
| 120 CGRect nameFrame = [nameLabel_ frame]; | |
| 121 nameFrame.origin = CGPointMake(nameX, nameLabelY); | |
|
groby-ooo-7-16
2015/02/19 17:01:33
NSMakePoint
dconnelly
2015/02/20 15:36:06
Done.
| |
| 122 [nameLabel_ setFrame:nameFrame]; | |
| 123 | |
| 124 const CGFloat usernameX = | |
| 125 base::i18n::IsRTL() | |
| 126 ? NSMinX([avatarView_ frame]) - | |
| 127 kHorizontalPaddingBetweenAvatarAndLabels - | |
| 128 CGRectGetWidth([usernameLabel_ frame]) | |
|
groby-ooo-7-16
2015/02/19 17:01:33
NSWidth - you *do* love CG functions, don't you? ;
dconnelly
2015/02/20 15:36:06
Sorry, yeah, the iOS idioms are just stickier in m
| |
| 129 : NSMaxX([avatarView_ frame]) + | |
| 130 kHorizontalPaddingBetweenAvatarAndLabels; | |
| 131 const CGFloat usernameLabelY = | |
| 132 NSMaxY(nameFrame) + kVerticalPaddingBetweenLabels; | |
| 133 CGRect usernameFrame = [usernameLabel_ frame]; | |
| 134 usernameFrame.origin = CGPointMake(usernameX, usernameLabelY); | |
| 135 [usernameLabel_ setFrame:usernameFrame]; | |
| 136 | |
| 137 // Use a default avatar and fetch the custom one, if it exists. | |
| 138 [self updateAvatar:[[self class] defaultAvatar]]; | |
| 139 if (passwordForm_.avatar_url.is_valid()) | |
| 140 [delegate_ fetchAvatar:passwordForm_.avatar_url forView:self]; | |
| 141 | |
| 142 // When resizing, stick to the left (resp. right for RTL) edge. | |
| 143 const NSUInteger autoresizingMask = | |
| 144 (base::i18n::IsRTL() ? NSViewMinXMargin : NSViewMaxXMargin); | |
| 145 [avatarView_ setAutoresizingMask:autoresizingMask]; | |
| 146 [usernameLabel_ setAutoresizingMask:autoresizingMask]; | |
| 147 [nameLabel_ setAutoresizingMask:autoresizingMask]; | |
| 148 [self setAutoresizingMask:NSViewWidthSizable]; | |
| 149 } | |
| 150 | |
| 151 return self; | |
| 152 } | |
| 153 | |
| 154 - (void)updateAvatar:(NSImage*)avatar { | |
| 155 [avatarView_ setImage:avatar]; | |
| 156 } | |
| 157 | |
| 158 + (NSImage*)defaultAvatar { | |
| 159 return gfx::NSImageFromImageSkia(ScaleImageForAccountAvatar( | |
| 160 *ResourceBundle::GetSharedInstance() | |
| 161 .GetImageNamed(IDR_PROFILE_AVATAR_PLACEHOLDER_LARGE) | |
| 162 .ToImageSkia())); | |
| 163 } | |
| 164 | |
| 165 + (Class)cellClass { | |
| 166 return [CredentialItemViewCell class]; | |
| 167 } | |
| 168 | |
| 169 - (void)click:(id)sender { | |
| 170 DCHECK_EQ(sender, self); | |
| 171 [delegate_ selectPasswordForm:passwordForm_ credentialType:credentialType_]; | |
| 172 } | |
| 173 | |
| 174 - (NSTextField*)nameLabel { | |
| 175 return nameLabel_.get(); | |
| 176 } | |
| 177 | |
| 178 - (NSTextField*)usernameLabel { | |
| 179 return usernameLabel_.get(); | |
| 180 } | |
| 181 | |
| 182 - (NSImageView*)avatarView { | |
| 183 return avatarView_.get(); | |
| 184 } | |
| 185 | |
| 186 @end | |
| 187 | |
| 188 @interface CredentialItemListView() | |
| 189 - (void)addCredentialItem:(CredentialItemView*)item; | |
| 190 @end | |
| 191 | |
| 192 @implementation CredentialItemListView | |
|
groby-ooo-7-16
2015/02/19 17:01:33
Question: Would this be better off as an NSTableVi
dconnelly
2015/02/20 15:36:06
You know, I've never written an NSTableView before
| |
| 193 | |
| 194 - (id)initWithItems:(NSArray*)items { | |
| 195 if ((self = [super initWithFrame:NSZeroRect])) { | |
| 196 for (CredentialItemView* item in items) | |
| 197 [self addCredentialItem:item]; | |
| 198 } | |
| 199 return self; | |
| 200 } | |
| 201 | |
| 202 - (void)addCredentialItem:(CredentialItemView*)item { | |
| 203 [self addSubview:item]; | |
| 204 | |
| 205 // Stack the credentials on top of each other. | |
|
groby-ooo-7-16
2015/02/19 17:01:33
Shorter (and hopefully clearer) version:
NSRect v
dconnelly
2015/02/20 15:36:06
TableView - removed all this
| |
| 206 const CGFloat y = | |
| 207 CGRectGetHeight([self frame]) + | |
| 208 ([[self subviews] count] > 1 ? kVerticalPaddingBetweenCredentials : 0.0f); | |
| 209 | |
| 210 // Update the size of the list view to accomodate the new item. | |
| 211 const CGFloat width = | |
| 212 std::max(CGRectGetWidth([self frame]), CGRectGetWidth([item frame])); | |
| 213 const CGFloat height = y + CGRectGetHeight([item frame]); | |
| 214 [self setFrameSize:CGSizeMake(width, height)]; | |
| 215 | |
| 216 const CGFloat x = 0; | |
|
groby-ooo-7-16
2015/02/19 17:01:33
You could replace the entire code block with
[item
dconnelly
2015/02/20 15:36:06
TableView - removed all this
| |
| 217 NSRect itemFrame = [item frame]; | |
| 218 itemFrame.size.width = width; | |
| 219 itemFrame.origin = CGPointMake(x, y); | |
| 220 [item setFrame:itemFrame]; | |
| 221 } | |
| 222 | |
| 223 - (NSArray*)items { | |
| 224 return [self subviews]; | |
| 225 } | |
| 226 | |
| 227 @end | |
| OLD | NEW |