blob: 191d5b745a5d9122f354cb52d92750126f3224c5 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/tab_switcher/ui_bundled/tab_utils.h"
#import <set>
#import "ios/chrome/browser/shared/model/browser/browser.h"
#import "ios/chrome/browser/shared/model/browser/browser_list.h"
#import "ios/chrome/browser/shared/model/web_state_list/tab_group.h"
#import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/grid/grid_item_identifier.h"
#import "ios/chrome/browser/tab_switcher/ui_bundled/tab_grid/tab_context_menu/tab_item.h"
#import "ios/chrome/browser/tab_switcher/ui_bundled/tab_group_item.h"
#import "ios/chrome/browser/tab_switcher/ui_bundled/tab_switcher_item.h"
#import "ios/chrome/browser/tabs/model/tab_title_util.h"
#import "ios/web/public/web_state.h"
namespace {
// Magic padding to fit UX mocks for items sizes. See where it is used for more
// details.
constexpr CGFloat kMagicPadding = 50;
// Items aspect ratios.
constexpr CGFloat kPortraitAspectRatio = 4. / 3.;
// Different width thresholds for determining the columns count.
constexpr CGFloat kSmallWidthThreshold = 500;
constexpr CGFloat kLargeWidthThreshold = 1000;
} // namespace
CGFloat TabGridItemAspectRatio(CGSize size) {
const CGFloat width = size.width;
const CGFloat height = size.height;
const CGRect screen_bounds = UIScreen.mainScreen.bounds;
const CGFloat screen_aspect_ratio =
CGRectGetHeight(screen_bounds) / CGRectGetWidth(screen_bounds);
// On iPad Landscape with 3/4 - 1/4 Split View, the 3/4 width is just a bit
// smaller than the height, but design-wise, a landscape aspect ratio should
// be preferred. Pad a bit the width with a magic constant before comparing to
// the height.
return width + kMagicPadding > height ? screen_aspect_ratio
: kPortraitAspectRatio;
}
NSInteger TabGridColumnsCount(CGSize size,
UIContentSizeCategory content_size_category) {
const CGFloat width = size.width;
NSInteger count;
if (width < kSmallWidthThreshold) {
count = 2;
} else if (width < kLargeWidthThreshold) {
count = 3;
} else {
count = 4;
}
// If Dynamic Type uses an Accessibility setting, just remove a column.
if (UIContentSizeCategoryIsAccessibilityCategory(content_size_category)) {
count -= 1;
}
return count;
}
TabItem* GetTabItem(WebStateList* web_state_list,
WebStateSearchCriteria criteria) {
web::WebState* web_state = GetWebState(web_state_list, criteria);
if (!web_state) {
return nil;
}
TabItem* item =
[[TabItem alloc] initWithTitle:tab_util::GetTabTitle(web_state)
URL:web_state->GetVisibleURL()];
return item;
}
bool HasDuplicateGroupsAndTabsIdentifiers(NSArray<GridItemIdentifier*>* items) {
std::set<web::WebStateID> identifiers;
std::set<const TabGroup*> groups;
for (GridItemIdentifier* item in items) {
switch (item.type) {
case GridItemType::kInactiveTabsButton:
NOTREACHED();
case GridItemType::kTab:
identifiers.insert(item.tabSwitcherItem.identifier);
break;
case GridItemType::kGroup:
groups.insert(item.tabGroupItem.tabGroup);
break;
case GridItemType::kSuggestedActions:
NOTREACHED();
case GridItemType::kActivitySummary:
NOTREACHED();
}
}
return (identifiers.size() + groups.size()) != items.count;
}
bool HasDuplicateIdentifiers(NSArray<TabSwitcherItem*>* items) {
std::set<web::WebStateID> identifiers;
for (TabSwitcherItem* item in items) {
identifiers.insert(item.identifier);
}
return identifiers.size() != items.count;
}
Browser* GetBrowserForTabWithCriteria(BrowserList* browser_list,
WebStateSearchCriteria criteria,
bool is_otr_tab) {
const BrowserList::BrowserType browser_types =
is_otr_tab ? BrowserList::BrowserType::kIncognito
: BrowserList::BrowserType::kRegularAndInactive;
std::set<Browser*> browsers = browser_list->BrowsersOfType(browser_types);
for (Browser* browser : browsers) {
WebStateList* web_state_list = browser->GetWebStateList();
int index = GetWebStateIndex(web_state_list, criteria);
if (index != WebStateList::kInvalidIndex) {
return browser;
}
}
return nullptr;
}