mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-17 22:00:40 -07:00
New iOS-first companion (Expo SDK 54 + NativeWind v4) with three tabs: Captures (the hero — floating gold mic, live mic-meter waveform, expand-row playback), Generate (profile picker + speak + autoplay + recent), and Voices (searchable profile list). Pairing (V0): backend mints a one-time token, mobile scans/pastes the voicebox:// URL, server returns a long-lived bearer it stores only as a SHA-256 hash. Bearer-or-loopback auth applied to every user-data router so binding 0.0.0.0 doesn't leak existing endpoints. Loopback callers (the desktop app) keep their friction-free access. Desktop Settings → Mobile pane: live host picker (LAN / Tailscale auto- detected via the App-bundle binary path on macOS), QR rendering, 5-minute expiry countdown, copyable URL fallback, paired-device list with revoke. Auto-closes when a new device pairs. just dev now binds the backend to 0.0.0.0 so paired phones can reach it — and just setup-python pins mlx-audio==0.4.1 + mlx-lm so fresh Apple Silicon worktrees get a working STT path on first install.
47 lines
1.3 KiB
TypeScript
47 lines
1.3 KiB
TypeScript
import '../global.css';
|
|
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { Stack } from 'expo-router';
|
|
import { StatusBar } from 'expo-status-bar';
|
|
import { useEffect, useState } from 'react';
|
|
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
import { colors } from '@/lib/colors';
|
|
import { useSession } from '@/lib/session';
|
|
|
|
export default function RootLayout() {
|
|
const hydrate = useSession((s) => s.hydrate);
|
|
const [queryClient] = useState(
|
|
() =>
|
|
new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 5_000,
|
|
retry: 1,
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
|
|
useEffect(() => {
|
|
void hydrate();
|
|
}, [hydrate]);
|
|
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
<GestureHandlerRootView style={{ flex: 1, backgroundColor: colors.background }}>
|
|
<SafeAreaProvider>
|
|
<StatusBar style="light" />
|
|
<Stack
|
|
screenOptions={{
|
|
headerShown: false,
|
|
contentStyle: { backgroundColor: colors.background },
|
|
animation: 'fade',
|
|
}}
|
|
/>
|
|
</SafeAreaProvider>
|
|
</GestureHandlerRootView>
|
|
</QueryClientProvider>
|
|
);
|
|
}
|