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") { ...@@ -67,6 +67,7 @@ source_set("badges") {
"//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util",
"//ios/chrome/browser/web", "//ios/chrome/browser/web",
"//ios/chrome/browser/web_state_list", "//ios/chrome/browser/web_state_list",
"//ios/chrome/common:timing",
"//ios/chrome/common/colors", "//ios/chrome/common/colors",
"//ios/chrome/common/ui/util", "//ios/chrome/common/ui/util",
"//ios/web/public", "//ios/web/public",
......
...@@ -31,8 +31,6 @@ ...@@ -31,8 +31,6 @@
#endif #endif
namespace { namespace {
// The number of Fullscreen badges
const int kNumberOfFullScrenBadges = 1;
// The minimum number of non-Fullscreen badges to display the overflow popup // The minimum number of non-Fullscreen badges to display the overflow popup
// menu. // menu.
const int kMinimumNonFullScreenBadgesForOverflow = 2; const int kMinimumNonFullScreenBadgesForOverflow = 2;
...@@ -155,8 +153,6 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2; ...@@ -155,8 +153,6 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
- (void)updateBadgesForActiveWebState { - (void)updateBadgesForActiveWebState {
if (self.webState) { if (self.webState) {
self.badges = [self.badgeTabHelper->GetInfobarBadgeItems() mutableCopy]; self.badges = [self.badgeTabHelper->GetInfobarBadgeItems() mutableCopy];
if (self.offTheRecordBadge)
[self.badges addObject:self.offTheRecordBadge];
} else { } else {
self.badges = [NSMutableArray<id<BadgeItem>> array]; self.badges = [NSMutableArray<id<BadgeItem>> array];
} }
...@@ -171,18 +167,14 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2; ...@@ -171,18 +167,14 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
if (!self.badges) if (!self.badges)
[self updateBadgesForActiveWebState]; [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 = BOOL shouldDisplayOverflowBadge =
self.badges.count - fullscreenBadgeCount > 1; self.badges.count >= kMinimumNonFullScreenBadgesForOverflow;
id<BadgeItem> displayedBadge = nil; id<BadgeItem> displayedBadge = nil;
if (shouldDisplayOverflowBadge) { if (shouldDisplayOverflowBadge) {
displayedBadge = [[BadgeTappableItem alloc] displayedBadge = [[BadgeTappableItem alloc]
initWithBadgeType:BadgeType::kBadgeTypeOverflow]; initWithBadgeType:BadgeType::kBadgeTypeOverflow];
} else { } else {
id<BadgeItem> firstBadge = [self.badges firstObject]; displayedBadge = [self.badges firstObject];
displayedBadge = firstBadge.fullScreen ? nil : firstBadge;
} }
// Update the consumer with the new badge items. // Update the consumer with the new badge items.
[self.consumer setupWithDisplayedBadge:displayedBadge [self.consumer setupWithDisplayedBadge:displayedBadge
...@@ -367,7 +359,7 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2; ...@@ -367,7 +359,7 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
// non-fullscreen badges. // non-fullscreen badges.
- (void)updateConsumerReadStatus { - (void)updateConsumerReadStatus {
for (id<BadgeItem> item in self.badges) { for (id<BadgeItem> item in self.badges) {
if (!item.fullScreen && !(item.badgeState & BadgeStateRead)) { if (!(item.badgeState & BadgeStateRead)) {
[self.consumer markDisplayedBadgeAsRead:NO]; [self.consumer markDisplayedBadgeAsRead:NO];
return; return;
} }
...@@ -385,29 +377,19 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2; ...@@ -385,29 +377,19 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
// multiple non-fullscreen badges, additional logic below determines what // multiple non-fullscreen badges, additional logic below determines what
// badge will be shown. // badge will be shown.
id<BadgeItem> displayedBadge; 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 // The badge that is current displaying its banner. This will be set as the
// displayedBadge if there are multiple badges. // displayedBadge if there are multiple badges.
id<BadgeItem> presentingBadge; id<BadgeItem> presentingBadge;
for (id<BadgeItem> item in self.badges) { for (id<BadgeItem> item in self.badges) {
if (item.fullScreen) {
fullScreenBadge = item;
} else {
if (item.badgeState & BadgeStatePresented) { if (item.badgeState & BadgeStatePresented) {
presentingBadge = item; presentingBadge = item;
} }
displayedBadge = item; displayedBadge = item;
}
} }
// Figure out what displayedBadge should be showing if there are multiple // Figure out what displayedBadge should be showing if there are multiple
// non-Fullscreen badges. // non-Fullscreen badges.
NSInteger count = [self.badges count]; NSInteger count = [self.badges count];
if (fullScreenBadge) {
count -= kNumberOfFullScrenBadges;
}
if (count >= kMinimumNonFullScreenBadgesForOverflow) { if (count >= kMinimumNonFullScreenBadgesForOverflow) {
// If a badge's banner is being presented, then show that badge as the // If a badge's banner is being presented, then show that badge as the
// displayed badge. Otherwise, show the overflow badge. // displayed badge. Otherwise, show the overflow badge.
...@@ -421,7 +403,7 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2; ...@@ -421,7 +403,7 @@ const int kMinimumNonFullScreenBadgesForOverflow = 2;
displayedBadge.badgeState |= BadgeStateRead; displayedBadge.badgeState |= BadgeStateRead;
} }
[self.consumer updateDisplayedBadge:displayedBadge [self.consumer updateDisplayedBadge:displayedBadge
fullScreenBadge:fullScreenBadge]; fullScreenBadge:self.offTheRecordBadge];
[self updateConsumerReadStatus]; [self updateConsumerReadStatus];
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "ios/chrome/browser/overlays/test/fake_overlay_presentation_context.h" #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_consumer.h"
#import "ios/chrome/browser/ui/badges/badge_item.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" #include "ios/chrome/browser/ui/badges/badge_type_util.h"
#import "ios/chrome/browser/ui/infobars/test_infobar_delegate.h" #import "ios/chrome/browser/ui/infobars/test_infobar_delegate.h"
#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h" #import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
...@@ -55,19 +56,23 @@ enum class TestParam { ...@@ -55,19 +56,23 @@ enum class TestParam {
// Fake of BadgeConsumer. // Fake of BadgeConsumer.
@interface FakeBadgeConsumer : NSObject <BadgeConsumer> @interface FakeBadgeConsumer : NSObject <BadgeConsumer>
@property(nonatomic, strong) id<BadgeItem> displayedBadge; @property(nonatomic, strong) id<BadgeItem> displayedBadge;
@property(nonatomic, assign) BOOL hasFullscreenBadge; @property(nonatomic, assign) BOOL hasFullscreenOffTheRecordBadge;
@property(nonatomic, assign) BOOL hasUnreadBadge; @property(nonatomic, assign) BOOL hasUnreadBadge;
@end @end
@implementation FakeBadgeConsumer @implementation FakeBadgeConsumer
- (void)setupWithDisplayedBadge:(id<BadgeItem>)displayedBadgeItem - (void)setupWithDisplayedBadge:(id<BadgeItem>)displayedBadgeItem
fullScreenBadge:(id<BadgeItem>)fullscreenBadgeItem { fullScreenBadge:(id<BadgeItem>)fullscreenBadgeItem {
self.hasFullscreenBadge = fullscreenBadgeItem != nil; self.hasFullscreenOffTheRecordBadge =
fullscreenBadgeItem != nil &&
fullscreenBadgeItem.badgeType == BadgeType::kBadgeTypeIncognito;
self.displayedBadge = displayedBadgeItem; self.displayedBadge = displayedBadgeItem;
} }
- (void)updateDisplayedBadge:(id<BadgeItem>)displayedBadgeItem - (void)updateDisplayedBadge:(id<BadgeItem>)displayedBadgeItem
fullScreenBadge:(id<BadgeItem>)fullscreenBadgeItem { fullScreenBadge:(id<BadgeItem>)fullscreenBadgeItem {
self.hasFullscreenBadge = fullscreenBadgeItem != nil; self.hasFullscreenOffTheRecordBadge =
fullscreenBadgeItem != nil &&
fullscreenBadgeItem.badgeType == BadgeType::kBadgeTypeIncognito;
self.displayedBadge = displayedBadgeItem; self.displayedBadge = displayedBadgeItem;
} }
- (void)markDisplayedBadgeAsRead:(BOOL)read { - (void)markDisplayedBadgeAsRead:(BOOL)read {
...@@ -168,7 +173,8 @@ class BadgeMediatorTest : public testing::TestWithParam<TestParam> { ...@@ -168,7 +173,8 @@ class BadgeMediatorTest : public testing::TestWithParam<TestParam> {
TEST_P(BadgeMediatorTest, BadgeMediatorTestNoInfobar) { TEST_P(BadgeMediatorTest, BadgeMediatorTestNoInfobar) {
InsertActivatedWebState(/*index=*/0); InsertActivatedWebState(/*index=*/0);
EXPECT_FALSE(badge_consumer_.displayedBadge); 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 // Test that the BadgeMediator responds with one new badge when an infobar is
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#import "ios/chrome/browser/ui/elements/extended_touch_target_button.h" #import "ios/chrome/browser/ui/elements/extended_touch_target_button.h"
#import "ios/chrome/browser/ui/util/named_guide.h" #import "ios/chrome/browser/ui/util/named_guide.h"
#import "ios/chrome/common/colors/semantic_color_names.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" #import "ios/chrome/common/ui/util/constraints_ui_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
...@@ -31,6 +32,9 @@ const CGFloat kUnreadIndicatorViewSpacing = 10.0; ...@@ -31,6 +32,9 @@ const CGFloat kUnreadIndicatorViewSpacing = 10.0;
// Height of |unreadIndicatorView|. // Height of |unreadIndicatorView|.
const CGFloat kUnreadIndicatorViewHeight = 6.0; const CGFloat kUnreadIndicatorViewHeight = 6.0;
// Damping ratio of animating a change to the displayed badge.
const CGFloat kUpdateDisplayedBadgeAnimationDamping = 0.85;
} // namespace } // namespace
@interface BadgeViewController () @interface BadgeViewController ()
...@@ -137,8 +141,7 @@ const CGFloat kUnreadIndicatorViewHeight = 6.0; ...@@ -137,8 +141,7 @@ const CGFloat kUnreadIndicatorViewHeight = 6.0;
self.unreadIndicatorView = [[UIView alloc] init]; self.unreadIndicatorView = [[UIView alloc] init];
self.unreadIndicatorView.layer.cornerRadius = self.unreadIndicatorView.layer.cornerRadius =
kUnreadIndicatorViewHeight / 2; kUnreadIndicatorViewHeight / 2;
self.unreadIndicatorView.backgroundColor = self.unreadIndicatorView.backgroundColor = [UIColor colorNamed:kBlueColor];
[UIColor colorNamed:kToolbarButtonColor];
self.unreadIndicatorView.translatesAutoresizingMaskIntoConstraints = NO; self.unreadIndicatorView.translatesAutoresizingMaskIntoConstraints = NO;
self.unreadIndicatorView.accessibilityIdentifier = self.unreadIndicatorView.accessibilityIdentifier =
kBadgeUnreadIndicatorAccessibilityIdentifier; kBadgeUnreadIndicatorAccessibilityIdentifier;
...@@ -189,6 +192,10 @@ const CGFloat kUnreadIndicatorViewHeight = 6.0; ...@@ -189,6 +192,10 @@ const CGFloat kUnreadIndicatorViewHeight = 6.0;
#pragma mark - Getter/Setter #pragma mark - Getter/Setter
- (void)setDisplayedBadge:(BadgeButton*)badgeButton { - (void)setDisplayedBadge:(BadgeButton*)badgeButton {
if (badgeButton.badgeType == self.displayedBadge.badgeType) {
return;
}
[self.stackView removeArrangedSubview:_displayedBadge]; [self.stackView removeArrangedSubview:_displayedBadge];
[_displayedBadge removeFromSuperview]; [_displayedBadge removeFromSuperview];
if (!badgeButton) { if (!badgeButton) {
...@@ -197,7 +204,21 @@ const CGFloat kUnreadIndicatorViewHeight = 6.0; ...@@ -197,7 +204,21 @@ const CGFloat kUnreadIndicatorViewHeight = 6.0;
return; return;
} }
_displayedBadge = badgeButton; _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]; [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 NamedGuide* guide = [NamedGuide guideWithName:kBadgeOverflowMenuGuide
view:_displayedBadge]; view:_displayedBadge];
guide.constrainedView = _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