Make every settings row reachable, and every accessibility switch honest
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -412,35 +412,71 @@ Singleton {
|
||||
// dozen overlapping bells, which is a noise rather than a notification.
|
||||
property real lastBellAt: 0
|
||||
|
||||
function playBell(notification: var): void {
|
||||
if (!SoundFeedback.eventSounds)
|
||||
return;
|
||||
// Emitted for every notification that is bell-eligible, whether or not a
|
||||
// bell is actually audible. modules/notifications/VisualBell.qml listens.
|
||||
signal bellEligible(var notification)
|
||||
|
||||
// Would this notification ring the bell, setting aside whether sound is
|
||||
// switched on at all?
|
||||
//
|
||||
// THE PINNED RULE, because it is the whole point of visual alerts: the
|
||||
// flash follows this predicate, and the bell follows this predicate AND
|
||||
// SoundFeedback.eventSounds. Every gate below is shared -- an application
|
||||
// you silenced stays silent both ways, a low-urgency notification stays
|
||||
// quiet both ways, and an application that says it played its own sound is
|
||||
// taken at its word both ways -- but the event-sounds switch is NOT.
|
||||
//
|
||||
// Gating the flash on event sounds would make Visual Alerts do nothing for
|
||||
// exactly the person it exists for: somebody who cannot hear the bell has
|
||||
// no reason to have event sounds on, and would turn on a switch that stays
|
||||
// dark. The flash is not a picture of the bell; it is the same alert in the
|
||||
// sense the person can receive.
|
||||
//
|
||||
// Sound RESOLUTION is deliberately not part of this. playBell gives up when
|
||||
// it cannot find a file to play, which is a fact about the sound theme on
|
||||
// disk; losing the flash because a theme is missing an ogg would be absurd.
|
||||
function bellWouldRing(notification: var): bool {
|
||||
// The per-application sound switch. Narrower than turning the
|
||||
// application off: its notifications still arrive and still show, they
|
||||
// just stop making noise.
|
||||
if (!root.appRule(root.notificationAppId(notification)).sound)
|
||||
return;
|
||||
return false;
|
||||
|
||||
// Low urgency is the "you did not need to know this" tier -- battery
|
||||
// reaching full, a sync completing. It stays silent by design, and it
|
||||
// is the effective urgency, so "treat as low" is a way to keep an
|
||||
// application audible in principle but quiet in practice.
|
||||
if (root.effectiveUrgency(notification) === NotificationUrgency.Low)
|
||||
return;
|
||||
return false;
|
||||
|
||||
// The freedesktop sound hints. This is the fix for the double chime:
|
||||
// an application that plays its own sound sets suppress-sound so the
|
||||
// The freedesktop sound hint. This is the fix for the double chime: an
|
||||
// application that plays its own sound sets suppress-sound so the
|
||||
// notification server stays quiet, and Panama ignoring it meant one
|
||||
// notification made two noises a beat apart.
|
||||
//
|
||||
// The other two say what to play instead of the theme bell --
|
||||
// sound-file is an absolute path the application supplies, sound-name
|
||||
// is a theme sound resolved through the same chain the bell uses.
|
||||
const hints = notification.hints ?? {};
|
||||
if (hints["suppress-sound"] === true)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function playBell(notification: var): void {
|
||||
if (!root.bellWouldRing(notification))
|
||||
return;
|
||||
|
||||
// Announced BEFORE the event-sounds gate, on purpose. See the rule
|
||||
// pinned above bellWouldRing.
|
||||
root.bellEligible(notification);
|
||||
|
||||
if (!SoundFeedback.eventSounds)
|
||||
return;
|
||||
|
||||
// The remaining two sound hints say what to play instead of the theme
|
||||
// bell -- sound-file is an absolute path the application supplies,
|
||||
// sound-name is a theme sound resolved through the same chain the bell
|
||||
// uses. Neither can make a notification ineligible, so neither is part
|
||||
// of the predicate above.
|
||||
const hints = notification.hints ?? {};
|
||||
const soundFile = String(hints["sound-file"] ?? "");
|
||||
const soundName = String(hints["sound-name"] ?? "");
|
||||
const candidates = soundFile.startsWith("/")
|
||||
|
||||
Reference in New Issue
Block a user