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 0000000..9c91811 Binary files /dev/null and b/static/sounds/achievement.mp3 differ