```
refactor: centralize global footer and simplify agent screen input handling ```
This commit is contained in:
@@ -7,6 +7,7 @@ import { SessionProvider } from "@/contexts/session-context";
|
|||||||
import { RealtimeProvider } from "@/contexts/realtime-context";
|
import { RealtimeProvider } from "@/contexts/realtime-context";
|
||||||
import { useSettings } from "@/hooks/use-settings";
|
import { useSettings } from "@/hooks/use-settings";
|
||||||
import { View, ActivityIndicator } from "react-native";
|
import { View, ActivityIndicator } from "react-native";
|
||||||
|
import { GlobalFooter } from "@/components/global-footer";
|
||||||
|
|
||||||
function ProvidersWrapper({ children }: { children: React.ReactNode }) {
|
function ProvidersWrapper({ children }: { children: React.ReactNode }) {
|
||||||
const { settings, isLoading } = useSettings();
|
const { settings, isLoading } = useSettings();
|
||||||
@@ -40,23 +41,26 @@ export default function RootLayout() {
|
|||||||
<KeyboardProvider>
|
<KeyboardProvider>
|
||||||
<BottomSheetModalProvider>
|
<BottomSheetModalProvider>
|
||||||
<ProvidersWrapper>
|
<ProvidersWrapper>
|
||||||
<Stack
|
<View style={{ flex: 1 }}>
|
||||||
screenOptions={{
|
<Stack
|
||||||
headerShown: false,
|
screenOptions={{
|
||||||
animation: "slide_from_right",
|
headerShown: false,
|
||||||
animationDuration: 250,
|
animation: "slide_from_right",
|
||||||
gestureEnabled: true,
|
animationDuration: 250,
|
||||||
gestureDirection: "horizontal",
|
gestureEnabled: true,
|
||||||
fullScreenGestureEnabled: true,
|
gestureDirection: "horizontal",
|
||||||
animationMatchesGesture: true,
|
fullScreenGestureEnabled: true,
|
||||||
}}
|
animationMatchesGesture: true,
|
||||||
>
|
}}
|
||||||
<Stack.Screen name="index" />
|
>
|
||||||
<Stack.Screen name="orchestrator" />
|
<Stack.Screen name="index" />
|
||||||
<Stack.Screen name="agent/[id]" />
|
<Stack.Screen name="orchestrator" />
|
||||||
<Stack.Screen name="settings" />
|
<Stack.Screen name="agent/[id]" />
|
||||||
<Stack.Screen name="audio-test" />
|
<Stack.Screen name="settings" />
|
||||||
</Stack>
|
<Stack.Screen name="audio-test" />
|
||||||
|
</Stack>
|
||||||
|
<GlobalFooter />
|
||||||
|
</View>
|
||||||
</ProvidersWrapper>
|
</ProvidersWrapper>
|
||||||
</BottomSheetModalProvider>
|
</BottomSheetModalProvider>
|
||||||
</KeyboardProvider>
|
</KeyboardProvider>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import ReanimatedAnimated, { useAnimatedStyle } from "react-native-reanimated";
|
|||||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||||
import { BackHeader } from "@/components/headers/back-header";
|
import { BackHeader } from "@/components/headers/back-header";
|
||||||
import { AgentStreamView } from "@/components/agent-stream-view";
|
import { AgentStreamView } from "@/components/agent-stream-view";
|
||||||
import { GlobalFooter } from "@/components/global-footer";
|
import { AgentInputArea } from "@/components/agent-input-area";
|
||||||
import { useSession } from "@/contexts/session-context";
|
import { useSession } from "@/contexts/session-context";
|
||||||
|
|
||||||
export default function AgentScreen() {
|
export default function AgentScreen() {
|
||||||
@@ -60,8 +60,10 @@ export default function AgentScreen() {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Footer */}
|
{/* Agent Input - will hide itself when realtime is active */}
|
||||||
<GlobalFooter agentId={id} />
|
<View style={[styles.inputContainer, { paddingBottom: insets.bottom }]}>
|
||||||
|
<AgentInputArea agentId={id!} />
|
||||||
|
</View>
|
||||||
</ReanimatedAnimated.View>
|
</ReanimatedAnimated.View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
@@ -75,6 +77,11 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
content: {
|
content: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
inputContainer: {
|
||||||
|
backgroundColor: theme.colors.background,
|
||||||
|
borderTopWidth: theme.borderWidth[1],
|
||||||
|
borderTopColor: theme.colors.border,
|
||||||
|
},
|
||||||
errorContainer: {
|
errorContainer: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|||||||
import { HomeHeader } from "@/components/headers/home-header";
|
import { HomeHeader } from "@/components/headers/home-header";
|
||||||
import { EmptyState } from "@/components/empty-state";
|
import { EmptyState } from "@/components/empty-state";
|
||||||
import { AgentList } from "@/components/agent-list";
|
import { AgentList } from "@/components/agent-list";
|
||||||
import { GlobalFooter } from "@/components/global-footer";
|
|
||||||
import { CreateAgentModal } from "@/components/create-agent-modal";
|
import { CreateAgentModal } from "@/components/create-agent-modal";
|
||||||
import { useSession } from "@/contexts/session-context";
|
import { useSession } from "@/contexts/session-context";
|
||||||
|
|
||||||
@@ -46,9 +45,6 @@ export default function HomeScreen() {
|
|||||||
) : (
|
) : (
|
||||||
<EmptyState onCreateAgent={handleCreateAgent} />
|
<EmptyState onCreateAgent={handleCreateAgent} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Footer */}
|
|
||||||
<GlobalFooter />
|
|
||||||
</ReanimatedAnimated.View>
|
</ReanimatedAnimated.View>
|
||||||
|
|
||||||
{/* Create Agent Modal */}
|
{/* Create Agent Modal */}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import ReanimatedAnimated, { useAnimatedStyle } from "react-native-reanimated";
|
|||||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||||
import { BackHeader } from "@/components/headers/back-header";
|
import { BackHeader } from "@/components/headers/back-header";
|
||||||
import { OrchestratorMessagesView } from "@/components/orchestrator-messages-view";
|
import { OrchestratorMessagesView } from "@/components/orchestrator-messages-view";
|
||||||
import { GlobalFooter } from "@/components/global-footer";
|
|
||||||
import { useSession } from "@/contexts/session-context";
|
import { useSession } from "@/contexts/session-context";
|
||||||
import type { ScrollView } from "react-native";
|
import type { ScrollView } from "react-native";
|
||||||
import type { Artifact } from "@/components/artifact-drawer";
|
import type { Artifact } from "@/components/artifact-drawer";
|
||||||
@@ -47,9 +46,6 @@ export default function OrchestratorScreen() {
|
|||||||
currentAssistantMessage={currentAssistantMessage}
|
currentAssistantMessage={currentAssistantMessage}
|
||||||
onArtifactClick={handleArtifactClick}
|
onArtifactClick={handleArtifactClick}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Footer */}
|
|
||||||
<GlobalFooter />
|
|
||||||
</ReanimatedAnimated.View>
|
</ReanimatedAnimated.View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ interface AgentInputAreaProps {
|
|||||||
export function AgentInputArea({ agentId }: AgentInputAreaProps) {
|
export function AgentInputArea({ agentId }: AgentInputAreaProps) {
|
||||||
const { theme } = useUnistyles();
|
const { theme } = useUnistyles();
|
||||||
const { agents, ws, sendAgentMessage, setAgentMode } = useSession();
|
const { agents, ws, sendAgentMessage, setAgentMode } = useSession();
|
||||||
const { startRealtime } = useRealtime();
|
const { isRealtimeMode, startRealtime } = useRealtime();
|
||||||
const audioRecorder = useAudioRecorder();
|
const audioRecorder = useAudioRecorder();
|
||||||
|
|
||||||
const [userInput, setUserInput] = useState("");
|
const [userInput, setUserInput] = useState("");
|
||||||
@@ -24,6 +24,11 @@ export function AgentInputArea({ agentId }: AgentInputAreaProps) {
|
|||||||
|
|
||||||
const agent = agents.get(agentId);
|
const agent = agents.get(agentId);
|
||||||
|
|
||||||
|
// Hide when realtime is active - global footer takes over
|
||||||
|
if (isRealtimeMode) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSendMessage() {
|
async function handleSendMessage() {
|
||||||
if (!userInput.trim() || !ws.isConnected) return;
|
if (!userInput.trim() || !ws.isConnected) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
import { View, Pressable } from "react-native";
|
import { View, Pressable } from "react-native";
|
||||||
import { usePathname } from "expo-router";
|
import { usePathname, useLocalSearchParams } from "expo-router";
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||||
import { AudioLines } from "lucide-react-native";
|
import { AudioLines } from "lucide-react-native";
|
||||||
import { useRealtime } from "@/contexts/realtime-context";
|
import { useRealtime } from "@/contexts/realtime-context";
|
||||||
import { useSession } from "@/contexts/session-context";
|
import { useSession } from "@/contexts/session-context";
|
||||||
import { RealtimeControls } from "./realtime-controls";
|
import { RealtimeControls } from "./realtime-controls";
|
||||||
import { AgentInputArea } from "./agent-input-area";
|
|
||||||
|
|
||||||
interface GlobalFooterProps {
|
export function GlobalFooter() {
|
||||||
agentId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function GlobalFooter({ agentId }: GlobalFooterProps) {
|
|
||||||
const { theme } = useUnistyles();
|
const { theme } = useUnistyles();
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
const params = useLocalSearchParams();
|
||||||
const { isRealtimeMode, startRealtime } = useRealtime();
|
const { isRealtimeMode, startRealtime } = useRealtime();
|
||||||
const { ws } = useSession();
|
const { ws } = useSession();
|
||||||
|
|
||||||
@@ -33,13 +29,9 @@ export function GlobalFooter({ agentId }: GlobalFooterProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If on agent screen, show full input area
|
// If on agent screen and realtime is off, hide footer (agent has its own controls)
|
||||||
if (isAgentScreen && agentId) {
|
if (isAgentScreen) {
|
||||||
return (
|
return null;
|
||||||
<View style={[styles.container, { paddingBottom: insets.bottom }]}>
|
|
||||||
<AgentInputArea agentId={agentId} />
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For home and orchestrator screens, show centered realtime button
|
// For home and orchestrator screens, show centered realtime button
|
||||||
|
|||||||
Reference in New Issue
Block a user