Files
paseo/packages/app/src/components/realtime-controls.tsx
T
Mohamed BoudraandClaude 98c24f22a0 refactor: simplify footer architecture by removing global footer pattern
Replace portal/registry pattern with direct rendering where each screen
owns its footer. This eliminates FooterControlsContext indirection and
makes the code follow standard React composition patterns.

- Remove GlobalFooter and FooterControlsProvider from _layout.tsx
- Add HomeFooter component rendered directly in home screen
- Render AgentInputArea directly in agent screen (not via registration)
- Add keyboard animation and safe area handling to AgentInputArea
- Move FOOTER_HEIGHT constant to shared constants/layout.ts
- Delete footer-controls-context.tsx and global-footer.tsx

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 22:25:30 +07:00

111 lines
2.7 KiB
TypeScript

import { View, Text, Pressable } from "react-native";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { MicOff, Square } from "lucide-react-native";
import { VolumeMeter } from "./volume-meter";
import { useRealtime } from "@/contexts/realtime-context";
import { FOOTER_HEIGHT } from "@/constants/layout";
const CONTROL_BUTTON_SIZE = 48;
const VERTICAL_PADDING = (FOOTER_HEIGHT - CONTROL_BUTTON_SIZE) / 2;
export function RealtimeControls() {
const { theme } = useUnistyles();
const {
volume,
isMuted,
isDetecting,
isSpeaking,
segmentDuration,
stopRealtime,
toggleMute,
} = useRealtime();
function handleStop() {
stopRealtime();
}
return (
<View style={styles.container}>
<View style={styles.volumeContainer}>
<VolumeMeter
volume={volume}
isMuted={isMuted}
isDetecting={isDetecting}
isSpeaking={isSpeaking}
orientation="horizontal"
/>
</View>
<View style={styles.buttons}>
{/* Mute button */}
<Pressable
onPress={toggleMute}
style={[
styles.muteButton,
isMuted && styles.muteButtonActive,
]}
>
<MicOff
size={20}
color={
isMuted
? theme.colors.background
: theme.colors.foreground
}
/>
</Pressable>
{/* Stop button */}
<Pressable
onPress={handleStop}
style={styles.stopButton}
>
<Square size={18} color="white" fill="white" />
</Pressable>
</View>
</View>
);
}
const styles = StyleSheet.create((theme) => ({
container: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
paddingHorizontal: theme.spacing[4],
paddingVertical: VERTICAL_PADDING,
height: FOOTER_HEIGHT,
},
volumeContainer: {
flex: 1,
justifyContent: "center",
alignItems: "flex-start",
},
buttons: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: theme.spacing[3],
},
muteButton: {
width: 48,
height: 48,
borderRadius: theme.borderRadius.full,
alignItems: "center",
justifyContent: "center",
backgroundColor: theme.colors.muted,
borderWidth: theme.borderWidth[2],
borderColor: theme.colors.border,
},
muteButtonActive: {
backgroundColor: theme.colors.palette.red[500],
borderColor: theme.colors.palette.red[600],
},
stopButton: {
width: 48,
height: 48,
borderRadius: theme.borderRadius.full,
alignItems: "center",
justifyContent: "center",
backgroundColor: theme.colors.palette.red[600],
},
}));