Skip to content

Commit

Permalink
Create side panel tutorial for reading list
Browse files Browse the repository at this point in the history
Add a tutorial to instruct how to use the side panel reading list.

Add to reading list step:
Any time the unread list changes, we will proceed to the "mark as read" step.

Mark as read step:
Clicking on the "Mark current tab as read" or any of the individual "Mark as read" buttons will proceed to the next tutorial step since they all show the user knows how to mark something as read.

Click dropdown step:
The user must open the side panel combobox and select any item to proceed to the next step.

Bug: 1385113
Change-Id: I07ccc0fcffbd7b2811fe238a7cc19f73d137c0fb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4044115
Reviewed-by: Caroline Rising <corising@chromium.org>
Reviewed-by: Dana Fried <dfried@chromium.org>
Commit-Queue: Mickey Burks <mickeyburks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1076408}
  • Loading branch information
Mickey Burks authored and Chromium LUCI CQ committed Nov 28, 2022
1 parent f97cb95 commit 33345f8
Show file tree
Hide file tree
Showing 15 changed files with 188 additions and 5 deletions.
20 changes: 20 additions & 0 deletions chrome/app/generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -7725,6 +7725,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
</if>

<!-- User Education Tutorial Strings -->
<message name="IDS_TUTORIAL_GENERIC_SUCCESS_TITLE" desc="The title of the generic success step in the user education tutorials">
Nicely Done!
</message>
<if expr="use_titlecase">
<message name="IDS_TUTORIAL_TAB_GROUP_ADD_TAB_TO_GROUP" desc="The description of the add tab step in the tab group tutorial">
Right-click on a tab and select "Add Tab To New Group"
Expand Down Expand Up @@ -7761,6 +7764,23 @@ Keep your key file in a safe place. You will need it to create new versions of y
Try using tab groups to organize tasks, for online shopping, and more
</message>

<!-- Side Panel Tutorial Strings -->
<message name="IDS_TUTORIAL_SIDE_PANEL_READING_LIST_OPEN_SIDE_PANEL" desc="The description of the 'open side panel' step in side panel reading list tutorial">
Click the side panel icon to open it
</message>
<message name="IDS_TUTORIAL_SIDE_PANEL_READING_LIST_ADD_TAB" desc="The description of the 'add tab' step in side panel reading list tutorial">
Now add the current tab to your list
</message>
<message name="IDS_TUTORIAL_SIDE_PANEL_READING_LIST_MARK_READ" desc="The description of the 'mark as read' step in side panel reading list tutorial">
Select “Mark as read” to move the page to the bottom of your list
</message>
<message name="IDS_TUTORIAL_SIDE_PANEL_READING_LIST_CLICK_DROPDOWN" desc="The description of the 'click drop down' step in side panel reading list tutorial">
Click the drop down to choose another panel
</message>
<message name="IDS_TUTORIAL_SIDE_PANEL_READING_LIST_SUCCESS_BODY" desc="The description of the body text in the 'success' step in side panel reading list tutorial">
Try using the side panel for bookmarks, journeys, and more
</message>

<!-- Browser Hung Plugin Detector -->
<if expr="is_win">
<message name="IDS_BROWSER_HANGMONITOR" desc="A plugin on a page has hung">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4d3016c7c6529eddebffeb1f20af39d2044489cc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7c39a115bde5dd88697c32cf4afba6ccfc4095e7
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6bd3dfe3be7549b325614ba1e1d41dad229f27a6
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ebe12684aaccf5d188075388c470d50a039e3aa5
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4a3c5a0fa88d644161c878d4cf10151c1f0be2fa
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
8a9ad203042b2347b3a7f0891a4a10acc8f9e061
4 changes: 2 additions & 2 deletions chrome/browser/resources/side_panel/reading_list/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@
<div hidden="[[!unreadItems_.length]]" class="sub-heading">
$i18n{unreadHeader}
</div>
<template id="ureadItemsList" is="dom-repeat" items="[[unreadItems_]]">
<template id="unreadItemsList" is="dom-repeat" items="[[unreadItems_]]">
<reading-list-item data-url$="[[item.url.url]]" on-focus="onItemFocus_"
aria-label="[[ariaLabel_(item)]]" class="mwb-list-item"
aria-label="[[ariaLabel_(item)]]" class="mwb-list-item unread-item"
data="[[item]]" button-ripples="[[buttonRipples]]" tabindex="0">
</reading-list-item>
</template>
Expand Down
48 changes: 46 additions & 2 deletions chrome/browser/resources/side_panel/reading_list/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ import '../strings.m.js';

