add list view

This commit is contained in:
m
2026-08-28 23:03:35 +02:00
parent 57d8e70d7f
commit 523454fe91
15 changed files with 422 additions and 353 deletions
+1
View File
@@ -25,6 +25,7 @@ function recordToUnifiedItem(record: ReturnType<typeof fileStore.getById>): Unif
parentResourceId: record.parentResourceId ?? undefined,
ownerId: record.ownerId ?? undefined,
thumbnailUrl: record.thumbnailUrl ?? undefined,
thumbnailLocal: record.thumbnailLocal ?? undefined,
isDeviceFile: record.source === 'local' && !record.backendId,
};
}
+41 -12
View File
@@ -1,29 +1,56 @@
import { useMemo, useEffect, useRef } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { useDeviceFiles } from './useDeviceFiles';
import { fileStore } from '../services/fileStore';
import { generateLocalThumbnail } from '../services/thumbnail';
import { UnifiedFileItem } from '../types';
export function useLocalFiles() {
const { files: deviceFiles, isLoading: deviceLoading, hasPermission, requestPermission, rescan, pickAndScanRecursive, folders, refreshFolders, discovered, discoverMediaAlbums } = useDeviceFiles();
const queryClient = useQueryClient();
const lastDeviceCount = useRef(0);
const thumbnailQueue = useRef<Set<string>>(new Set());
useEffect(() => {
if (deviceFiles.length === 0) return;
if (deviceFiles.length === lastDeviceCount.current) return;
lastDeviceCount.current = deviceFiles.length;
fileStore.mergeFromDevice(
deviceFiles.map((df) => ({
id: df.id,
uri: df.uri,
name: df.name,
mimeType: df.mimeType,
size: df.size,
createdAt: df.createdAt,
folderId: df.folderId,
})),
);
}, [deviceFiles]);
const toMerge = deviceFiles.map((df) => ({
id: df.id,
uri: df.uri,
name: df.name,
mimeType: df.mimeType,
size: df.size,
createdAt: df.createdAt,
folderId: df.folderId,
}));
fileStore.mergeFromDevice(toMerge);
const jobs: Promise<void>[] = [];
for (const df of toMerge) {
if (thumbnailQueue.current.has(df.id)) continue;
const mime = (df.mimeType ?? '').toLowerCase();
if (!mime.startsWith('image/')) continue;
if (fileStore.getById(df.id)?.thumbnailLocal) continue;
thumbnailQueue.current.add(df.id);
jobs.push(
generateLocalThumbnail(df.uri, df.mimeType).then((thumb) => {
try {
if (thumb) fileStore.setThumbnailLocal(df.id, thumb);
} catch {}
}).finally(() => {
thumbnailQueue.current.delete(df.id);
}),
);
}
if (jobs.length > 0) {
Promise.all(jobs).finally(() => {
queryClient.invalidateQueries({ queryKey: ['resources'] });
});
}
}, [deviceFiles, queryClient]);
const localFiles = useMemo(() => {
const registryEntries = fileStore.getAllLocal();
@@ -40,6 +67,8 @@ export function useLocalFiles() {
source: entry.source as UnifiedFileItem['source'],
syncStatus: entry.syncStatus as UnifiedFileItem['syncStatus'],
localUri: entry.localUri ?? undefined,
thumbnailUrl: entry.thumbnailUrl ?? undefined,
thumbnailLocal: entry.thumbnailLocal ?? undefined,
tags: entry.tags ?? [],
isFolder: entry.isFolder === 1,
parentResourceId: entry.parentResourceId ?? undefined,
+1
View File
@@ -21,6 +21,7 @@ function recordToUnifiedItem(record: ReturnType<typeof fileStore.getById>): Unif
parentResourceId: record.parentResourceId ?? undefined,
ownerId: record.ownerId ?? undefined,
thumbnailUrl: record.thumbnailUrl ?? undefined,
thumbnailLocal: record.thumbnailLocal ?? undefined,
isDeviceFile: record.source === 'local' && !record.backendId,
};
}