import React from "react";
import { View, FlatList } from "react-native";
import { Text, Chip, Menu, Button } from "react-native-paper";
import API from "../API.js";
import i18n from "../i18nMessages.js";
const POLL_MS = 1800;
const toLangLabel = (lang = "") => {
const normalized = String(lang || "").toLowerCase();
if (!normalized || normalized === "original") return i18n.t("message.originalLanguage");
if (normalized === "en") return i18n.t("message.languageEnglish");
if (normalized === "es") return i18n.t("message.languageSpanish");
if (normalized === "fr") return i18n.t("message.languageFrench");
if (normalized === "da") return i18n.t("message.languageDanish");
return normalized.toUpperCase();
};
const CaptionRow = ({ item, selectedLang }) => {
const translation = item?.translations?.[selectedLang];
const displayTranslation = translation || item?.original || "";
const isFallback = !translation && selectedLang && selectedLang !== "original" && selectedLang !== item?.sourceLang;
return (
{item?.sourceLang ? `${i18n.t("message.originalLanguage")}: ${toLangLabel(item.sourceLang)}` : i18n.t("message.originalLanguage")}
{item?.original || ""}
{i18n.t("message.selectedTranslation")}: {toLangLabel(selectedLang)}
{displayTranslation}
{isFallback ? (
{i18n.t("message.translationFallback")}
) : <>>}
);
};
const LiveCaptions = () => {
const [captions, setCaptions] = React.useState([]);
const [availableLanguages, setAvailableLanguages] = React.useState([]);
const [selectedLang, setSelectedLang] = React.useState((i18n?.locale || "en").toLowerCase());
const [isLoading, setIsLoading] = React.useState(true);
const [langMenuVisible, setLangMenuVisible] = React.useState(false);
const latestSequenceRef = React.useRef(0);
const refresh = React.useCallback(async (initial = false) => {
const sinceSequence = initial ? undefined : latestSequenceRef.current;
const response = await API.getLiveCaptions(sinceSequence, 50);
const incoming = Array.isArray(response?.captions) ? response.captions : [];
const languages = Array.isArray(response?.availableLanguages) ? response.availableLanguages : [];
if (initial) {
setCaptions(incoming);
} else if (incoming.length > 0) {
setCaptions((prev) => {
const bySequence = new Map(prev.map((item) => [item.sequence, item]));
incoming.forEach((item) => {
if (!item || !Number.isFinite(item.sequence)) return;
bySequence.set(item.sequence, item);
});
return Array.from(bySequence.values()).sort((a, b) => (a.sequence || 0) - (b.sequence || 0)).slice(-150);
});
}
if (Number.isFinite(response?.latestSequence)) {
latestSequenceRef.current = response.latestSequence;
} else if (incoming.length) {
const maxSeq = incoming.reduce((acc, item) => Math.max(acc, Number(item?.sequence) || 0), latestSequenceRef.current);
latestSequenceRef.current = maxSeq;
}
setAvailableLanguages(languages);
setIsLoading(false);
}, []);
React.useEffect(() => {
refresh(true);
const interval = setInterval(() => {
refresh(false);
}, POLL_MS);
return () => clearInterval(interval);
}, [refresh]);
const languageOptions = React.useMemo(() => {
const unique = new Set(["original", ...availableLanguages]);
return Array.from(unique).filter(Boolean);
}, [availableLanguages]);
React.useEffect(() => {
if (languageOptions.includes(selectedLang)) return;
if (languageOptions.length) setSelectedLang(languageOptions[0]);
}, [languageOptions, selectedLang]);
return (
{i18n.t("message.liveCaptions")}
{i18n.t("message.liveCaptionsSubtitle")}
{i18n.t("message.liveNow")}
{i18n.t("message.translationLanguage")}
{isLoading ? {i18n.t("message.loadingLiveCaptions")} : <>>}
{!isLoading && captions.length === 0 ? {i18n.t("message.awaitingLiveCaptions")} : <>>}
`${item?.sequence || "caption"}-${index}`}
renderItem={({ item }) => }
contentContainerStyle={{ paddingBottom: 18 }}
style={{ flex: 1 }}
/>
);
};
export default LiveCaptions;