Commit 22065f24 authored by sczs@chromium.org's avatar sczs@chromium.org Committed by Commit Bot

[ios] Creates TableViewLoadingView, adds it to HistoryTableVC.

- Creates TableViewLoadingView, which is added as a backgroundView of ChromeTableVC.
- HistoryTableVC adds this TableViewLoadingView instead of implementing its own.
- Re-adds searching property to HistoryTableVC.

Screenshot:
https://drive.google.com/open?id=1gXnkLADyKrv3hqtijU7Su9t8gW0hR7el

Bug: 838577
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: Id494826f4bd522062f7d30bf4c6e7e81ceba6370
Reviewed-on: https://chromium-review.googlesource.com/1041187
Commit-Queue: Sergio Collazos <sczs@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#567095}
parent 64397686
......@@ -82,6 +82,8 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
BOOL shouldShowNoticeAboutOtherFormsOfBrowsingHistory;
// YES if there is an outstanding history query.
@property(nonatomic, assign, getter=isLoading) BOOL loading;
// YES if there is a search happening.
@property(nonatomic, assign) BOOL searchInProgress;
// YES if there are no more history entries to load.
@property(nonatomic, assign, getter=hasFinishedLoading) BOOL finishedLoading;
// YES if the table should be filtered by the next received query result.
......@@ -113,6 +115,7 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
@synthesize loading = _loading;
@synthesize localDispatcher = _localDispatcher;
@synthesize searchController = _searchController;
@synthesize searchInProgress = _searchInProgress;
@synthesize shouldShowNoticeAboutOtherFormsOfBrowsingHistory =
_shouldShowNoticeAboutOtherFormsOfBrowsingHistory;
@synthesize presentationDelegate = _presentationDelegate;
......@@ -188,18 +191,10 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
- (void)loadModel {
[super loadModel];
// Add initial info section as header.
// Add Status section, this section will always exist during the lifetime of
// HistoryTableVC. Its content will be driven by |updateEntriesStatusMessage|.
[self.tableViewModel
addSectionWithIdentifier:kEntriesStatusSectionIdentifier];
// TODO(crbug.com/833623): Temporary loading indicator, will update once we
// decide on a standard.
TableViewTextItem* entriesStatusItem =
[[TableViewTextItem alloc] initWithType:ItemTypeEntriesStatus];
entriesStatusItem.text = @"Loading";
entriesStatusItem.textColor = TextItemColorBlack;
[self.tableViewModel addItem:entriesStatusItem
toSectionWithIdentifier:kEntriesStatusSectionIdentifier];
_entryInserter =
[[HistoryEntryInserter alloc] initWithModel:self.tableViewModel];
_entryInserter.delegate = self;
......@@ -232,6 +227,9 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
return;
}
// At this point there has been a response, we can stop the loading indicator.
[self stopLoadingIndicatorWithCompletion:nil];
// If there are no results and no URLs have been loaded, report that no
// history entries were found.
if (results.empty() && self.empty) {
......@@ -269,7 +267,7 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
[self updateToolbarButtons];
if ((self.searchController.isActive && [searchQuery length] > 0 &&
if ((self.searchInProgress && [searchQuery length] > 0 &&
[self.currentQuery isEqualToString:searchQuery]) ||
self.filterQueryResult) {
// If in search mode, filter out entries that are not part of the
......@@ -360,10 +358,12 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
#pragma mark UISearchBarDelegate
- (void)searchBarTextDidBeginEditing:(UISearchBar*)searchBar {
self.searchInProgress = YES;
[self updateEntriesStatusMessage];
}
- (void)searchBarTextDidEndEditing:(UISearchBar*)searchBar {
self.searchInProgress = NO;
[self updateEntriesStatusMessage];
}
......@@ -439,7 +439,7 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
TableViewItem* item = [self.tableViewModel itemAtIndexPath:indexPath];
// Only navigate and record metrics if a ItemTypeHistoryEntry was selected.
if (item.type == ItemTypeHistoryEntry) {
if (self.searchController.isActive) {
if (self.searchInProgress) {
// Set the searchController active property to NO or the SearchBar will
// cause the navigation controller to linger for a second when
// dismissing.
......@@ -542,8 +542,9 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
- (void)fetchHistoryForQuery:(NSString*)query continuation:(BOOL)continuation {
self.loading = YES;
// Add loading indicator if no items are shown.
if (self.empty && !self.searchController.isActive) {
[self addLoadingIndicator];
if (self.empty && !self.searchInProgress) {
[self startLoadingIndicatorWithLoadingMessage:l10n_util::GetNSString(
IDS_HISTORY_NO_RESULTS)];
}
if (continuation) {
......@@ -582,17 +583,14 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
// section.
- (void)updateEntriesStatusMessage {
NSString* messageText = nil;
TextItemColor messageColor;
if (self.empty) {
messageText = self.searchController.isActive
messageText = self.searchInProgress
? l10n_util::GetNSString(IDS_HISTORY_NO_SEARCH_RESULTS)
: l10n_util::GetNSString(IDS_HISTORY_NO_RESULTS);
messageColor = TextItemColorBlack;
: nil;
} else if (self.shouldShowNoticeAboutOtherFormsOfBrowsingHistory &&
!self.searchController.isActive) {
!self.searchInProgress) {
messageText =
l10n_util::GetNSString(IDS_IOS_HISTORY_OTHER_FORMS_OF_HISTORY);
messageColor = TextItemColorLightGrey;
}
// Get the number of items currently at the StatusMessageSection.
......@@ -624,7 +622,6 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
if ([messageText isEqualToString:oldEntriesStatusTextItem.text])
return;
oldEntriesStatusTextItem.text = messageText;
oldEntriesStatusTextItem.textColor = messageColor;
NSIndexPath* statusMessageIndexPath = [self.tableViewModel
indexPathForItemType:ItemTypeEntriesStatus
sectionIdentifier:kEntriesStatusSectionIdentifier];
......@@ -635,7 +632,6 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
TableViewTextItem* entriesStatusItem =
[[TableViewTextItem alloc] initWithType:ItemTypeEntriesStatus];
entriesStatusItem.text = messageText;
entriesStatusItem.textColor = messageColor;
[self.tableViewModel addItem:entriesStatusItem
toSectionWithIdentifier:kEntriesStatusSectionIdentifier];
NSIndexPath* statusMessageIndexPath =
......@@ -697,12 +693,6 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
}
}
// Adds loading indicator to the top of the history tableView, if one is not
// already present.
- (void)addLoadingIndicator {
// TODO(crbug.com/805190): Migrate.
}
#pragma mark Navigation Toolbar Configuration
// Animates the view configuration after flipping the current status of |[self
......
......@@ -429,6 +429,7 @@ id<GREYMatcher> ConfirmClearBrowsingDataButton() {
// Navigates to history and checks elements for accessibility.
- (void)testAccessibilityOnHistory {
[self loadTestURLs];
[self openHistoryPanel];
chrome_test_util::VerifyAccessibilityForCurrentScreen();
// Close history.
......@@ -461,17 +462,27 @@ id<GREYMatcher> ConfirmClearBrowsingDataButton() {
}
- (void)assertNoHistoryShown {
id<GREYMatcher> noHistoryMessageMatcher =
grey_allOf(grey_text(l10n_util::GetNSString(IDS_HISTORY_NO_RESULTS)),
grey_sufficientlyVisible(), nil);
[[EarlGrey selectElementWithMatcher:noHistoryMessageMatcher]
assertWithMatcher:grey_notNil()];
if (IsUIRefreshPhase1Enabled()) {
// TODO(crbug.com/838579): Add empty table matcher once its implemented.
id<GREYMatcher> historyEntryMatcher =
grey_allOf(grey_kindOfClass([TableViewURLCell class]),
grey_sufficientlyVisible(), nil);
[[EarlGrey selectElementWithMatcher:historyEntryMatcher]
assertWithMatcher:grey_nil()];
id<GREYMatcher> historyEntryMatcher =
grey_allOf(grey_kindOfClass([LegacyHistoryEntryCell class]),
grey_sufficientlyVisible(), nil);
[[EarlGrey selectElementWithMatcher:historyEntryMatcher]
assertWithMatcher:grey_nil()];
} else {
id<GREYMatcher> noHistoryMessageMatcher =
grey_allOf(grey_text(l10n_util::GetNSString(IDS_HISTORY_NO_RESULTS)),
grey_sufficientlyVisible(), nil);
[[EarlGrey selectElementWithMatcher:noHistoryMessageMatcher]
assertWithMatcher:grey_notNil()];
id<GREYMatcher> historyEntryMatcher =
grey_allOf(grey_kindOfClass([LegacyHistoryEntryCell class]),
grey_sufficientlyVisible(), nil);
[[EarlGrey selectElementWithMatcher:historyEntryMatcher]
assertWithMatcher:grey_nil()];
}
}
- (void)resetBrowsingDataPrefs {
......
......@@ -20,6 +20,7 @@ source_set("table_view") {
deps = [
":presentation",
":styler",
":views",
"//base",
"//ios/chrome/browser/ui/list_model",
"//ios/chrome/browser/ui/material_components",
......@@ -59,6 +60,21 @@ source_set("presentation") {
]
}
source_set("views") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
"table_view_loading_view.h",
"table_view_loading_view.mm",
]
deps = [
"//base",
"//ios/chrome/browser/ui",
"//ios/chrome/browser/ui/colors",
"//ios/chrome/browser/ui/material_components",
"//ios/third_party/material_components_ios",
]
}
source_set("unit_tests") {
configs += [ "//build/config/compiler:enable_arc" ]
testonly = true
......
......@@ -7,6 +7,7 @@
#import <UIKit/UIKit.h>
#include "base/ios/block_types.h"
#import "ios/chrome/browser/ui/material_components/app_bar_presenting.h"
#import "ios/chrome/browser/ui/table_view/chrome_table_view_consumer.h"
#import "ios/chrome/browser/ui/table_view/table_view_model.h"
......@@ -49,6 +50,14 @@ typedef NS_ENUM(NSInteger, ChromeTableViewControllerStyle) {
// override this method in order to get a clean tableViewModel.
- (void)loadModel NS_REQUIRES_SUPER;
// Adds and starts a loading indicator in the center of the
// ChromeTableViewController, if one is not already present. This will remove
// any existing table view background views.
- (void)startLoadingIndicatorWithLoadingMessage:(NSString*)loadingMessage;
// Removes and stops the loading indicator, if one is present.
- (void)stopLoadingIndicatorWithCompletion:(ProceduralBlock)completion;
// Methods for reconfiguring and reloading the table view are provided by
// ChromeTableViewConsumer.
......
......@@ -9,6 +9,7 @@
#import "ios/chrome/browser/ui/table_view/cells/table_view_header_footer_item.h"
#import "ios/chrome/browser/ui/table_view/cells/table_view_item.h"
#import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
#import "ios/chrome/browser/ui/table_view/table_view_loading_view.h"
#import "ios/chrome/browser/ui/table_view/table_view_model.h"
#import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h"
......@@ -16,8 +17,15 @@
#error "This file requires ARC support."
#endif
@interface ChromeTableViewController ()
// The loading view that will be displayed for [self
// startLoadingIndicatorWithLoadingMessage].
@property(nonatomic, strong) TableViewLoadingView* loadingView;
@end
@implementation ChromeTableViewController
@synthesize appBar = _appBar;
@synthesize loadingView = _loadingView;
@synthesize styler = _styler;
@synthesize tableViewModel = _tableViewModel;
......@@ -63,8 +71,6 @@
}
}
#pragma mark - ViewLifeCycle
- (void)viewDidLoad {
[super viewDidLoad];
......@@ -82,6 +88,29 @@
}
}
- (void)startLoadingIndicatorWithLoadingMessage:(NSString*)loadingMessage {
if (!self.loadingView) {
TableViewLoadingView* waitingView =
[[TableViewLoadingView alloc] initWithFrame:self.view.bounds
loadingMessage:loadingMessage];
self.loadingView = waitingView;
self.tableView.backgroundView = self.loadingView;
[self.loadingView startLoadingIndicator];
}
}
- (void)stopLoadingIndicatorWithCompletion:(ProceduralBlock)completion {
if (self.loadingView) {
[self.loadingView stopLoadingIndicatorWithCompletion:^{
if (completion)
completion();
[self.loadingView removeFromSuperview];
self.tableView.backgroundView = nil;
self.loadingView = nil;
}];
}
}
#pragma mark - UITableViewDataSource
- (UITableViewCell*)tableView:(UITableView*)tableView
......
// Copyright 2018 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.
#ifndef IOS_CHROME_BROWSER_UI_TABLE_VIEW_TABLE_VIEW_LOADING_VIEW_H_
#define IOS_CHROME_BROWSER_UI_TABLE_VIEW_TABLE_VIEW_LOADING_VIEW_H_
#import <UIKit/UIKit.h>
#include "base/ios/block_types.h"
// Displays an activity indicator with an optional message over a
// clearBackground.
@interface TableViewLoadingView : UIView
- (instancetype)initWithFrame:(CGRect)frame
loadingMessage:(NSString*)message NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
// Call this method when this view is added to the visible view hierarchy.
// An activity indicator will be presented if this view is still in the view
// hierarchy at that time.
- (void)startLoadingIndicator;
// Call this method when this view is removed from the visible view hierarchy.
// |completion| will be called when this view is done animating out, and can be
// nil.
- (void)stopLoadingIndicatorWithCompletion:(ProceduralBlock)completion;
@end
#endif // IOS_CHROME_BROWSER_UI_TABLE_VIEW_TABLE_VIEW_LOADING_VIEW_H_
// Copyright 2018 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/table_view/table_view_loading_view.h"
#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
#import "ios/chrome/browser/ui/material_components/activity_indicator.h"
#import "ios/chrome/browser/ui/rtl_geometry.h"
#import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// The MDCActivityIndicator radius.
const float kLoadingIndicatorRadius = 9.0;
// The StackView width.
const float kStackViewWidth = 227.0;
// The StackView vertical spacing.
const float kStackViewVerticalSpacing = 30.0;
}
@interface TableViewLoadingView ()<MDCActivityIndicatorDelegate>
// MDCActivityIndicator that will be displayed.
@property(nonatomic, retain) MDCActivityIndicator* activityIndicator;
// Completion block ran after |self.activityIndicator| stops.
@property(nonatomic, copy) ProceduralBlock animateOutCompletionBlock;
// Message being displayed along the activity indicator.
@property(nonatomic, copy) NSString* loadingMessage;
@end
@implementation TableViewLoadingView
@synthesize activityIndicator = _activityIndicator;
@synthesize animateOutCompletionBlock = _animateOutCompletionBlock;
@synthesize loadingMessage = _loadingMessage;
#pragma mark - Public Interface
- (instancetype)initWithFrame:(CGRect)frame {
return [self initWithFrame:frame loadingMessage:nil];
}
- (instancetype)initWithFrame:(CGRect)frame loadingMessage:(NSString*)message {
self = [super initWithFrame:frame];
if (self) {
self.loadingMessage = message;
}
return self;
}
- (void)startLoadingIndicator {
self.activityIndicator =
[[MDCActivityIndicator alloc] initWithFrame:CGRectZero];
self.activityIndicator.radius = kLoadingIndicatorRadius;
self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
self.activityIndicator.cycleColors =
@[ [[MDCPalette cr_bluePalette] tint500] ];
self.activityIndicator.delegate = self;
UILabel* messageLabel = [[UILabel alloc] init];
messageLabel.text = self.loadingMessage;
messageLabel.numberOfLines = 0;
messageLabel.lineBreakMode = NSLineBreakByWordWrapping;
messageLabel.textAlignment = NSTextAlignmentCenter;
messageLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
messageLabel.textColor = [UIColor grayColor];
// Vertical stack view that holds the activity indicator and message.
UIStackView* verticalStack = [[UIStackView alloc]
initWithArrangedSubviews:@[ self.activityIndicator, messageLabel ]];
verticalStack.axis = UILayoutConstraintAxisVertical;
verticalStack.spacing = kStackViewVerticalSpacing;
verticalStack.distribution = UIStackViewDistributionFill;
verticalStack.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:verticalStack];
[NSLayoutConstraint activateConstraints:@[
[verticalStack.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
[verticalStack.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
[verticalStack.widthAnchor constraintEqualToConstant:kStackViewWidth]
]];
[self.activityIndicator startAnimating];
}
- (void)stopLoadingIndicatorWithCompletion:(ProceduralBlock)completion {
if (self.activityIndicator) {
self.animateOutCompletionBlock = completion;
[self.activityIndicator stopAnimating];
} else if (completion) {
completion();
}
}
#pragma mark - MDCActivityIndicatorDelegate
- (void)activityIndicatorAnimationDidFinish:
(MDCActivityIndicator*)activityIndicator {
[self.activityIndicator removeFromSuperview];
self.activityIndicator = nil;
if (self.animateOutCompletionBlock)
self.animateOutCompletionBlock();
self.animateOutCompletionBlock = nil;
}
@end
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