aboutsummaryrefslogtreecommitdiffstats
path: root/src/cardlayout.cpp
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-21 21:17:34 +0200
committerDanilo M. <danix@danix.xyz>2026-08-21 21:17:34 +0200
commitc72d96d6428f99f06c04868a70cb09c4a9180f98 (patch)
treef44b8e53ca192b5c0ecfe5600293cd465cc89c3b /src/cardlayout.cpp
parent84e3205ddcba3263e6c07fa314437318309d4b76 (diff)
downloadqtmaildir-c72d96d6428f99f06c04868a70cb09c4a9180f98.tar.gz
qtmaildir-c72d96d6428f99f06c04868a70cb09c4a9180f98.zip
feat(compose): the send popup and its undo window, item 123
Three rows in every state so nothing reflows and the window never jumps. The bar changes MODE rather than place: determinate while the countdown drains, because a countdown has measurable progress, and indeterminate once the command starts, because a send does not. That is the pairing item 134's widget was extracted to serve. The delay is where cancelling is safe and it is the only place it is. Nothing has reached a server during the countdown, so Undo means genuinely nothing happened; killing send_command once it runs leaves an UNKNOWN send, which is worse than either clean outcome. Undo therefore disables itself the moment the command starts, and stays visible while disabled: a control that vanishes re-lays out the popup mid-operation, and a greyed Undo says why cancelling is no longer possible where an absent one looks like it was never offered. The test for this asserts the NEGATIVE property, that committed() never fires after Undo, including after the original countdown would have elapsed. Asserting only that undone() fired would pass against a design that ran the command and threw the result away, which is the whole failure the delay exists to prevent. Removing the close BUTTON is not the same as closing the code path, and the first draft did only the former while its comments claimed otherwise. Escape still reached QDialog::reject(), and close() during the countdown hid the window while leaving the timer running, so the send committed with nothing on screen and the only cancel control destroyed: measured, committed=1 on a dialog the user had dismissed. A never-shown dialog did the same, since close() returns early without reaching done(). That is CLAUDE.md's done(int) trap in the one place it costs mail rather than state. Dismissal is REFUSED before commit rather than treated as an implicit Undo, at the user's decision: a close that silently means cancel overloads one gesture with two meanings, while a refusal leaves Undo as the only way out, which is what the popup's single control already says. done(int) refuses pre-commit and forces Accepted after, closeEvent covers the never-shown route done() cannot see, and Undo passes through both. Task 12 needs no special entry point, since it closes after the send finishes and that is post-commit by definition. A refusal must not read as a hang, so the label says how to leave. Making the hint silent was a mutation that SURVIVED, because the text was written in two places and neutering one was masked by the other; extracting it to one function exposed a real defect behind the wrong green, in that the next tick overwrote the hint 100ms later and the refusal was effectively silent anyway. It is held for 1500ms now, with a test that it survives a tick and still releases. setStage is public and Task 12 passes values into it, so it refuses to wind back to CountingDown after commit rather than trusting its caller with an invariant this class documents as inviolable; the label read "Sending in 0..." and the bar returned to determinate. Both m_committed guards carry tests: removing them left the suite green, so two deliberate safety additions rested on reasoning alone. Every route out is asserted, per the rule that a test using close() while the user uses Cancel covers one route of three: close() shown, close() never-shown, Escape bare and with Shift and Ctrl, reject() direct, and Undo, which must still work or the popup is a trap. The status label is sized to the longest string it can hold in the current language rather than to its content: Italian 'Rimozione della bozza...' is longer than 'Removing draft...', and a label sized to content resizes the popup between stages. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FXF741wz4SY7j5dqvAxMU5
Diffstat (limited to 'src/cardlayout.cpp')
0 files changed, 0 insertions, 0 deletions