fix(library): mark the roll's own row while it is read, and count rows from the catalogue up

This commit is contained in:
2026-10-08 08:05:18 +07:00
parent ac0337147f
commit 3242b3aa48
2 changed files with 33 additions and 30 deletions
+14 -15
View File
@@ -1648,12 +1648,12 @@ function Catalogue() {
// would be the same row for the whole of an afternoon while
// the work went on somewhere the reader cannot see — together
// with every folder above it, so a branch folded shut still
// shows the work going on under it. The roll's own row is
// never one of them: it is the head of everything below it,
// and a head that says all of a tree is being read says
// nothing about the folder the reading is actually in. The
// frames that sit in the roll's own folder are the one case
// left bare, and the toolbar's line is what carries them.
// shows the work going on under it. The roll's own row wears
// it too, and for two reasons: the frames that sit in the
// roll's own folder have no row but this one, and a reading
// kept to one folder leaves its branch folded or its folder
// off the column, which would otherwise be a whole reading
// reported by the toolbar's line alone.
const isScanFolderMatch = !!(live && folder && normPath(live.folder) === normPath(folder.name));
const scanAt = live?.progress.at ? normPath(live.progress.at) : '';
// The row's own path under its own roll, spelled the way the
@@ -1668,21 +1668,20 @@ function Catalogue() {
: n.key.slice(normFolder.length + 1);
const scanning =
isScanFolderMatch &&
n.depth > 0 &&
nodeRel !== '' &&
(scanAt === nodeRel || scanAt.startsWith(`${nodeRel}/`));
(n.depth === 0 || (nodeRel !== '' && (scanAt === nodeRel || scanAt.startsWith(`${nodeRel}/`))));
// What is waiting its turn is waiting on the row it was asked
// of, and on every row above it: a request under a folded
// branch still says the roll has work queued. The roll's own
// row says nothing, for the reason it says nothing of the
// reading — and a request belongs to the roll it was asked
// of, so another roll's queue is not this row's news.
// row carries it for the same reason it carries the reading —
// and a request belongs to the roll it was asked of, so
// another roll's queue is not this row's news.
const waiting =
!scanning &&
n.depth > 0 &&
nodeRel !== '' &&
(n.depth === 0 || nodeRel !== '') &&
scanQueue().some(
(j) => j.folder === folder?.name && (j.rel === `${nodeRel}/` || j.rel.startsWith(`${nodeRel}/`))
(j) =>
j.folder === folder?.name &&
(n.depth === 0 || j.rel === `${nodeRel}/` || j.rel.startsWith(`${nodeRel}/`))
);
const under = parents.has(n.key);
return (
+19 -15
View File
@@ -786,28 +786,28 @@ export async function scanFolder(
progress.written ??= 0;
progress.at ??= '';
const found = new Set(progress.dirs.map((d) => d.id));
const counts: Record<string, number> = progress.counts;
// Count the frame the moment the scan gets to it, before it knows whether the
// frame is new: the rows say how far the reading has come, not what it kept.
const count = (rel: string) => {
const normRoot = normPath(folder.name);
// The rows are counted from what the catalogue already holds, and the reading
// only adds to them. A number that started at nothing would sit under the
// catalogue's own for as long as the reading took to pass it, and the screen
// shows the larger of the two — so an update, where the reading is mostly
// frames the catalogue has, is a number that stands still and then jumps. What
// the reading adds is the frames it found that the catalogue does not hold yet:
// the number climbs for news alone, and ends on the true total.
const counts: Record<string, number> = {};
const count = (rel: string, n = 1) => {
const relNorm = rel.replace(/\\/g, '/');
const cut = relNorm.lastIndexOf('/');
const normRoot = normPath(folder.name);
// A reading kept to one folder says nothing about the roll it sits in: the
// roll's own row counts every frame of the roll, and a number that counted
// one branch of it would count the roll down to that branch. Its own frames
// are outside the reading anyway — a bounded walk starts at `from`, so every
// frame it reaches is under it, and the roll's row keeps the catalogue's
// number until the reading is through and the catalogue is read back.
if (!bounded) counts[normRoot] = (counts[normRoot] ?? 0) + 1;
counts[normRoot] = (counts[normRoot] ?? 0) + n;
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) + 1;
counts[key] = (counts[key] ?? 0) + n;
}
};
for (const id of known.keys()) count(id.startsWith(`${normRoot}/`) ? id.slice(normRoot.length + 1) : id);
// The frames the catalogue already holds of the folder being read, which is
// what the reading is measured against: a roll of a hundred thousand that has
// been read once before is a reading of a hundred thousand frames even while
@@ -984,7 +984,12 @@ export async function scanFolder(
addedAt: seen?.addedAt ?? Date.now(),
};
batch.push(row);
if (!seen) added.push(row);
if (!seen) {
added.push(row);
// A frame the catalogue did not hold is news the rows have to show: it is
// the one thing an update adds to a number the catalogue already set.
count(rel);
}
progress.added++;
inHand = inHand.filter((r) => r !== rel);
if (batch.length >= BATCH) await flush();
@@ -1013,7 +1018,6 @@ export async function scanFolder(
const at = rel.lastIndexOf('/');
progress.at = at < 0 ? '' : rel.slice(0, at);
progress.done++;
count(rel);
const read = readOne(handle, rel);
const lane = read
.catch(() => undefined)