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
ash / system / focus_mode / focus_mode_feature_pod_controller.cc [blame]
// Copyright 2023 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/focus_mode/focus_mode_feature_pod_controller.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/quick_settings_catalogs.h"
#include "ash/resources/vector_icons/vector_icons.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/system/focus_mode/focus_mode_controller.h"
#include "ash/system/focus_mode/focus_mode_session.h"
#include "ash/system/focus_mode/focus_mode_util.h"
#include "ash/system/unified/feature_tile.h"
#include "ash/system/unified/unified_system_tray_controller.h"
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/i18n/time_formatting.h"
#include "base/time/time.h"
#include "ui/base/l10n/l10n_util.h"
namespace ash {
FocusModeFeaturePodController::FocusModeFeaturePodController(
UnifiedSystemTrayController* tray_controller)
: tray_controller_(tray_controller) {
CHECK(features::IsFocusModeEnabled());
FocusModeController::Get()->AddObserver(this);
}
FocusModeFeaturePodController::~FocusModeFeaturePodController() {
FocusModeController::Get()->RemoveObserver(this);
}
std::unique_ptr<FeatureTile> FocusModeFeaturePodController::CreateTile(
bool compact) {
auto tile = std::make_unique<FeatureTile>(
base::BindRepeating(&FocusModeFeaturePodController::OnLabelPressed,
weak_factory_.GetWeakPtr()));
tile_ = tile.get();
const auto* session_controller = Shell::Get()->session_controller();
std::optional<user_manager::UserType> user_type =
session_controller->GetUserType();
// Only show the focus mode tile if it is a regular user or if the user
// session is not blocked (e.g. lock screen).
const bool should_show_tile =
(user_type && (*user_type == user_manager::UserType::kRegular ||
*user_type == user_manager::UserType::kChild)) &&
!session_controller->IsUserSessionBlocked();
tile_->SetVisible(should_show_tile);
if (should_show_tile) {
TrackVisibilityUMA();
}
tile_->SetIconClickable(true);
tile_->SetIconClickCallback(
base::BindRepeating(&FocusModeFeaturePodController::OnIconPressed,
weak_factory_.GetWeakPtr()));
tile_->CreateDecorativeDrillInArrow();
tile_->SetVectorIcon(kFocusModeLampIcon);
tile_->icon_button()->SetFlipCanvasOnPaintForRTLUI(false);
auto* controller = FocusModeController::Get();
tile_->SetToggled(controller->in_focus_session());
UpdateUI(controller->GetSnapshot(base::Time::Now()));
return tile;
}
QsFeatureCatalogName FocusModeFeaturePodController::GetCatalogName() {
return QsFeatureCatalogName::kFocusMode;
}
void FocusModeFeaturePodController::OnIconPressed() {
auto* controller = FocusModeController::Get();
// As part of the first time user flow, if the user has never started a
// session before, we want to direct them to the focus panel so they can get
// more context and change focus settings instead of starting a session
// immediately.
if (!controller->HasStartedSessionBefore()) {
OnLabelPressed();
return;
}
TrackToggleUMA(/*target_toggle_state=*/!controller->in_focus_session());
controller->ToggleFocusMode(
focus_mode_histogram_names::ToggleSource::kFeaturePod);
}
void FocusModeFeaturePodController::OnLabelPressed() {
TrackDiveInUMA();
tray_controller_->ShowFocusModeDetailedView();
}
void FocusModeFeaturePodController::OnFocusModeChanged(
FocusModeSession::State session_state) {
UpdateUI(FocusModeController::Get()->GetSnapshot(base::Time::Now()));
const bool in_focus_session = session_state == FocusModeSession::State::kOn;
tile_->SetToggled(in_focus_session);
}
void FocusModeFeaturePodController::OnTimerTick(
const FocusModeSession::Snapshot& session_snapshot) {
UpdateUI(session_snapshot);
}
void FocusModeFeaturePodController::OnInactiveSessionDurationChanged(
const base::TimeDelta& session_duration) {
CHECK(tile_);
if (!FocusModeController::Get()->HasStartedSessionBefore()) {
return;
}
const std::u16string duration_string = focus_mode_util::GetDurationString(
session_duration, /*digital_format=*/false);
tile_->SetSubLabel(duration_string);
tile_->SetTooltipText(l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_INACTIVE, duration_string));
tile_->SetIconButtonTooltipText(l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_FOCUS_MODE_TOGGLE_BUTTON_INACTIVE, duration_string));
}
void FocusModeFeaturePodController::OnActiveSessionDurationChanged(
const FocusModeSession::Snapshot& session_snapshot) {
UpdateUI(session_snapshot);
}
void FocusModeFeaturePodController::UpdateUI(
const FocusModeSession::Snapshot& session_snapshot) {
auto* controller = FocusModeController::Get();
CHECK(controller);
CHECK(tile_);
const bool in_focus_session =
session_snapshot.state == FocusModeSession::State::kOn;
tile_->SetLabel(l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_FOCUS_MODE));
// As part of the first time user flow, if the user has never started a
// session before, we hide the session duration sublabel since they are not
// able to start a focus session immediately anyway.
if (!controller->HasStartedSessionBefore()) {
const std::u16string tooltip_text =
l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_INITIAL);
tile_->SetTooltipText(tooltip_text);
tile_->SetIconButtonTooltipText(tooltip_text);
tile_->SetSubLabelVisibility(false);
tile_->SetIconClickable(false);
return;
}
const base::TimeDelta session_duration_remaining =
in_focus_session ? session_snapshot.remaining_time
: controller->GetSessionDuration();
const std::u16string duration_string = focus_mode_util::GetDurationString(
session_duration_remaining, /*digital_format=*/false);
tile_->SetSubLabel(
in_focus_session
? l10n_util::GetStringFUTF16(
IDS_ASH_STATUS_TRAY_FOCUS_MODE_TIME_SUBLABEL, duration_string)
: duration_string);
const std::u16string tooltip_duration_string =
session_duration_remaining < base::Minutes(1)
? l10n_util::GetStringUTF16(
IDS_ASH_STATUS_TRAY_FOCUS_MODE_SESSION_LESS_THAN_ONE_MINUTE)
: duration_string;
tile_->SetTooltipText(l10n_util::GetStringFUTF16(
in_focus_session ? IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_ACTIVE
: IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_INACTIVE,
tooltip_duration_string));
tile_->SetIconClickable(true);
tile_->SetIconButtonTooltipText(l10n_util::GetStringFUTF16(
in_focus_session ? IDS_ASH_STATUS_TRAY_FOCUS_MODE_TILE_BUTTON_ACTIVE
: IDS_ASH_STATUS_TRAY_FOCUS_MODE_TOGGLE_BUTTON_INACTIVE,
tooltip_duration_string));
}
} // namespace ash