import {HelpBubbleMixin, HelpBubbleMixinInterface} from 'chrome://resources/cr_components/help_bubble/help_bubble_mixin.js';
import {assertNotReached} from 'chrome://resources/js/assert_ts.js';
import {EventTracker} from 'chrome://resources/js/event_tracker.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {listenOnce} from 'chrome://resources/js/util_ts.js';
import {IronSelectorElement} from 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {DomRepeat, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {getTemplate} from './app.html.js';
import {CurrentPageActionButtonState, ReadLaterEntriesByStatus, ReadLaterEntry} from './reading_list.mojom-webui.js';
import {ReadingListApiProxy, ReadingListApiProxyImpl} from './reading_list_api_proxy.js';
import {ReadingListItemElement} from './reading_list_item.js';
import {MARKED_AS_READ_UI_EVENT, ReadingListItemElement} from './reading_list_item.js';

const navigationKeys: Set<string> = new Set(['ArrowDown', 'ArrowUp']);

Expand All @@ -34,9 +35,14 @@ export interface ReadingListAppElement {
$: {
readingListList: HTMLElement,
selector: IronSelectorElement,
unreadItemsList: DomRepeat,
};
}

// browser_element_identifiers constants
const ADD_CURRENT_TAB_ELEMENT_ID = 'kAddCurrentTabToReadingListElementId';
const READING_LIST_UNREAD_ELEMENT_ID = 'kSidePanelReadingListUnreadElementId';
const MARKED_AS_READ_NATIVE_EVENT_ID = 'kSidePanelReadingMarkedAsReadEventId';

export class ReadingListAppElement extends ReadingListAppElementBase {
static get is() {
Expand Down Expand Up @@ -91,6 +97,7 @@ export class ReadingListAppElement extends ReadingListAppElementBase {
ReadingListApiProxyImpl.getInstance();
private listenerIds_: number[] = [];
private visibilityChangedListener_: () => void;
private readingListEventTracker_: EventTracker = new EventTracker();

constructor() {
super();
Expand Down Expand Up @@ -126,6 +133,9 @@ export class ReadingListAppElement extends ReadingListAppElementBase {
this.updateReadLaterEntries_();
this.apiProxy_.updateCurrentPageActionButtonState();
}

this.readingListEventTracker_.add(
this.root!, MARKED_AS_READ_UI_EVENT, this.onMarkedAsRead.bind(this));
}

override disconnectedCallback() {
Expand All @@ -136,6 +146,27 @@ export class ReadingListAppElement extends ReadingListAppElementBase {

document.removeEventListener(
'visibilitychange', this.visibilityChangedListener_);

this.unregisterHelpBubble(READING_LIST_UNREAD_ELEMENT_ID);

this.readingListEventTracker_.remove(this.root!, MARKED_AS_READ_UI_EVENT);
}

override ready() {
super.ready();

this.registerHelpBubble(
ADD_CURRENT_TAB_ELEMENT_ID, '#currentPageActionButton');

this.$.unreadItemsList.addEventListener(
'rendered-item-count-changed', () => {
const firstUnreadItem =
this.root!.querySelector('.unread-item') as HTMLElement | null;
if (firstUnreadItem) {
this.registerHelpBubble(
READING_LIST_UNREAD_ELEMENT_ID, firstUnreadItem);
}
});
}

/**
Expand Down Expand Up @@ -232,11 +263,24 @@ export class ReadingListAppElement extends ReadingListAppElementBase {
private onCurrentPageActionButtonClick_() {
if (this.getCurrentPageActionButtonMarkAsRead_()) {
this.apiProxy_.markCurrentTabAsRead();
this.sendTutorialCustomEvent();
} else {
this.apiProxy_.addCurrentTab();
}
}

private onMarkedAsRead() {
this.sendTutorialCustomEvent();
}

private sendTutorialCustomEvent() {
this.notifyHelpBubbleAnchorCustomEvent(
READING_LIST_UNREAD_ELEMENT_ID,
MARKED_AS_READ_NATIVE_EVENT_ID,
);
}


private onItemKeyDown_(e: KeyboardEvent) {
if (e.shiftKey || !navigationKeys.has(e.key)) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {ReadLaterEntry} from './reading_list.mojom-webui.js';
import {ReadingListApiProxy, ReadingListApiProxyImpl} from './reading_list_api_proxy.js';
import {getTemplate} from './reading_list_item.html.js';

export const MARKED_AS_READ_UI_EVENT = 'reading-list-marked-as-read';

const navigationKeys: Set<string> =
new Set([' ', 'Enter', 'ArrowRight', 'ArrowLeft']);

Expand Down Expand Up @@ -137,6 +139,10 @@ export class ReadingListItemElement extends ReadingListItemElementBase {
private onUpdateStatusClick_(e: Event) {
e.stopPropagation();
this.apiProxy_.updateReadStatus(this.data.url, !this.data.read);
if (!this.data.read) {
this.dispatchEvent(new CustomEvent(
MARKED_AS_READ_UI_EVENT, {bubbles: true, composed: true}));
}
}

private onItemDeleteClick_(e: Event) {
Expand Down Expand Up @@ -169,6 +175,9 @@ declare global {
interface HTMLElementTagNameMap {
'reading-list-item': ReadingListItemElement;
}
interface HTMLElementEventMap {
[MARKED_AS_READ_UI_EVENT]: CustomEvent;
}
}

customElements.define(ReadingListItemElement.is, ReadingListItemElement);
5 changes: 5 additions & 0 deletions chrome/browser/ui/browser_element_identifiers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "ui/base/interaction/element_tracker.h"

// Please keep this list alphabetized.
DEFINE_ELEMENT_IDENTIFIER_VALUE(kAddCurrentTabToReadingListElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kAppMenuButtonElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kAppUninstallDialogOkButtonId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kAutofillCreditCardSuggestionEntryElementId);
Expand All @@ -26,7 +27,9 @@ DEFINE_ELEMENT_IDENTIFIER_VALUE(kPriceTrackingBookmarkViewElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kReadLaterButtonElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kReadLaterSidePanelWebViewElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kSidePanelCloseButtonElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kSidePanelComboboxElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kSidePanelOpenInNewTabButtonElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kSidePanelReadingListUnreadElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kSavePasswordComboboxElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kSideSearchButtonElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kTabAlertIndicatorButtonElementId);
Expand All @@ -42,3 +45,5 @@ DEFINE_ELEMENT_IDENTIFIER_VALUE(kTopContainerElementId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kWebUIIPHDemoElementIdentifier);

DEFINE_CUSTOM_ELEMENT_EVENT_TYPE(kTabGroupedCustomEventId);
DEFINE_CUSTOM_ELEMENT_EVENT_TYPE(kSidePanelComboboxChangedCustomEventId);
DEFINE_CUSTOM_ELEMENT_EVENT_TYPE(kSidePanelReadingMarkedAsReadEventId);
5 changes: 5 additions & 0 deletions chrome/browser/ui/browser_element_identifiers.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

// These should gradually replace values in view_ids.h.
// Please keep this list alphabetized.
DECLARE_ELEMENT_IDENTIFIER_VALUE(kAddCurrentTabToReadingListElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kAppMenuButtonElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kAppUninstallDialogOkButtonId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kAutofillCreditCardSuggestionEntryElementId);
Expand All @@ -35,7 +36,9 @@ DECLARE_ELEMENT_IDENTIFIER_VALUE(kPriceTrackingBookmarkViewElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kReadLaterButtonElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kReadLaterSidePanelWebViewElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kSidePanelCloseButtonElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kSidePanelComboboxElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kSidePanelOpenInNewTabButtonElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kSidePanelReadingListUnreadElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kSavePasswordComboboxElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kSideSearchButtonElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kTabAlertIndicatorButtonElementId);
Expand All @@ -51,5 +54,7 @@ DECLARE_ELEMENT_IDENTIFIER_VALUE(kTopContainerElementId);
DECLARE_ELEMENT_IDENTIFIER_VALUE(kWebUIIPHDemoElementIdentifier);

DECLARE_CUSTOM_ELEMENT_EVENT_TYPE(kTabGroupedCustomEventId);
DECLARE_CUSTOM_ELEMENT_EVENT_TYPE(kSidePanelComboboxChangedCustomEventId);
DECLARE_CUSTOM_ELEMENT_EVENT_TYPE(kSidePanelReadingMarkedAsReadEventId);

#endif // CHROME_BROWSER_UI_BROWSER_ELEMENT_IDENTIFIERS_H_
6 changes: 6 additions & 0 deletions chrome/browser/ui/views/side_panel/side_panel_coordinator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "components/feature_engagement/public/feature_constants.h"
#include "components/strings/grit/components_strings.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/base/interaction/element_tracker.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
Expand All @@ -37,6 +38,7 @@
#include "ui/views/controls/combobox/combobox.h"
#include "ui/views/controls/highlight_path_generator.h"
#include "ui/views/controls/separator.h"
#include "ui/views/interaction/element_tracker_views.h"
#include "ui/views/layout/flex_layout_view.h"
#include "ui/views/vector_icons.h"
#include "ui/views/view_class_properties.h"
Expand Down Expand Up @@ -530,6 +532,8 @@ std::unique_ptr<views::View> SidePanelCoordinator::CreateHeader() {

header_combobox_ = header->AddChildView(CreateCombobox());
header_combobox_->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
header_combobox_->SetProperty(views::kElementIdentifierKey,
kSidePanelComboboxElementId);

header_open_in_new_tab_button_ = header->AddChildView(CreateControlButton(
header.get(),
Expand Down Expand Up @@ -583,6 +587,8 @@ std::unique_ptr<views::Combobox> SidePanelCoordinator::CreateCombobox() {
bool SidePanelCoordinator::OnComboboxChangeTriggered(size_t index) {
SidePanelEntry::Key entry_key = combobox_model_->GetKeyAt(index);
Show(entry_key, SidePanelUtil::SidePanelOpenTrigger::kComboboxSelected);
views::ElementTrackerViews::GetInstance()->NotifyCustomEvent(
kSidePanelComboboxChangedCustomEventId, header_combobox_);
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ namespace {

const char kTabGroupTutorialMetricPrefix[] = "TabGroup";
const char kTabGroupWithGroupTutorialMetricPrefix[] = "TabGroupWithGroup";
const char kSidePanelReadingListTutorialMetricPrefix[] = "SidePanelReadingList";
constexpr char kTabGroupHeaderElementName[] = "TabGroupHeader";
constexpr char kReadingListItemElementName[] = "ReadingListItem";

class BrowserHelpBubbleDelegate : public user_education::HelpBubbleDelegate {
public:
Expand Down Expand Up @@ -125,6 +127,8 @@ class BrowserHelpBubbleDelegate : public user_education::HelpBubbleDelegate {
const char kTabGroupTutorialId[] = "Tab Group Tutorial";
const char kTabGroupWithExistingGroupTutorialId[] =
"Tab Group With Existing Group Tutorial";
const char kSidePanelReadingListTutorialId[] =
"Side Panel Reading List Tutorial";

user_education::HelpBubbleDelegate* GetHelpBubbleDelegate() {
static base::NoDestructor<BrowserHelpBubbleDelegate> delegate;
Expand Down Expand Up @@ -461,4 +465,84 @@ void MaybeRegisterChromeTutorials(
tutorial_registry.AddTutorial(kTabGroupWithExistingGroupTutorialId,
std::move(with_group_description));
}

{ // Side panel reading list tutorial

// The Description for kSidePanelReadingListTutorialId
TutorialDescription side_panel_description;

// Open side panel
TutorialDescription::Step open_side_panel_step(
0, IDS_TUTORIAL_SIDE_PANEL_READING_LIST_OPEN_SIDE_PANEL,
ui::InteractionSequence::StepType::kShown, kReadLaterButtonElementId,
std::string(), HelpBubbleArrow::kTopRight);
side_panel_description.steps.emplace_back(open_side_panel_step);

// Click "Add current tab"
TutorialDescription::Step add_current_tab_step(
0, IDS_TUTORIAL_SIDE_PANEL_READING_LIST_ADD_TAB,
ui::InteractionSequence::StepType::kShown,
kAddCurrentTabToReadingListElementId, std::string(),
HelpBubbleArrow::kTopLeft, ui::CustomElementEventType(), absl::nullopt,
/* transition_only_on_event =*/false,
user_education::TutorialDescription::NameElementsCallback(),
/* in_any_context =*/true);
side_panel_description.steps.emplace_back(add_current_tab_step);

// When shown, name the element
TutorialDescription::Step new_reading_list_item_step(
0, 0, ui::InteractionSequence::StepType::kShown,
kSidePanelReadingListUnreadElementId, std::string(),
HelpBubbleArrow::kNone, ui::CustomElementEventType(),
/* must_remain_visible =*/true,
/* transition_only_on_event =*/true,
base::BindRepeating(
[](ui::InteractionSequence* sequence, ui::TrackedElement* element) {
sequence->NameElement(
element, base::StringPiece(kReadingListItemElementName));
return true;
}),
/* in_any_context =*/true);
side_panel_description.steps.emplace_back(new_reading_list_item_step);

// Mark as read
TutorialDescription::Step mark_as_read_step(
0, IDS_TUTORIAL_SIDE_PANEL_READING_LIST_MARK_READ,
ui::InteractionSequence::StepType::kShown, ui::ElementIdentifier(),
kReadingListItemElementName, HelpBubbleArrow::kTopLeft);
side_panel_description.steps.emplace_back(mark_as_read_step);

TutorialDescription::Step detect_mark_as_read_step(
0, 0, ui::InteractionSequence::StepType::kCustomEvent,
ui::ElementIdentifier(), kReadingListItemElementName,
HelpBubbleArrow::kNone, kSidePanelReadingMarkedAsReadEventId);
side_panel_description.steps.emplace_back(detect_mark_as_read_step);

// Click drop down
TutorialDescription::Step click_dropdown_step(
0, IDS_TUTORIAL_SIDE_PANEL_READING_LIST_CLICK_DROPDOWN,
ui::InteractionSequence::StepType::kShown, kSidePanelComboboxElementId,
std::string(), HelpBubbleArrow::kTopLeft);
side_panel_description.steps.emplace_back(click_dropdown_step);

TutorialDescription::Step detect_click_dropdown_step(
0, 0, ui::InteractionSequence::StepType::kCustomEvent,
kSidePanelComboboxElementId, std::string(), HelpBubbleArrow::kNone,
kSidePanelComboboxChangedCustomEventId);
side_panel_description.steps.emplace_back(detect_click_dropdown_step);

// Completion of the tutorial.
TutorialDescription::Step success_step(
IDS_TUTORIAL_GENERIC_SUCCESS_TITLE,
IDS_TUTORIAL_SIDE_PANEL_READING_LIST_SUCCESS_BODY,
ui::InteractionSequence::StepType::kShown, kTabStripRegionElementId,
std::string(), HelpBubbleArrow::kNone);
side_panel_description.steps.emplace_back(success_step);

side_panel_description.histograms = user_education::MakeTutorialHistograms<
kSidePanelReadingListTutorialMetricPrefix>(
side_panel_description.steps.size());
tutorial_registry.AddTutorial(kSidePanelReadingListTutorialId,
std::move(side_panel_description));
}
}

0 comments on commit 33345f8

Please sign in to comment.