Commit d019d58c authored by Chris Lu's avatar Chris Lu Committed by Commit Bot

[ios] Rotate Recent Tabs Section Header Disclosure Accessory

Rotates Disclosure Accessory 90 degrees CW when showing section contents. Rotates back CCW when collapsing section.

Video: https://drive.google.com/file/d/1TWXnHpHqsfbrK26PsWraC6HTvaC_EGo5/view?usp=sharing

Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: I84f090bcbd43d0f69d50b8f0b48da35aff7efaf8
Reviewed-on: https://chromium-review.googlesource.com/994233
Commit-Queue: Chris Lu <thegreenfrog@google.com>
Reviewed-by: default avatarSergio Collazos <sczs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551472}
parent 1f4382b7
......@@ -33,6 +33,7 @@
#import "ios/chrome/browser/ui/signin_interaction/public/signin_presenter.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_signin_promo_item.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_text_header_footer_item.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
#include "ios/chrome/browser/ui/ui_util.h"
......@@ -184,6 +185,8 @@ const int kRelativeTimeMaxHours = 4;
header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_RECENTLY_CLOSED);
[model setHeader:header
forSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs];
header.collapsed = [self.tableViewModel
sectionIsCollapsed:SectionIdentifierRecentlyClosedTabs];
// Add Recently Closed Tabs Cells.
[self addRecentlyClosedTabItems];
......@@ -291,6 +294,7 @@ const int kRelativeTimeMaxHours = 4;
header.subtitleText = l10n_util::GetNSStringF(
IDS_IOS_OPEN_TABS_LAST_USED,
base::SysNSStringToUTF16([self lastSyncStringForSesssion:session]));
header.collapsed = [model sectionIsCollapsed:sessionIdentifier];
[model setHeader:header forSectionWithIdentifier:sessionIdentifier];
[self addItemsForSession:session];
}
......@@ -379,6 +383,7 @@ const int kRelativeTimeMaxHours = 4;
[[TableViewDisclosureHeaderFooterItem alloc]
initWithType:ItemTypeRecentlyClosedHeader];
header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OTHER_DEVICES);
header.collapsed = [model sectionIsCollapsed:SectionIdentifierOtherDevices];
[model setHeader:header
forSectionWithIdentifier:SectionIdentifierOtherDevices];
......@@ -773,15 +778,30 @@ const int kRelativeTimeMaxHours = 4;
[self toggleExpansionOfSectionIdentifier:
self.lastTappedHeaderSectionIdentifier];
// Highlight the section header being tapped.
NSInteger section = [self.tableViewModel
sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier];
UITableViewHeaderFooterView* headerView =
[self.tableView headerViewForSection:section];
TableViewDisclosureHeaderFooterView* headerTextView =
base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>(
headerView);
[headerTextView animateHighlight];
ListItem* headerItem = [self.tableViewModel headerForSection:section];
// Highlight and collapse the section header being tapped.
// Don't for the Loading Other Devices section header.
if (headerItem.type == ItemTypeRecentlyClosedHeader ||
headerItem.type == ItemTypeSessionHeader) {
TableViewDisclosureHeaderFooterView* disclosureHeaderView =
base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>(
headerView);
TableViewDisclosureHeaderFooterItem* disclosureItem =
base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterItem>(
headerItem);
BOOL collapsed = [self.tableViewModel
sectionIsCollapsed:[self.tableViewModel
sectionIdentifierForSection:section]];
DisclosureDirection direction =
collapsed ? DisclosureDirectionRight : DisclosureDirectionDown;
[disclosureHeaderView animateHighlightAndRotateToDirection:direction];
disclosureItem.collapsed = collapsed;
}
}
}
......@@ -833,12 +853,16 @@ const int kRelativeTimeMaxHours = 4;
// Highlight the section header being long pressed.
NSInteger section = [self.tableViewModel
sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier];
ListItem* headerItem = [self.tableViewModel headerForSection:section];
UITableViewHeaderFooterView* headerView =
[self.tableView headerViewForSection:section];
TableViewDisclosureHeaderFooterView* headerTextView =
base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>(
headerView);
[headerTextView animateHighlight];
if (headerItem.type == ItemTypeRecentlyClosedHeader ||
headerItem.type == ItemTypeSessionHeader) {
TableViewDisclosureHeaderFooterView* textHeaderView =
base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>(
headerView);
[textHeaderView animateHighlight];
}
web::ContextMenuParams params;
// Get view coordinates in local space.
......
......@@ -13,7 +13,7 @@ extern const CGFloat kTableViewCellViewSpacing;
// The vertical spacing between text labels in a stackView.
extern const CGFloat kTableViewVerticalLabelStackSpacing;
// Animation Duration for highlighting selected section header.
// Animation duration for highlighting selected section header.
extern const CGFloat kTableViewCellSelectionAnimationDuration;
// Color and alpha used to highlight a cell with a middle gray color to
......
......@@ -16,18 +16,34 @@
@property(nonatomic, readwrite, strong) NSString* text;
// Header subtitle displayed as a smaller font under title.
@property(nonatomic, readwrite, strong) NSString* subtitleText;
// Determines the direction of the disclosure view.
@property(nonatomic, readwrite, assign) BOOL collapsed;
@end
// UITableViewHeaderFooterView that displays a text label, subtitle, and a
// disclosure accessory view.
@interface TableViewDisclosureHeaderFooterView : UITableViewHeaderFooterView
// Indicates in what direction the disclosure accessory should point.
typedef NS_ENUM(NSInteger, DisclosureDirection) {
DisclosureDirectionRight = 0,
DisclosureDirectionDown,
};
// Shows the text of the TableViewDisclosureHeaderFooterItem.
@property(nonatomic, readwrite, strong) UILabel* titleLabel;
// Shows the subtitleText of the TableViewDisclosureHeaderFooterItem.
@property(nonatomic, readwrite, strong) UILabel* subtitleLabel;
// Determines if disclosureImageView should be pointing down or to the right.
@property(nonatomic, assign) DisclosureDirection disclosureDirection;
// Animates a change in the backgroundView color and then changes it back to the
// original backGround color in order to simulate a selection highlight.
- (void)animateHighlight;
// Sets initial direction of disclosure view.
- (void)setInitialDirection:(DisclosureDirection)direction;
// Animates a change in the backgroundView color and then changes it back to the
// original backGround color in order to simulate a selection highlight AND
// Rotates the disclosure view if the direction parameter is different from its
// current state.
- (void)animateHighlightAndRotateToDirection:(DisclosureDirection)direction;
@end
#endif // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_DISCLOSURE_HEADER_FOOTER_ITEM_H_
......@@ -5,6 +5,7 @@
#import "ios/chrome/browser/ui/table_view/cells/table_view_disclosure_header_footer_item.h"
#include "base/mac/foundation_util.h"
#include "base/numerics/math_constants.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h"
......@@ -13,9 +14,18 @@
#error "This file requires ARC support."
#endif
namespace {
// Rotates the disclosure back to its original position.
const float kToggleDisclosureOriginalPositionAngle = 0;
// 90 degree CCW rotation
constexpr float kRotationNinetyCCW = (90 / 180.0) * M_PI;
}
@implementation TableViewDisclosureHeaderFooterItem
@synthesize subtitleText = _subtitleText;
@synthesize text = _text;
@synthesize collapsed = _collapsed;
- (instancetype)initWithType:(NSInteger)type {
self = [super initWithType:type];
......@@ -37,6 +47,9 @@
headerFooter);
header.titleLabel.text = self.text;
header.subtitleLabel.text = self.subtitleText;
DisclosureDirection direction =
self.collapsed ? DisclosureDirectionRight : DisclosureDirectionDown;
[header setInitialDirection:direction];
}
@end
......@@ -46,10 +59,14 @@
@interface TableViewDisclosureHeaderFooterView ()
// Animator that handles all cell animations.
@property(strong, nonatomic) UIViewPropertyAnimator* cellAnimator;
// ImageView that holds the disclosure accessory icon.
@property(strong, nonatomic) UIImageView* disclosureImageView;
@end
@implementation TableViewDisclosureHeaderFooterView
@synthesize cellAnimator = _cellAnimator;
@synthesize disclosureDirection = disclosureDirection;
@synthesize disclosureImageView = _disclosureImageView;
@synthesize subtitleLabel = _subtitleLabel;
@synthesize titleLabel = _titleLabel;
......@@ -71,16 +88,16 @@
verticalStack.axis = UILayoutConstraintAxisVertical;
verticalStack.spacing = kTableViewVerticalLabelStackSpacing;
// Disclosure ImageView.
UIImageView* disclosureImageView = [[UIImageView alloc]
// Disclosure ImageView. Initial pointing direction is to the right.
_disclosureImageView = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:@"table_view_cell_chevron"]];
[disclosureImageView
[_disclosureImageView
setContentHuggingPriority:UILayoutPriorityDefaultHigh
forAxis:UILayoutConstraintAxisHorizontal];
// Horizontal StackView.
UIStackView* horizontalStack = [[UIStackView alloc]
initWithArrangedSubviews:@[ verticalStack, disclosureImageView ]];
initWithArrangedSubviews:@[ verticalStack, _disclosureImageView ]];
horizontalStack.axis = UILayoutConstraintAxisHorizontal;
horizontalStack.spacing = kTableViewCellViewSpacing;
horizontalStack.translatesAutoresizingMaskIntoConstraints = NO;
......@@ -111,7 +128,9 @@
return self;
}
- (void)animateHighlight {
#pragma mark - internal methods
- (void)addAnimationHighlightToAnimator {
UIColor* originalBackgroundColor = self.contentView.backgroundColor;
self.cellAnimator = [[UIViewPropertyAnimator alloc]
initWithDuration:kTableViewCellSelectionAnimationDuration
......@@ -125,6 +144,45 @@
[self.cellAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
weakSelf.contentView.backgroundColor = originalBackgroundColor;
}];
}
// When view is being initialized, it has not been added to the hierarchy yet.
// So, in order to set the initial direction, a non-animation transform is
// needed.
- (void)rotateToDirection:(DisclosureDirection)direction animate:(BOOL)animate {
DisclosureDirection originalDirection = self.disclosureDirection;
if (originalDirection != direction) {
self.disclosureDirection = direction;
CGFloat angle = direction == DisclosureDirectionDown
? kRotationNinetyCCW
: kToggleDisclosureOriginalPositionAngle;
if (animate) {
__weak TableViewDisclosureHeaderFooterView* weakSelf = self;
[self.cellAnimator addAnimations:^{
weakSelf.disclosureImageView.transform =
CGAffineTransformRotate(CGAffineTransformIdentity, angle);
}];
} else {
self.disclosureImageView.transform =
CGAffineTransformRotate(CGAffineTransformIdentity, angle);
}
}
}
#pragma mark - public methods
- (void)animateHighlight {
[self addAnimationHighlightToAnimator];
[self.cellAnimator startAnimation];
}
- (void)setInitialDirection:(DisclosureDirection)direction {
[self rotateToDirection:direction animate:NO];
}
- (void)animateHighlightAndRotateToDirection:(DisclosureDirection)direction {
[self addAnimationHighlightToAnimator];
[self rotateToDirection:direction animate:YES];
[self.cellAnimator startAnimation];
}
......
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