Skip to content

Commit

Permalink
[M103][ios][ConfirmationAlertViewController] Add option to enclose im…
Browse files Browse the repository at this point in the history
…age in view with shadow and badge

Previous uses of ConfirmationAlertViewController use an image
that already has a shadow baked into the image.

In FirstFollowViewController, we want to be able to set a
favicon image inside a frame view that has a shadow. These
favicons will not already have a shadow. Furthermore, we
want a green checkmark badge on the upper right corner.

New screenshots:
https://screenshot.googleplex.com/3pVdiNyHhwW4tzv.png
https://screenshot.googleplex.com/4QzpmWf3uRfEXZ9.png
https://screenshot.googleplex.com/4hgqHKo4te2UWko.png
https://screenshot.googleplex.com/9w5DkS82yNuWSsW.png
https://screenshot.googleplex.com/tjSscgwCB24NAjh.png
https://screenshot.googleplex.com/BzgXFprpyFpzZGu.png

This CL has not affected existing uses of
ConfirmationAlertViewController.

Existing uses of ConfirmationAlertViewController screenshots:
https://screenshot.googleplex.com/6PU9B6LkgFqKfQh.png
https://screenshot.googleplex.com/3CD9LkaiqY3uC67.png
https://screenshot.googleplex.com/5bj8TwAFVHgyiH8.png
https://screenshot.googleplex.com/3bZg6Lu6gF9QZ9o.png

(cherry picked from commit ba21cfb)

