import type { OoMoment } from "@rakazo/core"; import { ACTIVE_RUN_STATUSES, DEFAULT_OO_AVATAR, decodeOoAvatar, OO_SUCCESS_SECONDS, ooIdentityShapeIndex, ooMomentAfterStatus, ooMomentForStatus, resolveOoColor, } from "@rakazo/core"; import { memo, useEffect, useMemo, useRef, useState } from "react"; import { Image, View } from "react-native"; import { useI18n } from "../lib/i18n"; import { NativeSymbol } from "./native-symbol"; import { OoFigure } from "./oo-figure"; /** A short moment after a status change, such as joy when a run finishes. */ function useOoStatusMoment(status?: string): OoMoment | null { const previous = useRef(status); const [moment, setMoment] = useState(null); useEffect(() => { const next = ooMomentAfterStatus(previous.current, status); previous.current = status; setMoment(next); if (!next) return; const timer = setTimeout(() => setMoment(null), OO_SUCCESS_SECONDS * 1000); return () => clearTimeout(timer); }, [status]); return moment; } export const BotAvatar = memo(function BotAvatar({ color, size = 54, status, identity, moment, still, muted = false, }: { color: string; size?: number; status?: string; identity?: string; /** Explicit moment; wins over `status`. */ moment?: OoMoment; still?: boolean; muted?: boolean; }) { const { t } = useI18n(); const isWorking = ACTIVE_RUN_STATUSES.some((activeStatus) => activeStatus === status); const picture = color.startsWith("data:image/") ? color : null; const look = useMemo(() => decodeOoAvatar(color) ?? DEFAULT_OO_AVATAR, [color]); const seed = identity || (picture ? "agent" : color) || "agent"; const body = resolveOoColor(seed, look.color).hex; const statusMoment = useOoStatusMoment(status); return ( {picture ? ( ) : ( )} {isWorking ? ( ) : null} {muted ? ( ) : null} ); });