blob: f03f2d03a88b47a19f6b90e2c700d64262c14db8 [file] [log] [blame]
// 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_TABS_TAB_GROUP_DELETION_DIALOG_CONTROLLER_H_
#define CHROME_BROWSER_UI_TABS_TAB_GROUP_DELETION_DIALOG_CONTROLLER_H_
#include <memory>
#include <optional>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"
namespace ui {
class DialogModel;
}
class BrowserWindowInterface;
class Profile;
namespace tab_groups {
typedef base::RepeatingCallback<void(std::unique_ptr<ui::DialogModel>)>
ShowDialogModelCallback;
// Controller that is responsible for showing/hiding and performing callbacks
// for group deletions. Manages the state on a per-browser basis. Browsers can
// only have 1 of these dialogs at a time, therefore only 1 controller. An
// example of this showing up is on Ungroup from the tab group editor bubble.
class DeletionDialogController : public TabStripModelObserver {
public:
// Mapping of the different text strings and user preferences on this dialog.
enum class DialogType {
// Saved tab group dialogs.
DeleteSingle,
UngroupSingle,
RemoveTabAndDelete,
CloseTabAndDelete,
// Shared tab group dialogs.
DeleteSingleShared,
CloseTabAndKeepOrLeaveGroup,
CloseTabAndKeepOrDeleteGroup,
LeaveGroup,
};
enum class DeletionDialogTiming {
Synchronous,
Asynchronous,
};
// Encapsulates metadata required to determine which strings should be
// displayed in the deletion dialog.
struct DialogMetadata {
DialogMetadata(DialogType type,
int closing_group_count,
bool closing_multiple_tabs);
// Used for testing.
explicit DialogMetadata(DialogType type);
DialogMetadata(const DialogMetadata&) = delete;
~DialogMetadata();
DialogType type;
int closing_group_count = 0;
bool closing_multiple_tabs = false;
std::optional<std::u16string> title_of_closing_group;
};
// State object that represents the current dialog that is being shown.
struct DialogState {
DialogState(DialogType type_,
ui::DialogModel* dialog_model_,
base::OnceCallback<void(DeletionDialogTiming)> callback_,
std::optional<base::OnceClosure> keep_groups_);
~DialogState();
// The type the dialog was initiated with.
DialogType type;
// A ptr to the original dialog model. Used to access the checkbox value
// for setting the preference.
raw_ptr<ui::DialogModel> dialog_model;
// Callback that runs when the OK button is pressed.
base::OnceCallback<void(DeletionDialogTiming)> callback;
// Callback to handle the 'keep' case of CloseTabAndKeepOrLeaveGroup.
std::optional<base::OnceClosure> keep_groups;
};
DeletionDialogController(BrowserWindowInterface* browser,
Profile* profile,
TabStripModel* tab_strip_model);
DeletionDialogController(BrowserWindowInterface* browser,
Profile* profile,
TabStripModel* tab_strip_model,
ShowDialogModelCallback show_dialog_model);
DeletionDialogController(const DeletionDialogController&) = delete;
DeletionDialogController& operator=(const DeletionDialogController&) = delete;
~DeletionDialogController() override;
// If the BrowserWindow is currently in state where the dialog can be shown.
bool CanShowDialog() const;
// Whether the dialog is showing or not.
bool IsShowingDialog() const;
// Gets the dialog state for tests. Allows for calling the callbacks without
// going through views code.
void SimulateOkButtonForTesting() { OnDialogOk(); }
void CreateDialogFromBrowser(BrowserWindowInterface* browser,
std::unique_ptr<ui::DialogModel> dialog_model);
// Attempt to show the dialog. The dialog will only show if it is not already
// showing, and if the skip dialog option hasn't been set to true.
// `dialog_metadata` contains information that is used to help construct the
// strings for the dialog.
bool MaybeShowDialog(
const DialogMetadata& dialog_metadata,
base::OnceCallback<void(DeletionDialogTiming)> callback,
std::optional<base::OnceCallback<void()>> keep_groups = std::nullopt);
// TabStripModelObserver implementation:
void OnTabStripModelChanged(
TabStripModel* tab_strip_model,
const TabStripModelChange& change,
const TabStripSelectionChange& selection) override;
void SetPrefsPreventShowingDialogForTesting(bool should_prevent_dialog);
private:
// Builds a DialogModel for showing the dialog.
std::unique_ptr<ui::DialogModel> BuildDialogModel(
const DialogMetadata& dialog_metadata);
// Methods that are bound by the DialogModel to call the callbacks.
void OnDialogOk();
void OnDialogCancel();
Profile* GetProfile();
// The profile this controller is created for. Provides prefs and sync
// settings.
const raw_ref<Profile> profile_;
// The state needed for showing the dialog. Only exists if the dialog is
// currently showing.
std::optional<DialogState> state_;
// The function used to show the dialog when requested. This is injected so
// that tests can instrument showing the dialog model.
ShowDialogModelCallback show_dialog_model_fn_;
raw_ptr<views::Widget> widget_;
const raw_ref<TabStripModel> tab_strip_model_;
};
} // namespace tab_groups
#endif // CHROME_BROWSER_UI_TABS_TAB_GROUP_DELETION_DIALOG_CONTROLLER_H_