Commit 0a9fafbb authored by sczs's avatar sczs Committed by Commit Bot

[ios] Adds RecentTabsVC TableViewModel support.

Deletes old table view DataSource implementation and creates a TableViewModel instead.
Moves Item/Cell configuration logic from recent_tabs/views/ into the VC.
Some helper methods are being re-used.


Screenshots:
https://drive.google.com/open?id=1n-IYyIffatHC2ok9fnvyIRhqH6rLADuh
https://drive.google.com/open?id=14NuWwnYFncYfijRpjIuy8kQ-EDYuIze6

Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: If997fb74862d135ff68e2b4aafd930d90f13f159
Reviewed-on: https://chromium-review.googlesource.com/954227
Commit-Queue: Sergio Collazos <sczs@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542239}
parent 1ff872df
...@@ -33,6 +33,7 @@ source_set("recent_tabs") { ...@@ -33,6 +33,7 @@ source_set("recent_tabs") {
"//base", "//base",
"//components/browser_sync", "//components/browser_sync",
"//components/sessions", "//components/sessions",
"//components/strings",
"//components/sync", "//components/sync",
"//ios/chrome/app/strings", "//ios/chrome/app/strings",
"//ios/chrome/app/theme", "//ios/chrome/app/theme",
......
...@@ -9,10 +9,11 @@ ...@@ -9,10 +9,11 @@
#include "base/metrics/user_metrics_action.h" #include "base/metrics/user_metrics_action.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "components/browser_sync/profile_sync_service.h" #include "components/browser_sync/profile_sync_service.h"
#include "components/sessions/core/tab_restore_service.h"
#include "components/strings/grit/components_strings.h"
#include "components/sync/driver/sync_service.h" #include "components/sync/driver/sync_service.h"
#include "components/sync_sessions/open_tabs_ui_delegate.h" #include "components/sync_sessions/open_tabs_ui_delegate.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/experimental_flags.h"
#import "ios/chrome/browser/metrics/new_tab_page_uma.h" #import "ios/chrome/browser/metrics/new_tab_page_uma.h"
#include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.h" #include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.h"
#include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios_factory.h" #include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios_factory.h"
...@@ -28,24 +29,16 @@ ...@@ -28,24 +29,16 @@
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h" #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_handset_view_controller.h" #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_handset_view_controller.h"
#include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h" #include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/header_of_collapsable_section_protocol.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/show_full_history_view.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_in_progress_view.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_on_no_sessions_view.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/spacers_view.h"
#import "ios/chrome/browser/ui/settings/sync_utils/sync_presenter.h" #import "ios/chrome/browser/ui/settings/sync_utils/sync_presenter.h"
#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_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" #include "ios/chrome/browser/ui/ui_util.h"
#import "ios/chrome/browser/ui/url_loader.h" #import "ios/chrome/browser/ui/url_loader.h"
#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
#import "ios/chrome/browser/ui/util/top_view_controller.h" #import "ios/chrome/browser/ui/util/top_view_controller.h"
#include "ios/chrome/grit/ios_chromium_strings.h" #include "ios/chrome/grit/ios_chromium_strings.h"
#include "ios/chrome/grit/ios_strings.h" #include "ios/chrome/grit/ios_strings.h"
#include "ios/web/public/referrer.h"
#import "ios/web/public/web_state/context_menu_params.h" #import "ios/web/public/web_state/context_menu_params.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
...@@ -55,40 +48,34 @@ ...@@ -55,40 +48,34 @@
namespace { namespace {
typedef NS_ENUM(NSInteger, SectionIdentifier) {
SectionIdentifierRecentlyClosedTabs = kSectionIdentifierEnumZero,
SectionIdentifierOtherDevices,
// The first SessionsSectionIdentifier index.
kFirstSessionSectionIdentifier,
};
typedef NS_ENUM(NSInteger, ItemType) {
ItemTypeRecentlyClosedHeader = kItemTypeEnumZero,
ItemTypeRecentlyClosed,
ItemTypeOtherDevicesHeader,
ItemTypeOtherDevicesSyncOff,
ItemTypeOtherDevicesNoSessions,
ItemTypeOtherDevicesSigninPromo,
ItemTypeOtherDevicesSyncInProgress,
ItemTypeSessionHeader,
ItemTypeSessionTabData,
ItemTypeShowFullHistory,
};
// Key for saving whether the Other Device section is collapsed. // Key for saving whether the Other Device section is collapsed.
NSString* const kOtherDeviceCollapsedKey = @"OtherDevicesCollapsed"; NSString* const kOtherDeviceCollapsedKey = @"OtherDevicesCollapsed";
// Key for saving whether the Recently Closed section is collapsed. // Key for saving whether the Recently Closed section is collapsed.
NSString* const kRecentlyClosedCollapsedKey = @"RecentlyClosedCollapsed"; NSString* const kRecentlyClosedCollapsedKey = @"RecentlyClosedCollapsed";
// There are 2 static sections before the first SessionSection.
// Tag to extract the section headers from the cells. int const kNumberOfSectionsBeforeSessions = 2;
enum { kSectionHeader = 1 }; // Estimated Table Row height.
const CGFloat kEstimatedRowHeight = 56;
// Margin at the top of the sigin-in promo view.
const CGFloat kSigninPromoViewTopMargin = 24;
// Types of sections.
enum SectionType {
SEPARATOR_SECTION,
CLOSED_TAB_SECTION,
OTHER_DEVICES_SECTION,
SESSION_SECTION,
};
// Types of cells.
enum CellType {
CELL_CLOSED_TAB_SECTION_HEADER,
CELL_CLOSED_TAB_DATA,
CELL_SHOW_FULL_HISTORY,
CELL_SEPARATOR,
CELL_OTHER_DEVICES_SECTION_HEADER,
CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF,
CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS,
CELL_OTHER_DEVICES_SIGNIN_PROMO,
CELL_OTHER_DEVICES_SYNC_IN_PROGRESS,
CELL_SESSION_SECTION_HEADER,
CELL_SESSION_TAB_DATA,
};
} // namespace } // namespace
...@@ -120,14 +107,9 @@ enum CellType { ...@@ -120,14 +107,9 @@ enum CellType {
#pragma mark - Public Interface #pragma mark - Public Interface
- (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState - (instancetype)init {
loader:(id<UrlLoader>)loader
dispatcher:(id<ApplicationCommands>)dispatcher {
self = [super initWithStyle:UITableViewStylePlain]; self = [super initWithStyle:UITableViewStylePlain];
if (self) { if (self) {
_dispatcher = dispatcher;
_loader = loader;
_browserState = browserState;
_sessionState = SessionsSyncUserState::USER_SIGNED_OUT; _sessionState = SessionsSyncUserState::USER_SIGNED_OUT;
_syncedSessions.reset(new synced_sessions::SyncedSessions()); _syncedSessions.reset(new synced_sessions::SyncedSessions());
} }
...@@ -140,14 +122,14 @@ enum CellType { ...@@ -140,14 +122,14 @@ enum CellType {
- (void)viewDidLoad { - (void)viewDidLoad {
[super viewDidLoad]; [super viewDidLoad];
[self loadModel];
self.view.accessibilityIdentifier = self.view.accessibilityIdentifier =
kRecentTabsTableViewControllerAccessibilityIdentifier; kRecentTabsTableViewControllerAccessibilityIdentifier;
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight =
[SessionTabDataView desiredHeightInUITableViewCell];
[self.tableView setSeparatorColor:[UIColor clearColor]];
[self.tableView setDataSource:self];
[self.tableView setDelegate:self]; [self.tableView setDelegate:self];
self.tableView.estimatedRowHeight = kEstimatedRowHeight;
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedSectionHeaderHeight = kEstimatedRowHeight;
self.tableView.sectionFooterHeight = 0.0;
UILongPressGestureRecognizer* longPress = UILongPressGestureRecognizer* longPress =
[[UILongPressGestureRecognizer alloc] [[UILongPressGestureRecognizer alloc]
initWithTarget:self initWithTarget:self
...@@ -156,91 +138,360 @@ enum CellType { ...@@ -156,91 +138,360 @@ enum CellType {
[self.tableView addGestureRecognizer:longPress]; [self.tableView addGestureRecognizer:longPress];
} }
- (SectionType)sectionType:(NSInteger)section { #pragma mark - TableViewModel
if (section == 0) {
return CLOSED_TAB_SECTION; - (void)loadModel {
} [super loadModel];
if (section == 1) { [self addRecentlyClosedSection];
return SEPARATOR_SECTION;
} // The other Devices header section is always present regardless if it has any
if (section < [self numberOfSectionsBeforeSessionOrOtherDevicesSections]) { // items or not.
return CLOSED_TAB_SECTION; [self addOtherDevicesSectionHeader];
}
if (self.sessionState == if (self.sessionState ==
SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) { SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) {
return SESSION_SECTION; [self addSessionSections];
} else {
[self addOtherDevicesItemForState:self.sessionState];
} }
// Other cases of recent_tabs::USER_SIGNED_IN_SYNC_OFF, }
// recent_tabs::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS, and
// recent_tabs::USER_SIGNED_OUT falls through to here. #pragma mark Recently Closed Section
return OTHER_DEVICES_SECTION;
} - (void)addRecentlyClosedSection {
TableViewModel* model = self.tableViewModel;
- (CellType)cellType:(NSIndexPath*)indexPath {
SectionType sectionType = [self sectionType:indexPath.section]; // Recently Closed Section.
switch (sectionType) { [model addSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs];
case CLOSED_TAB_SECTION: TableViewTextHeaderFooterItem* header = [[TableViewTextHeaderFooterItem alloc]
if (indexPath.row == 0) { initWithType:ItemTypeRecentlyClosedHeader];
return CELL_CLOSED_TAB_SECTION_HEADER; header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_RECENTLY_CLOSED);
} [model setHeader:header
// The last cell of the section is to access the history panel. forSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs];
if (indexPath.row ==
[self numberOfCellsInRecentlyClosedTabsSection] - 1) { // Add Recently Closed Tabs Cells.
return CELL_SHOW_FULL_HISTORY; [self addRecentlyClosedTabItems];
}
return CELL_CLOSED_TAB_DATA; // Add show full history item last.
case SEPARATOR_SECTION: TableViewURLItem* historyItem =
return CELL_SEPARATOR; [[TableViewURLItem alloc] initWithType:ItemTypeShowFullHistory];
case SESSION_SECTION: historyItem.title = l10n_util::GetNSString(IDS_HISTORY_SHOWFULLHISTORY_LINK);
if (indexPath.row == 0) { historyItem.favicon = [UIImage imageNamed:@"ntp_opentabs_clock"];
return CELL_SESSION_SECTION_HEADER; [model addItem:historyItem
} toSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs];
return CELL_SESSION_TAB_DATA; }
case OTHER_DEVICES_SECTION:
if (self.sessionState == - (void)addRecentlyClosedTabItems {
SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS) { if (!self.tabRestoreService)
return CELL_OTHER_DEVICES_SYNC_IN_PROGRESS; return;
}
if (indexPath.row == 0) { // Note that std:list<> can only be accessed sequentially, which is
return CELL_OTHER_DEVICES_SECTION_HEADER; // suboptimal when using Cocoa table APIs. This list doesn't appear
// to get very long, so it probably won't matter for perf.
for (auto iter = self.tabRestoreService->entries().begin();
iter != self.tabRestoreService->entries().end(); ++iter) {
DCHECK(iter->get());
const sessions::TabRestoreService::Entry* entry = iter->get();
DCHECK(entry);
// Use the page's title for the label, or its URL if title is empty.
NSString* entryTitle;
NSString* entryURL = @"";
GURL entryGURL;
switch (entry->type) {
case sessions::TabRestoreService::TAB: {
const sessions::TabRestoreService::Tab* tab =
static_cast<const sessions::TabRestoreService::Tab*>(entry);
const sessions::SerializedNavigationEntry& entry =
tab->navigations[tab->current_navigation_index];
// Use the page's title for the label, or its URL if title is empty.
if (entry.title().size()) {
entryTitle = base::SysUTF16ToNSString(entry.title());
entryURL = base::SysUTF8ToNSString(entry.virtual_url().spec());
} else {
entryTitle = base::SysUTF8ToNSString(entry.virtual_url().spec());
}
entryGURL = entry.virtual_url();
break;
} }
switch (self.sessionState) { case sessions::TabRestoreService::WINDOW: {
case SessionsSyncUserState::USER_SIGNED_OUT: // Only TAB type is handled.
return CELL_OTHER_DEVICES_SIGNIN_PROMO; entryTitle = @"Window type - NOTIMPLEMENTED";
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF: break;
return CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF;
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS:
return CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS;
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS:
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS:
NOTREACHED();
// These cases should never occur. Still, this method needs to
// return _something_, so it's returning the least wrong cell type.
return CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS;
} }
}
// Configure and add the Item.
TableViewURLItem* recentlyClosedTab =
[[TableViewURLItem alloc] initWithType:ItemTypeRecentlyClosed];
recentlyClosedTab.favicon = [UIImage imageNamed:@"default_favicon"];
recentlyClosedTab.title = entryTitle;
recentlyClosedTab.URL = entryURL;
[self.tableViewModel addItem:recentlyClosedTab
toSectionWithIdentifier:SectionIdentifierRecentlyClosedTabs];
} }
} }
- (NSInteger)sectionIndexForSectionType:(SectionType)sectionType { #pragma mark Sessions Section
NSUInteger sectionCount = [self numberOfSectionsInTableView:self.tableView];
for (NSUInteger sectionIndex = 0; sectionIndex < sectionCount; // Cleans up the model in order to update the Session sections. Needs to be
++sectionIndex) { // called inside a [UITableView beginUpdates] block on iOS10, or
if ([self sectionType:sectionIndex] == sectionType) // performBatchUpdates on iOS11+.
return sectionIndex; - (void)updateSessionSections {
SessionsSyncUserState previousState = self.sessionState;
if (previousState !=
SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) {
// The previous state was one of the OtherDevices states, remove it to clean
// it up and re-add just the header.
[self.tableViewModel
removeSectionWithIdentifier:SectionIdentifierOtherDevices];
[self addOtherDevicesSectionHeader];
// Reload the TableViews section.
[self.tableView reloadSections:[self otherDevicesSectionIndexSet]
withRowAnimation:UITableViewRowAnimationNone];
}
// Clean up any previously added SessionSections.
[self removeSessionSections];
// Re-Add the session sections to |self.tableViewModel| and insert them into
// |self.tableView|.
[self addSessionSections];
[self.tableView insertSections:[self sessionSectionIndexSet]
withRowAnimation:UITableViewRowAnimationNone];
}
// Adds all the Remote Sessions sections with its respective items.
- (void)addSessionSections {
TableViewModel* model = self.tableViewModel;
for (NSUInteger i = 0; i < [self numberOfSessions]; i++) {
synced_sessions::DistantSession const* session =
_syncedSessions->GetSession(i);
NSInteger sessionIdentifier = [self sectionIdentifierForSession:session];
[model addSectionWithIdentifier:sessionIdentifier];
TableViewTextHeaderFooterItem* header =
[[TableViewTextHeaderFooterItem alloc]
initWithType:ItemTypeSessionHeader];
header.text = base::SysUTF8ToNSString(session->name);
[model setHeader:header forSectionWithIdentifier:sessionIdentifier];
[self addItemsForSession:session];
} }
return NSNotFound;
} }
- (NSInteger)numberOfSectionsBeforeSessionOrOtherDevicesSections { - (void)addItemsForSession:(synced_sessions::DistantSession const*)session {
// The 2 sections are CLOSED_TAB_SECTION and SEPARATOR_SECTION. TableViewModel* model = self.tableViewModel;
return 2; NSInteger numberOfTabs = static_cast<NSInteger>(session->tabs.size());
for (int i = 0; i < numberOfTabs; i++) {
synced_sessions::DistantTab const* sessionTab = session->tabs[i].get();
NSString* title = base::SysUTF16ToNSString(sessionTab->title);
GURL url = sessionTab->virtual_url;
TableViewURLItem* sessionTabItem =
[[TableViewURLItem alloc] initWithType:ItemTypeSessionTabData];
sessionTabItem.favicon = [UIImage imageNamed:@"default_favicon"];
sessionTabItem.title = title;
sessionTabItem.URL = base::SysUTF8ToNSString(url.host());
[model addItem:sessionTabItem
toSectionWithIdentifier:[self sectionIdentifierForSession:session]];
}
} }
- (void)dismissModals { // Remove all SessionSections from |self.tableViewModel| and |self.tableView|
[self.contextMenuCoordinator stop]; // Needs to be called inside a [UITableView beginUpdates] block on iOS10, or
// performBatchUpdates on iOS11+.
- (void)removeSessionSections {
// Get the numberOfSessionSections from |self.tableViewModel|, since
// |_syncedSessions| has been updated by now.
int numberOfSessionSections =
[self.tableViewModel numberOfSections] - kNumberOfSectionsBeforeSessions;
for (int i = 0; i < numberOfSessionSections; i++) {
[self.tableView
deleteSections:[NSIndexSet
indexSetWithIndex:i +
kNumberOfSectionsBeforeSessions]
withRowAnimation:UITableViewRowAnimationNone];
[self.tableViewModel
removeSectionWithIdentifier:i + kFirstSessionSectionIdentifier];
}
} }
#pragma mark - Recently closed tab helpers #pragma mark Other Devices Section
// Cleans up the model in order to update the Other devices section. Needs to be
// called inside a [UITableView beginUpdates] block on iOS10, or
// performBatchUpdates on iOS11+.
- (void)updateOtherDevicesSectionForState:(SessionsSyncUserState)newState {
TableViewModel* model = self.tableViewModel;
SessionsSyncUserState previousState = self.sessionState;
switch (previousState) {
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF:
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS:
case SessionsSyncUserState::USER_SIGNED_OUT:
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS:
// The OtherDevices section will be updated, remove it in order to clean
// it up. After the clean up add just the header.
[model removeSectionWithIdentifier:SectionIdentifierOtherDevices];
[self addOtherDevicesSectionHeader];
break;
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS:
// The Sessions Section exists, remove it.
[self removeSessionSections];
break;
}
// Add updated OtherDevices Item.
[self addOtherDevicesItemForState:newState];
// Update OtherDevices TableView Section.
[self.tableView reloadSections:[self otherDevicesSectionIndexSet]
withRowAnimation:UITableViewRowAnimationNone];
}
// Adds Other Devices Section and its header.
- (void)addOtherDevicesSectionHeader {
TableViewModel* model = self.tableViewModel;
[model addSectionWithIdentifier:SectionIdentifierOtherDevices];
TableViewTextHeaderFooterItem* header = [[TableViewTextHeaderFooterItem alloc]
initWithType:ItemTypeRecentlyClosedHeader];
header.text = l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OTHER_DEVICES);
[model setHeader:header
forSectionWithIdentifier:SectionIdentifierOtherDevices];
}
// Adds Other Devices item for |state|.
- (void)addOtherDevicesItemForState:(SessionsSyncUserState)state {
// Add item depending on |state|.
TableViewTextItem* dummyCell = nil;
switch (state) {
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS:
NOTREACHED();
return;
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF:
dummyCell =
[[TableViewTextItem alloc] initWithType:ItemTypeOtherDevicesSyncOff];
dummyCell.text =
l10n_util::GetNSString(IDS_IOS_OPEN_TABS_ENABLE_SYNC_MOBILE);
break;
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS:
dummyCell = [[TableViewTextItem alloc]
initWithType:ItemTypeOtherDevicesNoSessions];
dummyCell.text =
l10n_util::GetNSString(IDS_IOS_OPEN_TABS_NO_SESSION_INSTRUCTIONS);
break;
case SessionsSyncUserState::USER_SIGNED_OUT:
dummyCell = [[TableViewTextItem alloc]
initWithType:ItemTypeOtherDevicesSigninPromo];
dummyCell.text = l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_RECENT_TABS);
break;
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS:
dummyCell = [[TableViewTextItem alloc]
initWithType:ItemTypeOtherDevicesSyncInProgress];
dummyCell.text = @"Sync in progress";
}
[self.tableViewModel addItem:dummyCell
toSectionWithIdentifier:SectionIdentifierOtherDevices];
}
#pragma mark - TableViewModel Helpers
// Ordered array of all section identifiers.
- (NSArray*)allSessionSectionIdentifiers {
NSMutableArray* allSessionSectionIdentifiers = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < [self numberOfSessions]; i++) {
[allSessionSectionIdentifiers
addObject:@(i + kFirstSessionSectionIdentifier)];
}
return allSessionSectionIdentifiers;
}
// Returns the TableViewModel SectionIdentifier for |distantSession|. Returns -1
// if |distantSession| doesn't exists.
- (NSInteger)sectionIdentifierForSession:
(synced_sessions::DistantSession const*)distantSession {
for (NSUInteger i = 0; i < [self numberOfSessions]; i++) {
synced_sessions::DistantSession const* session =
_syncedSessions->GetSession(i);
if (session->tag == distantSession->tag)
return i + kFirstSessionSectionIdentifier;
}
NOTREACHED();
return -1;
}
// Returns an IndexSet containing the Other Devices Section.
- (NSIndexSet*)otherDevicesSectionIndexSet {
NSUInteger otherDevicesSection = [self.tableViewModel
sectionForSectionIdentifier:SectionIdentifierOtherDevices];
return [NSIndexSet indexSetWithIndex:otherDevicesSection];
}
// Returns an IndexSet containing the all the Session Sections.
- (NSIndexSet*)sessionSectionIndexSet {
// Create a range of all Session Sections.
NSRange rangeOfSessionSections =
NSMakeRange(kNumberOfSectionsBeforeSessions, [self numberOfSessions]);
NSIndexSet* sessionSectionIndexes =
[NSIndexSet indexSetWithIndexesInRange:rangeOfSessionSections];
return sessionSectionIndexes;
}
// Returns YES if |sectionIdentifier| is a Sessions sectionIdentifier.
- (BOOL)isSessionSectionIdentifier:(NSInteger)sectionIdentifier {
NSArray* sessionSectionIdentifiers = [self allSessionSectionIdentifiers];
NSNumber* sectionIdentifierObject = @(sectionIdentifier);
return [sessionSectionIdentifiers containsObject:sectionIdentifierObject];
}
#pragma mark - Consumer Protocol
- (void)refreshUserState:(SessionsSyncUserState)newSessionState {
if ((newSessionState == self.sessionState &&
self.sessionState !=
SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) ||
self.signinPromoViewMediator.isSigninInProgress) {
// No need to refresh the sections since all states other than
// USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS only have static content. This means
// that if the previous State is the same as the new one the static content
// won't change.
return;
}
syncer::SyncService* syncService =
IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState);
_syncedSessions.reset(new synced_sessions::SyncedSessions(syncService));
// Update the TableView and TableViewModel sections to match the new
// sessionState.
// Turn Off animations since UITableViewRowAnimationNone still animates.
[UIView setAnimationsEnabled:NO];
// If iOS11+ use performBatchUpdates: instead of begin/endUpdates.
if (@available(iOS 11, *)) {
if (newSessionState ==
SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) {
[self.tableView performBatchUpdates:^{
[self updateSessionSections];
}
completion:nil];
} else {
[self.tableView performBatchUpdates:^{
[self updateOtherDevicesSectionForState:newSessionState];
}
completion:nil];
}
} else {
[self.tableView beginUpdates];
if (newSessionState ==
SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) {
[self updateSessionSections];
} else {
[self updateOtherDevicesSectionForState:newSessionState];
}
[self.tableView endUpdates];
}
[UIView setAnimationsEnabled:YES];
self.sessionState = newSessionState;
if (self.sessionState != SessionsSyncUserState::USER_SIGNED_OUT) {
[self.signinPromoViewMediator signinPromoViewRemoved];
self.signinPromoViewMediator = nil;
}
}
- (void)refreshRecentlyClosedTabs { - (void)refreshRecentlyClosedTabs {
[self.tableView reloadData]; [self.tableView reloadData];
...@@ -250,22 +501,54 @@ enum CellType { ...@@ -250,22 +501,54 @@ enum CellType {
_tabRestoreService = tabRestoreService; _tabRestoreService = tabRestoreService;
} }
- (NSInteger)numberOfCellsInRecentlyClosedTabsSection { - (void)dismissModals {
// + 2 because of the section header, and the "Show full history" cell. [self.contextMenuCoordinator stop];
return [self numberOfRecentlyClosedTabs] + 2; }
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView*)tableView
didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
DCHECK_EQ(tableView, self.tableView);
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
NSInteger itemTypeSelected =
[self.tableViewModel itemTypeForIndexPath:indexPath];
switch (itemTypeSelected) {
case ItemTypeRecentlyClosed:
[self
openTabWithTabRestoreEntry:[self
tabRestoreEntryAtIndexPath:indexPath]];
break;
case ItemTypeSessionTabData:
[self
openTabWithContentOfDistantTab:[self
distantTabAtIndexPath:indexPath]];
break;
case ItemTypeShowFullHistory:
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[self showFullHistory];
break;
case ItemTypeOtherDevicesSyncOff:
case ItemTypeOtherDevicesNoSessions:
case ItemTypeOtherDevicesSigninPromo:
case ItemTypeOtherDevicesSyncInProgress:
break;
}
} }
#pragma mark - Recently closed tab helpers
- (NSInteger)numberOfRecentlyClosedTabs { - (NSInteger)numberOfRecentlyClosedTabs {
if (!self.tabRestoreService) if (!self.tabRestoreService)
return 0; return 0;
return static_cast<NSInteger>(self.tabRestoreService->entries().size()); return static_cast<NSInteger>(self.tabRestoreService->entries().size());
} }
- (const sessions::TabRestoreService::Entry*)tabRestoreEntryAtIndex: - (const sessions::TabRestoreService::Entry*)tabRestoreEntryAtIndexPath:
(NSIndexPath*)indexPath { (NSIndexPath*)indexPath {
DCHECK_EQ([self sectionType:indexPath.section], CLOSED_TAB_SECTION); DCHECK_EQ([self.tableViewModel sectionIdentifierForSection:indexPath.section],
// "- 1" because of the section header. SectionIdentifierRecentlyClosedTabs);
NSInteger index = indexPath.row - 1; NSInteger index = indexPath.row;
DCHECK_LE(index, [self numberOfRecentlyClosedTabs]); DCHECK_LE(index, [self numberOfRecentlyClosedTabs]);
if (!self.tabRestoreService) if (!self.tabRestoreService)
return nullptr; return nullptr;
...@@ -281,7 +564,52 @@ enum CellType { ...@@ -281,7 +564,52 @@ enum CellType {
return iter->get(); return iter->get();
} }
#pragma mark - Helpers to open tabs, or show the full history view. // TO IMPLEMENT. Remove this depending on which TableStyle we'll use.
- (CGFloat)tableView:(UITableView*)tableView
heightForFooterInSection:(NSInteger)section {
return 1.0;
}
#pragma mark - Distant Sessions helpers
- (NSUInteger)numberOfSessions {
if (!_syncedSessions)
return 0;
return _syncedSessions->GetSessionCount();
}
// Returns the Session Index for a given Session Tab |indexPath|.
- (size_t)indexOfSessionForTabAtIndexPath:(NSIndexPath*)indexPath {
DCHECK_EQ([self.tableViewModel itemTypeForIndexPath:indexPath],
ItemTypeSessionTabData);
// Get the sectionIdentifier for |indexPath|,
NSNumber* sectionIdentifierForIndexPath =
@([self.tableViewModel sectionIdentifierForSection:indexPath.section]);
// Get the index of this sectionIdentifier.
size_t indexOfSession = [[self allSessionSectionIdentifiers]
indexOfObject:sectionIdentifierForIndexPath];
DCHECK_LT(indexOfSession, _syncedSessions->GetSessionCount());
return indexOfSession;
}
- (synced_sessions::DistantSession const*)sessionForTabAtIndexPath:
(NSIndexPath*)indexPath {
return _syncedSessions->GetSession(
[self indexOfSessionForTabAtIndexPath:indexPath]);
}
- (synced_sessions::DistantTab const*)distantTabAtIndexPath:
(NSIndexPath*)indexPath {
DCHECK_EQ([self.tableViewModel itemTypeForIndexPath:indexPath],
ItemTypeSessionTabData);
size_t indexOfDistantTab = indexPath.row;
synced_sessions::DistantSession const* session =
[self sessionForTabAtIndexPath:indexPath];
DCHECK_LT(indexOfDistantTab, session->tabs.size());
return session->tabs[indexOfDistantTab].get();
}
#pragma mark - Navigation helpers
- (void)dismissRecentTabsModal { - (void)dismissRecentTabsModal {
[self.handsetCommandHandler dismissRecentTabsWithCompletion:nil]; [self.handsetCommandHandler dismissRecentTabsWithCompletion:nil];
...@@ -309,7 +637,7 @@ enum CellType { ...@@ -309,7 +637,7 @@ enum CellType {
DCHECK(entry); DCHECK(entry);
if (!entry) if (!entry)
return; return;
// We only handle the TAB type. // Only TAB type is handled.
if (entry->type != sessions::TabRestoreService::TAB) if (entry->type != sessions::TabRestoreService::TAB)
return; return;
TabRestoreServiceDelegateImplIOS* delegate = TabRestoreServiceDelegateImplIOS* delegate =
...@@ -324,16 +652,6 @@ enum CellType { ...@@ -324,16 +652,6 @@ enum CellType {
WindowOpenDisposition::CURRENT_TAB); WindowOpenDisposition::CURRENT_TAB);
} }
- (void)openTabWithURL:(const GURL&)url {
if (url.is_valid()) {
[self dismissRecentTabsModal];
[self.loader loadURL:url
referrer:web::Referrer()
transition:ui::PAGE_TRANSITION_TYPED
rendererInitiated:NO];
}
}
- (void)showFullHistory { - (void)showFullHistory {
__weak RecentTabsTableViewController* weakSelf = self; __weak RecentTabsTableViewController* weakSelf = self;
ProceduralBlock openHistory = ^{ ProceduralBlock openHistory = ^{
...@@ -343,79 +661,10 @@ enum CellType { ...@@ -343,79 +661,10 @@ enum CellType {
[self.handsetCommandHandler dismissRecentTabsWithCompletion:openHistory]; [self.handsetCommandHandler dismissRecentTabsWithCompletion:openHistory];
} }
#pragma mark - Handling of the collapsed sections. #pragma mark - Collapse sections
- (void)toggleExpansionOfSection:(NSInteger)sectionIndex { - (void)toggleExpansionOfSection:(NSInteger)sectionIndex {
NSString* sectionCollapseKey = nil; // TO IMPLEMENT!
int cellCount = 0;
SectionType section = [self sectionType:sectionIndex];
switch (section) {
case CLOSED_TAB_SECTION:
sectionCollapseKey = kRecentlyClosedCollapsedKey;
// - 1 because the header does not count.
cellCount = [self numberOfCellsInRecentlyClosedTabsSection] - 1;
break;
case SEPARATOR_SECTION:
NOTREACHED();
return;
case OTHER_DEVICES_SECTION:
cellCount = 1;
sectionCollapseKey = kOtherDeviceCollapsedKey;
break;
case SESSION_SECTION: {
size_t indexOfSession =
sectionIndex -
[self numberOfSectionsBeforeSessionOrOtherDevicesSections];
DCHECK_LT(indexOfSession, _syncedSessions->GetSessionCount());
synced_sessions::DistantSession const* distantSession =
_syncedSessions->GetSession(indexOfSession);
cellCount = distantSession->tabs.size();
sectionCollapseKey = [self keyForDistantSession:distantSession];
break;
}
}
DCHECK(sectionCollapseKey);
BOOL collapsed = ![self sectionIsCollapsed:sectionCollapseKey];
[self setSection:sectionCollapseKey collapsed:collapsed];
// Builds an array indexing all the cells needing to be removed or inserted to
// collapse/expand the section.
NSMutableArray* cellIndexPathsToDeleteOrInsert = [NSMutableArray array];
for (int i = 1; i <= cellCount; i++) {
NSIndexPath* tabIndexPath =
[NSIndexPath indexPathForRow:i inSection:sectionIndex];
[cellIndexPathsToDeleteOrInsert addObject:tabIndexPath];
}
// Update the table view.
[self.tableView beginUpdates];
if (collapsed) {
[self.tableView deleteRowsAtIndexPaths:cellIndexPathsToDeleteOrInsert
withRowAnimation:UITableViewRowAnimationFade];
} else {
[self.tableView insertRowsAtIndexPaths:cellIndexPathsToDeleteOrInsert
withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView endUpdates];
// Rotate disclosure icon.
NSIndexPath* sectionCellIndexPath =
[NSIndexPath indexPathForRow:0 inSection:sectionIndex];
UITableViewCell* sectionCell =
[self.tableView cellForRowAtIndexPath:sectionCellIndexPath];
UIView* subview = [sectionCell viewWithTag:kSectionHeader];
DCHECK([subview
conformsToProtocol:@protocol(HeaderOfCollapsableSectionProtocol)]);
id<HeaderOfCollapsableSectionProtocol> headerView =
static_cast<id<HeaderOfCollapsableSectionProtocol>>(subview);
[headerView setSectionIsCollapsed:collapsed animated:YES];
}
- (NSString*)keyForDistantSession:
(synced_sessions::DistantSession const*)distantSession {
return base::SysUTF8ToNSString(distantSession->tag);
} }
- (void)setSection:(NSString*)sectionKey collapsed:(BOOL)collapsed { - (void)setSection:(NSString*)sectionKey collapsed:(BOOL)collapsed {
...@@ -442,95 +691,6 @@ enum CellType { ...@@ -442,95 +691,6 @@ enum CellType {
return [value boolValue]; return [value boolValue];
} }
#pragma mark - Distant Sessions helpers
- (void)refreshUserState:(SessionsSyncUserState)newSessionState {
if ((newSessionState == self.sessionState &&
self.sessionState !=
SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) ||
self.signinPromoViewMediator.isSigninInProgress) {
// No need to refresh the sections.
return;
}
[self.tableView beginUpdates];
NSIndexSet* indexesToBeDeleted = [self sessionOrOtherDevicesSectionsIndexes];
[self.tableView deleteSections:indexesToBeDeleted
withRowAnimation:UITableViewRowAnimationFade];
syncer::SyncService* syncService =
IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState);
_syncedSessions.reset(new synced_sessions::SyncedSessions(syncService));
self.sessionState = newSessionState;
if (self.sessionState ==
SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS) {
// Expand the "Other Device" section once sync is finished.
[self setSection:kOtherDeviceCollapsedKey collapsed:NO];
}
NSIndexSet* indexesToBeInserted = [self sessionOrOtherDevicesSectionsIndexes];
[self.tableView insertSections:indexesToBeInserted
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
if (self.sessionState != SessionsSyncUserState::USER_SIGNED_OUT) {
[self.signinPromoViewMediator signinPromoViewRemoved];
self.signinPromoViewMediator = nil;
}
}
- (NSInteger)numberOfSessionSections {
DCHECK(self.sessionState ==
SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS);
return _syncedSessions->GetSessionCount();
}
- (NSIndexSet*)sessionOrOtherDevicesSectionsIndexes {
NSInteger sectionCount = 0;
switch (self.sessionState) {
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS:
sectionCount = [self numberOfSessionSections];
break;
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF:
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS:
case SessionsSyncUserState::USER_SIGNED_OUT:
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS:
sectionCount = 1;
break;
}
NSRange rangeOfSessionSections = NSMakeRange(
[self numberOfSectionsBeforeSessionOrOtherDevicesSections], sectionCount);
NSIndexSet* sessionSectionsIndexes =
[NSIndexSet indexSetWithIndexesInRange:rangeOfSessionSections];
return sessionSectionsIndexes;
}
- (size_t)indexOfSessionAtIndexPath:(NSIndexPath*)indexPath {
DCHECK_EQ([self sectionType:indexPath.section], SESSION_SECTION);
size_t indexOfSession =
indexPath.section -
[self numberOfSectionsBeforeSessionOrOtherDevicesSections];
DCHECK_LT(indexOfSession, _syncedSessions->GetSessionCount());
return indexOfSession;
}
- (synced_sessions::DistantSession const*)sessionAtIndexPath:
(NSIndexPath*)indexPath {
return _syncedSessions->GetSession(
[self indexOfSessionAtIndexPath:indexPath]);
}
- (synced_sessions::DistantTab const*)distantTabAtIndex:
(NSIndexPath*)indexPath {
DCHECK_EQ([self sectionType:indexPath.section], SESSION_SECTION);
// "- 1" because of the section header.
size_t indexOfDistantTab = indexPath.row - 1;
synced_sessions::DistantSession const* session =
[self sessionAtIndexPath:indexPath];
DCHECK_LT(indexOfDistantTab, session->tabs.size());
return session->tabs[indexOfDistantTab].get();
}
#pragma mark - Long press and context menus #pragma mark - Long press and context menus
- (void)handleLongPress:(UILongPressGestureRecognizer*)longPressGesture { - (void)handleLongPress:(UILongPressGestureRecognizer*)longPressGesture {
...@@ -543,8 +703,8 @@ enum CellType { ...@@ -543,8 +703,8 @@ enum CellType {
DCHECK_LE(indexPath.section, DCHECK_LE(indexPath.section,
[self numberOfSectionsInTableView:self.tableView]); [self numberOfSectionsInTableView:self.tableView]);
CellType cellType = [self cellType:indexPath]; NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
if (cellType != CELL_SESSION_SECTION_HEADER) { if ([self isSessionSectionIdentifier:itemType]) {
NOTREACHED(); NOTREACHED();
return; return;
} }
...@@ -590,8 +750,10 @@ enum CellType { ...@@ -590,8 +750,10 @@ enum CellType {
} }
- (void)openTabsFromSessionAtIndexPath:(NSIndexPath*)indexPath { - (void)openTabsFromSessionAtIndexPath:(NSIndexPath*)indexPath {
// TO-ADAPT.
return;
synced_sessions::DistantSession const* session = synced_sessions::DistantSession const* session =
[self sessionAtIndexPath:indexPath]; [self sessionForTabAtIndexPath:indexPath];
[self dismissRecentTabsModal]; [self dismissRecentTabsModal];
for (auto const& tab : session->tabs) { for (auto const& tab : session->tabs) {
[self.loader webPageOrderedOpen:tab->virtual_url [self.loader webPageOrderedOpen:tab->virtual_url
...@@ -602,15 +764,20 @@ enum CellType { ...@@ -602,15 +764,20 @@ enum CellType {
} }
- (void)removeSessionAtIndexPath:(NSIndexPath*)indexPath { - (void)removeSessionAtIndexPath:(NSIndexPath*)indexPath {
DCHECK_EQ([self cellType:indexPath], CELL_SESSION_SECTION_HEADER); // TO-ADAPT.
return;
DCHECK([self
isSessionSectionIdentifier:
[self.tableViewModel sectionIdentifierForSection:indexPath.section]]);
synced_sessions::DistantSession const* session = synced_sessions::DistantSession const* session =
[self sessionAtIndexPath:indexPath]; [self sessionForTabAtIndexPath:indexPath];
std::string sessionTagCopy = session->tag; std::string sessionTagCopy = session->tag;
syncer::SyncService* syncService = syncer::SyncService* syncService =
IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState); IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState);
sync_sessions::OpenTabsUIDelegate* openTabs = sync_sessions::OpenTabsUIDelegate* openTabs =
syncService->GetOpenTabsUIDelegate(); syncService->GetOpenTabsUIDelegate();
_syncedSessions->EraseSession([self indexOfSessionAtIndexPath:indexPath]); _syncedSessions->EraseSession(
[self indexOfSessionForTabAtIndexPath:indexPath]);
[self.tableView [self.tableView
deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]
withRowAnimation:UITableViewRowAnimationLeft]; withRowAnimation:UITableViewRowAnimationLeft];
...@@ -625,298 +792,18 @@ enum CellType { ...@@ -625,298 +792,18 @@ enum CellType {
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer {
CGPoint point = [gestureRecognizer locationInView:self.tableView]; CGPoint point = [gestureRecognizer locationInView:self.tableView];
NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:point]; // Context menus can be opened on a Session section header.
if (!indexPath) for (NSInteger section = 0; section < [self.tableViewModel numberOfSections];
return NO; section++) {
CellType cellType = [self cellType:indexPath]; NSInteger itemType =
// Context menus can be opened on a section header for tabs. [self.tableViewModel sectionIdentifierForSection:section];
return cellType == CELL_SESSION_SECTION_HEADER; if (CGRectContainsPoint([self.tableView rectForHeaderInSection:section],
} point) &&
[self isSessionSectionIdentifier:itemType]) {
#pragma mark - UITableViewDataSource return YES;
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {
switch (self.sessionState) {
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS:
return [self numberOfSectionsBeforeSessionOrOtherDevicesSections] +
[self numberOfSessionSections];
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF:
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS:
case SessionsSyncUserState::USER_SIGNED_OUT:
case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS:
return [self numberOfSectionsBeforeSessionOrOtherDevicesSections] + 1;
}
}
- (NSInteger)tableView:(UITableView*)tableView
numberOfRowsInSection:(NSInteger)section {
switch ([self sectionType:section]) {
case CLOSED_TAB_SECTION:
if ([self sectionIsCollapsed:kRecentlyClosedCollapsedKey])
return 1;
else
return [self numberOfCellsInRecentlyClosedTabsSection];
case SEPARATOR_SECTION:
return 1;
case OTHER_DEVICES_SECTION:
if (self.sessionState ==
SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS)
return 1;
if ([self sectionIsCollapsed:kOtherDeviceCollapsedKey])
return 1;
else
return 2;
case SESSION_SECTION: {
DCHECK(self.sessionState ==
SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS);
size_t sessionIndex =
section - [self numberOfSectionsBeforeSessionOrOtherDevicesSections];
DCHECK_LT(sessionIndex, _syncedSessions->GetSessionCount());
synced_sessions::DistantSession const* distantSession =
_syncedSessions->GetSession(sessionIndex);
NSString* key = [self keyForDistantSession:distantSession];
if ([self sectionIsCollapsed:key])
return 1;
else
return distantSession->tabs.size() + 1;
}
}
}
- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
UITableViewCell* cell =
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:nil];
UIView* contentView = cell.contentView;
CGFloat contentViewTopMargin = 0;
UIView* subview;
CellType cellType = [self cellType:indexPath];
switch (cellType) {
case CELL_CLOSED_TAB_SECTION_HEADER: {
BOOL collapsed = [self sectionIsCollapsed:kRecentlyClosedCollapsedKey];
subview = [[GenericSectionHeaderView alloc]
initWithType:recent_tabs::RECENTLY_CLOSED_TABS_SECTION_HEADER
sectionIsCollapsed:collapsed];
[subview setTag:kSectionHeader];
break;
}
case CELL_CLOSED_TAB_DATA: {
SessionTabDataView* genericTabData =
[[SessionTabDataView alloc] initWithFrame:CGRectZero];
[genericTabData
updateWithTabRestoreEntry:[self tabRestoreEntryAtIndex:indexPath]
browserState:self.browserState];
subview = genericTabData;
break;
}
case CELL_SHOW_FULL_HISTORY:
subview = [[ShowFullHistoryView alloc] initWithFrame:CGRectZero];
break;
case CELL_SEPARATOR:
subview = [[RecentlyClosedSectionFooter alloc] initWithFrame:CGRectZero];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
break;
case CELL_OTHER_DEVICES_SECTION_HEADER: {
BOOL collapsed = [self sectionIsCollapsed:kOtherDeviceCollapsedKey];
subview = [[GenericSectionHeaderView alloc]
initWithType:recent_tabs::OTHER_DEVICES_SECTION_HEADER
sectionIsCollapsed:collapsed];
[subview setTag:kSectionHeader];
break;
}
case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF:
subview = [[SignedInSyncOffView alloc] initWithFrame:CGRectZero
browserState:self.browserState
presenter:self];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
break;
case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS:
subview = [[SignedInSyncOnNoSessionsView alloc] initWithFrame:CGRectZero];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
break;
case CELL_OTHER_DEVICES_SIGNIN_PROMO: {
if (!self.signinPromoViewMediator) {
self.signinPromoViewMediator = [[SigninPromoViewMediator alloc]
initWithBrowserState:self.browserState
accessPoint:signin_metrics::AccessPoint::
ACCESS_POINT_RECENT_TABS
presenter:self /* id<SigninPresenter> */];
self.signinPromoViewMediator.consumer = self;
}
contentViewTopMargin = kSigninPromoViewTopMargin;
SigninPromoView* signinPromoView =
[[SigninPromoView alloc] initWithFrame:CGRectZero];
signinPromoView.delegate = self.signinPromoViewMediator;
signinPromoView.textLabel.text =
l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_RECENT_TABS);
signinPromoView.textLabel.preferredMaxLayoutWidth =
CGRectGetWidth(self.tableView.bounds) -
2 * signinPromoView.horizontalPadding;
SigninPromoViewConfigurator* configurator =
[self.signinPromoViewMediator createConfigurator];
[configurator configureSigninPromoView:signinPromoView];
subview = signinPromoView;
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
[self.signinPromoViewMediator signinPromoViewVisible];
break;
}
case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS:
subview = [[SignedInSyncInProgressView alloc] initWithFrame:CGRectZero];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
break;
case CELL_SESSION_SECTION_HEADER: {
synced_sessions::DistantSession const* distantSession =
[self sessionAtIndexPath:indexPath];
NSString* key = [self keyForDistantSession:distantSession];
BOOL collapsed = [self sectionIsCollapsed:key];
SessionSectionHeaderView* sessionSectionHeader =
[[SessionSectionHeaderView alloc] initWithFrame:CGRectZero
sectionIsCollapsed:collapsed];
[sessionSectionHeader updateWithSession:distantSession];
subview = sessionSectionHeader;
[subview setTag:kSectionHeader];
break;
} }
case CELL_SESSION_TAB_DATA: {
SessionTabDataView* genericTabData =
[[SessionTabDataView alloc] initWithFrame:CGRectZero];
[genericTabData updateWithDistantTab:[self distantTabAtIndex:indexPath]
browserState:self.browserState];
subview = genericTabData;
break;
}
}
DCHECK(subview);
[contentView addSubview:subview];
// Sets constraints on the subview.
[subview setTranslatesAutoresizingMaskIntoConstraints:NO];
NSDictionary* viewsDictionary = @{@"view" : subview};
// This set of constraints should match the constraints set on the
// RecentlyClosedSectionFooter.
// clang-format off
NSArray* constraints = @[
@"V:|-(TopMargin)-[view]-0-|",
@"H:|-(>=0)-[view(<=548)]-(>=0)-|",
@"H:[view(==548@500)]"
];
// clang-format on
[contentView addConstraint:[NSLayoutConstraint
constraintWithItem:subview
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:contentView
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0]];
NSDictionary* metrics = @{ @"TopMargin" : @(contentViewTopMargin) };
ApplyVisualConstraintsWithMetrics(constraints, viewsDictionary, metrics);
return cell;
}
#pragma mark - UITableViewDelegate
- (NSIndexPath*)tableView:(UITableView*)tableView
willSelectRowAtIndexPath:(NSIndexPath*)indexPath {
DCHECK_EQ(tableView, self.tableView);
CellType cellType = [self cellType:indexPath];
switch (cellType) {
case CELL_CLOSED_TAB_SECTION_HEADER:
case CELL_OTHER_DEVICES_SECTION_HEADER:
case CELL_SESSION_SECTION_HEADER:
case CELL_CLOSED_TAB_DATA:
case CELL_SESSION_TAB_DATA:
case CELL_SHOW_FULL_HISTORY:
return indexPath;
case CELL_SEPARATOR:
case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF:
case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS:
case CELL_OTHER_DEVICES_SIGNIN_PROMO:
case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS:
return nil;
}
}
- (void)tableView:(UITableView*)tableView
didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
DCHECK_EQ(tableView, self.tableView);
CellType cellType = [self cellType:indexPath];
switch (cellType) {
case CELL_CLOSED_TAB_SECTION_HEADER:
case CELL_OTHER_DEVICES_SECTION_HEADER:
case CELL_SESSION_SECTION_HEADER:
// Collapse or uncollapse section.
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[self toggleExpansionOfSection:indexPath.section];
break;
case CELL_CLOSED_TAB_DATA:
// Open new tab.
[self openTabWithTabRestoreEntry:[self tabRestoreEntryAtIndex:indexPath]];
break;
case CELL_SESSION_TAB_DATA:
// Open new tab.
[self openTabWithContentOfDistantTab:[self distantTabAtIndex:indexPath]];
break;
case CELL_SHOW_FULL_HISTORY:
[tableView deselectRowAtIndexPath:indexPath animated:NO];
[self showFullHistory];
break;
case CELL_SEPARATOR:
case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF:
case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS:
case CELL_OTHER_DEVICES_SIGNIN_PROMO:
case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS:
NOTREACHED();
break;
}
}
- (CGFloat)tableView:(UITableView*)tableView
heightForRowAtIndexPath:(NSIndexPath*)indexPath {
DCHECK_EQ(self.tableView, tableView);
CellType cellType = [self cellType:indexPath];
switch (cellType) {
case CELL_SHOW_FULL_HISTORY:
return [ShowFullHistoryView desiredHeightInUITableViewCell];
case CELL_SEPARATOR:
return [RecentlyClosedSectionFooter desiredHeightInUITableViewCell];
case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF:
return [SignedInSyncOffView desiredHeightInUITableViewCell];
case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS:
return [SignedInSyncOnNoSessionsView desiredHeightInUITableViewCell];
case CELL_OTHER_DEVICES_SIGNIN_PROMO:
return UITableViewAutomaticDimension;
case CELL_SESSION_SECTION_HEADER:
return [SessionSectionHeaderView desiredHeightInUITableViewCell];
case CELL_CLOSED_TAB_DATA:
case CELL_SESSION_TAB_DATA:
return [SessionTabDataView desiredHeightInUITableViewCell];
case CELL_CLOSED_TAB_SECTION_HEADER:
case CELL_OTHER_DEVICES_SECTION_HEADER:
return [GenericSectionHeaderView desiredHeightInUITableViewCell];
case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS:
return [SignedInSyncInProgressView desiredHeightInUITableViewCell];
}
}
- (UIView*)tableView:(UITableView*)tableView
viewForHeaderInSection:(NSInteger)section {
if ([self sectionType:section] == CLOSED_TAB_SECTION) {
return [[RecentlyTabsTopSpacingHeader alloc] initWithFrame:CGRectZero];
}
return nil;
}
- (CGFloat)tableView:(UITableView*)tableView
heightForHeaderInSection:(NSInteger)section {
if ([self sectionType:section] == CLOSED_TAB_SECTION) {
return [RecentlyTabsTopSpacingHeader desiredHeightInUITableViewCell];
} }
return 0; return NO;
} }
#pragma mark - SigninPromoViewConsumer #pragma mark - SigninPromoViewConsumer
...@@ -927,11 +814,9 @@ enum CellType { ...@@ -927,11 +814,9 @@ enum CellType {
DCHECK(self.signinPromoViewMediator); DCHECK(self.signinPromoViewMediator);
if ([self sectionIsCollapsed:kOtherDeviceCollapsedKey]) if ([self sectionIsCollapsed:kOtherDeviceCollapsedKey])
return; return;
NSInteger sectionIndex =
[self sectionIndexForSectionType:OTHER_DEVICES_SECTION];
DCHECK(sectionIndex != NSNotFound);
NSIndexPath* indexPath = NSIndexPath* indexPath =
[NSIndexPath indexPathForRow:1 inSection:sectionIndex]; [self.tableViewModel indexPathForItemType:ItemTypeOtherDevicesSigninPromo
sectionIdentifier:SectionIdentifierOtherDevices];
if (identityChanged) { if (identityChanged) {
[self.tableView reloadRowsAtIndexPaths:@[ indexPath ] [self.tableView reloadRowsAtIndexPaths:@[ indexPath ]
withRowAnimation:UITableViewRowAnimationNone]; withRowAnimation:UITableViewRowAnimationNone];
......
...@@ -31,6 +31,10 @@ const CGFloat kMargin = 16; ...@@ -31,6 +31,10 @@ const CGFloat kMargin = 16;
TableViewTextHeaderFooterView* header = TableViewTextHeaderFooterView* header =
base::mac::ObjCCastStrict<TableViewTextHeaderFooterView>(headerFooter); base::mac::ObjCCastStrict<TableViewTextHeaderFooterView>(headerFooter);
header.textLabel.text = self.text; header.textLabel.text = self.text;
// Set the contentView backgroundColor, not the header's.
header.contentView.backgroundColor = [UIColor whiteColor];
header.textLabel.font =
[UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
} }
@end @end
...@@ -46,7 +50,6 @@ const CGFloat kMargin = 16; ...@@ -46,7 +50,6 @@ const CGFloat kMargin = 16;
// Text Label, set font sizes using dynamic type. // Text Label, set font sizes using dynamic type.
_textLabel = [[UILabel alloc] init]; _textLabel = [[UILabel alloc] init];
_textLabel.translatesAutoresizingMaskIntoConstraints = NO; _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
_textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
// Container View. // Container View.
UIView* containerView = [[UIView alloc] init]; UIView* containerView = [[UIView alloc] init];
......
...@@ -21,6 +21,15 @@ ...@@ -21,6 +21,15 @@
_tableViewModel = [[TableViewModel alloc] init]; _tableViewModel = [[TableViewModel alloc] init];
} }
#pragma mark - ViewLifeCycle
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView setBackgroundColor:[UIColor whiteColor]];
[self.tableView setSeparatorColor:[UIColor grayColor]];
[self.tableView setSeparatorInset:UIEdgeInsetsMake(0, 56, 0, 0)];
}
#pragma mark - UITableViewDataSource #pragma mark - UITableViewDataSource
- (UITableViewCell*)tableView:(UITableView*)tableView - (UITableViewCell*)tableView:(UITableView*)tableView
...@@ -54,7 +63,7 @@ ...@@ -54,7 +63,7 @@
TableViewHeaderFooterItem* item = TableViewHeaderFooterItem* item =
[self.tableViewModel headerForSection:section]; [self.tableViewModel headerForSection:section];
if (!item) if (!item)
return [super tableView:self.tableView viewForHeaderInSection:section]; return [[UIView alloc] initWithFrame:CGRectZero];
Class headerFooterClass = [item cellClass]; Class headerFooterClass = [item cellClass];
NSString* reuseIdentifier = NSStringFromClass(headerFooterClass); NSString* reuseIdentifier = NSStringFromClass(headerFooterClass);
[self.tableView registerClass:headerFooterClass [self.tableView registerClass:headerFooterClass
...@@ -70,7 +79,7 @@ ...@@ -70,7 +79,7 @@
TableViewHeaderFooterItem* item = TableViewHeaderFooterItem* item =
[self.tableViewModel footerForSection:section]; [self.tableViewModel footerForSection:section];
if (!item) if (!item)
return [super tableView:self.tableView viewForHeaderInSection:section]; return [[UIView alloc] initWithFrame:CGRectZero];
Class headerFooterClass = [item cellClass]; Class headerFooterClass = [item cellClass];
NSString* reuseIdentifier = NSStringFromClass(headerFooterClass); NSString* reuseIdentifier = NSStringFromClass(headerFooterClass);
[self.tableView registerClass:headerFooterClass [self.tableView registerClass:headerFooterClass
......
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