add files listing

This commit is contained in:
m
2026-07-27 20:50:23 +02:00
parent 0cc261105a
commit 5c85ffa5fe
25 changed files with 1312 additions and 32 deletions
+98
View File
@@ -0,0 +1,98 @@
import { createMMKV } from 'react-native-mmkv';
import { FileDetectedEvent } from '../modules/expo-download-detect';
const storage = createMMKV({ id: 'vaultdrop-download-registry' });
const FILES_KEY = 'detected_files';
export type DownloadRegistryEntry = {
id: string;
uri: string;
name: string;
mimeType: string;
size: number;
createdAt: number;
source: string;
detectedAt: number;
};
function getAllRaw(): DownloadRegistryEntry[] {
const raw = storage.getString(FILES_KEY);
if (!raw) return [];
return JSON.parse(raw) as DownloadRegistryEntry[];
}
function saveAll(entries: DownloadRegistryEntry[]) {
storage.set(FILES_KEY, JSON.stringify(entries));
}
export const downloadRegistry = {
getAll(): DownloadRegistryEntry[] {
return getAllRaw();
},
getById(id: string): DownloadRegistryEntry | undefined {
return getAllRaw().find((e) => e.id === id);
},
add(event: FileDetectedEvent): DownloadRegistryEntry | null {
const entries = getAllRaw();
if (entries.some((e) => e.id === event.id)) return null;
const entry: DownloadRegistryEntry = {
id: event.id,
uri: event.uri,
name: event.name,
mimeType: event.mimeType,
size: event.size,
createdAt: event.createdAt,
source: event.source,
detectedAt: Date.now(),
};
entries.push(entry);
saveAll(entries);
return entry;
},
addBatch(events: FileDetectedEvent[]): DownloadRegistryEntry[] {
const entries = getAllRaw();
const existingIds = new Set(entries.map((e) => e.id));
const newEntries: DownloadRegistryEntry[] = [];
for (const event of events) {
if (existingIds.has(event.id)) continue;
const entry: DownloadRegistryEntry = {
id: event.id,
uri: event.uri,
name: event.name,
mimeType: event.mimeType,
size: event.size,
createdAt: event.createdAt,
source: event.source,
detectedAt: Date.now(),
};
newEntries.push(entry);
existingIds.add(event.id);
}
if (newEntries.length > 0) {
saveAll([...entries, ...newEntries]);
}
return newEntries;
},
remove(id: string) {
const entries = getAllRaw().filter((e) => e.id !== id);
saveAll(entries);
},
clear() {
storage.remove(FILES_KEY);
},
count(): number {
return getAllRaw().length;
},
};
+55
View File
@@ -0,0 +1,55 @@
import { createMMKV } from 'react-native-mmkv';
import { ONBOARDING_STEPS, CURRENT_ONBOARDING_VERSION, type OnboardingStep } from '../config/onboarding';
import { safDirectory } from './safDirectory';
const storage = createMMKV({ id: 'vaultdrop-onboarding' });
const COMPLETED_VERSION_KEY = 'completed_version';
const SEEN_STEPS_KEY = 'seen_steps';
export const onboardingStorage = {
getCompletedVersion(): number | undefined {
const raw = storage.getNumber(COMPLETED_VERSION_KEY);
return raw != null ? raw : undefined;
},
setCompletedVersion(version: number) {
storage.set(COMPLETED_VERSION_KEY, version);
},
getSeenSteps(): string[] {
const raw = storage.getString(SEEN_STEPS_KEY);
if (!raw) return [];
return JSON.parse(raw) as string[];
},
markStepSeen(stepId: string) {
const seen = this.getSeenSteps();
if (!seen.includes(stepId)) {
seen.push(stepId);
storage.set(SEEN_STEPS_KEY, JSON.stringify(seen));
}
},
getPendingSteps(): OnboardingStep[] {
const lastVersion = this.getCompletedVersion();
const seenIds = this.getSeenSteps();
const folders = safDirectory.getAll();
return ONBOARDING_STEPS.filter((step) => {
if (lastVersion != null && step.version <= lastVersion) return false;
if (seenIds.includes(step.id)) return false;
if (step.condition === 'has_no_folders' && folders.length > 0) return false;
return true;
});
},
needsOnboarding(): boolean {
return this.getPendingSteps().length > 0;
},
reset() {
storage.remove(COMPLETED_VERSION_KEY);
storage.remove(SEEN_STEPS_KEY);
},
};
+63
View File
@@ -0,0 +1,63 @@
import { createMMKV } from 'react-native-mmkv';
export type StoredFolder = {
id: string;
uri: string;
name: string;
visible: boolean;
};
const storage = createMMKV({ id: 'vaultdrop-saf' });
const FOLDERS_KEY = 'saf_folders';
function generateId(): string {
return `folder_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
}
function getAllRaw(): StoredFolder[] {
const raw = storage.getString(FOLDERS_KEY);
if (!raw) return [];
return JSON.parse(raw) as StoredFolder[];
}
function saveAll(folders: StoredFolder[]) {
storage.set(FOLDERS_KEY, JSON.stringify(folders));
}
export const safDirectory = {
getAll(): StoredFolder[] {
return getAllRaw();
},
getVisibleFolders(): StoredFolder[] {
return getAllRaw().filter((f) => f.visible);
},
addFolder(uri: string, name: string): StoredFolder {
const folders = getAllRaw();
if (folders.some((f) => f.uri === uri)) {
return folders.find((f) => f.uri === uri)!;
}
const folder: StoredFolder = { id: generateId(), uri, name, visible: true };
folders.push(folder);
saveAll(folders);
return folder;
},
removeFolder(id: string) {
const folders = getAllRaw().filter((f) => f.id !== id);
saveAll(folders);
},
toggleVisibility(id: string) {
const folders = getAllRaw().map((f) =>
f.id === id ? { ...f, visible: !f.visible } : f
);
saveAll(folders);
},
clear() {
storage.remove(FOLDERS_KEY);
},
};