fix(app): better sound effect disabling ux

This commit is contained in:
Adam
2026-02-20 11:24:02 -06:00
parent 950df3de19
commit ce2763720e
17 changed files with 65 additions and 53 deletions

View File

@@ -20,12 +20,17 @@ let demoSoundState = {
// To prevent audio from overlapping/playing very quickly when navigating the settings menus, // To prevent audio from overlapping/playing very quickly when navigating the settings menus,
// delay the playback by 100ms during quick selection changes and pause existing sounds. // delay the playback by 100ms during quick selection changes and pause existing sounds.
const playDemoSound = (src: string) => { const stopDemoSound = () => {
if (demoSoundState.cleanup) { if (demoSoundState.cleanup) {
demoSoundState.cleanup() demoSoundState.cleanup()
} }
clearTimeout(demoSoundState.timeout) clearTimeout(demoSoundState.timeout)
demoSoundState.cleanup = undefined
}
const playDemoSound = (src: string | undefined) => {
stopDemoSound()
if (!src) return
demoSoundState.timeout = setTimeout(() => { demoSoundState.timeout = setTimeout(() => {
demoSoundState.cleanup = playSound(src) demoSoundState.cleanup = playSound(src)
@@ -132,11 +137,17 @@ export const SettingsGeneral: Component = () => {
] as const ] as const
const fontOptionsList = [...fontOptions] const fontOptionsList = [...fontOptions]
const soundOptions = [...SOUND_OPTIONS] const noneSound = { id: "none", label: "sound.option.none", src: undefined } as const
const soundOptions = [noneSound, ...SOUND_OPTIONS]
const soundSelectProps = (current: () => string, set: (id: string) => void) => ({ const soundSelectProps = (
enabled: () => boolean,
current: () => string,
setEnabled: (value: boolean) => void,
set: (id: string) => void,
) => ({
options: soundOptions, options: soundOptions,
current: soundOptions.find((o) => o.id === current()), current: enabled() ? (soundOptions.find((o) => o.id === current()) ?? noneSound) : noneSound,
value: (o: (typeof soundOptions)[number]) => o.id, value: (o: (typeof soundOptions)[number]) => o.id,
label: (o: (typeof soundOptions)[number]) => language.t(o.label), label: (o: (typeof soundOptions)[number]) => language.t(o.label),
onHighlight: (option: (typeof soundOptions)[number] | undefined) => { onHighlight: (option: (typeof soundOptions)[number] | undefined) => {
@@ -145,6 +156,12 @@ export const SettingsGeneral: Component = () => {
}, },
onSelect: (option: (typeof soundOptions)[number] | undefined) => { onSelect: (option: (typeof soundOptions)[number] | undefined) => {
if (!option) return if (!option) return
if (option.id === "none") {
setEnabled(false)
stopDemoSound()
return
}
setEnabled(true)
set(option.id) set(option.id)
playDemoSound(option.src) playDemoSound(option.src)
}, },
@@ -319,66 +336,45 @@ export const SettingsGeneral: Component = () => {
title={language.t("settings.general.sounds.agent.title")} title={language.t("settings.general.sounds.agent.title")}
description={language.t("settings.general.sounds.agent.description")} description={language.t("settings.general.sounds.agent.description")}
> >
<div class="flex items-center gap-2"> <Select
<div data-action="settings-sounds-agent-enabled"> data-action="settings-sounds-agent"
<Switch {...soundSelectProps(
checked={settings.sounds.agentEnabled()} () => settings.sounds.agentEnabled(),
onChange={(checked) => settings.sounds.setAgentEnabled(checked)} () => settings.sounds.agent(),
/> (value) => settings.sounds.setAgentEnabled(value),
</div> (id) => settings.sounds.setAgent(id),
<Select )}
disabled={!settings.sounds.agentEnabled()} />
data-action="settings-sounds-agent"
{...soundSelectProps(
() => settings.sounds.agent(),
(id) => settings.sounds.setAgent(id),
)}
/>
</div>
</SettingsRow> </SettingsRow>
<SettingsRow <SettingsRow
title={language.t("settings.general.sounds.permissions.title")} title={language.t("settings.general.sounds.permissions.title")}
description={language.t("settings.general.sounds.permissions.description")} description={language.t("settings.general.sounds.permissions.description")}
> >
<div class="flex items-center gap-2"> <Select
<div data-action="settings-sounds-permissions-enabled"> data-action="settings-sounds-permissions"
<Switch {...soundSelectProps(
checked={settings.sounds.permissionsEnabled()} () => settings.sounds.permissionsEnabled(),
onChange={(checked) => settings.sounds.setPermissionsEnabled(checked)} () => settings.sounds.permissions(),
/> (value) => settings.sounds.setPermissionsEnabled(value),
</div> (id) => settings.sounds.setPermissions(id),
<Select )}
disabled={!settings.sounds.permissionsEnabled()} />
data-action="settings-sounds-permissions"
{...soundSelectProps(
() => settings.sounds.permissions(),
(id) => settings.sounds.setPermissions(id),
)}
/>
</div>
</SettingsRow> </SettingsRow>
<SettingsRow <SettingsRow
title={language.t("settings.general.sounds.errors.title")} title={language.t("settings.general.sounds.errors.title")}
description={language.t("settings.general.sounds.errors.description")} description={language.t("settings.general.sounds.errors.description")}
> >
<div class="flex items-center gap-2"> <Select
<div data-action="settings-sounds-errors-enabled"> data-action="settings-sounds-errors"
<Switch {...soundSelectProps(
checked={settings.sounds.errorsEnabled()} () => settings.sounds.errorsEnabled(),
onChange={(checked) => settings.sounds.setErrorsEnabled(checked)} () => settings.sounds.errors(),
/> (value) => settings.sounds.setErrorsEnabled(value),
</div> (id) => settings.sounds.setErrors(id),
<Select )}
disabled={!settings.sounds.errorsEnabled()} />
data-action="settings-sounds-errors"
{...soundSelectProps(
() => settings.sounds.errors(),
(id) => settings.sounds.setErrors(id),
)}
/>
</div>
</SettingsRow> </SettingsRow>
</div> </div>
</div> </div>

View File

@@ -565,6 +565,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "بلا",
"sound.option.alert01": "تنبيه 01", "sound.option.alert01": "تنبيه 01",
"sound.option.alert02": "تنبيه 02", "sound.option.alert02": "تنبيه 02",
"sound.option.alert03": "تنبيه 03", "sound.option.alert03": "تنبيه 03",

View File

@@ -571,6 +571,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "Nenhum",
"sound.option.alert01": "Alerta 01", "sound.option.alert01": "Alerta 01",
"sound.option.alert02": "Alerta 02", "sound.option.alert02": "Alerta 02",
"sound.option.alert03": "Alerta 03", "sound.option.alert03": "Alerta 03",

View File

@@ -639,6 +639,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "Nijedan",
"sound.option.alert01": "Upozorenje 01", "sound.option.alert01": "Upozorenje 01",
"sound.option.alert02": "Upozorenje 02", "sound.option.alert02": "Upozorenje 02",
"sound.option.alert03": "Upozorenje 03", "sound.option.alert03": "Upozorenje 03",

View File

@@ -635,6 +635,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "Ingen",
"sound.option.alert01": "Alarm 01", "sound.option.alert01": "Alarm 01",
"sound.option.alert02": "Alarm 02", "sound.option.alert02": "Alarm 02",
"sound.option.alert03": "Alarm 03", "sound.option.alert03": "Alarm 03",

View File

@@ -580,6 +580,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "Keine",
"sound.option.alert01": "Alarm 01", "sound.option.alert01": "Alarm 01",
"sound.option.alert02": "Alarm 02", "sound.option.alert02": "Alarm 02",
"sound.option.alert03": "Alarm 03", "sound.option.alert03": "Alarm 03",

View File

@@ -642,6 +642,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "None",
"sound.option.alert01": "Alert 01", "sound.option.alert01": "Alert 01",
"sound.option.alert02": "Alert 02", "sound.option.alert02": "Alert 02",
"sound.option.alert03": "Alert 03", "sound.option.alert03": "Alert 03",

View File

@@ -643,6 +643,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "Ninguno",
"sound.option.alert01": "Alerta 01", "sound.option.alert01": "Alerta 01",
"sound.option.alert02": "Alerta 02", "sound.option.alert02": "Alerta 02",
"sound.option.alert03": "Alerta 03", "sound.option.alert03": "Alerta 03",

View File

@@ -579,6 +579,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "Aucun",
"sound.option.alert01": "Alerte 01", "sound.option.alert01": "Alerte 01",
"sound.option.alert02": "Alerte 02", "sound.option.alert02": "Alerte 02",
"sound.option.alert03": "Alerte 03", "sound.option.alert03": "Alerte 03",

View File

@@ -569,6 +569,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "なし",
"sound.option.alert01": "アラート 01", "sound.option.alert01": "アラート 01",
"sound.option.alert02": "アラート 02", "sound.option.alert02": "アラート 02",
"sound.option.alert03": "アラート 03", "sound.option.alert03": "アラート 03",

View File

@@ -570,6 +570,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "없음",
"sound.option.alert01": "알림 01", "sound.option.alert01": "알림 01",
"sound.option.alert02": "알림 02", "sound.option.alert02": "알림 02",
"sound.option.alert03": "알림 03", "sound.option.alert03": "알림 03",

View File

@@ -642,6 +642,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "Ingen",
"sound.option.alert01": "Varsel 01", "sound.option.alert01": "Varsel 01",
"sound.option.alert02": "Varsel 02", "sound.option.alert02": "Varsel 02",
"sound.option.alert03": "Varsel 03", "sound.option.alert03": "Varsel 03",

View File

@@ -570,6 +570,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "Brak",
"sound.option.alert01": "Alert 01", "sound.option.alert01": "Alert 01",
"sound.option.alert02": "Alert 02", "sound.option.alert02": "Alert 02",
"sound.option.alert03": "Alert 03", "sound.option.alert03": "Alert 03",

View File

@@ -640,6 +640,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "Нет",
"sound.option.alert01": "Alert 01", "sound.option.alert01": "Alert 01",
"sound.option.alert02": "Alert 02", "sound.option.alert02": "Alert 02",
"sound.option.alert03": "Alert 03", "sound.option.alert03": "Alert 03",

View File

@@ -634,6 +634,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "ไม่มี",
"sound.option.alert01": "เสียงเตือน 01", "sound.option.alert01": "เสียงเตือน 01",
"sound.option.alert02": "เสียงเตือน 02", "sound.option.alert02": "เสียงเตือน 02",
"sound.option.alert03": "เสียงเตือน 03", "sound.option.alert03": "เสียงเตือน 03",

View File

@@ -633,6 +633,7 @@ export const dict = {
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "无",
"sound.option.alert01": "警报 01", "sound.option.alert01": "警报 01",
"sound.option.alert02": "警报 02", "sound.option.alert02": "警报 02",
"sound.option.alert03": "警报 03", "sound.option.alert03": "警报 03",

View File

@@ -629,6 +629,7 @@ export const dict = {
"font.option.sourceCodePro": "Source Code Pro", "font.option.sourceCodePro": "Source Code Pro",
"font.option.ubuntuMono": "Ubuntu Mono", "font.option.ubuntuMono": "Ubuntu Mono",
"font.option.geistMono": "Geist Mono", "font.option.geistMono": "Geist Mono",
"sound.option.none": "無",
"sound.option.alert01": "警報 01", "sound.option.alert01": "警報 01",
"sound.option.alert02": "警報 02", "sound.option.alert02": "警報 02",
"sound.option.alert03": "警報 03", "sound.option.alert03": "警報 03",