added new requirements and fix UI bugs

This commit is contained in:
rgrgogu
2026-07-15 16:26:59 +08:00
parent 95987edd22
commit 5a9c0390e6
27 changed files with 1423 additions and 232 deletions
@@ -32,8 +32,11 @@ const API_BASE = (import.meta.env.VITE_API_URL ?? "http://localhost:3024").repla
//
// content shape: { asset_id?, url?, storage_provider?, title?, artist?, tag?, thumbnail? }
export function AudioBlock({ content }) {
// onWatchProgress(percent) — optional, called (throttled) as playback advances and
// immediately at 100% on end. Backing the watch_percent completion requirement type.
export function AudioBlock({ content, onWatchProgress }) {
const audioRef = useRef(null);
const lastReportRef = useRef(0);
// ── Stream state ──────────────────────────────────────────────────────────
const [blobUrl, setBlobUrl] = useState(null);
@@ -116,9 +119,20 @@ export function AudioBlock({ content }) {
// ── Audio events ──────────────────────────────────────────────────────────
const onTimeUpdate = useCallback(() => setCurrentTime(audioRef.current?.currentTime ?? 0), []);
const onTimeUpdate = useCallback(() => {
const el = audioRef.current;
setCurrentTime(el?.currentTime ?? 0);
if (onWatchProgress && el?.duration) {
const pct = (el.currentTime / el.duration) * 100;
const now = Date.now();
if (now - lastReportRef.current > 3000) {
lastReportRef.current = now;
onWatchProgress(pct);
}
}
}, [onWatchProgress]);
const onLoadedMeta = useCallback(() => setDuration(audioRef.current?.duration ?? 0), []);
const onEnded = useCallback(() => setPlaying(false), []);
const onEnded = useCallback(() => { setPlaying(false); onWatchProgress?.(100); }, [onWatchProgress]);
const onProgress = useCallback(() => {
const el = audioRef.current;
if (el?.buffered.length && el.duration) {
@@ -159,9 +159,13 @@ function SettingsPanel({ speed, onSpeed, onClose }) {
//
// content shape: { asset_id, url, storage_provider, thumbnail_url? }
export function VideoBlock({ content }) {
// onWatchProgress(percent) — optional, called (throttled) as playback advances and
// immediately at 100% on end. Backing the watch_percent completion requirement type;
// harmless/unused when the lesson isn't configured for it (caller just won't pass it).
export function VideoBlock({ content, onWatchProgress }) {
const wrapRef = useRef(null);
const vidRef = useRef(null);
const lastReportRef = useRef(0);
// ── Stream state ──────────────────────────────────────────────────────────
const [blobUrl, setBlobUrl] = useState(null);
@@ -266,10 +270,23 @@ export function VideoBlock({ content }) {
const onTimeUpdate = () => {
setCurrentTime(v.currentTime);
if (v.duration) setProgress((v.currentTime / v.duration) * 100);
if (v.duration) {
const pct = (v.currentTime / v.duration) * 100;
setProgress(pct);
if (onWatchProgress) {
const now = Date.now();
if (now - lastReportRef.current > 3000) {
lastReportRef.current = now;
onWatchProgress(pct);
}
}
}
};
const onLoaded = () => setTotalDuration(v.duration);
const onEnded = () => { setPlaying(false); setOverlayVisible(false); setEnded(true); };
const onEnded = () => {
setPlaying(false); setOverlayVisible(false); setEnded(true);
onWatchProgress?.(100);
};
const onWaiting = () => setBuffering(true);
const onCanPlay = () => setBuffering(false);
const onProgress = () => {