import { useEffect, useRef } from 'react'; import { ScrollView, Text, View } from 'react-native'; import type { Particle } from '@/api/types'; import { MarkdownBody } from '@/components/MarkdownBody'; import { useStreamSafeArea } from './stream-safe-area'; type PaperParticle = Extract; interface PaperParticleViewProps { particle: PaperParticle; paused: boolean; onEnded: () => void; onProgress: (ratio: number) => void; } // Papers are longer-form documents, so they read at the text cadence but with a // higher cap — the reader can still scroll at their own pace while the timer // ticks toward auto-advance. const CHARS_PER_MINUTE = 1000; const MIN_DURATION_S = 4; const MAX_DURATION_S = 30; const TICK_MS = 100; function computeReadDuration(text: string): number { const base = (text.length / CHARS_PER_MINUTE) * 60; return Math.min(Math.max(base, MIN_DURATION_S), MAX_DURATION_S); } /** * Read-only paper (document) view. Mirrors desktop's paper rendering: a title * heading above markdown body, scrollable, with a length-based dwell timer. */ export function PaperParticleView({ particle, paused, onEnded, onProgress, }: PaperParticleViewProps) { const { title, content } = particle.properties; const safe = useStreamSafeArea(); const durationS = computeReadDuration(content); const elapsedRef = useRef(0); useEffect(() => { elapsedRef.current = 0; onProgress(0); }, [particle.id, onProgress]); useEffect(() => { if (paused) return; const interval = setInterval(() => { elapsedRef.current += TICK_MS / 1000; const ratio = Math.min(elapsedRef.current / durationS, 1); onProgress(ratio); if (ratio >= 1) { clearInterval(interval); onEnded(); } }, TICK_MS); return () => clearInterval(interval); }, [paused, durationS, onEnded, onProgress, particle.id]); return ( {title} ); }