feat(sound): 우하단 빠른 볼륨/3프리셋 및 더미 저장 복원 적용

This commit is contained in:
2026-03-04 15:20:56 +09:00
parent 8f64637b6f
commit 27a64d9d81
7 changed files with 368 additions and 112 deletions

View File

@@ -1,6 +1,6 @@
'use client';
import { useMemo, useState } from 'react';
import { useEffect, useMemo, useState } from 'react';
import { SOUND_PRESETS } from '@/entities/session';
const TRACK_KEYS = ['white', 'rain', 'cafe', 'wave', 'fan'] as const;
@@ -16,24 +16,93 @@ const DEFAULT_TRACK_LEVELS: Record<SoundTrackKey, number> = {
};
const DEFAULT_MASTER_VOLUME = 68;
const SOUND_PREF_STORAGE_KEY = 'viberoom:sound-pref:v1';
const clampVolume = (value: number) => {
return Math.min(100, Math.max(0, value));
};
interface StoredSoundPref {
selectedPresetId?: string;
masterVolume?: number;
isMuted?: boolean;
}
const readStoredSoundPref = (): StoredSoundPref => {
if (typeof window === 'undefined') {
return {};
}
const raw = window.localStorage.getItem(SOUND_PREF_STORAGE_KEY);
if (!raw) {
return {};
}
try {
const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== 'object') {
return {};
}
return parsed as StoredSoundPref;
} catch {
return {};
}
};
export const useSoundPresetSelection = (initialPresetId?: string) => {
const storedPref = useMemo(() => readStoredSoundPref(), []);
const safeInitialPresetId = useMemo(() => {
const hasPreset = SOUND_PRESETS.some((preset) => preset.id === initialPresetId);
return hasPreset && initialPresetId ? initialPresetId : SOUND_PRESETS[0].id;
}, [initialPresetId]);
const candidates = [initialPresetId, storedPref.selectedPresetId];
for (const candidate of candidates) {
if (!candidate) {
continue;
}
if (SOUND_PRESETS.some((preset) => preset.id === candidate)) {
return candidate;
}
}
return SOUND_PRESETS[0].id;
}, [initialPresetId, storedPref.selectedPresetId]);
const [selectedPresetId, setSelectedPresetId] = useState(safeInitialPresetId);
const [isMixerOpen, setMixerOpen] = useState(false);
const [isMuted, setMuted] = useState(false);
const [masterVolume, setMasterVolume] = useState(DEFAULT_MASTER_VOLUME);
const [isMuted, setMuted] = useState(Boolean(storedPref.isMuted));
const [masterVolume, setMasterVolume] = useState(
clampVolume(storedPref.masterVolume ?? DEFAULT_MASTER_VOLUME),
);
const [trackLevels, setTrackLevels] =
useState<Record<SoundTrackKey, number>>(DEFAULT_TRACK_LEVELS);
useEffect(() => {
if (typeof window === 'undefined') {
return;
}
window.localStorage.setItem(
SOUND_PREF_STORAGE_KEY,
JSON.stringify({
selectedPresetId,
masterVolume: clampVolume(masterVolume),
isMuted,
}),
);
}, [selectedPresetId, masterVolume, isMuted]);
const setTrackLevel = (track: SoundTrackKey, level: number) => {
setTrackLevels((current) => ({ ...current, [track]: level }));
};
const setMasterVolumeSafe = (nextVolume: number) => {
setMasterVolume(clampVolume(nextVolume));
};
return {
selectedPresetId,
setSelectedPresetId,
@@ -42,7 +111,7 @@ export const useSoundPresetSelection = (initialPresetId?: string) => {
isMuted,
setMuted,
masterVolume,
setMasterVolume,
setMasterVolume: setMasterVolumeSafe,
trackLevels,
setTrackLevel,
trackKeys: TRACK_KEYS,