1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_TABS_RECENT_ACTIVITY_BUBBLE_DIALOG_VIEW_H_
#define CHROME_BROWSER_UI_VIEWS_TABS_RECENT_ACTIVITY_BUBBLE_DIALOG_VIEW_H_
#include "base/scoped_observation.h"
#include "chrome/browser/ui/views/controls/hover_button.h"
#include "chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h"
#include "components/collaboration/public/messaging/activity_log.h"
#include "components/favicon_base/favicon_types.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/view_tracker.h"
#include "ui/views/widget/widget_observer.h"
namespace content {
class WebContents;
} // namespace content
class Profile;
class RecentActivityRowView;
class RecentActivityRowImageView;
using collaboration::messaging::ActivityLogItem;
DECLARE_ELEMENT_IDENTIFIER_VALUE(kRecentActivityBubbleDialogId);
// The bubble dialog view housing the Shared Tab Group Recent Activity.
// Shows at most kMaxNumberRows of the activity_log parameter.
class RecentActivityBubbleDialogView : public LocationBarBubbleDelegateView,
public ui::SimpleMenuModel::Delegate {
METADATA_HEADER(RecentActivityBubbleDialogView, LocationBarBubbleDelegateView)
public:
enum OptionsMenuItem { SEE_ALL_ACTIVITY };
DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kCloseButtonId);
DECLARE_CLASS_ELEMENT_IDENTIFIER_VALUE(kSeeAllActivityId);
RecentActivityBubbleDialogView(
View* anchor_view,
content::WebContents* web_contents,
std::vector<ActivityLogItem> tab_activity_log,
std::vector<ActivityLogItem> group_activity_log,
Profile* profile);
~RecentActivityBubbleDialogView() override;
// ui::SimpleMenuModel::Delegate:
void ExecuteCommand(int command_id, int event_flags) override;
// The maximum number of rows that can be displayed in this dialog.
static constexpr int kMaxNumberRows = 5;
// Creates a state indicating there is no activity to show.
void CreateEmptyState();
// Creates a view containing the single most recent tab activity.
void CreateTabActivity();
// Creates a view containing the most recent activity for the group.
void CreateGroupActivity();
// Returns the title view container including the title, the menu button, and
// the close button.
std::u16string GetTitleForTesting();
// Returns the row's view at the given index. This will look in both
// the tab activity container and the group activity container.
RecentActivityRowView* GetRowForTesting(int n);
views::View* tab_activity_container() const {
return tab_activity_container_;
}
views::View* group_activity_container() const {
return group_activity_container_;
}
private:
// View IDs used for selecting views in tests.
enum RecentActivityViewID {
TITLE_VIEW_ID,
TITLE_ID,
};
// Close this bubble.
void Close();
// Creates a button view for the close button.
std::unique_ptr<views::Button> CreateCloseButton();
// Creates a button view for the 3-dot menu button.
std::unique_ptr<views::Button> CreateOptionsMenuButton();
// Creates the top row of the dialog, including the title of the dialog, the
// 3-dot menu button, and the close button.
void CreateTitleView();
// Displays a context menu anchored to |source|, allowing users to access
// additional actions like "See All Activity".
void ShowOptionsMenu(views::Button* source);
std::unique_ptr<ui::SimpleMenuModel> options_menu_model_;
std::unique_ptr<views::MenuRunner> options_menu_runner_;
// Containers will always be non-null. Visibility is toggled based on
// whether rows are added to each container.
raw_ptr<views::View> tab_activity_container_ = nullptr;
raw_ptr<views::View> group_activity_container_ = nullptr;
std::vector<ActivityLogItem> tab_activity_log_;
std::vector<ActivityLogItem> group_activity_log_;
const raw_ptr<Profile> profile_;
base::WeakPtrFactory<RecentActivityBubbleDialogView> weak_factory_{this};
};
// View containing a single ActivityLogItem. Each row shows activity
// text, metadata text, and an avatar/favicon view.
class RecentActivityRowView : public HoverButton {
METADATA_HEADER(RecentActivityRowView, View)
public:
RecentActivityRowView(ActivityLogItem item,
Profile* profile,
base::OnceCallback<void()> close_callback);
~RecentActivityRowView() override;
// HoverButton
void ButtonPressed();
RecentActivityRowImageView* image_view() const { return image_view_; }
// RecentActivityAction handlers.
// Focuses the open tab in the tab strip.
void FocusTab();
// Reopens the tab at the end of the group.
void ReopenTab();
// Opens the Tab Group editor bubble for the group.
void OpenTabGroupEditDialog();
// Opens the Data Sharing management bubble for the group.
void ManageSharing();
private:
raw_ptr<RecentActivityRowImageView> image_view_ = nullptr;
ActivityLogItem item_;
const raw_ptr<Profile> profile_ = nullptr;
base::OnceCallback<void()> close_callback_;
};
// View containing the avatar image and, if the event refers to a tab, the
// favicon of the tab. This view performs both asynchronous image fetches.
class RecentActivityRowImageView : public views::View {
METADATA_HEADER(RecentActivityRowImageView, View)
public:
RecentActivityRowImageView(ActivityLogItem item, Profile* profile);
~RecentActivityRowImageView() override;
// Returns whether there is an avatar image to show.
bool ShouldShowAvatar() const { return avatar_request_complete_; }
// Returns whether there is a favicon image to show.
bool ShouldShowFavicon() const { return !resized_favicon_image_.isNull(); }
private:
// views::View
void OnPaint(gfx::Canvas* canvas) override;
// Perform the avatar fetch, calling `SetAvatar` when complete.
void FetchAvatar();
void SetAvatar(const gfx::Image& avatar);
// Perform the favicon fetch, calling `SetFavicon` when complete.
void FetchFavicon();
void SetFavicon(const favicon_base::FaviconImageResult& favicon);
void PaintFavicon(gfx::Canvas* canvas, const gfx::Rect& avatar_bounds);
void PaintPlaceholderBackground(gfx::Canvas* canvas, const gfx::Rect& bounds);
void PaintFallbackIcon(gfx::Canvas* canvas, const gfx::Rect& bounds);
// When the avatar request is complete (or there is no avatar to
// request), this will be set to true. While the value is false, we
// will paint the background color as a placeholder for the avatar.
bool avatar_request_complete_ = false;
base::CancelableTaskTracker favicon_fetching_task_tracker_;
gfx::ImageSkia avatar_image_;
gfx::ImageSkia resized_favicon_image_;
ActivityLogItem item_;
const raw_ptr<Profile> profile_ = nullptr;
base::WeakPtrFactory<RecentActivityRowImageView> weak_factory_{this};
};
// The bubble coordinator for Shared Tab Group Recent Activity.
class RecentActivityBubbleCoordinator : public views::WidgetObserver {
public:
RecentActivityBubbleCoordinator();
~RecentActivityBubbleCoordinator() override;
// WidgetObserver:
void OnWidgetDestroying(views::Widget* widget) override;
// The RecentActivity dialog is used in multiple places, anchoring to
// different items. Two public method overloads are supplied here so
// the correct arrow will be used.
//
// Calls ShowCommon with the default arrow.
void Show(views::View* anchor_view,
content::WebContents* web_contents,
std::vector<ActivityLogItem> activity_log,
Profile* profile);
// Same as above, but provides a default arrow for anchoring to the
// page action. The default for location bar bubbles is to have a
// TOP_RIGHT arrow.
void ShowForCurrentTab(views::View* anchor_view,
content::WebContents* web_contents,
std::vector<ActivityLogItem> tab_activity_log,
std::vector<ActivityLogItem> group_activity_log,
Profile* profile);
void Hide();
RecentActivityBubbleDialogView* GetBubble() const;
bool IsShowing();
private:
// Show a bubble containing the given activity log.
void ShowCommon(std::unique_ptr<RecentActivityBubbleDialogView> bubble);
views::ViewTracker tracker_;
base::ScopedObservation<views::Widget, views::WidgetObserver>
bubble_widget_observation_{this};
};
#endif // CHROME_BROWSER_UI_VIEWS_TABS_RECENT_ACTIVITY_BUBBLE_DIALOG_VIEW_H_
|