Bug: 1327057
Change-Id: I82dc1556bc49d6fc411109f07ee2b01b32b0545c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3649311
Commit-Queue: edchin <edchin@google.com>
Reviewed-by: Sergio Collazos <sczs@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1005278}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3656109
Cr-Commit-Position: refs/branch-heads/5060@{#144}
Cr-Branched-From: b83393d-refs/heads/main@{#1002911}
  • Loading branch information
edx246 authored and Chromium LUCI CQ committed May 20, 2022
1 parent 7aa3350 commit b39cb46
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ @implementation FirstFollowViewController

- (void)viewDidLoad {
self.imageHasFixedSize = YES;
self.imageEnclosedWithShadowAndBadge = YES;
self.showDismissBarButton = NO;
self.customSpacingBeforeImageIfNoToolbar =
customSpacingBeforeImageIfNoToolbar;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ extern NSString* const kConfirmationAlertSecondaryActionAccessibilityIdentifier;
// view is loaded.
@property(nonatomic) BOOL helpButtonAvailable;

// Set to YES to enclose the image in a frame with a shadow and a corner badge
// with a green checkmark. Must be set before the view is loaded. Default is NO.
@property(nonatomic) BOOL imageEnclosedWithShadowAndBadge;

// When set, this value will be set as the accessibility label for the help
// button.
@property(nonatomic, copy) NSString* helpButtonAccessibilityLabel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,29 @@
constexpr CGFloat kSafeAreaMultiplier = 0.65;
constexpr CGFloat kContentOptimalWidth = 327;

// The size of the symbol image.
constexpr NSInteger kSymbolBadgeImagePointSize = 13;

// The name of the checkmark symbol in filled circle.
NSString* const kCheckmarkSymbol = @"checkmark.circle.fill";

// Properties of the favicon.
constexpr CGFloat kFaviconCornerRadius = 13;
constexpr CGFloat kFaviconShadowOffsetX = 0;
constexpr CGFloat kFaviconShadowOffsetY = 0;
constexpr CGFloat kFaviconShadowRadius = 6;
constexpr CGFloat kFaviconShadowOpacity = 0.1;

// Length of each side of the favicon frame (which contains the favicon and the
// surrounding whitespace).
constexpr CGFloat kFaviconFrameSideLength = 60;

// Length of each side of the favicon.
constexpr CGFloat kFaviconSideLength = 30;

// Length of each side of the favicon badge.
constexpr CGFloat kFaviconBadgeSideLength = 24;

} // namespace

@interface ConfirmationAlertViewController () <UIToolbarDelegate>
Expand All @@ -55,6 +78,7 @@ @interface ConfirmationAlertViewController () <UIToolbarDelegate>
@property(nonatomic, strong) UIButton* tertiaryActionButton;
@property(nonatomic, strong) UIToolbar* topToolbar;
@property(nonatomic, strong) UIImageView* imageView;
@property(nonatomic, strong) UIView* imageContainerView;
@property(nonatomic, strong) NSLayoutConstraint* imageViewAspectRatioConstraint;
@end

Expand Down Expand Up @@ -82,16 +106,25 @@ - (void)viewDidLoad {
[self.view addSubview:self.topToolbar];
}

self.imageView = [self createImageView];
if (self.imageEnclosedWithShadowAndBadge) {
// The image view is set within the helper method.
self.imageContainerView = [self createImageContainerViewWithShadowAndBadge];
} else {
// The image container and the image view are the same.
self.imageView = [self createImageView];
self.imageContainerView = self.imageView;
}

UILabel* title = [self createTitleLabel];
UILabel* subtitle = [self createSubtitleLabel];

NSArray* stackSubviews = nil;
if ([self.secondaryTitleString length] != 0) {
UILabel* secondaryTitle = [self createSecondaryTitleLabel];
stackSubviews = @[ self.imageView, title, secondaryTitle, subtitle ];
stackSubviews =
@[ self.imageContainerView, title, secondaryTitle, subtitle ];
} else {
stackSubviews = @[ self.imageView, title, subtitle ];
stackSubviews = @[ self.imageContainerView, title, subtitle ];
}

DCHECK(stackSubviews);
Expand Down Expand Up @@ -313,6 +346,7 @@ - (void)updateViewConstraints {
// is active, the image's width also goes to 0, which causes the stack view
// width to become 0 too.
[self.imageView setHidden:isVerticalCompact];
[self.imageContainerView setHidden:isVerticalCompact];
self.imageViewAspectRatioConstraint.active = !isVerticalCompact;

// Allow toolbar to update its height based on new layout.
Expand Down Expand Up @@ -432,6 +466,73 @@ - (UIImageView*)createImageView {
return imageView;
}

// Helper to create the image view enclosed in a frame with a shadow and a
// corner badge with a green checkmark. |self.imageView| is set in this method.
- (UIView*)createImageContainerViewWithShadowAndBadge {
UIImageView* faviconBadgeView = [[UIImageView alloc] init];
faviconBadgeView.translatesAutoresizingMaskIntoConstraints = NO;
UIImageSymbolConfiguration* configuration = [UIImageSymbolConfiguration
configurationWithPointSize:kSymbolBadgeImagePointSize
weight:UIImageSymbolWeightMedium
scale:UIImageSymbolScaleMedium];
faviconBadgeView.image = [UIImage systemImageNamed:kCheckmarkSymbol
withConfiguration:configuration];
faviconBadgeView.tintColor = [UIColor colorNamed:kGreenColor];

UIImageView* faviconView = [[UIImageView alloc] initWithImage:self.image];
faviconView.translatesAutoresizingMaskIntoConstraints = NO;
faviconView.contentMode = UIViewContentModeScaleAspectFit;

UIView* frameView = [[UIView alloc] init];
frameView.translatesAutoresizingMaskIntoConstraints = NO;
frameView.backgroundColor = [UIColor colorNamed:kBackgroundColor];
frameView.layer.cornerRadius = kFaviconCornerRadius;
frameView.layer.shadowOffset =
CGSizeMake(kFaviconShadowOffsetX, kFaviconShadowOffsetY);
frameView.layer.shadowRadius = kFaviconShadowRadius;
frameView.layer.shadowOpacity = kFaviconShadowOpacity;
[frameView addSubview:faviconView];

UIView* containerView = [[UIView alloc] init];
[containerView addSubview:frameView];
[containerView addSubview:faviconBadgeView];

[NSLayoutConstraint activateConstraints:@[
// Size constraints.
[frameView.widthAnchor constraintEqualToConstant:kFaviconFrameSideLength],
[frameView.heightAnchor constraintEqualToConstant:kFaviconFrameSideLength],
[faviconView.widthAnchor constraintEqualToConstant:kFaviconSideLength],
[faviconView.heightAnchor constraintEqualToConstant:kFaviconSideLength],
[faviconBadgeView.widthAnchor
constraintEqualToConstant:kFaviconBadgeSideLength],
[faviconBadgeView.heightAnchor
constraintEqualToConstant:kFaviconBadgeSideLength],

// Badge is on the upper right corner of the frame.
[frameView.topAnchor
constraintEqualToAnchor:faviconBadgeView.centerYAnchor],
[frameView.trailingAnchor
constraintEqualToAnchor:faviconBadgeView.centerXAnchor],

// Favicon is centered in the frame.
[frameView.centerXAnchor constraintEqualToAnchor:faviconView.centerXAnchor],
[frameView.centerYAnchor constraintEqualToAnchor:faviconView.centerYAnchor],

// Frame and badge define the whole view returned by this method.
[containerView.leadingAnchor
constraintEqualToAnchor:frameView.leadingAnchor
constant:-kFaviconBadgeSideLength / 2],
[containerView.bottomAnchor constraintEqualToAnchor:frameView.bottomAnchor],
[containerView.topAnchor
constraintEqualToAnchor:faviconBadgeView.topAnchor],
[containerView.trailingAnchor
constraintEqualToAnchor:faviconBadgeView.trailingAnchor],
]];

self.imageView = faviconView;
return containerView;
}

// Creates a label with subtitle label defaults.
- (UILabel*)createLabel {
UILabel* label = [[UILabel alloc] init];
Expand Down
6 changes: 3 additions & 3 deletions ios/showcase/follow/sc_follow_view_controller.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@
constexpr CGFloat kHalfSheetCornerRadius = 20;

// An example favicon URL given from the Discover backend.
static NSString* const kExampleFaviconURL =
@"https://www.google.com/s2/favicons?domain=the-sun.com&sz=48";
static NSString* const kExampleFaviconURL = @"https://www.the-sun.com/";

// Specific symbols used to create favicons.
NSString* kGlobeSymbol = @"globe";
Expand Down Expand Up @@ -137,12 +136,13 @@ - (void)handleFirstFollowButtonTapped {
FollowedWebChannel* ch1 = [[FollowedWebChannel alloc] init];
ch1.title = @"First Web Channel";
ch1.available = YES;
ch1.faviconURL =
ch1.webPageURL =
[[CrURL alloc] initWithNSURL:[NSURL URLWithString:kExampleFaviconURL]];

firstFollowViewController.followedWebChannel = ch1;
self.alerter.baseViewController = firstFollowViewController;
firstFollowViewController.faviconDataSource = self;
firstFollowViewController.imageEnclosedWithShadowAndBadge = YES;

if (@available(iOS 15, *)) {
firstFollowViewController.modalPresentationStyle =
Expand Down

0 comments on commit b39cb46

Please sign in to comment.