import { Button, Icon } from "@nodedc/ui-react"; import type { ObservationTimelineMode } from "../core/runtime/contracts"; export function ObservationTimeline({ active, sourceCount, mode = "live-only", seekable = false, synchronization = "host-arrival-best-effort", rangeNs = null, currentNs = null, playing = false, onSeek, onPlayingChange, onJumpToEnd, accumulationSeconds, onAccumulationChange, onAccumulationCommit, className = "", }: { active: boolean; sourceCount: number; mode?: ObservationTimelineMode; seekable?: boolean; synchronization?: "host-arrival-best-effort" | "shared-clock" | "frame-accurate"; rangeNs?: { min: number; max: number } | null; currentNs?: number | null; playing?: boolean; onSeek?: (timeNs: number) => void; onPlayingChange?: (playing: boolean) => void; onJumpToEnd?: () => void; accumulationSeconds?: number; onAccumulationChange?: (value: number) => void; onAccumulationCommit?: () => void; className?: string; }) { const playbackRange = normalizeTimelineRange(rangeNs); const buffered = Boolean( seekable && (mode === "buffered" || mode === "recorded") && playbackRange, ); const elapsedSeconds = playbackRange ? timelineOffsetSeconds(playbackRange, currentNs ?? playbackRange.min) : 0; const durationSeconds = playbackRange ? Math.max(0, (playbackRange.max - playbackRange.min) / 1_000_000_000) : 0; const synchronizationLabel = { "host-arrival-best-effort": "Синхронизация по приходу", "shared-clock": "Общие часы", "frame-accurate": "Покадровая синхронизация", }[synchronization]; const accumulationValue = accumulationSeconds === undefined ? null : normalizeAccumulationSeconds(accumulationSeconds); return (
{formatAccumulationDuration(accumulationValue)}
{buffered
? `${formatTimelineDuration(elapsedSeconds)} / ${formatTimelineDuration(durationSeconds)}`
: active ? "LIVE" : "—:—:—.———"}
{buffered ? `${sourceCount} каналов` : `${synchronizationLabel} · буфер не включён`}