import React, { memo, useCallback, useMemo, type ReactNode } from "react"; import { View } from "react-native"; import { StyleSheet, withUnistyles } from "react-native-unistyles"; import { MAX_CONTENT_WIDTH } from "@/constants/layout"; import type { Theme } from "@/styles/theme"; import type { TurnTiming } from "@/timeline/turn-time"; import type { StreamItem } from "@/types/stream"; import { collectAssistantTurnContentForStreamRenderStrategy, type StreamStrategy, } from "./strategy"; import { AssistantTurnFooter, LiveElapsed, STREAM_METADATA_FONT_SIZE } from "@/components/message"; import type { TurnFooterHost } from "./layout"; import { SyncedLoader } from "@/components/synced-loader"; const ThemedSyncedLoader = withUnistyles(SyncedLoader); const workingIndicatorColorMapping = (theme: Theme) => ({ color: theme.colorScheme === "light" ? theme.colors.palette.amber[700] : theme.colors.palette.amber[500], }); export type TurnContentStrategy = StreamStrategy; export const TurnFooter = memo(function TurnFooter({ isRunning, inFlightTurnStartedAt, host, strategy, }: { isRunning: boolean; inFlightTurnStartedAt: Date | null; host: TurnFooterHost | null; strategy: TurnContentStrategy; }) { if (isRunning) { return ( ); } if (!host) { return null; } return ( ); }); export const CompletedTurnFooterRow = memo(function CompletedTurnFooterRow({ strategy, items, timing, startIndex, }: { strategy: TurnContentStrategy; items: StreamItem[]; timing?: TurnTiming; startIndex: number; }) { return ( ); }); const WorkingIndicator = memo(function WorkingIndicator({ inFlightTurnStartedAt = null, }: { inFlightTurnStartedAt?: Date | null; }) { return ( {inFlightTurnStartedAt ? ( ) : null} ); }); function RunningTurnFooter({ inFlightTurnStartedAt }: { inFlightTurnStartedAt: Date | null }) { return ( ); } function CompletedTurnFooter({ strategy, items, timing, startIndex, }: { strategy: TurnContentStrategy; items: StreamItem[]; timing?: TurnTiming; startIndex: number; }) { const getContent = useCallback( () => collectAssistantTurnContentForStreamRenderStrategy({ strategy, items, startIndex, }), [strategy, items, startIndex], ); return ( ); } function TurnFooterRow({ children }: { children: ReactNode }) { const rowStyle = useMemo(() => [stylesheet.streamItemWrapper, stylesheet.turnFooterRow], []); return {children}; } const stylesheet = StyleSheet.create((theme) => ({ streamItemWrapper: { width: "100%", maxWidth: MAX_CONTENT_WIDTH, alignSelf: "center", paddingHorizontal: theme.spacing[2], }, turnFooterRow: { marginTop: theme.spacing[4], }, turnFooterSlot: { flexDirection: "row", alignItems: "center", alignSelf: "flex-start", minHeight: 24, paddingBottom: theme.spacing[6], }, turnFooterContent: { height: 24, flexDirection: "row", alignItems: "center", justifyContent: "flex-start", gap: theme.spacing[3], }, workingElapsed: { color: theme.colors.foregroundMuted, fontSize: STREAM_METADATA_FONT_SIZE, fontVariant: ["tabular-nums"], }, workingLoader: { marginLeft: -2, }, }));