refactor(player): the watched toggle is stamped at each answer, with no hold while a write is out
The hold changed nothing a user could see (each answer stamps the toggle right after its own echo), and it would have outranked a mark made elsewhere after the click while the write was still out.
This commit is contained in:
@@ -163,12 +163,14 @@ const META_OWN_LINE = "w-full [&>span:first-child>[data-meta-sep]]:hidden";
|
||||
// the line wraps and the meta, or the actions after it, move down instead of squeezing.
|
||||
const META_MIN = "min-w-48 flex-1";
|
||||
|
||||
// The watched toggle's own word on an item: what it last asked for, how many of its writes are still
|
||||
// on the way, and when the last of them was answered (Infinity until then).
|
||||
type OwnMark = { status: VideoStatus; seq: number; pending: number; at: number };
|
||||
// The watched toggle's own word on an item: what it last asked for (`seq`, its write), and when — its
|
||||
// click, then the server's last answer to any of its writes.
|
||||
type OwnMark = { status: VideoStatus; seq: number; at: number };
|
||||
|
||||
// One of the toggle's writes was answered: stamped once none is left on the way; the latest refused,
|
||||
// the toggle's word is dropped and the item shows what the server holds.
|
||||
// One of the toggle's writes was answered. Its answer has just come back as a session mark too (the
|
||||
// write marks before it resolves), so the toggle's word is stamped after it and outranks it; a later
|
||||
// mark from elsewhere still outranks the toggle. The latest write refused, the toggle's word is
|
||||
// dropped and the item shows what the server holds.
|
||||
function settled(marks: Record<string, OwnMark>, id: string, seq: number, ok: boolean) {
|
||||
const own = marks[id];
|
||||
if (!own) return marks;
|
||||
@@ -177,8 +179,7 @@ function settled(marks: Record<string, OwnMark>, id: string, seq: number, ok: bo
|
||||
delete rest[id];
|
||||
return rest;
|
||||
}
|
||||
const pending = own.pending - 1;
|
||||
return { ...marks, [id]: { ...own, pending, at: pending > 0 ? Infinity : Date.now() } };
|
||||
return { ...marks, [id]: { ...own, at: Date.now() } };
|
||||
}
|
||||
|
||||
export default function PlayerModal({
|
||||
@@ -203,7 +204,7 @@ export default function PlayerModal({
|
||||
onClose: () => void;
|
||||
/** The player's own marks (its watched toggle, the auto-mark at the end), for the item it is on —
|
||||
* named by `video`, which may be none of the host's (a related video played in place). Returns
|
||||
* the write: the toggle holds its own word until the server has answered, and drops a refused one. */
|
||||
* the write: the toggle weighs its own word at the server's answer, and drops a refused one. */
|
||||
onState: (id: string, status: VideoStatus, video?: Video) => Promise<unknown>;
|
||||
/** A write the related list made itself, for a host that refetches once the player closes and its
|
||||
* writes have landed (the feed's player session). */
|
||||
@@ -573,10 +574,10 @@ export default function PlayerModal({
|
||||
// The newest word wins: this toggle's own mark, or one the session confirmed elsewhere since the
|
||||
// player opened (the related row's own menu, a notice's Undo — `useVideoMarks`), else the item as
|
||||
// it was opened. The toggle alone missed those, and its first click re-sent the same status.
|
||||
// Both are weighed when the server answered them: the toggle's own writes come back as session
|
||||
// marks too, stamped at their answer, so a click weighed at its own time lost to the late answer
|
||||
// of the click before it. While any of its writes is on the way the toggle's word holds; a refused
|
||||
// one is dropped, so the toggle does not keep showing what the server turned down.
|
||||
// The toggle's own writes come back as session marks too, stamped at their answer, so a click
|
||||
// weighed only at its own time lost to the late answer of the click before it: each answer stamps
|
||||
// the toggle's word again (`settled`). A refused one is dropped, so the toggle does not keep showing
|
||||
// what the server turned down.
|
||||
const [marks, setMarks] = useState<Record<string, OwnMark>>({});
|
||||
const ownSeq = useRef(0);
|
||||
const [openedAt] = useState(() => Date.now());
|
||||
@@ -593,10 +594,7 @@ export default function PlayerModal({
|
||||
const id = subject.id;
|
||||
const next = on ? "watched" : "new";
|
||||
const seq = ++ownSeq.current;
|
||||
setMarks((m) => ({
|
||||
...m,
|
||||
[id]: { status: next, seq, pending: (m[id]?.pending ?? 0) + 1, at: Infinity },
|
||||
}));
|
||||
setMarks((m) => ({ ...m, [id]: { status: next, seq, at: Date.now() } }));
|
||||
Promise.resolve(onState(id, next, subject)).then(
|
||||
() => setMarks((m) => settled(m, id, seq, true)),
|
||||
() => setMarks((m) => settled(m, id, seq, false)),
|
||||
|
||||
Reference in New Issue
Block a user