Commit 34aa80d6 authored by Chris Lu's avatar Chris Lu Committed by Commit Bot

[ios] Polish Messages badge UI

- self.offTheRecordBadge is the only fullscreen badge, it doesn't
have to be added to self.badges in BadgeMediator.
- animates the changing of the displayed badge in a spring/zoom in
motion.
- change color of unread indicator to blue instead of grey.

Bug: 1050781
Change-Id: I705baf6d65f04b08cb8e5b446cb7f8f0a580c537
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2045192
Commit-Queue: Chris Lu <thegreenfrog@chromium.org>
Reviewed-by: default avatarSergio Collazos <sczs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#742728}
parent 3d0fde3b
......@@ -67,6 +67,7 @@ source_set("badges") {
"//ios/chrome/browser/ui/util",
"//ios/chrome/browser/web",
"//ios/chrome/browser/web_state_list",
"//ios/chrome/common:timing",
"//ios/chrome/common/colors",
"//ios/chrome/common/ui/util",
"//ios/web/public",
......
......@@ -31,8 +31,6 @@
#endif
namespace {
// The number of Fullscreen badges
const int kNumberOfFullScrenBadges = 1;
// The minimum number of non-Fullscreen badges to display the overflow popup
// menu.
const int kMinimumNonFullScreenBadgesForOverflow = 2;
......@@ -155,8 +153,6 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
- (void)updateBadgesForActiveWebState {
if (self.webState) {
self.badges = [self.badgeTabHelper->GetInfobarBadgeItems() mutableCopy];
if (self.offTheRecordBadge)
[self.badges addObject:self.offTheRecordBadge];
} else {
self.badges = [NSMutableArray<id<BadgeItem>> array];
}
......@@ -171,18 +167,14 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
if (!self.badges)
[self updateBadgesForActiveWebState];
// Show the overflow badge if there are multiple BadgeItems. Otherwise, use
// the first badge if it's not fullscreen.
NSUInteger fullscreenBadgeCount = self.offTheRecordBadge ? 1U : 0U;
BOOL shouldDisplayOverflowBadge =
self.badges.count - fullscreenBadgeCount > 1;
self.badges.count >= kMinimumNonFullScreenBadgesForOverflow;
id<BadgeItem> displayedBadge = nil;
if (shouldDisplayOverflowBadge) {
displayedBadge = [[BadgeTappableItem alloc]
initWithBadgeType:BadgeType::kBadgeTypeOverflow];
} else {
id<BadgeItem> firstBadge = [self.badges firstObject];
displayedBadge = firstBadge.fullScreen ? nil : firstBadge;
displayedBadge = [self.badges firstObject];
}
// Update the consumer with the new badge items.
[self.consumer setupWithDisplayedBadge:displayedBadge
......@@ -367,7 +359,7 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
// non-fullscreen badges.
- (void)updateConsumerReadStatus {
for (id<BadgeItem> item in self.badges) {
if (!item.fullScreen && !(item.badgeState & BadgeStateRead)) {
if (!(item.badgeState & BadgeStateRead)) {
[self.consumer markDisplayedBadgeAsRead:NO];
return;
}
......@@ -385,29 +377,19 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
// multiple non-fullscreen badges, additional logic below determines what
// badge will be shown.
id<BadgeItem> displayedBadge;
// The fullscreen badge to show. There currently should only be one fullscreen
// badge at a given time.
id<BadgeItem> fullScreenBadge;
// The badge that is current displaying its banner. This will be set as the
// displayedBadge if there are multiple badges.
id<BadgeItem> presentingBadge;
for (id<BadgeItem> item in self.badges) {
if (item.fullScreen) {
fullScreenBadge = item;
} else {
if (item.badgeState & BadgeStatePresented) {
presentingBadge = item;
}
displayedBadge = item;
}
}
// Figure out what displayedBadge should be showing if there are multiple
// non-Fullscreen badges.
NSInteger count = [self.badges count];
if (fullScreenBadge) {
count -= kNumberOfFullScrenBadges;
}
if (count >= kMinimumNonFullScreenBadgesForOverflow) {
// If a badge's banner is being presented, then show that badge as the
// displayed badge. Otherwise, show the overflow badge.
......@@ -421,7 +403,7 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
displayedBadge.badgeState |= BadgeStateRead;
}
[self.consumer updateDisplayedBadge:displayedBadge
fullScreenBadge:fullScreenBadge];
fullScreenBadge:self.offTheRecordBadge];
[self updateConsumerReadStatus];
}
......
......@@ -23,6 +23,7 @@
#include "ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h"
#import "ios/chrome/browser/ui/badges/badge_consumer.h"
#import "ios/chrome/browser/ui/badges/badge_item.h"
#import "ios/chrome/browser/ui/badges/badge_type.h"
#include "ios/chrome/browser/ui/badges/badge_type_util.h"
#import "ios/chrome/browser/ui/infobars/test_infobar_delegate.h"
#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
......@@ -55,19 +56,23 @@ enum class TestParam {
// Fake of BadgeConsumer.
@interface FakeBadgeConsumer : NSObject <BadgeConsumer>
@property(nonatomic, strong) id<BadgeItem> displayedBadge;
@property(nonatomic, assign) BOOL hasFullscreenBadge;
@property(nonatomic, assign) BOOL hasFullscreenOffTheRecordBadge;
@property(nonatomic, assign) BOOL hasUnreadBadge;
@end
@implementation FakeBadgeConsumer
- (void)setupWithDisplayedBadge:(id<BadgeItem>)displayedBadgeItem
fullScreenBadge:(id<BadgeItem>)fullscreenBadgeItem {
self.hasFullscreenBadge = fullscreenBadgeItem != nil;
self.hasFullscreenOffTheRecordBadge =
fullscreenBadgeItem != nil &&
fullscreenBadgeItem.badgeType == BadgeType::kBadgeTypeIncognito;
self.displayedBadge = displayedBadgeItem;
}
- (void)updateDisplayedBadge:(id<BadgeItem>)displayedBadgeItem
fullScreenBadge:(id<BadgeItem>)fullscreenBadgeItem {
self.hasFullscreenBadge = fullscreenBadgeItem != nil;
self.hasFullscreenOffTheRecordBadge =
fullscreenBadgeItem != nil &&
fullscreenBadgeItem.badgeType == BadgeType::kBadgeTypeIncognito;
self.displayedBadge = displayedBadgeItem;
}
- (void)markDisplayedBadgeAsRead:(BOOL)read {
......@@ -168,7 +173,8 @@ class BadgeMediatorTest : public testing::TestWithParam<TestParam> {
TEST_P(BadgeMediatorTest, BadgeMediatorTestNoInfobar) {
InsertActivatedWebState(/*index=*/0);
EXPECT_FALSE(badge_consumer_.displayedBadge);
EXPECT_EQ(is_off_the_record(), badge_consumer_.hasFullscreenBadge);
EXPECT_EQ(is_off_the_record(),
badge_consumer_.hasFullscreenOffTheRecordBadge);
}
// Test that the BadgeMediator responds with one new badge when an infobar is
......
......@@ -12,6 +12,7 @@
#import "ios/chrome/browser/ui/elements/extended_touch_target_button.h"
#import "ios/chrome/browser/ui/util/named_guide.h"
#import "ios/chrome/common/colors/semantic_color_names.h"
#import "ios/chrome/common/material_timing.h"
#import "ios/chrome/common/ui/util/constraints_ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
......@@ -31,6 +32,9 @@ const CGFloat kUnreadIndicatorViewSpacing = 10.0;
// Height of |unreadIndicatorView|.
const CGFloat kUnreadIndicatorViewHeight = 6.0;
// Damping ratio of animating a change to the displayed badge.
const CGFloat kUpdateDisplayedBadgeAnimationDamping = 0.85;
} // namespace
@interface BadgeViewController ()
......@@ -137,8 +141,7 @@ const CGFloat kUnreadIndicatorViewHeight = 6.0;
self.unreadIndicatorView = [[UIView alloc] init];
self.unreadIndicatorView.layer.cornerRadius =
kUnreadIndicatorViewHeight / 2;
self.unreadIndicatorView.backgroundColor =
[UIColor colorNamed:kToolbarButtonColor];
self.unreadIndicatorView.backgroundColor = [UIColor colorNamed:kBlueColor];
self.unreadIndicatorView.translatesAutoresizingMaskIntoConstraints = NO;
self.unreadIndicatorView.accessibilityIdentifier =
kBadgeUnreadIndicatorAccessibilityIdentifier;
......@@ -189,6 +192,10 @@ const CGFloat kUnreadIndicatorViewHeight = 6.0;
#pragma mark - Getter/Setter
- (void)setDisplayedBadge:(BadgeButton*)badgeButton {
if (badgeButton.badgeType == self.displayedBadge.badgeType) {
return;
}
[self.stackView removeArrangedSubview:_displayedBadge];
[_displayedBadge removeFromSuperview];
if (!badgeButton) {
......@@ -197,7 +204,21 @@ const CGFloat kUnreadIndicatorViewHeight = 6.0;
return;
}
_displayedBadge = badgeButton;
// Configure the initial state of the animation.
self.view.alpha = 0;
self.view.transform = CGAffineTransformMakeScale(0.1, 0.1);
[self.stackView addArrangedSubview:_displayedBadge];
[UIView animateWithDuration:ios::material::kDuration2
delay:0
usingSpringWithDamping:kUpdateDisplayedBadgeAnimationDamping
initialSpringVelocity:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.view.alpha = 1;
self.view.transform = CGAffineTransformIdentity;
}
completion:nil];
NamedGuide* guide = [NamedGuide guideWithName:kBadgeOverflowMenuGuide
view:_displayedBadge];
guide.constrainedView = _displayedBadge;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment