Storage card and clear confirmation (Epic B, #966)
Material 3, light scheme, blue seed, as main.dart configures it. Dark follows the same tokens and is not drawn. Phone pane at 360 wide, the narrowest real target; the Windows pane is the same widget in a wider column. Numbers are the owner's actual install on 2026-10-22: 70.9 MB database, 47 migrated keys, 40 with a stale copy, 29,975 messages, about 16.6 MB reclaimable. Bullets under each card are the behaviour to build. Owner-approved 2026-10-23: all variants as drawn, and the label stays Clear Stale History Now rather than "Compact" — his reason is that the name generalises, so the same action can later cover clearing stale history for other reasons, such as the retention limit in #963. Variants 1 to 10 are built; 11 is the rejected label alternative, kept for the record.
Where it lives
1App Settings, bottom of the pane
A new Storage card after Cyr2Lat, last in the list. It is a read-only status plus one action, so it sits below the preference cards rather than among them.
‹App Settings
Cyrillic to Latin
Transliterate incoming Cyrillic text.
Storage
Message database: 70.9 MB
When your history moves to the new format, the old copy is kept for 30 days and then cleared on its own. You can clear it now instead.
Clear Stale History Now
- Last card, so a destructive action is never the first thing under a thumb.
- Size is read on build and after any clear. A failure to read it hides the row, never blocks the button (variant 7).
- Same widget on Windows; only the column width differs.
The card's states, as built today
2Working
The button disables and relabels while the sweep runs. A second tap in the same frame is also refused in code, because setState only schedules a rebuild.
Storage
Message database: 70.9 MB
When your history moves to the new format, the old copy is kept for 30 days and then cleared on its own. You can clear it now instead.
Clearing...
- Two concurrent sweeps would mean two concurrent VACUUMs.
- Re-enables on success and on failure, or the action works exactly once per launch.
3Cleared
Count and bytes returned, and the size row updates to what the sweep actually left behind rather than the number it started with.
Storage
Message database: 54.3 MB
When your history moves to the new format, the old copy is kept for 30 days and then cleared on its own. You can clear it now instead.
Clear Stale History Now
Cleared 40 old copies, 16.6 MB returned.
- Bytes come from SQLite either side of the sweep, not from adding up blob lengths.
- Pressing again is harmless: those keys have no copy left, so it reports nothing to clear.
4Cleared, with something kept back
A key whose rows could not be verified keeps its copy and is reported, not merely logged. This is the case the Epic exists for.
Storage
Message database: 54.3 MB
When your history moves to the new format, the old copy is kept for 30 days and then cleared on its own. You can clear it now instead.
Clear Stale History Now
Cleared 39 old copies, 16.2 MB returned.
Kept 1 that could not be verified. Your messages are intact; nothing was deleted for those.
- Shown even when a refusal is the reason nothing was cleared, which is the most important case to surface, not the least.
- The automatic 30-day sweep stays log-only: nobody is watching it.
- Which keys and which records are named in the durable audit, not on screen.
5Nothing to clear
The ordinary state for anyone who has already swept, or who has no migrated history yet.
Storage
Message database: 54.3 MB
When your history moves to the new format, the old copy is kept for 30 days and then cleared on its own. You can clear it now instead.
Clear Stale History Now
Nothing to clear.
- Says so plainly rather than showing a zero-byte success.
6Failed
It must not read as "something was half-deleted", and it must not claim nothing happened either, because the sweep deletes per key and a throw can follow real deletes.
Storage
Message database: 70.9 MB
When your history moves to the new format, the old copy is kept for 30 days and then cleared on its own. You can clear it now instead.
Clear Stale History Now
Could not finish, and some old copies may already have been cleared. Nothing was deleted that was not verified first, so your messages are intact.
- No exception text on screen; the reason goes to the log and the audit.
7Size unreadable
A size we cannot read is not a reason to block clearing, so the row is left out and the action stays live.
Storage
When your history moves to the new format, the old copy is kept for 30 days and then cleared on its own. You can clear it now instead.
Clear Stale History Now
- Logged as a warning, never surfaced as an error.
Proposed: confirm before deleting
None of this exists. It needs a preview pass in the sweep: verify every eligible key and total it, without deleting, so the dialog can state real numbers rather than a guess. The verification then runs twice, once to preview and once under the key lock to delete, which is the cost of saying what will go before it goes.
8Confirm, the normal case
States what will be cleared, what is not affected, and that it cannot be undone. The action button carries the count so the last thing read is the scope.
Clear stale history?
This removes 40 old copies of history that has already moved to the new format, freeing about 16.6 MB.
Your messages are not affected. All 29,975 stay.
This cannot be undone.
CancelClear 40 copies
- Counts come from a real preview pass, not an estimate.
- Cancel is the plain text button and sits left, so the destructive one is never the default target.
- Dismissing by tapping outside or back cancels.
9Confirm, with a forecast refusal
If the preview already knows a key cannot be verified, say so before the press rather than reporting it afterwards.
Clear stale history?
This removes 39 old copies of history that has already moved to the new format, freeing about 16.2 MB.
Your messages are not affected. All 29,975 stay.
1 copy will be kept back because its messages could not be verified. This cannot be undone.
CancelClear 39 copies
- The count in the button excludes what will be kept, so it matches what actually goes.
- A refusal discovered only at delete time still reports after the fact, as variant 4.
10Nothing eligible, no dialog
With nothing to clear there is nothing to confirm, so the press reports straight away rather than opening a dialog to say "zero".
Storage
Message database: 54.3 MB
When your history moves to the new format, the old copy is kept for 30 days and then cleared on its own. You can clear it now instead.
Clear Stale History Now
Nothing to clear.
- The preview runs on the press. Empty result means no dialog at all.
- So the preview must be cheap enough to run on a tap: it reads and verifies, it does not write.
11Label: the open question
The owner said "Compact"; the button says "Clear Stale History Now". Drawn here with his word in the title and the plain description in the body.
Storage
Message database: 70.9 MB
Compacting removes the old copy of history that has already moved to the new format, and returns the space. It happens on its own 30 days after the move.
Compact now
- "Compact" is what VACUUM does and reads less alarming; "Clear Stale History" says what is removed.
- Owner's call. Either way the dialog in variant 8 states the scope.