This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Timmy-time-dashboard/mobile-app/components/typing-indicator.tsx
Manus AI b4b508ff5a feat: add Timmy Chat mobile app (Expo/React Native)
- Single-screen chat interface with Timmy's sovereign AI personality
- Text messaging with real-time AI responses via server chat API
- Voice recording and playback with waveform visualization
- Image sharing (camera + photo library) with full-screen viewer
- File attachments via document picker
- Dark arcane theme matching the Timmy Time dashboard
- Custom app icon with glowing T circuit design
- Timmy system prompt ported from dashboard prompts.py
- Unit tests for chat utilities and message types
2026-02-26 21:55:41 -05:00

90 lines
2.2 KiB
TypeScript

import { useEffect } from "react";
import { View, StyleSheet } from "react-native";
import Animated, {
useSharedValue,
useAnimatedStyle,
withRepeat,
withTiming,
withDelay,
withSequence,
} from "react-native-reanimated";
import { useColors } from "@/hooks/use-colors";
export function TypingIndicator() {
const colors = useColors();
const dot1 = useSharedValue(0.3);
const dot2 = useSharedValue(0.3);
const dot3 = useSharedValue(0.3);
useEffect(() => {
const anim = (sv: { value: number }, delay: number) => {
sv.value = withDelay(
delay,
withRepeat(
withSequence(
withTiming(1, { duration: 400 }),
withTiming(0.3, { duration: 400 }),
),
-1,
),
);
};
anim(dot1, 0);
anim(dot2, 200);
anim(dot3, 400);
}, []);
const style1 = useAnimatedStyle(() => ({ opacity: dot1.value }));
const style2 = useAnimatedStyle(() => ({ opacity: dot2.value }));
const style3 = useAnimatedStyle(() => ({ opacity: dot3.value }));
const dotBase = [styles.dot, { backgroundColor: colors.primary }];
return (
<View style={[styles.row, { alignItems: "flex-end" }]}>
<View style={[styles.avatar, { backgroundColor: colors.primary }]}>
<Animated.Text style={styles.avatarText}>T</Animated.Text>
</View>
<View style={[styles.bubble, { backgroundColor: colors.surface, borderColor: colors.border }]}>
<Animated.View style={[dotBase, style1]} />
<Animated.View style={[dotBase, style2]} />
<Animated.View style={[dotBase, style3]} />
</View>
</View>
);
}
const styles = StyleSheet.create({
row: {
flexDirection: "row",
paddingHorizontal: 12,
marginBottom: 8,
},
avatar: {
width: 30,
height: 30,
borderRadius: 15,
alignItems: "center",
justifyContent: "center",
marginRight: 8,
},
avatarText: {
color: "#fff",
fontWeight: "700",
fontSize: 14,
},
bubble: {
flexDirection: "row",
gap: 5,
paddingHorizontal: 16,
paddingVertical: 14,
borderRadius: 16,
borderWidth: 1,
},
dot: {
width: 8,
height: 8,
borderRadius: 4,
},
});