Commit 663129e1 authored by sczs's avatar sczs Committed by Commit Bot

[ios] Creates TableViewEmptyView and adds it to History.

- Creates TableViewEmptyView class.
- Adds addEmptyTableViewWithMessage:image: to ChromeTableVC, these 2 methods add or remove a
TableViewEmptyView used to signal an empty state on the TableView.

Screenshot:
https://drive.google.com/open?id=1O17v-bVjJktj7bdlMBpVT8Ew-SdY8Mjn

Bug: 838579
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: Ifd9e69c1b187e1fffa9cc62f233777718481b57c
Reviewed-on: https://chromium-review.googlesource.com/1101827Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Commit-Queue: Sergio Collazos <sczs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#569651}
parent 2a7a2c2f
......@@ -112,6 +112,7 @@ source_set("history_ui") {
]
deps = [
"public",
"resources:empty_history",
"//base",
"//base:i18n",
"//components/browsing_data/core",
......
......@@ -237,19 +237,22 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
return;
}
// At this point there has been a response, we can stop the loading indicator.
// At this point there has been a response, 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) {
[self updateEntriesStatusMessage];
[self addEmptyTableViewWithMessage:l10n_util::GetNSString(
IDS_HISTORY_NO_RESULTS)
image:[UIImage imageNamed:@"empty_history"]];
[self updateToolbarButtons];
return;
}
self.finishedLoading = queryResultsInfo.reached_beginning;
self.empty = NO;
[self removeEmptyTableView];
// Header section should be updated outside of batch updates, otherwise
// loading indicator removal will not be observed.
......@@ -595,6 +598,9 @@ const CGFloat kSeparationSpaceBetweenSections = 9;
// If only the header section remains, there are no history entries.
if ([self.tableViewModel numberOfSections] == 1) {
self.empty = YES;
[self addEmptyTableViewWithMessage:l10n_util::GetNSString(
IDS_HISTORY_NO_RESULTS)
image:[UIImage imageNamed:@"empty_history"]];
}
[self updateEntriesStatusMessage];
[self updateToolbarButtons];
......
......@@ -462,21 +462,19 @@ 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()];
} 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);
......
# 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("//build/config/ios/asset_catalog.gni")
imageset("empty_history") {
sources = [
"empty_history.imageset/Contents.json",
"empty_history.imageset/empty_history.png",
"empty_history.imageset/empty_history@2x.png",
"empty_history.imageset/empty_history@3x.png",
]
}
{
"images": [
{
"idiom": "universal",
"scale": "1x",
"filename": "empty_history.png"
},
{
"idiom": "universal",
"scale": "2x",
"filename": "empty_history@2x.png"
},
{
"idiom": "universal",
"scale": "3x",
"filename": "empty_history@3x.png"
}
],
"info": {
"version": 1,
"author": "xcode"
}
}
......@@ -63,6 +63,8 @@ source_set("presentation") {
source_set("views") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
"table_view_empty_view.h",
"table_view_empty_view.mm",
"table_view_loading_view.h",
"table_view_loading_view.mm",
]
......
......@@ -58,6 +58,14 @@ typedef NS_ENUM(NSInteger, ChromeTableViewControllerStyle) {
// Removes and stops the loading indicator, if one is present.
- (void)stopLoadingIndicatorWithCompletion:(ProceduralBlock)completion;
// Adds an empty table view in the center of the ChromeTableViewController which
// displays |message| with |image| on top. This will remove any existing table
// view background views.
- (void)addEmptyTableViewWithMessage:(NSString*)message image:(UIImage*)image;
// Removes the empty table view, if one is present.
- (void)removeEmptyTableView;
// 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_empty_view.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"
......@@ -18,13 +19,15 @@
#endif
@interface ChromeTableViewController ()
// The loading view that will be displayed for [self
// startLoadingIndicatorWithLoadingMessage].
// The loading displayed by [self startLoadingIndicatorWithLoadingMessage:].
@property(nonatomic, strong) TableViewLoadingView* loadingView;
// The view displayed by [self addEmptyTableViewWithMessage:].
@property(nonatomic, strong) TableViewEmptyView* emptyView;
@end
@implementation ChromeTableViewController
@synthesize appBar = _appBar;
@synthesize emptyView = _emptyView;
@synthesize loadingView = _loadingView;
@synthesize styler = _styler;
@synthesize tableViewModel = _tableViewModel;
......@@ -90,12 +93,13 @@
- (void)startLoadingIndicatorWithLoadingMessage:(NSString*)loadingMessage {
if (!self.loadingView) {
TableViewLoadingView* waitingView =
self.loadingView =
[[TableViewLoadingView alloc] initWithFrame:self.view.bounds
loadingMessage:loadingMessage];
self.loadingView = waitingView;
self.tableView.backgroundView = self.loadingView;
[self.loadingView startLoadingIndicator];
// Since this would replace any emptyView, set it to nil.
self.emptyView = nil;
}
}
......@@ -105,12 +109,36 @@
if (completion)
completion();
[self.loadingView removeFromSuperview];
// Check that the tableView.backgroundView hasn't been modified
// before its removed.
DCHECK(self.tableView.backgroundView == self.loadingView);
self.tableView.backgroundView = nil;
self.loadingView = nil;
}];
}
}
- (void)addEmptyTableViewWithMessage:(NSString*)message image:(UIImage*)image {
if (!self.emptyView) {
self.emptyView = [[TableViewEmptyView alloc] initWithFrame:self.view.bounds
message:message
image:image];
self.tableView.backgroundView = self.emptyView;
// Since this would replace any loadingView, set it to nil.
self.loadingView = nil;
}
}
- (void)removeEmptyTableView {
if (self.emptyView) {
// Check that the tableView.backgroundView hasn't been modified
// before its removed.
DCHECK(self.tableView.backgroundView == self.emptyView);
self.tableView.backgroundView = nil;
self.emptyView = 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_EMPTY_VIEW_H_
#define IOS_CHROME_BROWSER_UI_TABLE_VIEW_TABLE_VIEW_EMPTY_VIEW_H_
#import <UIKit/UIKit.h>
// Displays an UIImage on top of a message over a clearBackground.
@interface TableViewEmptyView : UIView
// Designated initializer.
- (instancetype)initWithFrame:(CGRect)frame
message:(NSString*)message
image:(UIImage*)image NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
@end
#endif // IOS_CHROME_BROWSER_UI_TABLE_VIEW_TABLE_VIEW_EMPTY_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_empty_view.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// The StackView vertical spacing.
const float kStackViewVerticalSpacing = 23.0;
// The StackView width.
const float kStackViewWidth = 227.0;
}
@interface TableViewEmptyView ()
// The message that will be displayed.
@property(nonatomic, copy) NSString* message;
// The image that will be displayed.
@property(nonatomic, strong) UIImage* image;
@end
@implementation TableViewEmptyView
@synthesize message = _message;
@synthesize image = _image;
- (instancetype)initWithFrame:(CGRect)frame
message:(NSString*)message
image:(UIImage*)image {
self = [super initWithFrame:frame];
if (self) {
self.message = message;
self.image = image;
}
return self;
}
- (void)willMoveToSuperview:(UIView*)newSuperview {
// Return if the subviews have already been created and added.
if (!(self.subviews.count == 0))
return;
UIImageView* imageView = [[UIImageView alloc] initWithImage:self.image];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = YES;
UILabel* messageLabel = [[UILabel alloc] init];
messageLabel.text = self.message;
messageLabel.numberOfLines = 0;
messageLabel.lineBreakMode = NSLineBreakByWordWrapping;
messageLabel.textAlignment = NSTextAlignmentCenter;
messageLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
messageLabel.textColor = [UIColor grayColor];
// Vertical stack view that holds the image and message.
UIStackView* verticalStack = [[UIStackView alloc]
initWithArrangedSubviews:@[ imageView, 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]
]];
}
@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