From d72ca7a9753262396e0a11562289626ed8dd8091 Mon Sep 17 00:00:00 2001 From: Naomi Carrigan Date: Mon, 19 Jan 2026 19:25:19 -0800 Subject: [PATCH] feat: achievement sound --- src/lib/notifications/types.ts | 7 ++++ src/lib/sounds/achievement.ts | 19 ++++++++++ src/lib/stores/achievements.ts | 16 ++++++-- src/routes/test-achievement/+page.svelte | 45 +++++++++++++++++++++++ static/sounds/achievement.mp3 | Bin 0 -> 14829 bytes 5 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/lib/sounds/achievement.ts create mode 100644 src/routes/test-achievement/+page.svelte create mode 100644 static/sounds/achievement.mp3 diff --git a/src/lib/notifications/types.ts b/src/lib/notifications/types.ts index ceeae60..6fda8a2 100644 --- a/src/lib/notifications/types.ts +++ b/src/lib/notifications/types.ts @@ -4,6 +4,7 @@ export enum NotificationType { PERMISSION = "permission", CONNECTION = "connection", TASK_START = "task_start", + ACHIEVEMENT = "achievement", } export interface NotificationSound { @@ -45,4 +46,10 @@ export const NOTIFICATION_SOUNDS: Record = phrase: "Working on it!", volume: 0.6, }, + [NotificationType.ACHIEVEMENT]: { + type: NotificationType.ACHIEVEMENT, + filename: "achievement.mp3", + phrase: "Achievement Get~!", + volume: 0.8, + }, }; diff --git a/src/lib/sounds/achievement.ts b/src/lib/sounds/achievement.ts new file mode 100644 index 0000000..885c9f3 --- /dev/null +++ b/src/lib/sounds/achievement.ts @@ -0,0 +1,19 @@ +// Achievement sound player using the notification system + +import { soundPlayer } from '$lib/notifications'; +import { NotificationType } from '$lib/notifications/types'; + +export function playAchievementSound() { + // Use the soundPlayer which respects global notification settings + soundPlayer.play(NotificationType.ACHIEVEMENT); +} + +// Test function for development +export function testAchievementSound() { + try { + playAchievementSound(); + console.log('Achievement sound played successfully!'); + } catch (error) { + console.error('Error playing achievement sound:', error); + } +} \ No newline at end of file diff --git a/src/lib/stores/achievements.ts b/src/lib/stores/achievements.ts index 1785cf4..ab65ce3 100644 --- a/src/lib/stores/achievements.ts +++ b/src/lib/stores/achievements.ts @@ -2,6 +2,7 @@ import { writable, derived } from 'svelte/store'; import { listen } from '@tauri-apps/api/event'; import { invoke } from '@tauri-apps/api/core'; import type { Achievement, AchievementUnlockedEvent, AchievementId } from '$lib/types/achievements'; +import { playAchievementSound } from '$lib/sounds/achievement'; interface AchievementState { achievements: Record; @@ -304,7 +305,7 @@ function createAchievementsStore() { return { subscribe, - unlockAchievement: (event: AchievementUnlockedEvent) => { + unlockAchievement: (event: AchievementUnlockedEvent, playSound: boolean = true) => { update(state => { const achievement = state.achievements[event.achievement.id]; if (achievement && !achievement.unlocked) { @@ -312,6 +313,15 @@ function createAchievementsStore() { achievement.unlockedAt = event.achievement.unlocked_at ? new Date(event.achievement.unlocked_at) : new Date(); state.totalUnlocked++; state.lastUnlocked = achievement; + + // Play achievement sound only for new unlocks, not when loading saved ones + if (playSound) { + try { + playAchievementSound(); + } catch (error) { + console.error('Failed to play achievement sound:', error); + } + } } return state; }); @@ -386,9 +396,9 @@ export async function initAchievementsListener() { try { const savedAchievements = await invoke('load_saved_achievements'); - // Update the store with saved achievements + // Update the store with saved achievements (don't play sounds) for (const event of savedAchievements) { - achievementsStore.unlockAchievement(event); + achievementsStore.unlockAchievement(event, false); } } catch (error) { console.error('Failed to load saved achievements:', error); diff --git a/src/routes/test-achievement/+page.svelte b/src/routes/test-achievement/+page.svelte new file mode 100644 index 0000000..4dc0b5b --- /dev/null +++ b/src/routes/test-achievement/+page.svelte @@ -0,0 +1,45 @@ + + +
+

Achievement Sound Test

+ +
+ + + + +

+ Click the first button to test just the sound effect.
+ Click the second button to trigger a real achievement (if any are available to unlock). +

+
+
\ No newline at end of file diff --git a/static/sounds/achievement.mp3 b/static/sounds/achievement.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..9c918118cde8d0501c8709622ed6c19d530af37c GIT binary patch literal 14829 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 T@rSQ~?SzPu;{f3Q2K9dcA&!G1 literal 0 HcmV?d00001