helium/ui/tabs: tab muting, move indicator to left (#517)

- enabled the tab muting feature by default
- fixed the UX issue with the alert indicator and the close button
  swapping places on hover
- increased the minimum width for close buttons to prevent mute &
  close buttons from overlapping each other
- removed the fade animation from the indicator

closes #324
This commit is contained in:
wukko
2025-11-24 20:46:58 +06:00
committed by GitHub
parent 1a266da9a3
commit 94fa070851

View File

@@ -91,7 +91,71 @@
return TabGroupUnderline::kStrokeThickness;
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -1164,7 +1164,7 @@ void Tab::UpdateIconVisibility() {
@@ -129,6 +129,8 @@ constexpr int kTabAlertIndicatorCloseBut
// the discard ring by this amount if there is enough space.
constexpr int kIncreasedDiscardIndicatorRadiusDp = 2;
+constexpr int kIndicatorPadding = 2;
+
bool g_show_hover_card_on_mouse_hover = true;
// Helper functions ------------------------------------------------------------
@@ -428,19 +430,15 @@ void Tab::Layout(PassKey) {
}
close_button_->SetVisible(showing_close_button_);
+ int alert_indicator_right = contents_rect.right();
if (showing_alert_indicator_) {
- int right = contents_rect.right();
- if (showing_close_button_) {
- right = close_x;
- if (extra_alert_indicator_padding_) {
- right -= ui::TouchUiController::Get()->touch_ui()
- ? kTabAlertIndicatorCloseButtonPaddingAdjustmentTouchUI
- : kTabAlertIndicatorCloseButtonPaddingAdjustment;
- }
+ int alert_left = start;
+ if (showing_icon_) {
+ alert_left = favicon_bounds.right() + kIndicatorPadding;
}
const gfx::Size image_size = alert_indicator_button_->GetPreferredSize();
gfx::Rect bounds(
- std::max(contents_rect.x(), right - image_size.width()),
+ alert_left,
contents_rect.y() + Center(contents_rect.height(), image_size.height()),
image_size.width(), image_size.height());
if (center_icon_) {
@@ -451,6 +449,7 @@ void Tab::Layout(PassKey) {
MaybeAdjustLeftForPinnedTab(&bounds, bounds.width());
}
alert_indicator_button_->SetBoundsRect(bounds);
+ alert_indicator_right = bounds.right();
}
alert_indicator_button_->SetVisible(showing_alert_indicator_);
@@ -458,7 +457,9 @@ void Tab::Layout(PassKey) {
bool show_title = ShouldRenderAsNormalTab();
if (show_title) {
int title_left = start;
- if (showing_icon_) {
+ if (showing_alert_indicator_) {
+ title_left = alert_indicator_right + kIndicatorPadding;
+ } else if (showing_icon_) {
// When computing the spacing from the favicon, don't count the actual
// icon view width (which will include extra room for the alert
// indicator), but rather the normal favicon width which is what it will
@@ -469,9 +470,7 @@ void Tab::Layout(PassKey) {
title_left = std::max(title_left, after_favicon);
}
int title_right = contents_rect.right();
- if (showing_alert_indicator_) {
- title_right = alert_indicator_button_->x() - after_title_padding;
- } else if (showing_close_button_) {
+ if (showing_close_button_) {
// Allow the title to overlay the close button's empty border padding.
title_right = close_x - after_title_padding;
}
@@ -1164,7 +1163,7 @@ void Tab::UpdateIconVisibility() {
// left that needs to be considered.
const int close_button_width = GetLayoutConstant(TAB_CLOSE_BUTTON_SIZE) +
GetLayoutConstant(TAB_AFTER_TITLE_PADDING);
@@ -100,7 +164,7 @@
available_width >= (touch_ui ? kTouchMinimumContentsWidthForCloseButtons
: kMinimumContentsWidthForCloseButtons);
@@ -1212,6 +1212,10 @@ void Tab::UpdateIconVisibility() {
@@ -1212,6 +1211,10 @@ void Tab::UpdateIconVisibility() {
large_enough_for_close_button;
if (base::CommandLine::ForCurrentProcess()->HasSwitch("hide-tab-close-buttons"))
showing_close_button_ = false;
@@ -111,7 +175,7 @@
if (showing_close_button_) {
available_width -= close_button_width;
}
@@ -1229,10 +1233,6 @@ void Tab::UpdateIconVisibility() {
@@ -1229,10 +1232,6 @@ void Tab::UpdateIconVisibility() {
}
}
}
@@ -122,6 +186,41 @@
}
bool Tab::ShouldRenderAsNormalTab() const {
@@ -1253,15 +1252,25 @@ void Tab::UpdateTabIconNeedsAttentionBlo
}
int Tab::GetWidthOfLargestSelectableRegion() const {
- // Assume the entire region to the left of the alert indicator and/or close
- // buttons is available for click-to-select. If neither are visible, the
- // entire tab region is available.
- const int indicator_left = alert_indicator_button_->GetVisible()
- ? alert_indicator_button_->x()
- : width();
- const int close_button_left =
- close_button_->GetVisible() ? close_button_->x() : width();
- return std::min(indicator_left, close_button_left);
+ // Returns the rightmost boundary of the selectable region, aka
+ // the space where the user can click to select the tab.
+ //
+ // This area is between the alert indicator (if visible) and the close
+ // button (if visible). It's used by AlertIndicatorButton to determine
+ // if there's enough safe click area to enable the mute toggle on
+ // inactive tabs.
+
+ int selectable_region = width();
+
+ if (alert_indicator_button_->GetVisible()) {
+ selectable_region = alert_indicator_button_->bounds().right();
+ }
+
+ if (close_button_->GetVisible()) {
+ selectable_region = std::min(selectable_region, close_button_->x());
+ }
+
+ return selectable_region;
}
void Tab::UpdateForegroundColors() {
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -69,7 +69,7 @@ class Tab : public gfx::AnimationDelegat
@@ -129,7 +228,7 @@
// hide the close button on inactive tabs. Any smaller and they're too easy
// to hit on accident.
- static constexpr int kMinimumContentsWidthForCloseButtons = 68;
+ static constexpr int kMinimumContentsWidthForCloseButtons = 42;
+ static constexpr int kMinimumContentsWidthForCloseButtons = 56;
static constexpr int kTouchMinimumContentsWidthForCloseButtons = 100;
// Sets whether hover cards should appear on mouse hover. Used in browser
@@ -334,3 +433,67 @@
// Set the bounds of the sync icon first, followed by the title.
const int start_of_sync_icon = title_chip_insets.left();
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -324,7 +324,7 @@ BASE_FEATURE(kPictureInPictureShowWindow
#endif // !BUILDFLAG(IS_ANDROID)
// Enables user control over muting tab audio from the tab strip.
-BASE_FEATURE(kEnableTabMuting, base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kEnableTabMuting, base::FEATURE_ENABLED_BY_DEFAULT);
#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
// Enables HEVC hardware accelerated decoding.
--- a/chrome/browser/ui/views/tabs/alert_indicator_button.cc
+++ b/chrome/browser/ui/views/tabs/alert_indicator_button.cc
@@ -160,27 +160,8 @@ void AlertIndicatorButton::TransitionToA
UpdateIconForAlertState(next_state.value());
}
- if ((alert_state_ == tabs::TabAlert::AUDIO_PLAYING &&
- next_state == tabs::TabAlert::AUDIO_MUTING) ||
- (alert_state_ == tabs::TabAlert::AUDIO_MUTING &&
- next_state == tabs::TabAlert::AUDIO_PLAYING)) {
- // Instant user feedback: No fade animation.
- showing_alert_state_ = next_state;
- fade_animation_.reset();
- } else {
- if (!next_state) {
- showing_alert_state_ = alert_state_; // Fading-out indicator.
- } else {
- showing_alert_state_ = next_state; // Fading-in to next indicator.
- }
- fade_animation_ = CreateTabAlertIndicatorFadeAnimation(next_state);
- if (!fade_animation_delegate_) {
- fade_animation_delegate_ = std::make_unique<FadeAnimationDelegate>(this);
- }
- fade_animation_->set_delegate(fade_animation_delegate_.get());
- fade_animation_->Start();
- }
-
+ showing_alert_state_ = next_state;
+ fade_animation_.reset();
alert_state_ = next_state;
if (previous_alert_showing_state != showing_alert_state_) {
@@ -289,20 +270,7 @@ bool AlertIndicatorButton::IsTriggerable
}
void AlertIndicatorButton::PaintButtonContents(gfx::Canvas* canvas) {
- double opaqueness = 1.0;
- if (fade_animation_) {
- opaqueness = fade_animation_->GetCurrentValue();
- if (!alert_state_) {
- opaqueness = 1.0 - opaqueness; // Fading out, not in.
- }
- }
- if (opaqueness < 1.0) {
- canvas->SaveLayerAlpha(opaqueness * SK_AlphaOPAQUE);
- }
ImageButton::PaintButtonContents(canvas);
- if (opaqueness < 1.0) {
- canvas->Restore();
- }
}
gfx::ImageSkia AlertIndicatorButton::GetImageToPaint() {