import type { AutopilotBlock } from "@rakazo/contracts"; import { formatAutopilotDuration } from "@rakazo/core"; import { useState } from "react"; import { Pressable, Text, View } from "react-native"; import { dateLocaleForUi, useI18n } from "../lib/i18n"; import { useMobileTokens } from "../lib/native"; import { NativeSymbol } from "./native-symbol"; export type AutopilotAction = "stop" | "resume"; const ICONS = { "autopilot.started": { ios: "play.fill", android: "play" }, "autopilot.paused": { ios: "pause.fill", android: "pause" }, "autopilot.stopped": { ios: "stop.fill", android: "stop" }, "autopilot.finished": { ios: "checkmark.circle", android: "checkmark-circle-outline" }, } as const; /** One quiet line when the autopilot starts, pauses, stops or finishes. */ export function AutopilotLine({ block, onAction, }: { block: AutopilotBlock; onAction?: (action: AutopilotAction) => Promise; }) { const tokens = useMobileTokens(); const { t, locale } = useI18n(); const [busy, setBusy] = useState(false); const [failed, setFailed] = useState(false); const open = !block.ended && Boolean(onAction); const muted = { color: tokens.mutedForeground, fontSize: 13.5 }; async function act(action: AutopilotAction) { if (!onAction) return; setBusy(true); setFailed(false); try { await onAction(action); } catch { setFailed(true); } finally { setBusy(false); } } const parts: string[] = []; let label = t("Autopilot"); if (block.event === "autopilot.started") { parts.push(block.goal); if (block.until) { const until = new Intl.DateTimeFormat(dateLocaleForUi(locale), { hour: "numeric", minute: "2-digit", }).format(new Date(block.until)); parts.push(t("until {until}", { until })); } if (block.focus) parts.push(block.focus); if (block.allowed?.length) { parts.push(t("allowed: {allowed}", { allowed: block.allowed.join(", ") })); } } else if (block.event === "autopilot.paused") { label = t("Autopilot paused"); if (block.text) parts.push(block.text); } else { label = block.event === "autopilot.stopped" ? t("Autopilot stopped") : t("Autopilot finished"); if (block.durationMs !== undefined) parts.push(formatAutopilotDuration(block.durationMs)); } const icon = ICONS[block.event]; const link = (text: string, action: AutopilotAction) => ( void act(action)} style={{ opacity: busy ? 0.5 : 1 }} > {text} ); return ( {label} {parts.map((part, index) => ( · {part} ))} {open && block.event === "autopilot.paused" ? ( <> · {link(t("Continue"), "resume")} ) : null} {open && (block.event === "autopilot.started" || block.event === "autopilot.paused") ? ( <> · {link(failed ? t("Try again") : t("Stop"), "stop")} ) : null} {block.event === "autopilot.finished" && block.text ? ( {block.text} ) : null} ); }