blob: 3885a7a5ace67afa766577fd9467190842d9562d [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/tools_menu/reading_list_menu_view_item.h"
#include "base/mac/foundation_util.h"
#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
#import "ios/chrome/browser/ui/reading_list/number_badge_view.h"
#import "ios/chrome/browser/ui/reading_list/text_badge_view.h"
#import "ios/chrome/common/material_timing.h"
#include "ios/chrome/grit/ios_strings.h"
#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
#include "ui/base/l10n/l10n_util_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Accessibility identifier for the text badge on the reading list cell.
NSString* const kReadingListTextBadgeAccessibilityIdentifier =
@"kReadingListTextBadgeAccessibilityIdentifier";
namespace {
// ID for cell reuse
static NSString* const kReadingListCellID = @"ReadingListCellID";
const CGFloat kToolsMenuItemTrailingMargin = 25;
// How long (in seconds) it takes to animate in / out the text badge.
const NSTimeInterval kTextBadgeAnimationDuration = ios::material::kDuration3;
} // namespace
@interface ReadingListMenuViewCell ()
// A badge displaying how many unread items are in the user's reading list.
// Only one of |numberBadge| and |textBadge| can be shown at once. If both
// try to be shown at once, |numberBadge| takes precedence over |textBadge|.
@property(nonatomic, strong) NumberBadgeView* numberBadge;
// A badge displaying "NEW" to draw attention to the reading list cell.
@property(nonatomic, strong) TextBadgeView* textBadge;
@end
@implementation ReadingListMenuViewItem
+ (NSString*)cellID {
return kReadingListCellID;
}
+ (Class)cellClass {
return [ReadingListMenuViewCell class];
}
@end
@implementation ReadingListMenuViewCell
@synthesize numberBadge = _numberBadge;
@synthesize textBadge = _textBadge;
- (void)initializeViews {
if (self.numberBadge && self.textBadge && [self title]) {
return;
}
[super initializeViews];
self.numberBadge = [[NumberBadgeView alloc] initWithFrame:CGRectZero];
[self.contentView addSubview:self.numberBadge];
[self.contentView removeConstraints:self.contentView.constraints];
[NSLayoutConstraint activateConstraints:@[
[self.title.centerYAnchor
constraintEqualToAnchor:self.contentView.centerYAnchor]
]];
[self addConstraintsToBadge:self.numberBadge];
NSString* text = l10n_util::GetNSStringWithFixup(
IDS_IOS_READING_LIST_CELL_NEW_FEATURE_BADGE);
NSString* uppercaseText =
[text uppercaseStringWithLocale:[NSLocale currentLocale]];
self.textBadge = [[TextBadgeView alloc] initWithText:uppercaseText];
self.textBadge.hidden = YES;
self.textBadge.accessibilityIdentifier =
kReadingListTextBadgeAccessibilityIdentifier;
self.textBadge.accessibilityLabel = text;
[self.contentView addSubview:self.textBadge];
[self addConstraintsToBadge:self.textBadge];
}
- (void)updateBadgeCount:(NSInteger)count animated:(BOOL)animated {
[self.numberBadge setNumber:count animated:animated];
// If the number badge is shown, then the text badge must be hidden.
if (!self.numberBadge.isHidden && !self.textBadge.isHidden) {
[self updateShowTextBadge:NO animated:animated];
}
}
- (void)updateSeenState:(BOOL)hasUnseenItems animated:(BOOL)animated {
if (hasUnseenItems) {
UIColor* highlightedColor = [[MDCPalette cr_bluePalette] tint500];
[self.numberBadge setBackgroundColor:highlightedColor animated:animated];
[self.title setTextColor:highlightedColor];
} else {
UIColor* regularColor = [[MDCPalette greyPalette] tint500];
[self.numberBadge setBackgroundColor:regularColor animated:animated];
[self.title setTextColor:[UIColor blackColor]];
}
}
- (void)updateShowTextBadge:(BOOL)showTextBadge animated:(BOOL)animated {
// Only 1 badge can be visible at a time, and the number badge takes priority.
if (showTextBadge && !self.numberBadge.isHidden) {
return;
}
CGFloat alpha = (showTextBadge ? 1.0 : 0.0);
NSTimeInterval duration = (animated ? kTextBadgeAnimationDuration : 0.0);
if (showTextBadge) {
self.textBadge.hidden = NO;
} else if (!animated) {
DCHECK(!showTextBadge);
// The completion block in the animateWithDuration call is not called
// immediately if |duration| is 0.0 (unlike the animation block). This would
// cause the state to be incorrect until the completion callback is invoked,
// so its value must be set here if there is no animation.
self.textBadge.hidden = YES;
}
// If |duration| is 0.0, the block is executed immediately (that is, the
// properties are set directly without any actual animation). Else, the
// animation occurs as normal.
[UIView animateWithDuration:duration
animations:^{
self.textBadge.alpha = alpha;
}
completion:^(BOOL finished) {
if (finished && !showTextBadge) {
self.textBadge.hidden = YES;
}
}];
}
#pragma mark - Private Methods
// Adds autolayout constraints to |badgeView| that center it vertically in the
// cell and anchor it to the right.
- (void)addConstraintsToBadge:(UIView*)badgeView {
[badgeView setTranslatesAutoresizingMaskIntoConstraints:NO];
NSMutableArray<NSLayoutConstraint*>* constraintsToApply = [NSMutableArray
arrayWithArray:
[NSLayoutConstraint
constraintsWithVisualFormat:
@"H:|-(margin)-[title]->=8-[badge]-(endMargin)-|"
options:
NSLayoutFormatDirectionLeadingToTrailing
metrics:@{
@"margin" : @(self.horizontalMargin),
@"endMargin" :
@(kToolsMenuItemTrailingMargin)
}
views:@{
@"title" : self.title,
@"badge" : badgeView
}]];
[constraintsToApply
addObject:[badgeView.centerYAnchor
constraintEqualToAnchor:self.contentView.centerYAnchor]];
[NSLayoutConstraint activateConstraints:constraintsToApply];
}
@end