Pārlūkot izejas kodu

fix(app): better sound effect disabling ux

Adam 5 mēneši atpakaļ
vecāks
revīzija
ce2763720e

+ 49 - 53
packages/app/src/components/settings-general.tsx

@@ -20,12 +20,17 @@ let demoSoundState = {
 
 // 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.
-const playDemoSound = (src: string) => {
+const stopDemoSound = () => {
   if (demoSoundState.cleanup) {
     demoSoundState.cleanup()
   }
-
   clearTimeout(demoSoundState.timeout)
+  demoSoundState.cleanup = undefined
+}
+
+const playDemoSound = (src: string | undefined) => {
+  stopDemoSound()
+  if (!src) return
 
   demoSoundState.timeout = setTimeout(() => {
     demoSoundState.cleanup = playSound(src)
@@ -132,11 +137,17 @@ export const SettingsGeneral: Component = () => {
   ] as const
   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,
-    current: soundOptions.find((o) => o.id === current()),
+    current: enabled() ? (soundOptions.find((o) => o.id === current()) ?? noneSound) : noneSound,
     value: (o: (typeof soundOptions)[number]) => o.id,
     label: (o: (typeof soundOptions)[number]) => language.t(o.label),
     onHighlight: (option: (typeof soundOptions)[number] | undefined) => {
@@ -145,6 +156,12 @@ export const SettingsGeneral: Component = () => {
     },
     onSelect: (option: (typeof soundOptions)[number] | undefined) => {
       if (!option) return
+      if (option.id === "none") {
+        setEnabled(false)
+        stopDemoSound()
+        return
+      }
+      setEnabled(true)
       set(option.id)
       playDemoSound(option.src)
     },
@@ -319,66 +336,45 @@ export const SettingsGeneral: Component = () => {
           title={language.t("settings.general.sounds.agent.title")}
           description={language.t("settings.general.sounds.agent.description")}
         >
-          <div class="flex items-center gap-2">
-            <div data-action="settings-sounds-agent-enabled">
-              <Switch
-                checked={settings.sounds.agentEnabled()}
-                onChange={(checked) => settings.sounds.setAgentEnabled(checked)}
-              />
-            </div>
-            <Select
-              disabled={!settings.sounds.agentEnabled()}
-              data-action="settings-sounds-agent"
-              {...soundSelectProps(
-                () => settings.sounds.agent(),
-                (id) => settings.sounds.setAgent(id),
-              )}
-            />
-          </div>
+          <Select
+            data-action="settings-sounds-agent"
+            {...soundSelectProps(
+              () => settings.sounds.agentEnabled(),
+              () => settings.sounds.agent(),
+              (value) => settings.sounds.setAgentEnabled(value),
+              (id) => settings.sounds.setAgent(id),
+            )}
+          />
         </SettingsRow>
 
         <SettingsRow
           title={language.t("settings.general.sounds.permissions.title")}
           description={language.t("settings.general.sounds.permissions.description")}
         >
-          <div class="flex items-center gap-2">
-            <div data-action="settings-sounds-permissions-enabled">
-              <Switch
-                checked={settings.sounds.permissionsEnabled()}
-                onChange={(checked) => settings.sounds.setPermissionsEnabled(checked)}
-              />
-            </div>
-            <Select
-              disabled={!settings.sounds.permissionsEnabled()}
-              data-action="settings-sounds-permissions"
-              {...soundSelectProps(
-                () => settings.sounds.permissions(),
-                (id) => settings.sounds.setPermissions(id),
-              )}
-            />
-          </div>
+          <Select
+            data-action="settings-sounds-permissions"
+            {...soundSelectProps(
+              () => settings.sounds.permissionsEnabled(),
+              () => settings.sounds.permissions(),
+              (value) => settings.sounds.setPermissionsEnabled(value),
+              (id) => settings.sounds.setPermissions(id),
+            )}
+          />
         </SettingsRow>
 
         <SettingsRow
           title={language.t("settings.general.sounds.errors.title")}
           description={language.t("settings.general.sounds.errors.description")}
         >
-          <div class="flex items-center gap-2">
-            <div data-action="settings-sounds-errors-enabled">
-              <Switch
-                checked={settings.sounds.errorsEnabled()}
-                onChange={(checked) => settings.sounds.setErrorsEnabled(checked)}
-              />
-            </div>
-            <Select
-              disabled={!settings.sounds.errorsEnabled()}
-              data-action="settings-sounds-errors"
-              {...soundSelectProps(
-                () => settings.sounds.errors(),
-                (id) => settings.sounds.setErrors(id),
-              )}
-            />
-          </div>
+          <Select
+            data-action="settings-sounds-errors"
+            {...soundSelectProps(
+              () => settings.sounds.errorsEnabled(),
+              () => settings.sounds.errors(),
+              (value) => settings.sounds.setErrorsEnabled(value),
+              (id) => settings.sounds.setErrors(id),
+            )}
+          />
         </SettingsRow>
       </div>
     </div>

+ 1 - 0
packages/app/src/i18n/ar.ts

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

+ 1 - 0
packages/app/src/i18n/br.ts

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

+ 1 - 0
packages/app/src/i18n/bs.ts

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

+ 1 - 0
packages/app/src/i18n/da.ts

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

+ 1 - 0
packages/app/src/i18n/de.ts

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

+ 1 - 0
packages/app/src/i18n/en.ts

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

+ 1 - 0
packages/app/src/i18n/es.ts

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

+ 1 - 0
packages/app/src/i18n/fr.ts

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

+ 1 - 0
packages/app/src/i18n/ja.ts

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

+ 1 - 0
packages/app/src/i18n/ko.ts

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

+ 1 - 0
packages/app/src/i18n/no.ts

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

+ 1 - 0
packages/app/src/i18n/pl.ts

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

+ 1 - 0
packages/app/src/i18n/ru.ts

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

+ 1 - 0
packages/app/src/i18n/th.ts

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

+ 1 - 0
packages/app/src/i18n/zh.ts

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

+ 1 - 0
packages/app/src/i18n/zht.ts

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