Commit 2834c1f5 authored by Dominique Fauteux-Chapleau's avatar Dominique Fauteux-Chapleau Committed by Commit Bot

Add top images to the Deep Scanning upload UI

The added images support dark mode and vary depending on if the data
being scanned is "text" (dragged web content or pasted text) or an
"upload" (dragged file or file upload via a dialog).

Bug: 999145
Change-Id: I7f4e583bedf92a308dcc65b90f9c7714b0c891e1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1991710Reviewed-by: default avatarGreg Thompson <grt@chromium.org>
Reviewed-by: default avatarDaniel Rubery <drubery@chromium.org>
Reviewed-by: default avatarPeter Kasting <pkasting@chromium.org>
Commit-Queue: Dominique Fauteux-Chapleau <domfc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#735391}
parent 80225bae
...@@ -326,6 +326,20 @@ ...@@ -326,6 +326,20 @@
<!-- Instant Extended API toolbar background is common for all platforms. --> <!-- Instant Extended API toolbar background is common for all platforms. -->
<structure type="chrome_scaled_image" name="IDR_THEME_WINDOW_CONTROL_BACKGROUND" file="notused.png" /> <structure type="chrome_scaled_image" name="IDR_THEME_WINDOW_CONTROL_BACKGROUND" file="notused.png" />
<structure type="chrome_scaled_image" name="IDR_TRANSLATE_BUBBLE_ICON" file="common/translate_bubble_icon.png" /> <structure type="chrome_scaled_image" name="IDR_TRANSLATE_BUBBLE_ICON" file="common/translate_bubble_icon.png" />
<if expr="not is_android">
<structure type="chrome_scaled_image" name="IDR_UPLOAD_SCANNING" file="common/upload_scanning.png" />
<structure type="chrome_scaled_image" name="IDR_UPLOAD_SUCCESS" file="common/upload_success.png" />
<structure type="chrome_scaled_image" name="IDR_UPLOAD_VIOLATION" file="common/upload_violation.png" />
<structure type="chrome_scaled_image" name="IDR_UPLOAD_SCANNING_DARK" file="common/upload_scanning_dark.png" />
<structure type="chrome_scaled_image" name="IDR_UPLOAD_SUCCESS_DARK" file="common/upload_success_dark.png" />
<structure type="chrome_scaled_image" name="IDR_UPLOAD_VIOLATION_DARK" file="common/upload_violation_dark.png" />
<structure type="chrome_scaled_image" name="IDR_PASTE_SCANNING" file="common/paste_scanning.png" />
<structure type="chrome_scaled_image" name="IDR_PASTE_SUCCESS" file="common/paste_success.png" />
<structure type="chrome_scaled_image" name="IDR_PASTE_VIOLATION" file="common/paste_violation.png" />
<structure type="chrome_scaled_image" name="IDR_PASTE_SCANNING_DARK" file="common/paste_scanning_dark.png" />
<structure type="chrome_scaled_image" name="IDR_PASTE_SUCCESS_DARK" file="common/paste_success_dark.png" />
<structure type="chrome_scaled_image" name="IDR_PASTE_VIOLATION_DARK" file="common/paste_violation_dark.png" />
</if>
<if expr="not _google_chrome"> <if expr="not _google_chrome">
<if expr="not is_android"> <if expr="not is_android">
<structure type="chrome_scaled_image" name="IDR_WEBSTORE_ICON" file="chromium/webstore_icon.png" /> <structure type="chrome_scaled_image" name="IDR_WEBSTORE_ICON" file="chromium/webstore_icon.png" />
......
...@@ -360,8 +360,10 @@ void DeepScanningDialogDelegate::ShowForWebContents( ...@@ -360,8 +360,10 @@ void DeepScanningDialogDelegate::ShowForWebContents(
// If the UI is enabled, create the modal dialog. // If the UI is enabled, create the modal dialog.
if (show_ui) { if (show_ui) {
DeepScanningDialogDelegate* delegate_ptr = delegate.get(); DeepScanningDialogDelegate* delegate_ptr = delegate.get();
bool is_file_scan = !delegate_ptr->data_.paths.empty();
delegate_ptr->dialog_ = delegate_ptr->dialog_ =
new DeepScanningDialogViews(std::move(delegate), web_contents); new DeepScanningDialogViews(std::move(delegate), web_contents,
std::move(access_point), is_file_scan);
return; return;
} }
......
...@@ -8,24 +8,33 @@ ...@@ -8,24 +8,33 @@
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "cc/paint/paint_flags.h" #include "cc/paint/paint_flags.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h" #include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h"
#include "components/constrained_window/constrained_window_views.h" #include "components/constrained_window/constrained_window_views.h"
#include "components/strings/grit/components_strings.h" #include "components/strings/grit/components_strings.h"
#include "components/vector_icons/vector_icons.h" #include "components/vector_icons/vector_icons.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_types.h" #include "ui/base/ui_base_types.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h" #include "ui/gfx/color_palette.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/paint_vector_icon.h" #include "ui/gfx/paint_vector_icon.h"
#include "ui/gfx/text_constants.h" #include "ui/gfx/text_constants.h"
#include "ui/native_theme/native_theme.h"
#include "ui/views/background.h" #include "ui/views/background.h"
#include "ui/views/border.h" #include "ui/views/border.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/image_view.h" #include "ui/views/controls/image_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/throbber.h" #include "ui/views/controls/throbber.h"
#include "ui/views/layout/box_layout.h" #include "ui/views/layout/box_layout.h"
#include "ui/views/layout/fill_layout.h" #include "ui/views/layout/fill_layout.h"
#include "ui/views/layout/grid_layout.h"
namespace safe_browsing { namespace safe_browsing {
...@@ -43,7 +52,6 @@ constexpr base::TimeDelta kSuccessDialogTimeout = ...@@ -43,7 +52,6 @@ constexpr base::TimeDelta kSuccessDialogTimeout =
constexpr base::TimeDelta kResizeAnimationDuration = constexpr base::TimeDelta kResizeAnimationDuration =
base::TimeDelta::FromMilliseconds(100); base::TimeDelta::FromMilliseconds(100);
constexpr SkColor kScanPendingColor = gfx::kGoogleBlue500;
constexpr SkColor kScanSuccessColor = gfx::kGoogleGreen500; constexpr SkColor kScanSuccessColor = gfx::kGoogleGreen500;
constexpr SkColor kScanFailureColor = gfx::kGoogleRed500; constexpr SkColor kScanFailureColor = gfx::kGoogleRed500;
...@@ -51,14 +59,11 @@ constexpr SkColor kScanPendingSideImageColor = gfx::kGoogleBlue400; ...@@ -51,14 +59,11 @@ constexpr SkColor kScanPendingSideImageColor = gfx::kGoogleBlue400;
constexpr SkColor kScanDoneSideImageColor = SkColorSetRGB(0xFF, 0xFF, 0xFF); constexpr SkColor kScanDoneSideImageColor = SkColorSetRGB(0xFF, 0xFF, 0xFF);
constexpr int kSideImageSize = 24; constexpr int kSideImageSize = 24;
constexpr int kTopImageSize = 100;
constexpr gfx::Insets kSideImageInsets = gfx::Insets(8, 8, 8, 8); constexpr gfx::Insets kSideImageInsets = gfx::Insets(8, 8, 8, 8);
constexpr gfx::Insets kMessageAndIconRowInsets = gfx::Insets(0, 32, 0, 48); constexpr gfx::Insets kMessageAndIconRowInsets = gfx::Insets(0, 32, 0, 48);
constexpr int kSideIconBetweenChildSpacing = 16; constexpr int kSideIconBetweenChildSpacing = 16;
constexpr int kTextLineHeight = 20;
// A simple background class to show a colored circle behind the side icon once // A simple background class to show a colored circle behind the side icon once
// the scanning is done. // the scanning is done.
class CircleBackground : public views::Background { class CircleBackground : public views::Background {
...@@ -79,10 +84,30 @@ class CircleBackground : public views::Background { ...@@ -79,10 +84,30 @@ class CircleBackground : public views::Background {
} // namespace } // namespace
// An image class used for the image at the top of the dialog.
class DeepScanningTopImageView : public views::ImageView {
public:
explicit DeepScanningTopImageView(DeepScanningDialogViews* dialog)
: dialog_(dialog) {}
void Update() { SetImage(dialog_->GetTopImage()); }
protected:
void OnThemeChanged() override { Update(); }
private:
DeepScanningDialogViews* dialog_;
};
DeepScanningDialogViews::DeepScanningDialogViews( DeepScanningDialogViews::DeepScanningDialogViews(
std::unique_ptr<DeepScanningDialogDelegate> delegate, std::unique_ptr<DeepScanningDialogDelegate> delegate,
content::WebContents* web_contents) content::WebContents* web_contents,
: delegate_(std::move(delegate)), web_contents_(web_contents) { base::Optional<DeepScanAccessPoint> access_point,
bool is_file_scan)
: delegate_(std::move(delegate)),
web_contents_(web_contents),
access_point_(std::move(access_point)),
is_file_scan_(is_file_scan) {
// Show the pending dialog after a delay in case the response is fast enough. // Show the pending dialog after a delay in case the response is fast enough.
base::PostDelayedTask(FROM_HERE, {content::BrowserThread::UI}, base::PostDelayedTask(FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&DeepScanningDialogViews::Show, base::BindOnce(&DeepScanningDialogViews::Show,
...@@ -156,11 +181,10 @@ void DeepScanningDialogViews::UpdateDialog() { ...@@ -156,11 +181,10 @@ void DeepScanningDialogViews::UpdateDialog() {
// Update the buttons. // Update the buttons.
SetupButtons(); SetupButtons();
// Update the top image. Currently only the color changes. // Update the top image.
image_->SetImage(gfx::CreateVectorIcon(vector_icons::kBusinessIcon, image_->Update();
kTopImageSize, GetImageColor()));
// Update the side icon by changing it's image color, adding a background and // Update the side icon by changing its image color, adding a background and
// removing the spinner. // removing the spinner.
side_icon_image_->SetImage(gfx::CreateVectorIcon( side_icon_image_->SetImage(gfx::CreateVectorIcon(
vector_icons::kBusinessIcon, kSideImageSize, kScanDoneSideImageColor)); vector_icons::kBusinessIcon, kSideImageSize, kScanDoneSideImageColor));
...@@ -257,12 +281,6 @@ base::string16 DeepScanningDialogViews::GetDialogMessage() const { ...@@ -257,12 +281,6 @@ base::string16 DeepScanningDialogViews::GetDialogMessage() const {
: IDS_DEEP_SCANNING_DIALOG_UPLOAD_FAILURE_MESSAGE); : IDS_DEEP_SCANNING_DIALOG_UPLOAD_FAILURE_MESSAGE);
} }
SkColor DeepScanningDialogViews::GetImageColor() const {
if (!scan_success_.has_value())
return kScanPendingColor;
return scan_success_.value() ? kScanSuccessColor : kScanFailureColor;
}
base::string16 DeepScanningDialogViews::GetCancelButtonText() const { base::string16 DeepScanningDialogViews::GetCancelButtonText() const {
if (!scan_success_.has_value()) { if (!scan_success_.has_value()) {
return l10n_util::GetStringUTF16( return l10n_util::GetStringUTF16(
...@@ -295,10 +313,7 @@ void DeepScanningDialogViews::Show() { ...@@ -295,10 +313,7 @@ void DeepScanningDialogViews::Show() {
// Add the top image. // Add the top image.
layout->StartRow(views::GridLayout::kFixedSize, 0); layout->StartRow(views::GridLayout::kFixedSize, 0);
auto image = std::make_unique<views::ImageView>(); image_ = layout->AddView(std::make_unique<DeepScanningTopImageView>(this));
image->SetImage(gfx::CreateVectorIcon(vector_icons::kBusinessIcon,
kTopImageSize, GetImageColor()));
image_ = layout->AddView(std::move(image));
// Add padding to distance the top image from the icon and message. // Add padding to distance the top image from the icon and message.
layout->AddPaddingRow(views::GridLayout::kFixedSize, 16); layout->AddPaddingRow(views::GridLayout::kFixedSize, 16);
...@@ -321,7 +336,6 @@ void DeepScanningDialogViews::Show() { ...@@ -321,7 +336,6 @@ void DeepScanningDialogViews::Show() {
// Add the message. // Add the message.
auto label = std::make_unique<views::Label>(GetDialogMessage()); auto label = std::make_unique<views::Label>(GetDialogMessage());
label->SetMultiLine(true); label->SetMultiLine(true);
label->SetLineHeight(kTextLineHeight);
label->SetVerticalAlignment(gfx::ALIGN_MIDDLE); label->SetVerticalAlignment(gfx::ALIGN_MIDDLE);
label->SetHorizontalAlignment(gfx::ALIGN_LEFT); label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
message_ = icon_and_message_row->AddChildView(std::move(label)); message_ = icon_and_message_row->AddChildView(std::move(label));
...@@ -368,10 +382,38 @@ std::unique_ptr<views::View> DeepScanningDialogViews::CreateSideIcon() { ...@@ -368,10 +382,38 @@ std::unique_ptr<views::View> DeepScanningDialogViews::CreateSideIcon() {
SkColor DeepScanningDialogViews::GetSideImageBackgroundColor() const { SkColor DeepScanningDialogViews::GetSideImageBackgroundColor() const {
DCHECK(scan_success_.has_value()); DCHECK(scan_success_.has_value());
return scan_success_.value() ? kScanSuccessColor : kScanFailureColor;
}
int DeepScanningDialogViews::GetPasteImageId(bool use_dark) const {
if (!scan_success_.has_value())
return use_dark ? IDR_PASTE_SCANNING_DARK : IDR_PASTE_SCANNING;
if (scan_success_.value()) if (scan_success_.value())
return kScanSuccessColor; return use_dark ? IDR_PASTE_SUCCESS_DARK : IDR_PASTE_SUCCESS;
else return use_dark ? IDR_PASTE_VIOLATION_DARK : IDR_PASTE_VIOLATION;
return kScanFailureColor; }
int DeepScanningDialogViews::GetUploadImageId(bool use_dark) const {
if (!scan_success_.has_value())
return use_dark ? IDR_UPLOAD_SCANNING_DARK : IDR_UPLOAD_SCANNING;
if (scan_success_.value())
return use_dark ? IDR_UPLOAD_SUCCESS_DARK : IDR_UPLOAD_SUCCESS;
return use_dark ? IDR_UPLOAD_VIOLATION_DARK : IDR_UPLOAD_VIOLATION;
}
const gfx::ImageSkia* DeepScanningDialogViews::GetTopImage() const {
const bool use_dark =
color_utils::IsDark(GetBubbleFrameView()->GetBackgroundColor());
const bool treat_as_text_paste =
access_point_.has_value() &&
(access_point_.value() == DeepScanAccessPoint::PASTE ||
(access_point_.value() == DeepScanAccessPoint::DRAG_AND_DROP &&
!is_file_scan_));
int image_id = treat_as_text_paste ? GetPasteImageId(use_dark)
: GetUploadImageId(use_dark);
return ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(image_id);
} }
} // namespace safe_browsing } // namespace safe_browsing
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
#include <memory> #include <memory>
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h" #include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h"
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_utils.h"
#include "ui/views/animation/bounds_animator.h" #include "ui/views/animation/bounds_animator.h"
#include "ui/views/controls/label.h" #include "ui/views/controls/label.h"
#include "ui/views/window/dialog_delegate.h" #include "ui/views/window/dialog_delegate.h"
...@@ -18,6 +20,10 @@ namespace content { ...@@ -18,6 +20,10 @@ namespace content {
class WebContents; class WebContents;
} // namespace content } // namespace content
namespace gfx {
class ImageSkia;
} // namespace gfx
namespace views { namespace views {
class ImageView; class ImageView;
class Throbber; class Throbber;
...@@ -25,13 +31,16 @@ class Widget; ...@@ -25,13 +31,16 @@ class Widget;
} // namespace views } // namespace views
namespace safe_browsing { namespace safe_browsing {
class DeepScanningTopImageView;
// Dialog shown for Deep Scanning to offer the possibility of cancelling the // Dialog shown for Deep Scanning to offer the possibility of cancelling the
// upload to the user. // upload to the user.
class DeepScanningDialogViews : public views::DialogDelegate { class DeepScanningDialogViews : public views::DialogDelegate {
public: public:
DeepScanningDialogViews(std::unique_ptr<DeepScanningDialogDelegate> delegate, DeepScanningDialogViews(std::unique_ptr<DeepScanningDialogDelegate> delegate,
content::WebContents* web_contents); content::WebContents* web_contents,
base::Optional<DeepScanAccessPoint> access_point,
bool is_file_scan);
// views::DialogDelegate: // views::DialogDelegate:
base::string16 GetWindowTitle() const override; base::string16 GetWindowTitle() const override;
...@@ -45,6 +54,9 @@ class DeepScanningDialogViews : public views::DialogDelegate { ...@@ -45,6 +54,9 @@ class DeepScanningDialogViews : public views::DialogDelegate {
// nothing should be shown. // nothing should be shown.
void ShowResult(bool success); void ShowResult(bool success);
// Returns the appropriate top image depending on |scan_success_|.
const gfx::ImageSkia* GetTopImage() const;
private: private:
~DeepScanningDialogViews() override; ~DeepScanningDialogViews() override;
...@@ -66,15 +78,18 @@ class DeepScanningDialogViews : public views::DialogDelegate { ...@@ -66,15 +78,18 @@ class DeepScanningDialogViews : public views::DialogDelegate {
// Returns the appropriate dialog message depending on |scan_success_|. // Returns the appropriate dialog message depending on |scan_success_|.
base::string16 GetDialogMessage() const; base::string16 GetDialogMessage() const;
// Returns the image's color depending on |scan_success_|.
SkColor GetImageColor() const;
// Returns the side image's background circle color. // Returns the side image's background circle color.
SkColor GetSideImageBackgroundColor() const; SkColor GetSideImageBackgroundColor() const;
// Returns the appropriate dialog message depending on |scan_success_|. // Returns the appropriate dialog message depending on |scan_success_|.
base::string16 GetCancelButtonText() const; base::string16 GetCancelButtonText() const;
// Returns the appropriate paste top image ID depending on |scan_success_|.
int GetPasteImageId(bool use_dark) const;
// Returns the appropriate upload top image ID depending on |scan_success_|.
int GetUploadImageId(bool use_dark) const;
// Show the dialog. Sets |shown_| to true. // Show the dialog. Sets |shown_| to true.
void Show(); void Show();
...@@ -84,7 +99,7 @@ class DeepScanningDialogViews : public views::DialogDelegate { ...@@ -84,7 +99,7 @@ class DeepScanningDialogViews : public views::DialogDelegate {
// Views above the buttons. |contents_view_| owns every other view. // Views above the buttons. |contents_view_| owns every other view.
std::unique_ptr<views::View> contents_view_; std::unique_ptr<views::View> contents_view_;
views::ImageView* image_; DeepScanningTopImageView* image_;
views::ImageView* side_icon_image_; views::ImageView* side_icon_image_;
views::Throbber* side_icon_spinner_; views::Throbber* side_icon_spinner_;
views::Label* message_; views::Label* message_;
...@@ -103,6 +118,14 @@ class DeepScanningDialogViews : public views::DialogDelegate { ...@@ -103,6 +118,14 @@ class DeepScanningDialogViews : public views::DialogDelegate {
// Used to animate dialog height changes. // Used to animate dialog height changes.
std::unique_ptr<views::BoundsAnimator> bounds_animator_; std::unique_ptr<views::BoundsAnimator> bounds_animator_;
// The access point that caused this dialog to open. This changes what text
// and top image are shown to the user.
base::Optional<DeepScanAccessPoint> access_point_;
// Indicates whether the scan being done is for files or for text. This
// changes what text and top image are shown to the user.
bool is_file_scan_;
base::WeakPtrFactory<DeepScanningDialogViews> weak_ptr_factory_{this}; base::WeakPtrFactory<DeepScanningDialogViews> weak_ptr_factory_{this};
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment