chromium/ash/app_menu/notification_item_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/app_menu/notification_item_view.h"

#include "ash/public/cpp/app_menu_constants.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/text_elider.h"
#include "ui/message_center/views/proportional_image_view.h"
#include "ui/views/animation/slide_out_controller.h"
#include "ui/views/background.h"
#include "ui/views/border.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/menu/menu_config.h"
#include "ui/views/layout/box_layout.h"

namespace ash {

namespace {

// Line height of all text in NotificationItemView in dips.
constexpr int kNotificationItemTextLineHeight = 16;

// Padding of |proportional_icon_view_|.
constexpr int kIconVerticalPadding = 4;
constexpr int kIconHorizontalPadding = 12;

// Stroke width of MenuItemView border in dips, used to prevent
// NotificationItemView from exceeding the width of MenuItemView.
constexpr int kBorderStrokeWidth = 1;

// The size of the icon in NotificationItemView in dips.
constexpr gfx::Size kProportionalIconViewSize(24, 24);

// Text color of NotificationItemView's |message_|.
constexpr SkColor kNotificationMessageTextColor =
    SkColorSetARGB(179, 0x5F, 0x63, 0x68);

// Text color of NotificationItemView's |title_|.
constexpr SkColor kNotificationTitleTextColor =
    SkColorSetARGB(230, 0x21, 0x23, 0x24);

}  // namespace

NotificationItemView::NotificationItemView(
    NotificationMenuView::Delegate* delegate,
    views::SlideOutControllerDelegate* slide_out_controller_delegate,
    const std::u16string& title,
    const std::u16string& message,
    const ui::ImageModel& icon,
    const std::string& notification_id)
    : delegate_(delegate),
      slide_out_controller_(std::make_unique<views::SlideOutController>(
          this,
          slide_out_controller_delegate)),
      title_(title),
      message_(message),
      notification_id_(notification_id) {
  DCHECK(delegate_);
  DCHECK(slide_out_controller_delegate);

  // Paint to a new layer so |slide_out_controller_| can control the opacity.
  SetPaintToLayer();
  layer()->SetFillsBoundsOpaquely(true);
  SetBorder(views::CreateEmptyBorder(gfx::Insets::TLBR(
      kNotificationVerticalPadding, kNotificationHorizontalPadding,
      kNotificationVerticalPadding, kIconHorizontalPadding)));
  SetBackground(views::CreateSolidBackground(SK_ColorWHITE));

  text_container_ = new views::View();
  text_container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
      views::BoxLayout::Orientation::kVertical));
  AddChildView(text_container_.get());

  title_label_ = new views::Label(title_);
  title_label_->SetEnabledColor(kNotificationTitleTextColor);
  title_label_->SetLineHeight(kNotificationItemTextLineHeight);
  title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  text_container_->AddChildView(title_label_.get());

  message_label_ = new views::Label(message_);
  message_label_->SetEnabledColor(kNotificationMessageTextColor);
  message_label_->SetLineHeight(kNotificationItemTextLineHeight);
  message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  text_container_->AddChildView(message_label_.get());

  proportional_icon_view_ =
      new message_center::ProportionalImageView(kProportionalIconViewSize);
  AddChildView(proportional_icon_view_.get());
  proportional_icon_view_->SetImage(icon, kProportionalIconViewSize);
}

NotificationItemView::~NotificationItemView() = default;

void NotificationItemView::UpdateContents(const std::u16string& title,
                                          const std::u16string& message,
                                          const ui::ImageModel& icon) {
  if (title_ != title) {
    title_ = title;
    title_label_->SetText(title_);
  }
  if (message_ != message) {
    message_ = message;
    message_label_->SetText(message_);
  }
  proportional_icon_view_->SetImage(icon, kProportionalIconViewSize);
}

gfx::Size NotificationItemView::CalculatePreferredSize(
    const views::SizeBounds& available_size) const {
  return gfx::Size(views::MenuConfig::instance().touchable_menu_min_width -
                       kBorderStrokeWidth,
                   kNotificationItemViewHeight);
}

void NotificationItemView::Layout(PassKey) {
  gfx::Insets insets = GetInsets();
  // Enforce |text_container_| width, if necessary the labels will elide as a
  // result of |text_container_| being too small to hold the full width of its
  // children labels.
  const gfx::Size text_container_size(
      views::MenuConfig::instance().touchable_menu_min_width -
          kNotificationHorizontalPadding - kIconHorizontalPadding * 2 -
          kProportionalIconViewSize.width(),
      title_label_
              ->GetPreferredSize(views::SizeBounds(title_label_->width(), {}))
              .height() +
          message_label_
              ->GetPreferredSize(views::SizeBounds(message_label_->width(), {}))
              .height());
  text_container_->SetBounds(insets.left(), insets.top(),
                             text_container_size.width(),
                             text_container_size.height());

  proportional_icon_view_->SetBounds(
      width() - insets.right() - kProportionalIconViewSize.width(),
      insets.top() + kIconVerticalPadding, kProportionalIconViewSize.width(),
      kProportionalIconViewSize.height());
}

bool NotificationItemView::OnMousePressed(const ui::MouseEvent& event) {
  return true;
}

bool NotificationItemView::OnMouseDragged(const ui::MouseEvent& event) {
  return true;
}

void NotificationItemView::OnMouseReleased(const ui::MouseEvent& event) {
  gfx::Point location(event.location());
  views::View::ConvertPointToScreen(this, &location);
  if (!event.IsOnlyLeftMouseButton() ||
      !GetBoundsInScreen().Contains(location)) {
    return;
  }

  delegate_->ActivateNotificationAndClose(notification_id_);
}

void NotificationItemView::OnGestureEvent(ui::GestureEvent* event) {
  // Drag gestures are handled by |slide_out_controller_|.
  switch (event->type()) {
    case ui::EventType::kGestureTap:
      event->SetHandled();
      delegate_->ActivateNotificationAndClose(notification_id_);
      return;
    default:
      return;
  }
}

BEGIN_METADATA(NotificationItemView)
END_METADATA

}  // namespace ash