blob: 082b9b2c3607f9017e7ab4c29297817a52e68910 [file] [log] [blame]
// Copyright 2019 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.
#include "ash/public/cpp/app_list/app_list_config_provider.h"
#include <utility>
#include "ash/public/cpp/app_list/app_list_config.h"
#include "ash/public/cpp/app_list/app_list_features.h"
#include "base/no_destructor.h"
#include "ui/gfx/geometry/size.h"
namespace ash {
namespace {
// The minimum scale that can be used when scaling down the app list view UI.
constexpr float kMinimumConfigScale = 48. / 120.;
// Determines the app list config that should be used for a display work area
// size. It should not be used if ScalableAppList feature is disabled.
ash::AppListConfigType GetConfigTypeForDisplaySize(
const gfx::Size& display_size) {
DCHECK(app_list_features::IsScalableAppListEnabled());
// Landscape:
if (display_size.width() > display_size.height()) {
if (display_size.width() >= 1200)
return ash::AppListConfigType::kLarge;
if (display_size.width() >= 960)
return ash::AppListConfigType::kMedium;
return ash::AppListConfigType::kSmall;
}
// Portrait:
if (display_size.width() >= 768)
return ash::AppListConfigType::kLarge;
if (display_size.width() >= 600)
return ash::AppListConfigType::kMedium;
return ash::AppListConfigType::kSmall;
}
} // namespace
// static
AppListConfigProvider& AppListConfigProvider::Get() {
static base::NoDestructor<AppListConfigProvider> instance;
return *instance;
}
AppListConfigProvider::AppListConfigProvider() = default;
AppListConfigProvider::~AppListConfigProvider() = default;
void AppListConfigProvider::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void AppListConfigProvider::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
AppListConfig* AppListConfigProvider::GetConfigForType(
ash::AppListConfigType type,
bool can_create) {
const auto config_it = configs_.find(type);
if (config_it != configs_.end())
return config_it->second.get();
// Assume the shared config always exists.
if (type != ash::AppListConfigType::kShared && !can_create)
return nullptr;
DCHECK(type == ash::AppListConfigType::kShared ||
app_list_features::IsScalableAppListEnabled());
auto config = std::make_unique<AppListConfig>(type);
auto* result = config.get();
configs_.emplace(type, std::move(config));
if (type != ash::AppListConfigType::kShared) {
for (auto& observer : observers_)
observer.OnAppListConfigCreated(type);
}
return result;
}
std::unique_ptr<AppListConfig> AppListConfigProvider::CreateForAppListWidget(
const gfx::Size& display_work_area_size,
const gfx::Size& available_grid_size,
const AppListConfig* current_config) {
if (app_list_features::IsScalableAppListEnabled()) {
ash::AppListConfigType type =
GetConfigTypeForDisplaySize(display_work_area_size);
if (current_config && current_config->type() == type)
return nullptr;
// Ensure that the app list config provider has a config with the same
// type as the created config - the app list model will use the config owned
// by the AppListConfigProvider instance to generate folder icons needed by
// app list UI.
GetConfigForType(type, true /*can_create*/);
return std::make_unique<AppListConfig>(type);
}
AppListConfig& base_config = AppListConfig::instance();
const int min_grid_height =
(display_work_area_size.width() < display_work_area_size.height()
? base_config.preferred_cols()
: base_config.preferred_rows()) *
base_config.grid_tile_height();
const int min_grid_width =
(display_work_area_size.width() < display_work_area_size.height()
? base_config.preferred_rows()
: base_config.preferred_cols()) *
base_config.grid_tile_width();
float scale_x = 1;
float scale_y = 1;
float inner_tile_scale_y = 1;
if (available_grid_size.height() < min_grid_height) {
scale_y = std::max(
kMinimumConfigScale,
static_cast<float>(available_grid_size.height() -
2 * base_config.grid_fadeout_zone_height()) /
min_grid_height);
// Adjust scale to reflect the fact the app list item title height does not
// get scaled. The adjustment is derived from:
// s * x + c = S * (x + c) and t = x + c
// With: S - the target grid scale,
// x - scalable part of the tile (total title padding),
// c - constant part of the tile,
// t - tile height, and
// s - the adjusted scale.
const int total_title_padding = base_config.grid_title_bottom_padding() +
base_config.grid_title_top_padding();
inner_tile_scale_y =
(base_config.grid_tile_height() * (scale_y - 1) + total_title_padding) /
total_title_padding;
}
if (available_grid_size.width() < min_grid_width) {
scale_x = std::max(
kMinimumConfigScale,
static_cast<float>(available_grid_size.width()) / min_grid_width);
}
if (current_config && current_config->scale_x() == scale_x &&
current_config->scale_y() == scale_y) {
return nullptr;
}
return std::make_unique<AppListConfig>(base_config, scale_x, scale_y,
inner_tile_scale_y,
scale_y == kMinimumConfigScale);
}
void AppListConfigProvider::ResetForTesting() {
configs_.clear();
}
} // namespace ash