import { useEffect } from 'react';
import { Text, View } from 'react-native';
import Animated, {
Easing,
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
} from 'react-native-reanimated';
import type { Human } from '@/api/types';
import { resolveHumanDisplay } from '@/lib/humans';
import type { ComposingUser } from '@/features/stream-view/stream-presence-context';
interface ComposingIndicatorProps {
users: ComposingUser[];
networkHumans?: Human[];
}
/**
* Slim horizontal pill stack pinned just under the metadata header. Each
* pill is the typing/recording indicator for a single user. Rendered above
* the particle canvas with a translucent background so it reads on any
* media. Mobile equivalent of desktop's vertical writing-mode indicator.
*/
export function ComposingIndicator({
users,
networkHumans,
}: ComposingIndicatorProps) {
if (users.length === 0) return null;
return (
{users.map((u) => {
const { displayName } = resolveHumanDisplay(u.humanId, networkHumans);
const label =
u.mode === 'recording'
? `${displayName} is recording`
: u.mode === 'screen'
? `${displayName} is sharing`
: `${displayName} is typing`;
return (
{label}
);
})}
);
}
function BouncingDots() {
return (
);
}
function Dot({ delay }: { delay: number }) {
const y = useSharedValue(0);
useEffect(() => {
const start = setTimeout(() => {
y.value = withRepeat(
withTiming(-3, {
duration: 360,
easing: Easing.inOut(Easing.quad),
}),
-1,
true,
);
}, delay);
return () => clearTimeout(start);
}, [delay, y]);
const style = useAnimatedStyle(() => ({
transform: [{ translateY: y.value }],
}));
return (
);
}