ui cleanup
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
/**
|
||||
* PlayerPage — single-pane audio now-playing view.
|
||||
* PlayerPage — 2-pane yazi depth view of the now-playing episode.
|
||||
*
|
||||
* 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).
|
||||
* depth 0 (parent) — tab list (muted, read-only).
|
||||
* depth 0 (current) — the single now-playing pane (rich view + controls).
|
||||
*
|
||||
* No preview pane (YaziPaneRow `panes={2}`). Audio transport (play/pause,
|
||||
* next/prev, seek) is handled globally by the Shell router (P/N/B/</>); this
|
||||
* page only renders the now-playing surface. `h` at depth 0 returns to the
|
||||
* tab root.
|
||||
*/
|
||||
|
||||
import { Show } from "solid-js";
|
||||
@@ -13,7 +16,9 @@ import { RealtimeWaveform } from "./RealtimeWaveform";
|
||||
import { useAudio } from "@/hooks/useAudio";
|
||||
import { useAppStore } from "@/stores/app";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
import { useNavigation } from "@/context/NavigationContext";
|
||||
import { useNavigation, DEPTH_CENTER_PANE } from "@/context/NavigationContext";
|
||||
import { YaziPaneRow } from "@/components/YaziPaneRow";
|
||||
import { TabListPane } from "@/components/TabPanel";
|
||||
|
||||
export const PlayerPaneCount = 1;
|
||||
|
||||
@@ -23,9 +28,7 @@ export function PlayerPage() {
|
||||
const nav = useNavigation();
|
||||
const muted = () => theme.muted || theme.text;
|
||||
|
||||
// Single pane — always active.
|
||||
const isActive = () => true;
|
||||
const border = () => theme.accent;
|
||||
const isActive = () => nav.activePane() === DEPTH_CENTER_PANE;
|
||||
|
||||
const progressPercent = () => {
|
||||
const d = audio.duration();
|
||||
@@ -39,84 +42,86 @@ export function PlayerPage() {
|
||||
return `${m}:${String(s).padStart(2, "0")}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<box flexDirection="column" width="100%" height="100%">
|
||||
{/* ── pane 0: now playing ─────────────────────────────────────────── */}
|
||||
<box height={1} paddingLeft={1} backgroundColor={theme.background}>
|
||||
<text fg={theme.textSecondary}>Player</text>
|
||||
// ── parent pane: the tab list (muted) ──────────────────────────────────────
|
||||
const parentContent = () => <TabListPane muted />;
|
||||
|
||||
// ── current pane: now playing ───────────────────────────────────────────────
|
||||
const currentContent = () => (
|
||||
<box flexDirection="column" gap={1} padding={1}>
|
||||
<box flexDirection="row" justifyContent="space-between">
|
||||
<text fg={theme.text}>
|
||||
<strong>Now Playing</strong>
|
||||
</text>
|
||||
<text fg={muted()}>
|
||||
{formatTime(audio.position())} / {formatTime(audio.duration())} (
|
||||
{progressPercent()}%)
|
||||
</text>
|
||||
</box>
|
||||
<scrollbox
|
||||
height="100%"
|
||||
focused={isActive()}
|
||||
border
|
||||
borderColor={border()}
|
||||
backgroundColor={theme.background}
|
||||
|
||||
<Show when={audio.error()}>
|
||||
{(err) => <text fg={theme.error}>{err()}</text>}
|
||||
</Show>
|
||||
|
||||
<Show
|
||||
when={audio.currentEpisode()}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>No episode loaded.</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
<box flexDirection="column" gap={1} padding={1}>
|
||||
<box flexDirection="row" justifyContent="space-between">
|
||||
{(ep) => (
|
||||
<box flexDirection="column" gap={1}>
|
||||
<text fg={theme.text}>
|
||||
<strong>Now Playing</strong>
|
||||
<strong>{ep().title}</strong>
|
||||
</text>
|
||||
<text fg={muted()}>
|
||||
{formatTime(audio.position())} / {formatTime(audio.duration())} (
|
||||
{progressPercent()}%)
|
||||
{ep().description?.slice(0, 500) ?? "No description available."}
|
||||
</text>
|
||||
|
||||
<RealtimeWaveform
|
||||
visualizerConfig={(() => {
|
||||
const viz = useAppStore().state().settings.visualizer;
|
||||
return {
|
||||
bars: viz.bars,
|
||||
noiseReduction: viz.noiseReduction,
|
||||
lowCutOff: viz.lowCutOff,
|
||||
highCutOff: viz.highCutOff,
|
||||
};
|
||||
})()}
|
||||
/>
|
||||
</box>
|
||||
)}
|
||||
</Show>
|
||||
|
||||
<Show when={audio.error()}>
|
||||
{(err) => <text fg={theme.error}>{err()}</text>}
|
||||
</Show>
|
||||
<PlaybackControls
|
||||
isPlaying={audio.isPlaying()}
|
||||
volume={audio.volume()}
|
||||
speed={audio.speed()}
|
||||
backendName={audio.backendName()}
|
||||
hasAudioUrl={!!audio.currentEpisode()?.audioUrl}
|
||||
onToggle={audio.togglePlayback}
|
||||
onPrev={() => audio.seek(0)}
|
||||
onNext={() => audio.seek(audio.currentEpisode()?.duration ?? 0)}
|
||||
onSpeedChange={(s: number) => audio.setSpeed(s)}
|
||||
onVolumeChange={(v: number) => audio.setVolume(v)}
|
||||
/>
|
||||
|
||||
<Show
|
||||
when={audio.currentEpisode()}
|
||||
fallback={
|
||||
<box padding={1}>
|
||||
<text fg={muted()}>No episode loaded.</text>
|
||||
</box>
|
||||
}
|
||||
>
|
||||
{(ep) => (
|
||||
<box flexDirection="column" gap={1}>
|
||||
<text fg={theme.text}>
|
||||
<strong>{ep().title}</strong>
|
||||
</text>
|
||||
<text fg={muted()}>
|
||||
{ep().description?.slice(0, 500) ??
|
||||
"No description available."}
|
||||
</text>
|
||||
|
||||
<RealtimeWaveform
|
||||
visualizerConfig={(() => {
|
||||
const viz = useAppStore().state().settings.visualizer;
|
||||
return {
|
||||
bars: viz.bars,
|
||||
noiseReduction: viz.noiseReduction,
|
||||
lowCutOff: viz.lowCutOff,
|
||||
highCutOff: viz.highCutOff,
|
||||
};
|
||||
})()}
|
||||
/>
|
||||
</box>
|
||||
)}
|
||||
</Show>
|
||||
|
||||
<PlaybackControls
|
||||
isPlaying={audio.isPlaying()}
|
||||
volume={audio.volume()}
|
||||
speed={audio.speed()}
|
||||
backendName={audio.backendName()}
|
||||
hasAudioUrl={!!audio.currentEpisode()?.audioUrl}
|
||||
onToggle={audio.togglePlayback}
|
||||
onPrev={() => audio.seek(0)}
|
||||
onNext={() => audio.seek(audio.currentEpisode()?.duration ?? 0)}
|
||||
onSpeedChange={(s: number) => audio.setSpeed(s)}
|
||||
onVolumeChange={(v: number) => audio.setVolume(v)}
|
||||
/>
|
||||
|
||||
<box height={1} />
|
||||
<text fg={muted()}>{"P play/pause N next B prev </ seek"}</text>
|
||||
</box>
|
||||
</scrollbox>
|
||||
<box height={1} />
|
||||
<text fg={muted()}>
|
||||
{"P play/pause N next B prev </ seek · h back"}
|
||||
</text>
|
||||
</box>
|
||||
);
|
||||
|
||||
return (
|
||||
<YaziPaneRow
|
||||
parent={parentContent}
|
||||
current={currentContent}
|
||||
parentLabel="Up"
|
||||
currentLabel="Player"
|
||||
panes={2}
|
||||
focused={isActive}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user