import { useState } from 'react'; import { View, Pressable, StyleSheet, type LayoutChangeEvent } from 'react-native'; import { Image } from 'expo-image'; import { Ionicons } from '@expo/vector-icons'; import { useRouter } from 'expo-router'; import { Text } from './Text'; import { AstraLogo } from './AstraLogo'; import { SpectrumCurve } from './SpectrumCurve'; import { colors, radius, spacing } from '@/theme'; import { usePlayerStore } from '@/stores/playerStore'; import { skipToNext, togglePlay } from '@/audio/playbackController'; import { useScopeActive } from '@/scope/scopeStore'; import { useSpectrumCurve } from '@/scope/useSpectrumCurve'; const PILL_HEIGHT = 56; const ART = 42; const CURVE_POINTS = 64; /** * Persistent floating mini-player (M3 redesign): a rounded pill above the tab * bar with the live filled-line spectrum drifting behind the metadata. Tapping * opens the full now-playing screen. */ export function MiniPlayer() { const router = useRouter(); const track = usePlayerStore((s) => s.currentTrack); const playbackState = usePlayerStore((s) => s.playbackState); const currentTime = usePlayerStore((s) => s.currentTime); const duration = usePlayerStore((s) => s.duration); const scopeActive = useScopeActive(); const values = useSpectrumCurve(CURVE_POINTS, scopeActive); const [pillWidth, setPillWidth] = useState(0); if (!track) return null; const isPlaying = playbackState === 'playing'; const isLoading = playbackState === 'loading'; const progress = duration > 0 ? Math.min(1, currentTime / duration) : 0; const onLayout = (e: LayoutChangeEvent) => setPillWidth(e.nativeEvent.layout.width); return ( router.push('/now-playing')} onLayout={onLayout}> {scopeActive && pillWidth > 0 && ( )} {track.artworkData ? ( ) : ( )} {track.title} {track.artist} ); } const styles = StyleSheet.create({ pill: { height: PILL_HEIGHT, marginHorizontal: spacing.md, marginTop: spacing.sm, marginBottom: spacing.sm, borderRadius: radius.lg, backgroundColor: colors.bgTertiary, borderColor: colors.glassBorder, borderWidth: StyleSheet.hairlineWidth, overflow: 'hidden', justifyContent: 'center', }, spectrum: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, }, row: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: spacing.sm, gap: spacing.sm, }, art: { width: ART, height: ART, borderRadius: radius.sm, backgroundColor: colors.bgSecondary, alignItems: 'center', justifyContent: 'center', overflow: 'hidden', }, artImage: { width: '100%', height: '100%', }, meta: { flex: 1, }, title: { fontSize: 15, }, control: { width: 36, height: 36, alignItems: 'center', justifyContent: 'center', }, progressTrack: { position: 'absolute', left: 0, right: 0, bottom: 0, height: 2, backgroundColor: colors.glassBorder, }, progressFill: { height: 2, backgroundColor: colors.accent, }, }); export default MiniPlayer;