/** * PlayerPage — single-pane audio now-playing view. * * Audio transport (play/pause, next/prev, seek) is handled globally by the * Shell router (P/N/B/). This page renders a single rich pane showing the * current episode, waveform, and playback controls. Panes/swipe do nothing * (PaneCount=1). */ import { Show } from "solid-js"; import { PlaybackControls } from "./PlaybackControls"; import { RealtimeWaveform } from "./RealtimeWaveform"; import { useAudio } from "@/hooks/useAudio"; import { useAppStore } from "@/stores/app"; import { useTheme } from "@/context/ThemeContext"; import { useNavigation } from "@/context/NavigationContext"; export const PlayerPaneCount = 1; export function PlayerPage() { const audio = useAudio(); const { theme } = useTheme(); const nav = useNavigation(); const muted = () => theme.muted || theme.text; // Single pane — always active. const isActive = () => true; const border = () => theme.accent; const progressPercent = () => { const d = audio.duration(); if (d <= 0) return 0; return Math.min(100, Math.round((audio.position() / d) * 100)); }; const formatTime = (seconds: number) => { const m = Math.floor(seconds / 60); const s = Math.floor(seconds % 60); return `${m}:${String(s).padStart(2, "0")}`; }; return ( {/* ── pane 0: now playing ─────────────────────────────────────────── */} Player Now Playing {formatTime(audio.position())} / {formatTime(audio.duration())} ( {progressPercent()}%) {(err) => {err()}} No episode loaded. } > {(ep) => ( {ep().title} {ep().description?.slice(0, 500) ?? "No description available."} { const viz = useAppStore().state().settings.visualizer; return { bars: viz.bars, noiseReduction: viz.noiseReduction, lowCutOff: viz.lowCutOff, highCutOff: viz.highCutOff, }; })()} /> )} audio.seek(0)} onNext={() => audio.seek(audio.currentEpisode()?.duration ?? 0)} onSpeedChange={(s: number) => audio.setSpeed(s)} onVolumeChange={(v: number) => audio.setVolume(v)} /> {"P play/pause N next B prev ); }