fix(app): make click-through the default and move animation pausing to Accessibility (#1722)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-18 19:40:35 +02:00
1 parent 9e89539f0a
commit 4bbfee4cec
19 files changed
+96 -248

No files matched your search

@@ -3,6 +3,7 @@
import {
MiddleClickAutoscrollControl,
SmoothScrollingControl,
StayInteractiveUnfocusedControl,
TextSelectionControl,
VideoSeekThumbnailsControl,
} from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedAccessibilityControls';
@@ -34,10 +35,8 @@ import {
} from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedChatControls';
import {DeveloperModeControl} from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedClientDeveloperControls';
import {
FirstClickPassThroughControl,
HardwareAccelerationControl,
NativeTitleBarControl,
StayInteractiveUnfocusedControl,
} from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedDesktopControls';
import {UnreadBadgeCustomizationControl} from '@app/features/user/components/modals/tabs/advanced_settings_tab/AdvancedExperimentalControls';
import {
@@ -90,8 +89,7 @@ export const DIRECT_CONTROL_ITEM_IDS = new Set([
'voice-video-screen-share-encoder-controls',
'advanced-unread-badge-customization',
'client-developer-mode',
'advanced-stay-interactive-unfocused',
'first-click-pass-through',
'accessibility-stay-interactive-unfocused',
'advanced-native-title-bar',
'advanced-hardware-acceleration',
]);
@@ -126,8 +124,7 @@ export const COMPACT_SWITCH_CONTROL_ITEM_IDS = new Set([
'voice-video-openh264-codec',
'advanced-unread-badge-customization',
'client-developer-mode',
'advanced-stay-interactive-unfocused',
'first-click-pass-through',
'accessibility-stay-interactive-unfocused',
'advanced-native-title-bar',
'advanced-hardware-acceleration',
]);
@@ -298,14 +295,10 @@ export const AdvancedSettingControl = observer(({item}: {item: SearchableSetting
return (
<DeveloperModeControl data-flx="user.advanced-setting-direct-controls.advanced-setting-control.developer-mode-control" />
);
case 'advanced-stay-interactive-unfocused':
case 'accessibility-stay-interactive-unfocused':
return (
<StayInteractiveUnfocusedControl data-flx="user.advanced-setting-direct-controls.advanced-setting-control.stay-interactive-unfocused-control" />
);
case 'first-click-pass-through':
return (
<FirstClickPassThroughControl data-flx="user.advanced-setting-direct-controls.advanced-setting-control.first-click-pass-through-control" />
);
case 'advanced-native-title-bar':
return (
<NativeTitleBarControl data-flx="user.advanced-setting-direct-controls.advanced-setting-control.native-title-bar-control" />
@@ -32,6 +32,14 @@ const CONTENT_ANIMATIONS_STAY_IN_ANIMATION_TAB_DESCRIPTOR = msg({
message: 'Animated emojis, GIFs and stickers stay under your control in the Animation tab.',
comment: 'Extra hint shown beneath the reduce motion toggle while reduced motion is active.',
});
const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({
message: 'Stay fully interactive when unfocused',
comment: 'Label in the motion tab.',
});
const KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_RUNNING_DESCRIPTOR = msg({
message: 'Keep animations, GIF playback, hover effects, and tooltips running while the window is unfocused.',
comment: 'Description text in the motion tab.',
});
export const MotionTabContent: React.FC = observer(() => {
const {i18n} = useLingui();
const syncReducedMotionWithSystem = Accessibility.syncReducedMotionWithSystem;
@@ -60,6 +68,13 @@ export const MotionTabContent: React.FC = observer(() => {
onChange={(value) => AccessibilityCommands.update({reducedMotionOverride: value})}
data-flx="user.accessibility-tab.motion-tab.motion-tab-content.switch.update--2"
/>
<Switch
label={i18n._(STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR)}
description={i18n._(KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_RUNNING_DESCRIPTOR)}
value={Accessibility.stayInteractiveWhenUnfocused}
onChange={(value) => AccessibilityCommands.update({stayInteractiveWhenUnfocused: value})}
data-flx="user.accessibility-tab.motion-tab.motion-tab-content.switch.update--3"
/>
</>
);
});
@@ -32,6 +32,10 @@ const SMOOTH_SCROLLING_DESCRIPTOR = msg({
message: 'Smooth scrolling',
comment: 'Short label for an advanced desktop scrolling toggle.',
});
const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({
message: 'Stay fully interactive when unfocused',
comment: 'Short label for an advanced app interaction toggle.',
});
const USE_AUTOSCROLLING_DESCRIPTOR = msg({
message: 'Use autoscrolling',
comment: 'Short label for an advanced desktop scrolling toggle.',
@@ -135,6 +139,19 @@ export const TextSelectionControl = observer(() => {
);
});
export const StayInteractiveUnfocusedControl = observer(() => {
const {i18n} = useLingui();
return (
<Switch
ariaLabel={i18n._(STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR)}
value={Accessibility.stayInteractiveWhenUnfocused}
onChange={(value) => AccessibilityCommands.update({stayInteractiveWhenUnfocused: value})}
compact
data-flx="user.advanced-settings-tab.switch.stay-interactive-unfocused"
/>
);
});
export const VideoSeekThumbnailsControl = observer(() => {
const {i18n} = useLingui();
return (
@@ -1,7 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import * as AccessibilityCommands from '@app/features/accessibility/commands/AccessibilityCommands';
import Accessibility from '@app/features/accessibility/state/Accessibility';
import {ConfirmModal} from '@app/features/app/components/dialogs/ConfirmModal';
import {PRODUCT_NAME} from '@app/features/app/config/I18nDisplayConstants';
import {
@@ -25,14 +23,6 @@ import {Trans, useLingui} from '@lingui/react/macro';
import {observer} from 'mobx-react-lite';
import {useCallback, useLayoutEffect, useState} from 'react';
const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({
message: 'Stay fully interactive when unfocused',
comment: 'Short label for an advanced desktop preference.',
});
const FIRST_CLICK_PASS_THROUGH_WHEN_UNFOCUSED_DESCRIPTOR = msg({
message: 'First click pass-through when unfocused',
comment: 'Short label for an advanced desktop preference.',
});
const USE_NATIVE_TITLE_BAR_DESCRIPTOR = msg({
message: 'Use native title bar',
comment: 'Short label for an advanced desktop preference.',
@@ -128,32 +118,6 @@ function useDesktopTroubleshootingSettings() {
};
}
export const StayInteractiveUnfocusedControl = observer(() => {
const {i18n} = useLingui();
return (
<Switch
ariaLabel={i18n._(STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR)}
value={Accessibility.stayInteractiveWhenUnfocused}
onChange={(value) => AccessibilityCommands.update({stayInteractiveWhenUnfocused: value})}
compact
data-flx="user.advanced-settings-tab.switch.stay-interactive-unfocused"
/>
);
});
export const FirstClickPassThroughControl = observer(() => {
const {i18n} = useLingui();
return (
<Switch
ariaLabel={i18n._(FIRST_CLICK_PASS_THROUGH_WHEN_UNFOCUSED_DESCRIPTOR)}
value={Accessibility.firstClickPassThroughWhenUnfocused}
onChange={(value) => AccessibilityCommands.update({firstClickPassThroughWhenUnfocused: value})}
compact
data-flx="user.advanced-settings-tab.switch.first-click-pass-through"
/>
);
});
export const NativeTitleBarControl = observer(() => {
const {i18n} = useLingui();
const {desktopWindowBehavior, desktopWindowBehaviorBusy, updateDesktopWindowBehavior} =
@@ -342,6 +342,43 @@ const CONTROL_MIDDLE_CLICK_AUTOSCROLLING_DESCRIPTOR = msg({
message: 'Control Chromium middle-click autoscrolling in the desktop app',
comment: 'Settings search entry description. One-line summary of what the settings search entry controls.',
});
const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({
message: 'Stay fully interactive when unfocused',
comment: 'Settings search entry label. Names the settings search entry in the settings UI.',
});
const UNFOCUSED_DESCRIPTOR = msg({
message: 'Unfocused',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const WINDOW_FOCUS_DESCRIPTOR = msg({
message: 'Window focus',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const ANIMATIONS_WHILE_UNFOCUSED_DESCRIPTOR = msg({
message: 'Animations while unfocused',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const ANIMATION_PLAYBACK_DESCRIPTOR = msg({
message: 'Animation playback',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const HOVER_EFFECTS_DESCRIPTOR = msg({
message: 'Hover effects',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const TOOLTIPS_DESCRIPTOR = msg({
message: 'Tooltips',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const POWER_SAVING_DESCRIPTOR = msg({
message: 'Power saving',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_DESCRIPTOR = msg({
message: 'Keep animations, GIF playback, hover effects, and tooltips running while the window is unfocused.',
comment: 'Settings search entry description. One-line summary of what the settings search entry controls.',
});
export const accessibilityIndex: Array<SearchableSettingDescriptor> = [
{
id: 'accessibility-confirm-calls',
@@ -486,6 +523,24 @@ export const accessibilityIndex: Array<SearchableSettingDescriptor> = [
],
description: DISPLAY_A_VISIBLE_FOCUS_INDICATOR_AROUND_THE_MESSAGE_DESCRIPTOR,
},
{
id: 'accessibility-stay-interactive-unfocused',
tabType: 'accessibility',
sectionId: 'motion',
label: STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR,
keywords: [
UNFOCUSED_DESCRIPTOR,
WINDOW_FOCUS_DESCRIPTOR,
ANIMATIONS_WHILE_UNFOCUSED_DESCRIPTOR,
ANIMATION_PLAYBACK_DESCRIPTOR,
HOVER_EFFECTS_DESCRIPTOR,
TOOLTIPS_DESCRIPTOR,
POWER_SAVING_DESCRIPTOR,
],
description: KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_DESCRIPTOR,
audience: 'advanced',
tags: ['accessibility'],
},
{
id: 'accessibility-sync-reduced-motion',
tabType: 'accessibility',
@@ -7,66 +7,6 @@ import type {SearchableSettingDescriptor} from '@app/features/user/components/se
import {BACKGROUND_DESCRIPTOR} from '@app/features/user/components/settings_utils/search_index/SharedDescriptors';
import {msg} from '@lingui/core/macro';
const FIRST_CLICK_PASS_THROUGH_WHEN_UNFOCUSED_DESCRIPTOR = msg({
message: 'First click pass-through when unfocused',
comment: 'Settings search entry label. Names the settings search entry in the settings UI.',
});
const FIRST_CLICK_DESCRIPTOR = msg({
message: 'First click',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const CLICK_THROUGH_DESCRIPTOR = msg({
message: 'Click through',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const UNFOCUSED_DESCRIPTOR = msg({
message: 'Unfocused',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const WINDOW_FOCUS_DESCRIPTOR = msg({
message: 'Window focus',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const FOCUS_CLICK_DESCRIPTOR = msg({
message: 'Focus click',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const ACTIVATION_CLICK_DESCRIPTOR = msg({
message: 'Activation click',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const LET_THE_CLICK_THAT_FOCUSES_ALSO_ACTIVATE_THE_DESCRIPTOR = msg({
message: 'Let focus clicks activate controls.',
comment: 'Settings search entry description. One-line summary of what the settings search entry controls.',
});
const STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR = msg({
message: 'Stay fully interactive when unfocused',
comment: 'Settings search entry label. Names the settings search entry in the settings UI.',
});
const ANIMATIONS_WHILE_UNFOCUSED_DESCRIPTOR = msg({
message: 'Animations while unfocused',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const ANIMATION_PLAYBACK_DESCRIPTOR = msg({
message: 'Animation playback',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const HOVER_EFFECTS_DESCRIPTOR = msg({
message: 'Hover effects',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const TOOLTIPS_DESCRIPTOR = msg({
message: 'Tooltips',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const POWER_SAVING_DESCRIPTOR = msg({
message: 'Power saving',
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
});
const KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_DESCRIPTOR = msg({
message: 'Keep animations, GIFs, hover, and tooltips running unfocused',
comment: 'Settings search entry description. One-line summary of what the settings search entry controls.',
});
const HARDWARE_ACCELERATION_DESCRIPTOR = msg({
message: 'Hardware acceleration',
comment: 'Settings search entry label. Names the settings search entry in the settings UI.',
@@ -280,40 +220,6 @@ const KEEP_RUNNING_WHEN_THE_WINDOW_IS_CLOSED_DESCRIPTOR = msg({
comment: 'Settings search entry description. One-line summary of what the settings search entry controls.',
});
export const desktopSettingsIndex: Array<SearchableSettingDescriptor> = [
{
id: 'first-click-pass-through',
tabType: 'desktop_settings',
label: FIRST_CLICK_PASS_THROUGH_WHEN_UNFOCUSED_DESCRIPTOR,
keywords: [
FIRST_CLICK_DESCRIPTOR,
CLICK_THROUGH_DESCRIPTOR,
UNFOCUSED_DESCRIPTOR,
WINDOW_FOCUS_DESCRIPTOR,
FOCUS_CLICK_DESCRIPTOR,
ACTIVATION_CLICK_DESCRIPTOR,
],
description: LET_THE_CLICK_THAT_FOCUSES_ALSO_ACTIVATE_THE_DESCRIPTOR,
audience: 'advanced',
tags: ['desktop'],
isVisible: isDesktop,
},
{
id: 'advanced-stay-interactive-unfocused',
tabType: 'desktop_settings',
label: STAY_FULLY_INTERACTIVE_WHEN_UNFOCUSED_DESCRIPTOR,
keywords: [
UNFOCUSED_DESCRIPTOR,
WINDOW_FOCUS_DESCRIPTOR,
ANIMATIONS_WHILE_UNFOCUSED_DESCRIPTOR,
ANIMATION_PLAYBACK_DESCRIPTOR,
HOVER_EFFECTS_DESCRIPTOR,
TOOLTIPS_DESCRIPTOR,
POWER_SAVING_DESCRIPTOR,
],
description: KEEP_ANIMATIONS_GIF_PLAYBACK_HOVER_EFFECTS_AND_TOOLTIPS_DESCRIPTOR,
tags: ['desktop'],
isVisible: isDesktop,
},
{
id: 'advanced-hardware-acceleration',
tabType: 'desktop_settings',