diff --git a/src/main/events/themes/copy-theme-achievement-sound.ts b/src/main/events/themes/copy-theme-achievement-sound.ts index 72ec0c79..aec22cb2 100644 --- a/src/main/events/themes/copy-theme-achievement-sound.ts +++ b/src/main/events/themes/copy-theme-achievement-sound.ts @@ -37,4 +37,3 @@ const copyThemeAchievementSound = async ( }; registerEvent("copyThemeAchievementSound", copyThemeAchievementSound); - diff --git a/src/main/events/themes/get-theme-sound-path.ts b/src/main/events/themes/get-theme-sound-path.ts index 5dccbd4e..37783949 100644 --- a/src/main/events/themes/get-theme-sound-path.ts +++ b/src/main/events/themes/get-theme-sound-path.ts @@ -9,4 +9,3 @@ const getThemeSoundPathEvent = async ( }; registerEvent("getThemeSoundPath", getThemeSoundPathEvent); - diff --git a/src/main/events/themes/import-theme-sound-from-store.ts b/src/main/events/themes/import-theme-sound-from-store.ts index cd4c6fcd..588db6f5 100644 --- a/src/main/events/themes/import-theme-sound-from-store.ts +++ b/src/main/events/themes/import-theme-sound-from-store.ts @@ -22,7 +22,7 @@ const importThemeSoundFromStore = async ( for (const format of formats) { try { const soundUrl = `${storeUrl}/themes/${themeName.toLowerCase()}/achievement.${format}`; - + const response = await axios.get(soundUrl, { responseType: "arraybuffer", timeout: 10000, @@ -54,4 +54,3 @@ const importThemeSoundFromStore = async ( }; registerEvent("importThemeSoundFromStore", importThemeSoundFromStore); - diff --git a/src/main/events/themes/remove-theme-achievement-sound.ts b/src/main/events/themes/remove-theme-achievement-sound.ts index adb17a57..4ca738f3 100644 --- a/src/main/events/themes/remove-theme-achievement-sound.ts +++ b/src/main/events/themes/remove-theme-achievement-sound.ts @@ -36,4 +36,3 @@ const removeThemeAchievementSound = async ( }; registerEvent("removeThemeAchievementSound", removeThemeAchievementSound); - diff --git a/src/main/services/notifications/index.ts b/src/main/services/notifications/index.ts index d78a4d3f..f1df1478 100644 --- a/src/main/services/notifications/index.ts +++ b/src/main/services/notifications/index.ts @@ -5,7 +5,7 @@ import fs from "node:fs"; import axios from "axios"; import path from "node:path"; import sound from "sound-play"; -import { achievementSoundPath, DEFAULT_ACHIEVEMENT_SOUND_VOLUME } from "@main/constants"; +import { achievementSoundPath } from "@main/constants"; import icon from "@resources/icon.png?asset"; import { NotificationOptions, toXmlString } from "./xml"; import { logger } from "../logger"; @@ -59,22 +59,6 @@ async function getAchievementSoundPath(): Promise { return achievementSoundPath; } -async function getAchievementSoundVolume(): Promise { - try { - const userPreferences = await db.get( - levelKeys.userPreferences, - { - valueEncoding: "json", - } - ); - - return userPreferences?.achievementSoundVolume ?? DEFAULT_ACHIEVEMENT_SOUND_VOLUME; - } catch (error) { - logger.error("Failed to get achievement sound volume", error); - return DEFAULT_ACHIEVEMENT_SOUND_VOLUME; - } -} - export const publishDownloadCompleteNotification = async (game: Game) => { const userPreferences = await db.get( levelKeys.userPreferences, diff --git a/src/preload/index.ts b/src/preload/index.ts index 67ac0c73..951591a5 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -577,8 +577,17 @@ contextBridge.exposeInMainWorld("electron", { ipcRenderer.invoke("removeThemeAchievementSound", themeId), getThemeSoundPath: (themeId: string) => ipcRenderer.invoke("getThemeSoundPath", themeId), - importThemeSoundFromStore: (themeId: string, themeName: string, storeUrl: string) => - ipcRenderer.invoke("importThemeSoundFromStore", themeId, themeName, storeUrl), + importThemeSoundFromStore: ( + themeId: string, + themeName: string, + storeUrl: string + ) => + ipcRenderer.invoke( + "importThemeSoundFromStore", + themeId, + themeName, + storeUrl + ), /* Editor */ openEditorWindow: (themeId: string) => diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index fd1c2735..272551ad 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -24,7 +24,12 @@ import { UserFriendModal } from "./pages/shared-modals/user-friend-modal"; import { useSubscription } from "./hooks/use-subscription"; import { HydraCloudModal } from "./pages/shared-modals/hydra-cloud/hydra-cloud-modal"; -import { injectCustomCss, removeCustomCss, getAchievementSoundUrl, getAchievementSoundVolume } from "./helpers"; +import { + injectCustomCss, + removeCustomCss, + getAchievementSoundUrl, + getAchievementSoundVolume, +} from "./helpers"; import "./app.scss"; export interface AppProps { diff --git a/src/renderer/src/helpers.ts b/src/renderer/src/helpers.ts index 3ee04805..d5326de0 100644 --- a/src/renderer/src/helpers.ts +++ b/src/renderer/src/helpers.ts @@ -123,11 +123,12 @@ export const generateUUID = (): string => { }; export const getAchievementSoundUrl = async (): Promise => { - const defaultSound = (await import("@renderer/assets/audio/achievement.wav")).default; - + const defaultSound = (await import("@renderer/assets/audio/achievement.wav")) + .default; + try { const activeTheme = await window.electron.getActiveCustomTheme(); - + if (activeTheme?.hasCustomSound) { const soundPath = await window.electron.getThemeSoundPath(activeTheme.id); if (soundPath) { @@ -137,7 +138,7 @@ export const getAchievementSoundUrl = async (): Promise => { } catch (error) { console.error("Failed to get theme sound", error); } - + return defaultSound; }; diff --git a/src/renderer/src/pages/achievements/notification/achievement-notification.tsx b/src/renderer/src/pages/achievements/notification/achievement-notification.tsx index 02023f1d..38b2443b 100644 --- a/src/renderer/src/pages/achievements/notification/achievement-notification.tsx +++ b/src/renderer/src/pages/achievements/notification/achievement-notification.tsx @@ -4,7 +4,12 @@ import { AchievementCustomNotificationPosition, AchievementNotificationInfo, } from "@types"; -import { injectCustomCss, removeCustomCss, getAchievementSoundUrl, getAchievementSoundVolume } from "@renderer/helpers"; +import { + injectCustomCss, + removeCustomCss, + getAchievementSoundUrl, + getAchievementSoundVolume, +} from "@renderer/helpers"; import { AchievementNotificationItem } from "@renderer/components/achievements/notification/achievement-notification"; import app from "../../../app.scss?inline"; import styles from "../../../components/achievements/notification/achievement-notification.scss?inline"; diff --git a/src/renderer/src/pages/settings/settings-general.tsx b/src/renderer/src/pages/settings/settings-general.tsx index 6d81f763..172b3291 100644 --- a/src/renderer/src/pages/settings/settings-general.tsx +++ b/src/renderer/src/pages/settings/settings-general.tsx @@ -1,4 +1,11 @@ -import { useContext, useEffect, useMemo, useState, useCallback, useRef } from "react"; +import { + useContext, + useEffect, + useMemo, + useState, + useCallback, + useRef, +} from "react"; import { TextField, Button, @@ -51,7 +58,7 @@ export function SettingsGeneral() { const [languageOptions, setLanguageOptions] = useState([]); const [defaultDownloadsPath, setDefaultDownloadsPath] = useState(""); - + const volumeUpdateTimeoutRef = useRef(); useEffect(() => { @@ -116,7 +123,9 @@ export function SettingsGeneral() { userPreferences.achievementCustomNotificationsEnabled ?? true, achievementCustomNotificationPosition: userPreferences.achievementCustomNotificationPosition ?? "top-left", - achievementSoundVolume: Math.round((userPreferences.achievementSoundVolume ?? 0.15) * 100), + achievementSoundVolume: Math.round( + (userPreferences.achievementSoundVolume ?? 0.15) * 100 + ), friendRequestNotificationsEnabled: userPreferences.friendRequestNotificationsEnabled ?? false, friendStartGameNotificationsEnabled: @@ -155,17 +164,20 @@ export function SettingsGeneral() { await updateUserPreferences(values); }; - const handleVolumeChange = useCallback((newVolume: number) => { - setForm((prev) => ({ ...prev, achievementSoundVolume: newVolume })); - - if (volumeUpdateTimeoutRef.current) { - clearTimeout(volumeUpdateTimeoutRef.current); - } - - volumeUpdateTimeoutRef.current = setTimeout(() => { - updateUserPreferences({ achievementSoundVolume: newVolume / 100 }); - }, 300); - }, [updateUserPreferences]); + const handleVolumeChange = useCallback( + (newVolume: number) => { + setForm((prev) => ({ ...prev, achievementSoundVolume: newVolume })); + + if (volumeUpdateTimeoutRef.current) { + clearTimeout(volumeUpdateTimeoutRef.current); + } + + volumeUpdateTimeoutRef.current = setTimeout(() => { + updateUserPreferences({ achievementSoundVolume: newVolume / 100 }); + }, 300); + }, + [updateUserPreferences] + ); const handleChangeAchievementCustomNotificationPosition = async ( event: React.ChangeEvent @@ -347,13 +359,19 @@ export function SettingsGeneral() { handleVolumeChange(0); return; } - const volumePercent = Math.min(100, Math.max(0, parseInt(value, 10))); + const volumePercent = Math.min( + 100, + Math.max(0, parseInt(value, 10)) + ); if (!isNaN(volumePercent)) { handleVolumeChange(volumePercent); } }} onBlur={(e) => { - if (e.target.value === "" || isNaN(parseInt(e.target.value, 10))) { + if ( + e.target.value === "" || + isNaN(parseInt(e.target.value, 10)) + ) { handleVolumeChange(0); } }} @@ -365,11 +383,19 @@ export function SettingsGeneral() { type="button" onClick={(e) => { e.preventDefault(); - const newVolume = Math.min(100, form.achievementSoundVolume + 1); + const newVolume = Math.min( + 100, + form.achievementSoundVolume + 1 + ); handleVolumeChange(newVolume); }} > - + @@ -377,11 +403,19 @@ export function SettingsGeneral() { type="button" onClick={(e) => { e.preventDefault(); - const newVolume = Math.max(0, form.achievementSoundVolume - 1); + const newVolume = Math.max( + 0, + form.achievementSoundVolume - 1 + ); handleVolumeChange(newVolume); }} > - + diff --git a/src/renderer/src/pages/theme-editor/theme-editor.tsx b/src/renderer/src/pages/theme-editor/theme-editor.tsx index 8ae86f63..6057084f 100644 --- a/src/renderer/src/pages/theme-editor/theme-editor.tsx +++ b/src/renderer/src/pages/theme-editor/theme-editor.tsx @@ -4,10 +4,19 @@ import Editor from "@monaco-editor/react"; import { AchievementCustomNotificationPosition, Theme } from "@types"; import { useSearchParams } from "react-router-dom"; import { Button, SelectField } from "@renderer/components"; -import { CheckIcon, UploadIcon, TrashIcon, PlayIcon } from "@primer/octicons-react"; +import { + CheckIcon, + UploadIcon, + TrashIcon, + PlayIcon, +} from "@primer/octicons-react"; import { useTranslation } from "react-i18next"; import cn from "classnames"; -import { injectCustomCss, getAchievementSoundUrl, getAchievementSoundVolume } from "@renderer/helpers"; +import { + injectCustomCss, + getAchievementSoundUrl, + getAchievementSoundVolume, +} from "@renderer/helpers"; import { AchievementNotificationItem } from "@renderer/components/achievements/notification/achievement-notification"; import { generateAchievementCustomNotificationTest } from "@shared"; import { CollapsedMenu } from "@renderer/components/collapsed-menu/collapsed-menu";