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>
48 lines
1.1 KiB
TypeScript
48 lines
1.1 KiB
TypeScript
/**
|
|
* Camera component using expo-camera (works in Expo Go).
|
|
*/
|
|
|
|
import React, { forwardRef, useImperativeHandle, useRef } from "react";
|
|
import { StyleSheet } from "react-native";
|
|
import { CameraView } from "expo-camera";
|
|
|
|
export interface CameraHandle {
|
|
takePhoto: () => Promise<{ uri: string }>;
|
|
}
|
|
|
|
interface ExpoCameraProps {
|
|
flashEnabled?: boolean;
|
|
}
|
|
|
|
export const ExpoCamera = forwardRef<CameraHandle, ExpoCameraProps>(
|
|
({ flashEnabled = false }, ref) => {
|
|
const cameraRef = useRef<CameraView>(null);
|
|
|
|
useImperativeHandle(ref, () => ({
|
|
takePhoto: async () => {
|
|
if (!cameraRef.current) {
|
|
throw new Error("Camera not ready");
|
|
}
|
|
const photo = await cameraRef.current.takePictureAsync({
|
|
quality: 0.8,
|
|
base64: false,
|
|
});
|
|
if (!photo) {
|
|
throw new Error("Failed to capture photo");
|
|
}
|
|
return { uri: photo.uri };
|
|
},
|
|
}));
|
|
|
|
return (
|
|
<CameraView
|
|
ref={cameraRef}
|
|
style={StyleSheet.absoluteFill}
|
|
facing="back"
|
|
flash={flashEnabled ? "on" : "off"}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
ExpoCamera.displayName = "ExpoCamera";
|