feat(sound): 우하단 빠른 볼륨/3프리셋 및 더미 저장 복원 적용
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user