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>
This commit is contained in:
parent
56499d5af9
commit
83ab4df537
138 changed files with 19136 additions and 7681 deletions
102
lib/hooks/useSync.ts
Normal file
102
lib/hooks/useSync.ts
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/**
|
||||
* Hook for managing offline sync with local SQLite cache.
|
||||
*/
|
||||
|
||||
import { useEffect, useState, useCallback, useRef } from "react";
|
||||
import { useConvex } from "convex/react";
|
||||
import { createSyncService, type SyncService, type SyncStatus } from "../db/syncService";
|
||||
import { useHashCache } from "../context";
|
||||
|
||||
/**
|
||||
* Hook to manage sync service lifecycle and status.
|
||||
* Initializes local database, syncs with Convex, and provides hashes for recognition.
|
||||
*/
|
||||
export function useSync() {
|
||||
const convex = useConvex();
|
||||
const syncServiceRef = useRef<SyncService | null>(null);
|
||||
const [status, setStatus] = useState<SyncStatus>({
|
||||
isInitialized: false,
|
||||
isSyncing: false,
|
||||
lastSync: 0,
|
||||
localCardCount: 0,
|
||||
});
|
||||
|
||||
const { setCardHashes } = useHashCache();
|
||||
|
||||
// Initialize sync service
|
||||
useEffect(() => {
|
||||
if (!convex || syncServiceRef.current) return;
|
||||
|
||||
const service = createSyncService(convex);
|
||||
syncServiceRef.current = service;
|
||||
|
||||
// Subscribe to status changes
|
||||
const unsubscribe = service.onStatusChange(setStatus);
|
||||
|
||||
// Initialize and load cached hashes
|
||||
const init = async () => {
|
||||
await service.initialize();
|
||||
|
||||
// Load cached hashes into app store
|
||||
const hashes = await service.getHashes();
|
||||
if (hashes.length > 0) {
|
||||
setCardHashes(hashes);
|
||||
console.log(`[useSync] Loaded ${hashes.length} cached hashes`);
|
||||
}
|
||||
|
||||
// Start background sync
|
||||
service.sync().then(async () => {
|
||||
// Reload hashes after sync
|
||||
const updatedHashes = await service.getHashes();
|
||||
setCardHashes(updatedHashes);
|
||||
});
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, [convex, setCardHashes]);
|
||||
|
||||
// Manual sync trigger
|
||||
const sync = useCallback(async () => {
|
||||
if (!syncServiceRef.current) return;
|
||||
|
||||
await syncServiceRef.current.sync();
|
||||
|
||||
// Reload hashes after sync
|
||||
const hashes = await syncServiceRef.current.getHashes();
|
||||
setCardHashes(hashes);
|
||||
}, [setCardHashes]);
|
||||
|
||||
// Clear local cache
|
||||
const clearCache = useCallback(async () => {
|
||||
if (!syncServiceRef.current) return;
|
||||
|
||||
await syncServiceRef.current.clearLocalCache();
|
||||
setCardHashes([]);
|
||||
}, [setCardHashes]);
|
||||
|
||||
// Get current hashes from cache
|
||||
const getHashes = useCallback(async () => {
|
||||
if (!syncServiceRef.current) return [];
|
||||
return syncServiceRef.current.getHashes();
|
||||
}, []);
|
||||
|
||||
return {
|
||||
...status,
|
||||
sync,
|
||||
clearCache,
|
||||
getHashes,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Context-free sync initialization for use in _layout.tsx
|
||||
* Returns a component that initializes sync when mounted.
|
||||
*/
|
||||
export function SyncInitializer() {
|
||||
useSync();
|
||||
return null;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue