import { useState } from 'react'; import { Pressable, StyleSheet, View } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Text } from './Text'; import { SpectrumCurve } from './SpectrumCurve'; import { OscilloscopeWave } from './OscilloscopeWave'; import { colors, spacing } from '@/theme'; import { useScopeActive } from '@/scope/scopeStore'; const CANVAS_HEIGHT = 96; const STAGE_FRAME_MS = 0; // display-sync type Mode = 'spectrum' | 'scope'; interface VisualizerProps { width: number; height?: number; interactive?: boolean; showChrome?: boolean; mode?: Mode; edgeFade?: boolean; } /** * Visualizer for the now-playing screen. By default it remains an inline * interactive component; inside the media stage it can render chrome-free so * the parent owns artwork/scope switching without moving the surrounding UI. */ export function Visualizer({ width, height = CANVAS_HEIGHT, interactive = true, showChrome = true, mode: controlledMode, edgeFade = false, }: VisualizerProps) { const [uncontrolledMode, setUncontrolledMode] = useState('spectrum'); const mode = controlledMode ?? uncontrolledMode; const scopeActive = useScopeActive(); const spectrumActive = scopeActive && mode === 'spectrum'; const scopeWaveActive = scopeActive && mode === 'scope'; const toggle = () => { if (controlledMode) return; setUncontrolledMode((m) => (m === 'spectrum' ? 'scope' : 'spectrum')); }; const content = ( <> {showChrome && ( {mode === 'spectrum' ? 'SPECTRUM' : 'SCOPE'} )} {mode === 'spectrum' ? ( ) : ( )} ); if (!interactive) { return ( {content} ); } return ( {content} ); } const styles = StyleSheet.create({ wrap: { paddingVertical: spacing.xs, }, stageWrap: { overflow: 'hidden', }, caption: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: spacing.xs, }, captionText: { color: colors.textTertiary, letterSpacing: 1.5, fontSize: 10, }, }); export default Visualizer;