chromium/ash/system/notification_center/views/notification_swipe_control_view.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/system/notification_center/views/notification_swipe_control_view.h"
#include <memory>

#include "ash/style/icon_button.h"
#include "ash/system/notification_center/message_center_constants.h"
#include "ash/system/notification_center/message_center_style.h"
#include "ash/system/notification_center/message_center_utils.h"
#include "ash/system/notification_center/metrics_utils.h"
#include "base/functional/bind.h"
#include "base/i18n/rtl.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/compositor/layer.h"
#include "ui/events/event.h"
#include "ui/message_center/views/message_view.h"
#include "ui/message_center/views/notification_control_buttons_view.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/layout/box_layout.h"

namespace ash {

NotificationSwipeControlView::NotificationSwipeControlView(
    message_center::MessageView* message_view)
    : message_view_(message_view) {
  auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
      views::BoxLayout::Orientation::kHorizontal,
      kNotificationSwipeControlPadding,
      message_center_style::kSwipeControlButtonHorizontalMargin));
  layout->set_cross_axis_alignment(
      views::BoxLayout::CrossAxisAlignment::kCenter);
  layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kEnd);

  std::unique_ptr<views::ImageButton> settings_button;
  settings_button = std::make_unique<IconButton>(
      base::BindRepeating(&NotificationSwipeControlView::ButtonPressed,
                          base::Unretained(this)),
      IconButton::Type::kMedium, &vector_icons::kSettingsOutlineIcon,
      IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME);

  settings_button->SetImageHorizontalAlignment(
      views::ImageButton::ALIGN_CENTER);
  settings_button->SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);

  settings_button_ = AddChildView(std::move(settings_button));
  settings_button_->SetVisible(false);

  // Draw on their own layers to round corners and perform animation.
  settings_button_->SetPaintToLayer();
  settings_button_->layer()->SetFillsBoundsOpaquely(false);
  SetPaintToLayer();
  layer()->SetFillsBoundsOpaquely(false);
}

NotificationSwipeControlView::~NotificationSwipeControlView() = default;

void NotificationSwipeControlView::ShowButtons(ButtonPosition button_position,
                                               bool show_settings) {
  views::BoxLayout* layout = static_cast<views::BoxLayout*>(GetLayoutManager());
  if ((button_position == ButtonPosition::RIGHT) != base::i18n::IsRTL()) {
    layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kEnd);
  } else {
    layout->set_main_axis_alignment(
        views::BoxLayout::MainAxisAlignment::kStart);
  }
  ShowSettingsButton(show_settings);
  DeprecatedLayoutImmediately();
}

void NotificationSwipeControlView::HideButtons() {
  ShowSettingsButton(false);
  DeprecatedLayoutImmediately();
}

void NotificationSwipeControlView::UpdateButtonsVisibility() {
  float gesture_amount = message_view_->GetSlideAmount();
  if (gesture_amount == 0) {
    HideButtons();
    return;
  }

  NotificationSwipeControlView::ButtonPosition button_position =
      gesture_amount < 0 ? ButtonPosition::RIGHT : ButtonPosition::LEFT;
  message_center::NotificationControlButtonsView* buttons =
      message_view_->GetControlButtonsView();
  // Ignore when GetControlButtonsView() returns null.
  if (!buttons) {
    return;
  }
  bool has_settings_button = buttons->settings_button();

  if (!has_settings_button) {
    return;
  }

  int extra_padding = button_position == ButtonPosition::RIGHT
                          ? kNotificationSwipeControlPadding.left()
                          : kNotificationSwipeControlPadding.right();
  int settings_button_width = settings_button_->GetPreferredSize().width();

  // We only show the settings button if we have enough space for display.
  bool enough_space_to_show_button =
      abs(gesture_amount) >= settings_button_width + extra_padding;
  ShowButtons(button_position,
              has_settings_button && enough_space_to_show_button);

  message_view_->SetSlideButtonWidth(
      settings_button_ ? settings_button_width + settings_button_->width() : 0);
}

void NotificationSwipeControlView::ShowSettingsButton(bool show) {
  bool was_visible = settings_button_->GetVisible();
  settings_button_->SetVisible(show);

  // Fade in animation if the visibility changes from false to true.
  if (!was_visible && show) {
    message_center_utils::FadeInView(
        settings_button_, /*delay_in_ms=*/0,
        kNotificationSwipeControlFadeInDurationMs, gfx::Tween::Type::LINEAR,
        "Ash.Notification.SwipeControl.FadeIn.AnimationSmoothness");
  }
}

void NotificationSwipeControlView::ButtonPressed(const ui::Event& event) {
  auto weak_this = weak_factory_.GetWeakPtr();

  const std::string notification_id = message_view_->notification_id();
  message_view_->OnSettingsButtonPressed(event);
  metrics_utils::LogSettingsShown(notification_id,
                                  /*is_slide_controls=*/true,
                                  /*is_popup=*/false);

  // Button handlers of |message_view_| may have closed |this|.
  if (!weak_this) {
    return;
  }

  HideButtons();

  // Closing the swipe control is done in these button pressed handlers.
  // Otherwise, handlers might not work.
  message_view_->CloseSwipeControl();
}

BEGIN_METADATA(NotificationSwipeControlView)
END_METADATA

}  // namespace ash