Update education footer text in clipboard history menu.
When the clipboard history menu is not shown as a result of a Ctrl+V long press event, the education footer has different text. Note that the logic which shows the footer at the appropriate times has not yet been implemented. Keyboard w/ Search key: http://shortn/_GiwsaGrHPN Keyboard w/ Launcher key, Assistant enabled: http://shortn/_l0VUEPNT4H Keyboard w/ Launcher key, Assistant disabled: http://shortn/_cxEi9XFi0J Bug: b:267694412 Change-Id: I0503378f3c3c3abccdb72c0ae26c39b80f1b9146 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4750340 Reviewed-by: Angus McLean <angusmclean@google.com> Commit-Queue: David Black <dmblack@google.com> Cr-Commit-Position: refs/heads/main@{#1179364}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
56e579403a
commit
5a76f69a71
@ -6028,6 +6028,9 @@ Here are some things you can try to get started.
|
||||
<message name="IDS_ASH_CLIPBOARD_HISTORY_CONTROL_V_LONGPRESS_FOOTER" desc="The message used to educate users about the clipboard history menu that shows when they hold down Ctrl+V.">
|
||||
You’ll see the clipboard when you press and hold Ctrl + V. You can turn off this shortcut by disabling the #clipboard-history-longpress flag in chrome://flags (os://flags if using Lacros).
|
||||
</message>
|
||||
<message name="IDS_ASH_CLIPBOARD_HISTORY_FOOTER" desc="The message used to educate users about the clipboard history menu that shows when they use the feature for the first time (or for the first time in a long time).">
|
||||
Select an item to paste it. You can see the clipboard by pressing <ph name="SHORTCUT_KEY_NAME">$1<ex>Launcher</ex></ph> + v.
|
||||
</message>
|
||||
<message name="IDS_ASH_CLIPBOARD_HISTORY_HEADER_TITLE" desc="The title of the ChromeOS clipboard history menu, which shows the user's most recently copied items.">
|
||||
Clipboard
|
||||
</message>
|
||||
|
@ -0,0 +1 @@
|
||||
2a12f38fbc26673c249afd40154e9b401f013880
|
@ -57,6 +57,11 @@ namespace ash {
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns a font list resolved from the specified `typography_token`.
|
||||
gfx::FontList Resolve(TypographyToken typography_token) {
|
||||
return TypographyProvider::Get()->ResolveTypographyToken(typography_token);
|
||||
}
|
||||
|
||||
// Returns whether the clipboard history menu requires a header.
|
||||
bool IsHeaderRequired() {
|
||||
return chromeos::features::IsClipboardHistoryRefreshEnabled();
|
||||
@ -94,10 +99,74 @@ void InsertHeaderContent(views::MenuItemView* container) {
|
||||
}
|
||||
|
||||
// TODO(http://b/267694412): Add pixel test.
|
||||
// Populates `container` with education content to appear at the bottom of the
|
||||
// Populates `styled_label` with educational text to appear at the bottom of the
|
||||
// clipboard history menu. This method may only be called when clipboard history
|
||||
// refresh is enabled.
|
||||
void InsertFooterContentV2(views::MenuItemView* container) {
|
||||
void InsertFooterContentV2LabelStyledText(
|
||||
crosapi::mojom::ClipboardHistoryControllerShowSource show_source,
|
||||
views::StyledLabel* styled_label) {
|
||||
CHECK(chromeos::features::IsClipboardHistoryRefreshEnabled());
|
||||
|
||||
// Create text style.
|
||||
views::StyledLabel::RangeStyleInfo text_style;
|
||||
text_style.custom_font = Resolve(TypographyToken::kCrosAnnotation1);
|
||||
text_style.override_color_id = cros_tokens::kCrosSysOnSurfaceVariant;
|
||||
|
||||
// When the clipboard history menu is shown from a Ctrl+V long press event, a
|
||||
// specific educational text is used which does not require inline icons.
|
||||
using crosapi::mojom::ClipboardHistoryControllerShowSource;
|
||||
if (show_source == ClipboardHistoryControllerShowSource::kControlVLongpress) {
|
||||
styled_label->SetText(l10n_util::GetStringUTF16(
|
||||
IDS_ASH_CLIPBOARD_HISTORY_CONTROL_V_LONGPRESS_FOOTER));
|
||||
styled_label->AddStyleRange(gfx::Range(0u, styled_label->GetText().size()),
|
||||
std::move(text_style));
|
||||
return;
|
||||
}
|
||||
|
||||
// When the clipboard history menu is *not* shown from a Ctrl+V long press
|
||||
// event, set text based on keyboard layout, caching the offset where an
|
||||
// inline icon should be inserted.
|
||||
size_t inline_icon_offset;
|
||||
const auto& shortcut_key = clipboard_history_util::GetShortcutKeyName();
|
||||
styled_label->SetText(l10n_util::GetStringFUTF16(
|
||||
IDS_ASH_CLIPBOARD_HISTORY_FOOTER, shortcut_key, &inline_icon_offset));
|
||||
inline_icon_offset += shortcut_key.size();
|
||||
|
||||
// Set text styles.
|
||||
styled_label->AddStyleRange(gfx::Range(0u, inline_icon_offset), text_style);
|
||||
styled_label->AddStyleRange(
|
||||
gfx::Range(inline_icon_offset + 1u, styled_label->GetText().size()),
|
||||
std::move(text_style));
|
||||
|
||||
// Create inline icon.
|
||||
auto inline_icon =
|
||||
views::Builder<views::ImageView>()
|
||||
.SetBorder(views::CreateEmptyBorder(
|
||||
ClipboardHistoryViews::kInlineIconMargins))
|
||||
.SetImage(ui::ImageModel::FromVectorIcon(
|
||||
clipboard_history_util::GetShortcutKeyIcon(),
|
||||
cros_tokens::kCrosSysOnSurfaceVariant,
|
||||
ClipboardHistoryViews::kFooterContentV2InlineIconSize))
|
||||
.Build();
|
||||
|
||||
// Insert inline icon.
|
||||
views::StyledLabel::RangeStyleInfo inline_icon_style;
|
||||
inline_icon_style.custom_view = inline_icon.get();
|
||||
styled_label->AddStyleRange(
|
||||
gfx::Range(inline_icon_offset, inline_icon_offset + 1u),
|
||||
std::move(inline_icon_style));
|
||||
|
||||
// Transfer inline icon ownership.
|
||||
styled_label->AddCustomView(std::move(inline_icon));
|
||||
}
|
||||
|
||||
// TODO(http://b/267694412): Add pixel test.
|
||||
// Populates `container` with educational content to appear at the bottom of the
|
||||
// clipboard history menu. This method may only be called when clipboard history
|
||||
// refresh is enabled.
|
||||
void InsertFooterContentV2(
|
||||
views::MenuItemView* container,
|
||||
crosapi::mojom::ClipboardHistoryControllerShowSource show_source) {
|
||||
CHECK(chromeos::features::IsClipboardHistoryRefreshEnabled());
|
||||
|
||||
// Cache `menu_padding`.
|
||||
@ -132,38 +201,25 @@ void InsertFooterContentV2(views::MenuItemView* container) {
|
||||
ClipboardHistoryViews::kFooterContentV2IconSize)),
|
||||
views::Builder<views::StyledLabel>()
|
||||
.SetAutoColorReadabilityEnabled(false)
|
||||
.SetText(l10n_util::GetStringUTF16(
|
||||
IDS_ASH_CLIPBOARD_HISTORY_CONTROL_V_LONGPRESS_FOOTER))
|
||||
.SetID(clipboard_history_util::kFooterContentV2LabelID)
|
||||
.SizeToFit(
|
||||
footer_width -
|
||||
ClipboardHistoryViews::kFooterContentV2Insets.width() -
|
||||
ClipboardHistoryViews::kFooterContentV2IconSize -
|
||||
ClipboardHistoryViews::kFooterContentV2ChildSpacing)
|
||||
.CustomConfigure(
|
||||
base::BindOnce([](views::StyledLabel* label) {
|
||||
views::StyledLabel::RangeStyleInfo style;
|
||||
|
||||
style.custom_font =
|
||||
TypographyProvider::Get()->ResolveTypographyToken(
|
||||
TypographyToken::kCrosAnnotation1);
|
||||
|
||||
style.override_color_id =
|
||||
cros_tokens::kCrosSysOnSurfaceVariant;
|
||||
|
||||
// NOTE: `SetText()` must precede `AddStyleRange()`.
|
||||
label->AddStyleRange(
|
||||
gfx::Range(0u, label->GetText().size()),
|
||||
std::move(style));
|
||||
})))
|
||||
.CustomConfigure(base::BindOnce(
|
||||
&InsertFooterContentV2LabelStyledText, show_source)))
|
||||
.Build());
|
||||
}
|
||||
|
||||
// TODO(http://b/267694412): Add pixel test.
|
||||
// Populates `container` with educational content to appear at the bottom of the
|
||||
// clipboard history menu.
|
||||
void InsertFooterContent(views::MenuItemView* container) {
|
||||
void InsertFooterContent(
|
||||
views::MenuItemView* container,
|
||||
crosapi::mojom::ClipboardHistoryControllerShowSource show_source) {
|
||||
if (chromeos::features::IsClipboardHistoryRefreshEnabled()) {
|
||||
InsertFooterContentV2(container);
|
||||
InsertFooterContentV2(container, show_source);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -286,6 +342,7 @@ void ClipboardHistoryMenuModelAdapter::Run(
|
||||
run_before_ = true;
|
||||
|
||||
menu_open_time_ = base::TimeTicks::Now();
|
||||
menu_show_source_ = show_source;
|
||||
|
||||
int command_id = clipboard_history_util::kFirstItemCommandId;
|
||||
const auto& items = clipboard_history_->GetItems();
|
||||
@ -642,7 +699,7 @@ views::MenuItemView* ClipboardHistoryMenuModelAdapter::AppendMenuItem(
|
||||
InsertHeaderContent(container);
|
||||
} else if (footer_index_ == index) {
|
||||
CHECK_EQ(model->GetTypeAt(index), ui::MenuModel::ItemType::TYPE_TITLE);
|
||||
InsertFooterContent(container);
|
||||
InsertFooterContent(container, menu_show_source_.value());
|
||||
} else {
|
||||
CHECK_EQ(model->GetTypeAt(index), ui::MenuModel::ItemType::TYPE_COMMAND);
|
||||
std::unique_ptr<ClipboardHistoryItemView> item_view =
|
||||
|
@ -146,6 +146,10 @@ class ASH_EXPORT ClipboardHistoryMenuModelAdapter
|
||||
// The timestamp taken when the menu is opened. Used in metrics.
|
||||
base::TimeTicks menu_open_time_;
|
||||
|
||||
// The source which opened the menu, absent until the menu is `Run()`.
|
||||
absl::optional<crosapi::mojom::ClipboardHistoryControllerShowSource>
|
||||
menu_show_source_;
|
||||
|
||||
// The mapping between the command ids and items that are copied from
|
||||
// `clipboard_history_` when the menu is created. It is used to solve the
|
||||
// possible inconsistency between the menu model data and the clipboard
|
||||
|
@ -4,12 +4,15 @@
|
||||
|
||||
#include "ash/clipboard/clipboard_history_menu_model_adapter.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ash/clipboard/clipboard_history.h"
|
||||
#include "ash/clipboard/clipboard_history_controller_impl.h"
|
||||
#include "ash/clipboard/clipboard_history_util.h"
|
||||
#include "ash/clipboard/views/clipboard_history_view_constants.h"
|
||||
#include "ash/constants/ash_features.h"
|
||||
#include "ash/shell.h"
|
||||
#include "ash/strings/grit/ash_strings.h"
|
||||
#include "ash/test/ash_test_base.h"
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/test_future.h"
|
||||
@ -19,11 +22,13 @@
|
||||
#include "testing/gmock/include/gmock/gmock-matchers.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "ui/base/clipboard/scoped_clipboard_writer.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/models/simple_menu_model.h"
|
||||
#include "ui/base/ui_base_types.h"
|
||||
#include "ui/gfx/text_constants.h"
|
||||
#include "ui/views/controls/label.h"
|
||||
#include "ui/views/controls/menu/menu_item_view.h"
|
||||
#include "ui/views/controls/styled_label.h"
|
||||
#include "ui/views/view_utils.h"
|
||||
|
||||
namespace ash {
|
||||
@ -36,6 +41,7 @@ using ::testing::Eq;
|
||||
using ::testing::IsNull;
|
||||
using ::testing::NotNull;
|
||||
using ::testing::Property;
|
||||
using ::testing::ResultOf;
|
||||
using ::testing::ValuesIn;
|
||||
using ::testing::WithParamInterface;
|
||||
|
||||
@ -43,6 +49,8 @@ using crosapi::mojom::ClipboardHistoryControllerShowSource;
|
||||
|
||||
namespace {
|
||||
|
||||
// Helpers ---------------------------------------------------------------------
|
||||
|
||||
ClipboardHistoryControllerImpl* GetClipboardHistoryController() {
|
||||
return Shell::Get()->clipboard_history_controller();
|
||||
}
|
||||
@ -66,8 +74,21 @@ void FlushMessageLoop() {
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
// Matchers --------------------------------------------------------------------
|
||||
|
||||
template <typename ViewType, typename MatcherType>
|
||||
auto GetViewById(int id, MatcherType m) {
|
||||
return ResultOf(
|
||||
[id](const auto* arg) {
|
||||
return views::AsViewClass<ViewType>(arg->GetViewByID(id));
|
||||
},
|
||||
m);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ClipboardHistoryMenuModelAdapterRefreshTest ---------------------------------
|
||||
|
||||
// Base class for `ClipboardHistoryMenuModelAdapter` tests whose only required
|
||||
// parameterization is whether the clipboard history refresh is enabled.
|
||||
class ClipboardHistoryMenuModelAdapterRefreshTest
|
||||
@ -321,7 +342,20 @@ TEST_P(ClipboardHistoryMenuModelAdapterMenuItemTest,
|
||||
Conditional(IsClipboardHistoryRefreshEnabled(), IsNull(), NotNull()));
|
||||
EXPECT_THAT(
|
||||
footer->GetViewByID(clipboard_history_util::kFooterContentV2ViewID),
|
||||
Conditional(IsClipboardHistoryRefreshEnabled(), NotNull(), IsNull()));
|
||||
Conditional(
|
||||
IsClipboardHistoryRefreshEnabled(),
|
||||
GetViewById<views::StyledLabel>(
|
||||
clipboard_history_util::kFooterContentV2LabelID,
|
||||
Property(
|
||||
&views::StyledLabel::GetText,
|
||||
Conditional(
|
||||
IsClipboardHistoryLongpressEnabled(),
|
||||
l10n_util::GetStringUTF16(
|
||||
IDS_ASH_CLIPBOARD_HISTORY_CONTROL_V_LONGPRESS_FOOTER),
|
||||
l10n_util::GetStringFUTF16(
|
||||
IDS_ASH_CLIPBOARD_HISTORY_FOOTER,
|
||||
clipboard_history_util::GetShortcutKeyName())))),
|
||||
IsNull()));
|
||||
}
|
||||
|
||||
} // namespace ash
|
||||
|
@ -63,6 +63,7 @@ enum MenuViewID {
|
||||
kDeleteButtonViewID,
|
||||
kDisplayTextLabelID,
|
||||
kFooterContentViewID,
|
||||
kFooterContentV2LabelID,
|
||||
kFooterContentV2ViewID,
|
||||
kSecondaryDisplayTextLabelID,
|
||||
};
|
||||
|
@ -25,6 +25,9 @@ constexpr int kFooterContentV2ChildSpacing = 6;
|
||||
// The icon size for footer content v2.
|
||||
constexpr int kFooterContentV2IconSize = 20;
|
||||
|
||||
// The inline icon size for footer content v2.
|
||||
constexpr int kFooterContentV2InlineIconSize = 16;
|
||||
|
||||
// The insets for footer content v2.
|
||||
constexpr auto kFooterContentV2Insets = gfx::Insets(8);
|
||||
|
||||
|
Reference in New Issue
Block a user