evOo-local/apps/mobile/app/_layout.tsx
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

135 lines
5.2 KiB
TypeScript

import { DarkTheme, Stack, ThemeProvider } from "expo-router";
import { StatusBar } from "expo-status-bar";
import { useEffect, useMemo, useState } from "react";
import { View } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { KeyboardProvider } from "react-native-keyboard-controller";
import { AvatarStyleProvider } from "../components/avatar-style";
import { ComputerUpdateProgress } from "../components/computer-update-progress";
import { currentApiBase, loadApiBase, loadSessionToken, selectedSpaceId } from "../lib/api";
import { loadAppearancePreference, mobileTokens } from "../lib/appearance";
import { bootstrapI18n, useI18n } from "../lib/i18n";
import {
configureForegroundNotifications,
resumeLiveNotifications,
} from "../lib/live-notifications";
import { native, useResolvedAppearance } from "../lib/native";
configureForegroundNotifications();
export default function Layout() {
const { t } = useI18n();
const [ready, setReady] = useState(false);
const resolved = useResolvedAppearance();
const navigationTheme = useMemo(() => {
const tokens = mobileTokens();
return {
...DarkTheme,
dark: resolved === "dark",
colors: {
...DarkTheme.colors,
background: tokens.background,
card: tokens.background,
text: tokens.foreground,
border: tokens.border,
primary: tokens.primary,
notification: tokens.foreground,
},
};
}, [resolved]);
useEffect(() => {
void Promise.all([
Promise.all([loadApiBase(), loadAppearancePreference()])
.then(async () =>
resumeLiveNotifications(
currentApiBase(),
await loadSessionToken(),
selectedSpaceId() ?? "",
),
)
.catch(() => undefined),
bootstrapI18n(),
]).finally(() => setReady(true));
}, []);
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<KeyboardProvider>
{ready ? (
<AvatarStyleProvider>
<ThemeProvider value={navigationTheme}>
<StatusBar style={resolved === "light" ? "dark" : "light"} />
<Stack
screenOptions={{
headerStyle: { backgroundColor: navigationTheme.colors.background },
headerTintColor: navigationTheme.colors.text,
headerShadowVisible: false,
headerBackButtonDisplayMode: "minimal",
contentStyle: { backgroundColor: String(native.page) },
}}
>
<Stack.Screen name="index" options={{ headerShown: false, title: "Rakazo" }} />
<Stack.Screen name="sign-in" options={{ headerShown: false }} />
<Stack.Screen
name="integration-setup"
options={{ title: t("Server integrations") }}
/>
<Stack.Screen name="ai-data-sharing" options={{ title: "AI data sharing" }} />
<Stack.Screen name="account" options={{ title: t("Account") }} />
<Stack.Screen
name="change-password"
options={{
title: t("Change password"),
presentation: "formSheet",
sheetAllowedDetents: [0.6, 1],
sheetGrabberVisible: true,
}}
/>
<Stack.Screen name="models" options={{ title: t("Models") }} />
<Stack.Screen name="voice" options={{ title: t("Voice") }} />
<Stack.Screen name="integrations" options={{ title: t("Integrations") }} />
<Stack.Screen
name="new"
options={{
title: t("New bot"),
presentation: "modal",
gestureEnabled: true,
headerBackVisible: false,
}}
/>
<Stack.Screen
name="new-group"
options={{
title: t("New group"),
presentation: "modal",
gestureEnabled: true,
}}
/>
<Stack.Screen
name="new-space"
options={{
title: t("New space"),
presentation: "modal",
gestureEnabled: true,
headerBackVisible: false,
}}
/>
<Stack.Screen name="group-thread" options={{ title: t("Group") }} />
<Stack.Screen name="group-settings" options={{ title: t("Group settings") }} />
<Stack.Screen name="bot-settings" options={{ title: t("Chat settings") }} />
<Stack.Screen name="thread" options={{ title: t("Thread") }} />
<Stack.Screen name="routine" options={{ title: t("Routine") }} />
<Stack.Screen name="computer" options={{ title: t("Computer") }} />
</Stack>
<ComputerUpdateProgress />
</ThemeProvider>
</AvatarStyleProvider>
) : (
<View style={{ flex: 1, backgroundColor: String(native.page) }} />
)}
</KeyboardProvider>
</GestureHandlerRootView>
);
}