Skip to content

Commit

Permalink
Move snooze logic out of FeaturePromoBubbleView
Browse files Browse the repository at this point in the history
In preparation for IPH tutorials, this moves snooze-specific logic out
of FeaturePromoBubbleView. Instead it provides a way of specifying
buttons in its creation parameters. FeaturePromoControllerViews now
adds the appropriate buttons when snooze is enabled.

This further allows snooze-unrelated buttons as is desired for IPH
tutorials.

Bug: 1156839
Change-Id: Ia5de5a9870d71fb60ff815ac2819105fe67887fa
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2787218
Reviewed-by: Dana Fried <dfried@chromium.org>
Commit-Queue: Collin Baker <collinbaker@chromium.org>
Cr-Commit-Position: refs/heads/master@{#867884}
  • Loading branch information
chbaker0 authored and Chromium LUCI CQ committed Mar 31, 2021
1 parent facf833 commit 381258f
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 154 deletions.
106 changes: 47 additions & 59 deletions chrome/browser/ui/views/user_education/feature_promo_bubble_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,8 @@ constexpr SkColor kBubbleButtonFocusRingColor = SK_ColorWHITE;

// The background color of the button when focused.
constexpr SkColor kBubbleButtonFocusedBackgroundColor = gfx::kGoogleBlue600;
} // namespace

namespace views {

class MdIPHBubbleButton : public MdTextButton {
class MdIPHBubbleButton : public views::MdTextButton {
public:
METADATA_HEADER(MdIPHBubbleButton);

Expand Down Expand Up @@ -120,8 +117,8 @@ class MdIPHBubbleButton : public MdTextButton {
has_border_ ? kBubbleButtonBorderColor : kBubbleBackgroundColor;

SetBackground(CreateBackgroundFromPainter(
Painter::CreateRoundRectWith1PxBorderPainter(bg_color, stroke_color,
GetCornerRadius())));
views::Painter::CreateRoundRectWith1PxBorderPainter(
bg_color, stroke_color, GetCornerRadius())));
}

private:
Expand All @@ -131,32 +128,28 @@ class MdIPHBubbleButton : public MdTextButton {
BEGIN_METADATA(MdIPHBubbleButton, MdTextButton)
END_METADATA

} // namespace views
} // namespace

