fix: realtime subfolder discovery, count updates, and deep level scan indicator

This commit is contained in:
2026-10-08 19:09:27 +07:00
parent bfda4b4b9e
commit 779ae14a21
4 changed files with 39 additions and 6 deletions
+36 -5
View File
@@ -620,10 +620,20 @@ function Catalogue() {
const shape = progress.dirs.length ? `${progress.dirs.length}:${progress.dirs[progress.dirs.length - 1].id}` : '';
if (shape !== drew) {
drew = shape;
// The names of a reading kept to one folder are the folders under that
// one and no others: the column keeps what it has, and the rows it
// already drew stay where they are.
if (!progress.from) setDirs(progress.dirs);
if (progress.dirs.length) {
setDirs((prev) => {
const map = new Map(prev.map((d) => [normPath(d.id).toLowerCase(), d]));
let changed = false;
for (const d of progress.dirs) {
const k = normPath(d.id).toLowerCase();
if (!map.has(k)) {
map.set(k, d);
changed = true;
}
}
return changed ? [...map.values()] : prev;
});
}
}
// A window beside the reading is handed the progress of another build, which
// may have no such count: the frames it has stored are then read back on a
@@ -1031,7 +1041,9 @@ function Catalogue() {
const { hits, foldersUnder } = baseTreeInfo;
const counted = (key: string, hit: number | undefined) => {
const normKey = (key || '').replace(/\\/g, '/');
return Math.max(hit ?? 0, read?.[normKey] ?? read?.[key] ?? 0);
const lowerKey = normKey.toLowerCase();
const readVal = read?.[normKey] ?? read?.[lowerKey] ?? read?.[key] ?? 0;
return Math.max(hit ?? 0, readVal);
};
const out: Node[] = [];
for (const folder of folders) {
@@ -1110,6 +1122,25 @@ function Catalogue() {
return nKey === mOwn || mOwn.startsWith(`${nKey}/`);
};
// Auto-expand parent folders of the active scan path so deep subfolders (levels 4, 5, 6, 7+)
// are visible in the tree while being scanned.
useEffect(() => {
if (!liveMark) return;
const parts = normPath(liveMark.own).split('/');
if (parts.length <= 1) return;
const toExpand: string[] = [];
for (let i = 1; i < parts.length; i++) {
toExpand.push(parts.slice(0, i).join('/'));
}
setExpanded((prev) => {
const missing = toExpand.filter((k) => !prev.has(k));
if (!missing.length) return prev;
const next = new Set(prev);
for (const k of missing) next.add(k);
return next;
});
}, [liveMark?.own]);
// A remembered subfolder that no longer holds a frame falls back to the folder
// it sits in, so the screen never opens on a node that is not drawn.
useEffect(() => {
+2
View File
@@ -798,12 +798,14 @@ export async function scanFolder(
const relNorm = rel.replace(/\\/g, '/');
const cut = relNorm.lastIndexOf('/');
counts[normRoot] = (counts[normRoot] ?? 0) + n;
counts[normRoot.toLowerCase()] = counts[normRoot];
let path = '';
for (const part of (cut < 0 ? '' : relNorm.slice(0, cut)).split('/')) {
if (!part) continue;
path = path ? `${path}/${part}` : part;
const key = `${normRoot}/${path}`;
counts[key] = (counts[key] ?? 0) + n;
counts[key.toLowerCase()] = counts[key];
}
};
for (const id of known.keys()) count(id.startsWith(`${normRoot}/`) ? id.slice(normRoot.length + 1) : id);
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
431247d71c50662a2ee41d5d418c2966fc8a8496ea0a7f0909014916e0accd1a recipescam-images.tar.gz
3e9a0f2173ec2dd5df1d1d6b3925ce16ac637e82746a316cc90cf35a82fb2c14 recipescam-images.tar.gz