scry/app/_layout.tsx
Chris Kruining 83ab4df537
Migrate from .NET MAUI to Expo + Convex
Complete rewrite of Scry using TypeScript stack:

- Expo/React Native with Expo Router (file-based routing)
- Convex backend (serverless functions + real-time database)
- Adaptive camera system (expo-camera in Expo Go, Vision Camera in production)
- React Native Skia + fast-opencv for image processing
- GDPR-compliant auth setup with Zitadel OIDC (pending configuration)

Key features:
- Card recognition pipeline ported to TypeScript
- Perceptual hashing (192-bit color pHash)
- CLAHE preprocessing for lighting normalization
- Local SQLite cache with Convex sync
- Collection management with offline support

Removes all .NET/MAUI code (src/, test/, tools/).

💘 Generated with Crush

Assisted-by: Claude Opus 4.5 via Crush <crush@charm.land>
2026-02-09 16:16:34 +01:00

72 lines
1.7 KiB
TypeScript

import React, { useEffect } from "react";
import FontAwesome from "@expo/vector-icons/FontAwesome";
import { useFonts } from "expo-font";
import * as SplashScreen from "expo-splash-screen";
import { Stack } from "expo-router";
import { ConvexProvider, ConvexReactClient } from "convex/react";
import { HashCacheProvider } from "@/lib/context";
import { useColorScheme } from "@/components/useColorScheme";
// Initialize Convex client
const convex = new ConvexReactClient(
process.env.EXPO_PUBLIC_CONVEX_URL as string
);
// Keep splash screen visible while loading fonts
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const [loaded, error] = useFonts({
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
...FontAwesome.font,
});
useEffect(() => {
if (error) throw error;
}, [error]);
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null;
}
return (
<ConvexProvider client={convex}>
<HashCacheProvider>
<RootLayoutNav />
</HashCacheProvider>
</ConvexProvider>
);
}
function RootLayoutNav() {
const colorScheme = useColorScheme();
return (
<Stack
screenOptions={{
headerStyle: {
backgroundColor: colorScheme === "dark" ? "#1a1a1a" : "#fff",
},
headerTintColor: colorScheme === "dark" ? "#fff" : "#000",
contentStyle: {
backgroundColor: colorScheme === "dark" ? "#1a1a1a" : "#fff",
},
}}
>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen
name="modal"
options={{
presentation: "modal",
title: "Card Details",
}}
/>
</Stack>
);
}