// Explicitly don't use the default DIALOG_SHADOW as it will show a black
// outline in dark mode on Mac. Use our own shadow instead. The shadow type is
// the same for all other platforms.
FeaturePromoBubbleView::FeaturePromoBubbleView(
CreateParams params,
base::RepeatingClosure snooze_callback,
base::RepeatingClosure dismiss_callback)
FeaturePromoBubbleView::FeaturePromoBubbleView(CreateParams params)
: BubbleDialogDelegateView(params.anchor_view,
params.arrow,
views::BubbleBorder::STANDARD_SHADOW),
focusable_(params.focusable),
persist_on_blur_(params.persist_on_blur),
snoozable_(params.snoozable),
preferred_width_(params.preferred_width) {
DCHECK(params.anchor_view);
DCHECK(!params.snoozable || params.focusable)
DCHECK(params.buttons.empty() || params.focusable)
<< "A snoozable bubble must be focusable to allow keyboard "
"accessibility.";
DCHECK(!params.persist_on_blur || params.focusable)
<< "A bubble that persists on blur must be focusable.";
UseCompactMargins();

// Bubble will not auto-dismiss for snoozble IPH.
if (!snoozable_) {
// Bubble will not auto-dismiss if there's buttons.
if (params.buttons.empty()) {
feature_promo_bubble_timeout_ = std::make_unique<FeaturePromoBubbleTimeout>(
params.timeout_default ? *params.timeout_default : kDelayDefault,
params.timeout_short ? *params.timeout_short : kDelayShort);
Expand Down Expand Up @@ -219,7 +212,7 @@ FeaturePromoBubbleView::FeaturePromoBubbleView(
body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
body_label->SetMultiLine(true);

if (snoozable_) {
if (!params.buttons.empty()) {
auto* button_container = AddChildView(std::make_unique<views::View>());
auto* button_layout =
button_container->SetLayoutManager(std::make_unique<views::BoxLayout>(
Expand All @@ -230,43 +223,35 @@ FeaturePromoBubbleView::FeaturePromoBubbleView(
button_container->SetProperty(
views::kMarginsKey, gfx::Insets(button_vertical_spacing, 0, 0, 0));

const std::u16string snooze_text =
l10n_util::GetStringUTF16(IDS_PROMO_SNOOZE_BUTTON);
const std::u16string dismiss_text =
l10n_util::GetStringUTF16(IDS_PROMO_DISMISS_BUTTON);
bool dismiss_is_leading = views::PlatformStyle::kIsOkButtonLeading;

auto close_bubble_and_run_callback = [](FeaturePromoBubbleView* view,
base::RepeatingClosure callback,
const ui::Event& event) {
view->CloseBubble();
callback.Run();
};

snooze_button_ = button_container->AddChildView(
std::make_unique<views::MdIPHBubbleButton>(
base::BindRepeating(close_bubble_and_run_callback,
base::Unretained(this), snooze_callback),
snooze_text, false));
dismiss_button_ = button_container->AddChildViewAt(
std::make_unique<views::MdIPHBubbleButton>(
base::BindRepeating(close_bubble_and_run_callback,
base::Unretained(this), dismiss_callback),
dismiss_text, true),
dismiss_is_leading ? 0 : 1);

auto* leading_button =
dismiss_is_leading ? dismiss_button_ : snooze_button_;
leading_button->SetProperty(
views::kMarginsKey,
gfx::Insets(0, layout_provider->GetDistanceMetric(
views::DISTANCE_RELATED_BUTTON_HORIZONTAL)));

// The text in dismiss button will be shorter than the default min size.
// Set min size to 0 so that the custom padding is effective.
dismiss_button_->SetMinSize(gfx::Size(0, 0));
snooze_button_->SetCustomPadding(kBubbleButtonPadding);
dismiss_button_->SetCustomPadding(kBubbleButtonPadding);
const int button_spacing = layout_provider->GetDistanceMetric(
views::DISTANCE_RELATED_BUTTON_HORIZONTAL);

bool is_first_button = true;
for (ButtonParams& button_params : params.buttons) {
MdIPHBubbleButton* const button =
button_container->AddChildView(std::make_unique<MdIPHBubbleButton>(
base::BindRepeating(close_bubble_and_run_callback,
base::Unretained(this),
std::move(button_params.callback)),
std::move(button_params.text), button_params.has_border));
buttons_.push_back(button);

button->SetMinSize(gfx::Size(0, 0));
button->SetCustomPadding(kBubbleButtonPadding);

if (!is_first_button) {
button->SetProperty(views::kMarginsKey,
gfx::Insets(0, button_spacing, 0, 0));
}
is_first_button = false;
}
}

if (!focusable_)
Expand All @@ -292,18 +277,25 @@ FeaturePromoBubbleView::FeaturePromoBubbleView(

FeaturePromoBubbleView::~FeaturePromoBubbleView() = default;

FeaturePromoBubbleView::ButtonParams::ButtonParams() = default;
FeaturePromoBubbleView::ButtonParams::ButtonParams(ButtonParams&&) = default;
FeaturePromoBubbleView::ButtonParams::~ButtonParams() = default;

FeaturePromoBubbleView::ButtonParams&
FeaturePromoBubbleView::ButtonParams::operator=(
FeaturePromoBubbleView::ButtonParams&&) = default;

FeaturePromoBubbleView::CreateParams::CreateParams() = default;
FeaturePromoBubbleView::CreateParams::CreateParams(CreateParams&&) = default;
FeaturePromoBubbleView::CreateParams::~CreateParams() = default;

FeaturePromoBubbleView::CreateParams&
FeaturePromoBubbleView::CreateParams::operator=(
FeaturePromoBubbleView::CreateParams&&) = default;

// static
FeaturePromoBubbleView* FeaturePromoBubbleView::Create(
CreateParams params,
base::RepeatingClosure snooze_callback,
base::RepeatingClosure dismiss_callback) {
return new FeaturePromoBubbleView(std::move(params),
std::move(snooze_callback),
std::move(dismiss_callback));
FeaturePromoBubbleView* FeaturePromoBubbleView::Create(CreateParams params) {
return new FeaturePromoBubbleView(std::move(params));
}

void FeaturePromoBubbleView::CloseBubble() {
Expand Down Expand Up @@ -352,12 +344,8 @@ gfx::Size FeaturePromoBubbleView::CalculatePreferredSize() const {
return layout_manager_preferred_size;
}

views::Button* FeaturePromoBubbleView::GetDismissButtonForTesting() const {
return dismiss_button_;
}

views::Button* FeaturePromoBubbleView::GetSnoozeButtonForTesting() const {
return snooze_button_;
views::Button* FeaturePromoBubbleView::GetButtonForTesting(int index) const {
return buttons_[index];
}

BEGIN_METADATA(FeaturePromoBubbleView, views::BubbleDialogDelegateView)
Expand Down
38 changes: 21 additions & 17 deletions chrome/browser/ui/views/user_education/feature_promo_bubble_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,34 @@ class FeaturePromoBubbleView : public views::BubbleDialogDelegateView {
FeaturePromoBubbleView& operator=(const FeaturePromoBubbleView&) = delete;
~FeaturePromoBubbleView() override;

struct ButtonParams {
ButtonParams();
ButtonParams(ButtonParams&&);
~ButtonParams();

ButtonParams& operator=(ButtonParams&&);

std::u16string text;
bool has_border;
base::RepeatingClosure callback;
};

struct CreateParams {
CreateParams();
CreateParams(CreateParams&&);
~CreateParams();

CreateParams& operator=(CreateParams&&);

views::View* anchor_view = nullptr;
views::BubbleBorder::Arrow arrow = views::BubbleBorder::TOP_LEFT;

std::u16string body_text;
base::Optional<std::u16string> title_text;
base::Optional<std::u16string> screenreader_text;

bool snoozable = false;
std::vector<ButtonParams> buttons;

views::BubbleBorder::Arrow arrow = views::BubbleBorder::TOP_LEFT;
base::Optional<int> preferred_width;

bool focusable = false;
Expand All @@ -66,21 +80,15 @@ class FeaturePromoBubbleView : public views::BubbleDialogDelegateView {
//
// Creates the promo. The returned pointer is only valid until the
// widget is destroyed. It must not be manually deleted by the caller.
static FeaturePromoBubbleView* Create(
CreateParams params,
base::RepeatingClosure snooze_callback = base::RepeatingClosure(),
base::RepeatingClosure dismiss_callback = base::RepeatingClosure());
static FeaturePromoBubbleView* Create(CreateParams params);

// Closes the promo bubble.
void CloseBubble();

views::Button* GetDismissButtonForTesting() const;
views::Button* GetSnoozeButtonForTesting() const;
views::Button* GetButtonForTesting(int index) const;

private:
FeaturePromoBubbleView(CreateParams params,
base::RepeatingClosure snooze_callback,
base::RepeatingClosure dismiss_callback);
explicit FeaturePromoBubbleView(CreateParams params);

// BubbleDialogDelegateView:
bool OnMousePressed(const ui::MouseEvent& event) override;
Expand All @@ -103,12 +111,8 @@ class FeaturePromoBubbleView : public views::BubbleDialogDelegateView {
// get blurred.
bool persist_on_blur_ = false;

// Determines if this bubble has dismiss and snooze buttons.
// If true, |focusable_| must be true for keyboard accessibility.
bool snoozable_;

views::MdTextButton* dismiss_button_ = nullptr;
views::MdTextButton* snooze_button_ = nullptr;
// If the bubble has buttons, it must be focusable.
std::vector<views::MdTextButton*> buttons_;

std::u16string accessible_name_;

Expand Down

0 comments on commit 381258f

Please sign in to comment.