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 @@ ...@@ -33,6 +33,7 @@
#import "ios/chrome/browser/ui/signin_interaction/public/signin_presenter.h" #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_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_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_text_item.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h" #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
#include "ios/chrome/browser/ui/ui_util.h" #include "ios/chrome/browser/ui/ui_util.h"
...@@ -184,6 +185,8 @@ const int kRelativeTimeMaxHours = 4; ...@@ -184,6 +185,8 @@ const int kRelativeTimeMaxHours = 4;
header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_RECENTLY_CLOSED); header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_RECENTLY_CLOSED);
[model setHeader:header [model setHeader:header
forSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs]; forSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs];
header.collapsed = [self.tableViewModel
sectionIsCollapsed:SectionIdentifierRecentlyClosedTabs];
// Add Recently Closed Tabs Cells. // Add Recently Closed Tabs Cells.
[self addRecentlyClosedTabItems]; [self addRecentlyClosedTabItems];
...@@ -291,6 +294,7 @@ const int kRelativeTimeMaxHours = 4; ...@@ -291,6 +294,7 @@ const int kRelativeTimeMaxHours = 4;
header.subtitleText = l10n_util::GetNSStringF( header.subtitleText = l10n_util::GetNSStringF(
IDS_IOS_OPEN_TABS_LAST_USED, IDS_IOS_OPEN_TABS_LAST_USED,
base::SysNSStringToUTF16([self lastSyncStringForSesssion:session])); base::SysNSStringToUTF16([self lastSyncStringForSesssion:session]));
header.collapsed = [model sectionIsCollapsed:sessionIdentifier];
[model setHeader:header forSectionWithIdentifier:sessionIdentifier]; [model setHeader:header forSectionWithIdentifier:sessionIdentifier];
[self addItemsForSession:session]; [self addItemsForSession:session];
} }
...@@ -379,6 +383,7 @@ const int kRelativeTimeMaxHours = 4; ...@@ -379,6 +383,7 @@ const int kRelativeTimeMaxHours = 4;
[[TableViewDisclosureHeaderFooterItem alloc] [[TableViewDisclosureHeaderFooterItem alloc]
initWithType:ItemTypeRecentlyClosedHeader]; initWithType:ItemTypeRecentlyClosedHeader];
header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OTHER_DEVICES); header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OTHER_DEVICES);
header.collapsed = [model sectionIsCollapsed:SectionIdentifierOtherDevices];
[model setHeader:header [model setHeader:header
forSectionWithIdentifier:SectionIdentifierOtherDevices]; forSectionWithIdentifier:SectionIdentifierOtherDevices];
...@@ -773,15 +778,30 @@ const int kRelativeTimeMaxHours = 4; ...@@ -773,15 +778,30 @@ const int kRelativeTimeMaxHours = 4;
[self toggleExpansionOfSectionIdentifier: [self toggleExpansionOfSectionIdentifier:
self.lastTappedHeaderSectionIdentifier]; self.lastTappedHeaderSectionIdentifier];
// Highlight the section header being tapped.
NSInteger section = [self.tableViewModel NSInteger section = [self.tableViewModel
sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier]; sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier];
UITableViewHeaderFooterView* headerView = UITableViewHeaderFooterView* headerView =
[self.tableView headerViewForSection:section]; [self.tableView headerViewForSection:section];
TableViewDisclosureHeaderFooterView* headerTextView = ListItem* headerItem = [self.tableViewModel headerForSection:section];
base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>( // Highlight and collapse the section header being tapped.
headerView); // Don't for the Loading Other Devices section header.
[headerTextView animateHighlight]; 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; ...@@ -833,12 +853,16 @@ const int kRelativeTimeMaxHours = 4;
// Highlight the section header being long pressed. // Highlight the section header being long pressed.
NSInteger section = [self.tableViewModel NSInteger section = [self.tableViewModel
sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier]; sectionForSectionIdentifier:self.lastTappedHeaderSectionIdentifier];
ListItem* headerItem = [self.tableViewModel headerForSection:section];
UITableViewHeaderFooterView* headerView = UITableViewHeaderFooterView* headerView =
[self.tableView headerViewForSection:section]; [self.tableView headerViewForSection:section];
TableViewDisclosureHeaderFooterView* headerTextView = if (headerItem.type == ItemTypeRecentlyClosedHeader ||
base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>( headerItem.type == ItemTypeSessionHeader) {
headerView); TableViewDisclosureHeaderFooterView* textHeaderView =
[headerTextView animateHighlight]; base::mac::ObjCCastStrict<TableViewDisclosureHeaderFooterView>(
headerView);
[textHeaderView animateHighlight];
}
web::ContextMenuParams params; web::ContextMenuParams params;
// Get view coordinates in local space. // Get view coordinates in local space.
......
...@@ -13,7 +13,7 @@ extern const CGFloat kTableViewCellViewSpacing; ...@@ -13,7 +13,7 @@ extern const CGFloat kTableViewCellViewSpacing;
// The vertical spacing between text labels in a stackView. // The vertical spacing between text labels in a stackView.
extern const CGFloat kTableViewVerticalLabelStackSpacing; extern const CGFloat kTableViewVerticalLabelStackSpacing;
// Animation Duration for highlighting selected section header. // Animation duration for highlighting selected section header.
extern const CGFloat kTableViewCellSelectionAnimationDuration; extern const CGFloat kTableViewCellSelectionAnimationDuration;
// Color and alpha used to highlight a cell with a middle gray color to // Color and alpha used to highlight a cell with a middle gray color to
......
...@@ -16,18 +16,34 @@ ...@@ -16,18 +16,34 @@
@property(nonatomic, readwrite, strong) NSString* text; @property(nonatomic, readwrite, strong) NSString* text;
// Header subtitle displayed as a smaller font under title. // Header subtitle displayed as a smaller font under title.
@property(nonatomic, readwrite, strong) NSString* subtitleText; @property(nonatomic, readwrite, strong) NSString* subtitleText;
// Determines the direction of the disclosure view.
@property(nonatomic, readwrite, assign) BOOL collapsed;
@end @end
// UITableViewHeaderFooterView that displays a text label, subtitle, and a // UITableViewHeaderFooterView that displays a text label, subtitle, and a
// disclosure accessory view. // disclosure accessory view.
@interface TableViewDisclosureHeaderFooterView : UITableViewHeaderFooterView @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. // Shows the text of the TableViewDisclosureHeaderFooterItem.
@property(nonatomic, readwrite, strong) UILabel* titleLabel; @property(nonatomic, readwrite, strong) UILabel* titleLabel;
// Shows the subtitleText of the TableViewDisclosureHeaderFooterItem. // Shows the subtitleText of the TableViewDisclosureHeaderFooterItem.
@property(nonatomic, readwrite, strong) UILabel* subtitleLabel; @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 // Animates a change in the backgroundView color and then changes it back to the
// original backGround color in order to simulate a selection highlight. // original backGround color in order to simulate a selection highlight.
- (void)animateHighlight; - (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 @end
#endif // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_DISCLOSURE_HEADER_FOOTER_ITEM_H_ #endif // IOS_CHROME_BROWSER_UI_TABLE_VIEW_CELLS_TABLE_VIEW_DISCLOSURE_HEADER_FOOTER_ITEM_H_
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#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_disclosure_header_footer_item.h"
#include "base/mac/foundation_util.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/cells/table_view_cells_constants.h"
#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h" #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h" #import "ios/chrome/browser/ui/uikit_ui_util.h"
...@@ -13,9 +14,18 @@ ...@@ -13,9 +14,18 @@
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #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 @implementation TableViewDisclosureHeaderFooterItem
@synthesize subtitleText = _subtitleText; @synthesize subtitleText = _subtitleText;
@synthesize text = _text; @synthesize text = _text;
@synthesize collapsed = _collapsed;
- (instancetype)initWithType:(NSInteger)type { - (instancetype)initWithType:(NSInteger)type {
self = [super initWithType:type]; self = [super initWithType:type];
...@@ -37,6 +47,9 @@ ...@@ -37,6 +47,9 @@
headerFooter); headerFooter);
header.titleLabel.text = self.text; header.titleLabel.text = self.text;
header.subtitleLabel.text = self.subtitleText; header.subtitleLabel.text = self.subtitleText;
DisclosureDirection direction =
self.collapsed ? DisclosureDirectionRight : DisclosureDirectionDown;
[header setInitialDirection:direction];
} }
@end @end
...@@ -46,10 +59,14 @@ ...@@ -46,10 +59,14 @@
@interface TableViewDisclosureHeaderFooterView () @interface TableViewDisclosureHeaderFooterView ()
// Animator that handles all cell animations. // Animator that handles all cell animations.
@property(strong, nonatomic) UIViewPropertyAnimator* cellAnimator; @property(strong, nonatomic) UIViewPropertyAnimator* cellAnimator;
// ImageView that holds the disclosure accessory icon.
@property(strong, nonatomic) UIImageView* disclosureImageView;
@end @end
@implementation TableViewDisclosureHeaderFooterView @implementation TableViewDisclosureHeaderFooterView
@synthesize cellAnimator = _cellAnimator; @synthesize cellAnimator = _cellAnimator;
@synthesize disclosureDirection = disclosureDirection;
@synthesize disclosureImageView = _disclosureImageView;
@synthesize subtitleLabel = _subtitleLabel; @synthesize subtitleLabel = _subtitleLabel;
@synthesize titleLabel = _titleLabel; @synthesize titleLabel = _titleLabel;
...@@ -71,16 +88,16 @@ ...@@ -71,16 +88,16 @@
verticalStack.axis = UILayoutConstraintAxisVertical; verticalStack.axis = UILayoutConstraintAxisVertical;
verticalStack.spacing = kTableViewVerticalLabelStackSpacing; verticalStack.spacing = kTableViewVerticalLabelStackSpacing;
// Disclosure ImageView. // Disclosure ImageView. Initial pointing direction is to the right.
UIImageView* disclosureImageView = [[UIImageView alloc] _disclosureImageView = [[UIImageView alloc]
initWithImage:[UIImage imageNamed:@"table_view_cell_chevron"]]; initWithImage:[UIImage imageNamed:@"table_view_cell_chevron"]];
[disclosureImageView [_disclosureImageView
setContentHuggingPriority:UILayoutPriorityDefaultHigh setContentHuggingPriority:UILayoutPriorityDefaultHigh
forAxis:UILayoutConstraintAxisHorizontal]; forAxis:UILayoutConstraintAxisHorizontal];
// Horizontal StackView. // Horizontal StackView.
UIStackView* horizontalStack = [[UIStackView alloc] UIStackView* horizontalStack = [[UIStackView alloc]
initWithArrangedSubviews:@[ verticalStack, disclosureImageView ]]; initWithArrangedSubviews:@[ verticalStack, _disclosureImageView ]];
horizontalStack.axis = UILayoutConstraintAxisHorizontal; horizontalStack.axis = UILayoutConstraintAxisHorizontal;
horizontalStack.spacing = kTableViewCellViewSpacing; horizontalStack.spacing = kTableViewCellViewSpacing;
horizontalStack.translatesAutoresizingMaskIntoConstraints = NO; horizontalStack.translatesAutoresizingMaskIntoConstraints = NO;
...@@ -111,7 +128,9 @@ ...@@ -111,7 +128,9 @@
return self; return self;
} }
- (void)animateHighlight { #pragma mark - internal methods
- (void)addAnimationHighlightToAnimator {
UIColor* originalBackgroundColor = self.contentView.backgroundColor; UIColor* originalBackgroundColor = self.contentView.backgroundColor;
self.cellAnimator = [[UIViewPropertyAnimator alloc] self.cellAnimator = [[UIViewPropertyAnimator alloc]
initWithDuration:kTableViewCellSelectionAnimationDuration initWithDuration:kTableViewCellSelectionAnimationDuration
...@@ -125,6 +144,45 @@ ...@@ -125,6 +144,45 @@
[self.cellAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) { [self.cellAnimator addCompletion:^(UIViewAnimatingPosition finalPosition) {
weakSelf.contentView.backgroundColor = originalBackgroundColor; 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]; [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