P6.1: lock input for the full in-flight animation window

A swipe that began while a move animation was playing could still commit:
mouse_down latched the drag unconditionally and the animation-active check
sat at mouse_up, so a press made mid-animation committed once the timeline
finished before release — against a board mid-transition.

Gate input at gesture START instead. Add a pure `accepts_input(anim)`
predicate (false while a timeline is active) and check it at mouse_down: a
press begun mid-animation is dropped and never latches a drag, so it cannot
commit when the animation later settles. The now-dead mouse_up gate is
removed. Animation visuals and the logical model are unchanged.

Extend tests/anim_plan.sx to assert accepts_input rejects for the whole
window (idle accept / busy reject / settled accept) and that press-gating
drops the exact failure gesture a release-gate would let through.
This commit is contained in:
swipelab
2026-06-05 01:23:12 +03:00
parent 0b858f7724
commit 5ec7247001
5 changed files with 59 additions and 3 deletions

View File

@@ -400,6 +400,12 @@ impl View for BoardView {
self.compute_layout(frame);
if event.* == {
case .mouse_down: (d) {
// Gate input at gesture START: while a move animation is in
// flight the board ignores new gestures for the WHOLE in-flight
// window, so a press begun mid-animation never latches a drag and
// so can't commit when the animation later ends. The press is
// still consumed; input resumes once the timeline settles.
if !accepts_input(self.anim) { return true; }
self.drag.begin(d.position);
return true;
}
@@ -407,9 +413,6 @@ impl View for BoardView {
if !self.drag.active { return false; }
start := self.drag.start;
self.drag.clear();
// Ignore swipes while a move is still animating so two timelines
// never overlap; the model is already settled by then either way.
if self.anim != null and self.anim.active { return true; }
if intent := swipe_intent(@self.layout, start, d.position) {
mv := plan_and_commit(self.board, intent.a, intent.b);
if self.anim != null { self.anim.begin(mv); }