// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/app_list/reorder/app_list_reorder_util.h"
#include "ash/strings/grit/ash_strings.h"
#include "base/i18n/string_compare.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/ash/app_icon_color_cache/app_icon_color_cache.h"
#include "ui/base/l10n/l10n_util.h"
namespace app_list {
namespace reorder {
namespace {
std::u16string GetItemName(const std::string& name, bool is_folder) {
if (is_folder && name.empty())
return l10n_util::GetStringUTF16(IDS_APP_LIST_FOLDER_NAME_PLACEHOLDER);
return base::UTF8ToUTF16(name);
}
} // namespace
constexpr float kOrderResetThreshold = 0.2f;
// ReorderParam ----------------------------------------------------------------
ReorderParam::ReorderParam(const std::string& new_sync_item_id,
const syncer::StringOrdinal& new_ordinal)
: sync_item_id(new_sync_item_id), ordinal(new_ordinal) {}
ReorderParam::ReorderParam(const ReorderParam&) = default;
ReorderParam::~ReorderParam() = default;
// SyncItemWrapper<std::u16string> ---------------------------------------------
template <>
SyncItemWrapper<std::u16string>::SyncItemWrapper(
const AppListSyncableService::SyncItem& sync_item)
: id(sync_item.item_id),
item_ordinal(sync_item.item_ordinal),
is_folder(sync_item.item_type == sync_pb::AppListSpecifics::TYPE_FOLDER),
key_attribute(GetItemName(sync_item.item_name, is_folder)) {}
template <>
SyncItemWrapper<std::u16string>::SyncItemWrapper(
const ash::AppListItemMetadata& metadata)
: id(metadata.id),
item_ordinal(metadata.position),
is_folder(metadata.is_folder),
key_attribute(GetItemName(metadata.name, is_folder)) {}
// SyncItemWrapper<ash::IconColor> ---------------------------------------------
template <>
SyncItemWrapper<ash::IconColor>::SyncItemWrapper(
const AppListSyncableService::SyncItem& sync_item)
: id(sync_item.item_id),
item_ordinal(sync_item.item_ordinal),
is_folder(sync_item.item_type == sync_pb::AppListSpecifics::TYPE_FOLDER),
key_attribute(sync_item.item_color) {}
template <>
SyncItemWrapper<ash::IconColor>::SyncItemWrapper(
const ash::AppListItemMetadata& metadata)
: id(metadata.id),
item_ordinal(metadata.position),
is_folder(metadata.is_folder),
key_attribute(metadata.icon_color) {}
// EphemeralAwareName ----------------------------------------------------------
EphemeralAwareName::EphemeralAwareName(bool is_ephemeral, std::u16string name)
: is_ephemeral(is_ephemeral), name(name) {}
EphemeralAwareName::~EphemeralAwareName() = default;
// SyncItemWrapper<EphemeralAwareName> -----------------------------------------
template <>
SyncItemWrapper<EphemeralAwareName>::SyncItemWrapper(
const AppListSyncableService::SyncItem& sync_item)
: id(sync_item.item_id),
item_ordinal(sync_item.item_ordinal),
is_folder(sync_item.item_type == sync_pb::AppListSpecifics::TYPE_FOLDER),
key_attribute(sync_item.is_ephemeral,
GetItemName(sync_item.item_name, is_folder)) {}
template <>
SyncItemWrapper<EphemeralAwareName>::SyncItemWrapper(
const ash::AppListItemMetadata& metadata)
: id(metadata.id),
item_ordinal(metadata.position),
is_folder(metadata.is_folder),
key_attribute(metadata.is_ephemeral,
GetItemName(metadata.name, is_folder)) {}
// IconColorWrapperComparator -------------------------------------------------
IconColorWrapperComparator::IconColorWrapperComparator() = default;
bool IconColorWrapperComparator::operator()(
const reorder::SyncItemWrapper<ash::IconColor>& lhs,
const reorder::SyncItemWrapper<ash::IconColor>& rhs) const {
// Folders are placed at the bottom of the app list in color sort.
if (lhs.is_folder != rhs.is_folder)
return rhs.is_folder;
if (lhs.key_attribute != rhs.key_attribute)
return lhs.key_attribute < rhs.key_attribute;
const syncer::StringOrdinal& lhs_ordinal = lhs.item_ordinal;
const syncer::StringOrdinal& rhs_ordinal = rhs.item_ordinal;
if (lhs_ordinal.IsValid() && rhs_ordinal.IsValid() &&
!lhs_ordinal.Equals(rhs_ordinal)) {
lhs.item_ordinal.LessThan(rhs.item_ordinal);
}
// Compare ids so that sorting with this comparator is stable.
return lhs.id < rhs.id;
}
// StringWrapperComparator ----------------------------------------------------
StringWrapperComparator::StringWrapperComparator(bool increasing,
icu::Collator* collator)
: increasing_(increasing), collator_(collator) {}
bool StringWrapperComparator::operator()(
const reorder::SyncItemWrapper<std::u16string>& lhs,
const reorder::SyncItemWrapper<std::u16string>& rhs) const {
// If the collator is not created successfully, compare the string values
// using operators.
if (!collator_) {
if (increasing_)
return lhs.key_attribute < rhs.key_attribute;
return lhs.key_attribute > rhs.key_attribute;
}
UCollationResult result = base::i18n::CompareString16WithCollator(
*collator_, lhs.key_attribute, rhs.key_attribute);
if (increasing_)
return result == UCOL_LESS;
return result == UCOL_GREATER;
}
// EphemeralStateAndNameComparator ---------------------------------------------
EphemeralStateAndNameComparator::EphemeralStateAndNameComparator(
icu::Collator* collator)
: collator_(collator) {}
bool EphemeralStateAndNameComparator::operator()(
const reorder::SyncItemWrapper<EphemeralAwareName>& lhs,
const reorder::SyncItemWrapper<EphemeralAwareName>& rhs) const {
if (lhs.key_attribute.is_ephemeral != rhs.key_attribute.is_ephemeral)
return lhs.key_attribute.is_ephemeral > rhs.key_attribute.is_ephemeral;
if (!collator_)
return lhs.key_attribute.name < rhs.key_attribute.name;
UCollationResult result = base::i18n::CompareString16WithCollator(
*collator_, lhs.key_attribute.name, rhs.key_attribute.name);
return result == UCOL_LESS;
}
} // namespace reorder
} // namespace app_list