diff --git a/src/services/media/gallery.service.ts b/src/services/media/gallery.service.ts new file mode 100644 index 0000000..b2d2147 --- /dev/null +++ b/src/services/media/gallery.service.ts @@ -0,0 +1,50 @@ +import * as MediaLibrary from "expo-media-library"; +import * as ImageManipulator from "expo-image-manipulator"; +import { Dimensions } from "react-native"; + +const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get("screen"); + +export async function requestGalleryPermission(): Promise { + const { status } = await MediaLibrary.requestPermissionsAsync(); + return status === "granted"; +} + +export async function getRecentPhotos( + count: number = 50, + offset: number = 0 +): Promise<{ assets: MediaLibrary.Asset[]; hasMore: boolean }> { + const query = new MediaLibrary.Query() + .eq(MediaLibrary.AssetField.MEDIA_TYPE, MediaLibrary.MediaType.IMAGE) + .orderBy({ + key: MediaLibrary.AssetField.CREATION_TIME, + ascending: false, + }) + .limit(count) + .offset(offset); + + const assets = await query.exe(); + + return { + assets, + hasMore: assets.length === count, + }; +} + +export async function prepareImageForWallpaper( + uri: string +): Promise { + const result = await ImageManipulator.manipulateAsync( + uri, + [ + { + resize: { + width: SCREEN_WIDTH * 2, + height: SCREEN_HEIGHT * 2, + }, + }, + ], + { compress: 0.95, format: ImageManipulator.SaveFormat.JPEG } + ); + + return result.uri; +} diff --git a/src/services/ml/depth.service.ts b/src/services/ml/depth.service.ts new file mode 100644 index 0000000..81e3b86 --- /dev/null +++ b/src/services/ml/depth.service.ts @@ -0,0 +1,46 @@ +import { Platform } from "react-native"; + +// Depth estimation service — V1.5 feature +// Uses MiDaS v2.1 small (TFLite) for on-device depth map generation +// Model size: ~17MB, inference: ~50-80ms on mid-range devices + +export interface DepthMapResult { + uri: string; // Path to grayscale depth map PNG + width: number; + height: number; + inferenceTimeMs: number; +} + +export async function isDepthEstimationAvailable(): Promise { + // Will check for TFLite model availability + // For now, return false — not yet implemented + return false; +} + +export async function generateDepthMap( + imageUri: string +): Promise { + // TODO V1.5: Implement with react-native-fast-tflite or ONNX Runtime + // + // Pipeline: + // 1. Load image, resize to MiDaS input size (256x256 or 384x384) + // 2. Normalize to [0,1] float tensor + // 3. Run MiDaS inference + // 4. Resize output to original image dimensions + // 5. Normalize depth values to [0,255] grayscale + // 6. Save as PNG, return URI + // + // The depth map will be cached in MMKV keyed by image URI hash + // to avoid recomputation. + + throw new Error( + "Depth estimation not yet available. Coming in V1.5 with MiDaS on-device inference." + ); +} + +export async function downloadDepthModel(): Promise { + // TODO: Download MiDaS TFLite model from Cloudflare R2 + // Model is not bundled in the app to keep binary size down + // Download on first use of depth-parallax animation + throw new Error("Model download not yet implemented."); +}