Phase 9 완료: 전체 남은 기능 구현

1. RecordingTip: thinking 상태 전환 시 opacity 보장
2. 히스토리 오디오 경로: WAV 파일 경로를 DB에 기록
3. 마이크 테스트 UI: Settings Audio 탭에 TEST 버튼 + 레벨 바
4. 온보딩 플로우: 첫 실행 시 3단계 안내 (환영→마이크→핫키→완료)
5. MetalDial 컴포넌트: 동심원 그루브, 회전 포인터, LED 인디케이터
This commit is contained in:
Yun Chan 2026-04-05 12:16:39 +09:00
parent d7074e359d
commit c338a19c90
7 changed files with 431 additions and 4 deletions

View file

@ -191,6 +191,8 @@ export function SettingsModal({ open, onClose }: SettingsModalProps): React.Reac
// 오디오 디바이스
const [audioDevices, setAudioDevices] = useState<AudioDevice[]>([])
const [selectedDeviceId, setSelectedDeviceId] = useState<string>('default')
const [micTesting, setMicTesting] = useState(false)
const [micLevel, setMicLevel] = useState(0)
// 설정 로드
useEffect(() => {
@ -500,6 +502,58 @@ export function SettingsModal({ open, onClose }: SettingsModalProps): React.Reac
</Select>
</FormControl>
{/* 마이크 테스트 */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
<Button
variant={micTesting ? 'contained' : 'outlined'}
size="small"
onClick={() => {
if (micTesting) {
setMicTesting(false)
setMicLevel(0)
} else {
setMicTesting(true)
// 3초 후 자동 종료
const unsub = window.electronAPI.voice.onAudioLevel((e) => {
setMicLevel(e.level)
})
setTimeout(() => {
setMicTesting(false)
setMicLevel(0)
unsub()
}, 5000)
}
}}
sx={{
fontFamily: d3roFontMono,
fontSize: '11px',
minWidth: 80,
}}
>
{micTesting ? 'STOP' : 'TEST'}
</Button>
<Box
sx={{
flex: 1,
height: 8,
bgcolor: d3roPalette.bg.inset,
borderRadius: '4px',
overflow: 'hidden',
boxShadow: 'inset 0 1px 3px rgba(0,0,0,0.4)',
}}
>
<Box
sx={{
width: `${Math.min(100, micLevel * 100)}%`,
height: '100%',
bgcolor: micLevel > 0.7 ? d3roPalette.tag.red : d3roPalette.accent.amber,
borderRadius: '4px',
transition: 'width 100ms ease-out',
}}
/>
</Box>
</Box>
<Divider sx={{ borderColor: d3roPalette.border.subtle }} />
<Typography variant="overline" sx={{ color: d3roPalette.text.label, letterSpacing: '1.5px' }}>