The lane-resize release gets its own hold — the strip stops two-stepping through the stale snapshot
LaneWidthHold: after the release the session's frozen standard and the WRITTEN unit count keep governing the strip until a landed snapshot carries that width back — dividing the already-grown window by the stale unit total in between was the visible two-step. A deliberately separate type from CommittedHold: that hold stands in for an arrangement and any landing retires it; this one stands in for a value and only a landing that carries it will do. Echo reads through LaneLayoutMath.displayUnits so the width-1 key-removal case compares right; the watch rides landedReloads so a value-equal echo still answers; width writes now return whether bytes reached disk so a refused or no-op write dissolves the hold instead of arming it; the 1500ms timeout family covers the rest. Drag-perf card 231e3693. Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
@@ -172,6 +172,17 @@ struct BoardView: View {
|
||||
.onChange(of: store.snapshotGeneration) { _, generation in
|
||||
appModel.dragSession.handOff(root: store.rootKey, generation: generation)
|
||||
}
|
||||
// **The lane-resize release hold's hand-off** (`LaneWidthHold`), the same shape one rung
|
||||
// narrower: that overlay stands in for an *arrangement* and any landing retires it, this one
|
||||
// for a *width* and only a landing that carries it will do — an unrelated reload arriving
|
||||
// first must not hand the strip back to a snapshot that still says the old unit count.
|
||||
//
|
||||
// **`landedReloads`, not `snapshotGeneration`**: the question is "is the width current",
|
||||
// asked on every walk that landed, so a reload whose tree came back value-equal — which
|
||||
// skips the assignment and moves no generation — still gets to answer it.
|
||||
.onChange(of: store.landedReloads) { _, _ in
|
||||
resize.handOff(against: store.snapshot.lanes)
|
||||
}
|
||||
.trashPurgeAlert(store: store, confirmations: confirmations)
|
||||
// The board's own anchor for the Style… popover — the surface a board-targeted session hangs
|
||||
// off, since the board has no item to attach to (`styleEditorPresentation`'s `nil` anchor).
|
||||
@@ -435,8 +446,12 @@ struct BoardView: View {
|
||||
/// cross-board case alone, ⌥ being ignored by a within-board lane drag.
|
||||
@ViewBuilder
|
||||
private func laneSlot(_ lane: Lane, standard: CGFloat) -> some View {
|
||||
let resizing = resize.isResizing(lane.id)
|
||||
let units = resizing ? resize.units : LaneLayoutMath.displayUnits(of: lane)
|
||||
// **The session governs through the release**, not just the drag: after the release its
|
||||
// frozen standard and the unit count it *wrote* keep answering here until the snapshot
|
||||
// carries that width back (`LaneWidthHold`). Reading `lane.width` in that window would draw
|
||||
// the pre-drag layout for a round trip.
|
||||
let resizing = resize.governs(lane.id)
|
||||
let units = resize.displayUnits(of: lane)
|
||||
let slotWidth = LaneLayoutMath.slotWidth(units: units, standard: standard, gap: spacing)
|
||||
ZStack(alignment: .topLeading) {
|
||||
if resizing {
|
||||
@@ -474,7 +489,7 @@ struct BoardView: View {
|
||||
store: store,
|
||||
session: resize,
|
||||
laneID: lane.id,
|
||||
committedUnits: LaneLayoutMath.displayUnits(of: lane),
|
||||
committedUnits: units,
|
||||
standard: standard,
|
||||
gap: spacing,
|
||||
window: window
|
||||
@@ -561,6 +576,12 @@ struct BoardView: View {
|
||||
/// value equals what the formula yields once the session ends — the handoff is seamless (see
|
||||
/// `LaneResizeSession`).
|
||||
///
|
||||
/// **"Once the session ends" is the echo, not the release** (`LaneWidthHold`). The equality that
|
||||
/// makes the handoff seamless is between the frozen standard and the formula run over the *new*
|
||||
/// unit total, and the write takes a watcher round trip to put that total in the snapshot;
|
||||
/// dividing the already-grown window by the stale total in between is exactly the two-step the
|
||||
/// hold exists to remove.
|
||||
///
|
||||
/// Otherwise it is the ordinary division, over three contributions:
|
||||
///
|
||||
/// - the **live lanes**' units. A lane in flight is still a lane on the board, so a within-board
|
||||
|
||||
Reference in New Issue
Block a user