Skip to content

Add a 5-minute Undo window for deleted clips - #88

Closed
alvst wants to merge 1 commit into
momenbasel:mainfrom
alvst:alvie/pr-undo
Closed

alvst wants to merge 1 commit into
momenbasel:mainfrom
alvst:alvie/pr-undo

Conversation

@alvst

@alvst alvst commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Deleting a clip is currently final and one keystroke away. This gives a deleted clip five minutes in which ⌘Z puts it back exactly where it was, with an opt-out for users who don't want deleted content recoverable at all.

What changed

  • ClipDeletionLedger records each deleted clip's exact placement (index, predecessor, successor) in whichever container it came from. The payload is kept separate from a small durable tombstone, so a stale synced snapshot can't resurrect an intentional deletion. Payloads are dropped after five minutes; tombstones stay.
  • ⌘Z restores the most recent still-undoable deletion at its original position; repeated presses walk back through independent deletions in order.
  • An Undo button appears in the bar's top-right while anything is still recoverable, and the bulk-delete confirmation now says so instead of "There is no undo."
  • A "Delete permanently" setting (off by default) skips the ledger entirely, plus a per-deletion Option-key override that bypasses Undo for that one deletion regardless of the setting.
  • Ledgered clips' image files are protected from cleanup while they're still restorable.

Screenshots

Before:
00-baseline screenshots bar.png

After:
07-undo screenshots bar.png
07-undo screenshots settings.png

Notes for review

  • Clear History and deleting a whole Pinboard are deliberately outside the ledger. Both are bulk operations: ledgering them means holding the entire history — every image file included — recoverable in store.json for five minutes, which is exactly the retention users who reach for "Clear History" are trying to avoid, and a payload the ledger's per-deletion design isn't shaped for. Single-clip deletion is the frequent accidental one and is what this covers. Clear History keeps its existing confirmation; deleting a Pinboard keeps its existing behavior. Both are unchanged by this PR, not newly excepted by it — happy to add a confirm to Clear History in a follow-up if you'd rather.
  • The Option-key bypass and the Settings override both apply per deletion; neither retroactively purges an existing ledger entry beyond the normal five-minute expiry.
  • No dependencies; merges in any order.

This feature should be bundled into v2.

Part of #80.

- ClipDeletionLedger records the exact placement (index, predecessor,
  successor) of each deleted clip in whichever container it was removed
  from, keeping the payload separate from the small durable tombstone
  marker so a stale synced snapshot can't resurrect an intentional
  deletion. Payloads are dropped (but tombstones kept) five minutes
  after deletion.
- Command-Z restores the most recent still-undoable deletion at its
  original position; repeated presses walk backward through independent
  deletions in order. An Undo button appears in the bar's top-right
  whenever a deletion is still recoverable, and the bulk-delete
  confirmation now correctly says so instead of "There is no undo."
- Added a "Delete permanently" Settings toggle (off by default) for
  users who don't want deleted content sitting recoverable in store.json
  at all, plus a per-deletion Option-key override that bypasses Undo
  for just that one deletion regardless of the setting.
@momenbasel

Copy link
Copy Markdown
Owner

Closing in favour of 2763443 on main (through #104), which is designed after this PR and keeps your placement bookkeeping (predecessor, successor, original index), the Undo button and the alert copy, with credit in the commit body.

What I did not take is the ledger. It writes the deleted payloads and tombstones into store.json and merges them through the iCloud Drive snapshot and the sync path, so a five-minute undo buffer became persistent on-disk state with its own merge rules in three places that all have to stay right, and deleted content outlived the deletion on disk. The version on main is an in-memory stack: nothing deleted is ever written back, there are no tombstones, the sync code is untouched, and the image files of restorable clips are released when the window closes, on Clear History, when a Pinboard is deleted, or at quit. Bulk deletes come back as one Undo, a clip that reappeared by other means in the meantime is left alone rather than doubled, the "Delete permanently" setting and the Option modifier behave the way you specified, and the Option state comes from the key event itself. Thanks @alvst.

@momenbasel momenbasel closed this Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants