Skip to content

Commit 400dbfd

Browse files
committed
implemented deleting multiple messages using the visual mode
1 parent 57801b5 commit 400dbfd

13 files changed

Lines changed: 915 additions & 225 deletions

File tree

‎PLAN.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Current Stage
44

5-
Implementation is past the local-shell phase and currently sits at a DB-first, live WhatsApp client with remote history/media support, outbound text, single-attachment media send, recent-sticker send, external-editor draft composition, normal-mode text clipboard paste into the composer, protocol-backed read receipts, reactions with a quick picker, own-message text editing, own-message delete-for-everybody, replies, quote-jump, a right-edge reply gesture in the message pane, typing presence, hybrid fuzzy group-member mention autocomplete, accent-aware search, visible-first chat-avatar sync/rendering with full profile images, first-class sticker receive/render/download behavior, app-state-backed muted/pinned chat settings, stable pending/paused/resumed pixel overlays for media/avatar/sticker rendering, direct-chat PN/LID canonicalization plus split-thread repair, desktop notifications with cached chat-avatar icons where supported plus a local global mute key/right-side configurable status-bar indicator, immediate DB catch-up sync overlay blocking with non-blocking startup app-state sync, async store/protocol-backed TUI actions for sends, lazy loads, filters, read receipts, reactions, retries, stickers, drafts, and mentions, denormalized chat-list previews, media retry UX, first-use-state logout reset, temp-backed non-exported chat media caches, clipboard attachment paste with Windows file-drop support, a persistent in-chat new-message divider, hardened Windows inline preview defaults, composer tail-follow scrolling, detached Shift+Enter external media launch, and the planned media/export CLI helpers. The next major gaps are live validation/polish of the notification and media-send paths on real chats, especially desktop delivery on fresh Linux and Windows installs, notification backend default resolution on a fresh config, audio/document fallback behavior, the new avatar/sticker behavior under daily use, plus attachment draft persistence and follow-on resend polish for failed rows.
5+
Implementation is past the local-shell phase and currently sits at a DB-first, live WhatsApp client with remote history/media support, outbound text, single-attachment media send, recent-sticker send, external-editor draft composition, normal-mode text clipboard paste into the composer, protocol-backed read receipts, reactions with a quick picker, own-message text editing, own-message delete-for-everybody with in-chat tombstones, replies, quote-jump, a right-edge reply gesture in the message pane, typing presence, hybrid fuzzy group-member mention autocomplete, accent-aware search, visible-first chat-avatar sync/rendering with full profile images, first-class sticker receive/render/download behavior, app-state-backed muted/pinned chat settings, stable pending/paused/resumed pixel overlays for media/avatar/sticker rendering, direct-chat PN/LID canonicalization plus split-thread repair, desktop notifications with cached chat-avatar icons where supported plus a local global mute key/right-side configurable status-bar indicator, immediate DB catch-up sync overlay blocking with non-blocking startup app-state sync, async store/protocol-backed TUI actions for sends, lazy loads, filters, read receipts, reactions, retries, stickers, drafts, and mentions, denormalized chat-list previews, media retry UX, first-use-state logout reset, temp-backed non-exported chat media caches, clipboard attachment paste with Windows file-drop support, a persistent in-chat new-message divider, hardened Windows inline preview defaults, composer tail-follow scrolling, detached Shift+Enter external media launch, and the planned media/export CLI helpers. The next major gaps are live validation/polish of the notification and media-send paths on real chats, especially desktop delivery on fresh Linux and Windows installs, notification backend default resolution on a fresh config, audio/document fallback behavior, the new avatar/sticker behavior under daily use, plus attachment draft persistence and follow-on resend polish for failed rows.
66

77
### Implemented now
88

@@ -22,7 +22,7 @@ Implementation is past the local-shell phase and currently sits at a DB-first, l
2222
- Recent sticker send support: WhatsApp recent-sticker history/app-state sync is persisted in SQLite, startup app-state metadata/mute/pin handling runs off the live event critical path, renderable WebP stickers are cached under the transient app directory as background best-effort work with URL-first/direct-path fallback and live-event file downloads are handled by a bounded worker pool after metadata ingestion, `key_normal_pick_sticker` defaults to `leader t`, the picker command is configurable with an `nsxiv -t -o -p {files}` Linux default, Enter selects the highlighted nsxiv thumbnail immediately, and selected stickers are sent through a dedicated WhatsApp sticker message path. Lottie/TGS stickers are metadata-only for now.
2323
- Real outbound send from the inline composer for plain text plus one local attachment per message, with precomputed WhatsApp message IDs, local `sending`/`sent`/`failed` status updates, draft preservation on failure, captions for image/video/document sends, audio-caption rejection before queueing, ffprobe-backed generic audio send, and document fallback when audio metadata is unavailable.
2424
- CLI helpers for persisted data: `vimwhat media open <message-id>` reuses the normal opener flow and auto-downloads remote media when possible, while `vimwhat export chat <jid>` writes a local-only Markdown transcript into the configured downloads directory.
25-
- Protocol-backed message interactions: auto/manual mark-read, monotonic outgoing receipt status updates with seen/read receipts rendered as boxed ticks, reaction send/clear through `:react` and a configurable quick picker plus reaction rendering, own outgoing text edit via WhatsApp edit with local rewrite after ACK, inbound edit ingestion, own outgoing message delete-for-everybody via WhatsApp revoke with local deletion after ACK, inbound revoke ingestion, text replies with quoted metadata, quote-jump into loaded history, a right-edge `l` reply gesture from the message pane when no further pane exists to the right, direct-chat typing/online/last-seen presence in a two-line active chat header, and best-effort composing/paused presence send while typing.
25+
- Protocol-backed message interactions: auto/manual mark-read, monotonic outgoing receipt status updates with seen/read receipts rendered as boxed ticks, reaction send/clear through `:react` and a configurable quick picker plus reaction rendering, own outgoing text edit via WhatsApp edit with local rewrite after ACK, inbound edit ingestion, own outgoing message delete-for-everybody via WhatsApp revoke with a WhatsApp-style in-chat tombstone after ACK, inbound revoke ingestion with tombstone rendering, text replies with quoted metadata, quote-jump into loaded history, a right-edge `l` reply gesture from the message pane when no further pane exists to the right, direct-chat typing/online/last-seen presence in a two-line active chat header, and best-effort composing/paused presence send while typing.
2626
- Group-member mention autocomplete in the insert composer: typing `@` in group chats opens participant suggestions, typed text filters them with hybrid fuzzy, accent-aware matching, `Enter` or configurable `key_insert_mention_select_alt` completes the highlighted contact, local contact names are preferred across PN/LID aliases, and outgoing text/media captions send WhatsApp-compatible mention wire text plus `mentioned_jid` context while preserving readable local display text.
2727
- Cross-platform desktop notifications for new incoming messages in inactive, unmuted chats, with native Linux/macOS/Windows backends, WhatsApp mute-state sync from app-state patches, a persistent local global mute toggle plus right-side configurable status-bar indicator, cached chat-avatar icons on Linux when available, resilient Linux helper fallback, safe command override support, notification preview formatting for media-only messages, backend diagnostics in `doctor`, and active-chat suppression that only applies while the app window is known to be focused.
2828
- Retry/resend UX for failed outgoing media rows in the TUI via `R` and `:retry-message`, keeping the original failed row in chat and queueing a brand-new send attempt when the local attachment file still exists.
@@ -113,7 +113,7 @@ The app should feel closer to `vim` plus `yazi` than to WhatsApp Web: fast keybo
113113
user can stay here for all messages if desired.
114114
- `visual` mode:
115115
message-wise selection only in v1, not character-wise text editing inside a message;
116-
selection supports yank, copy to register, forwarding, export, and batch download of attachments.
116+
selection supports yank, copy to register, forwarding, delete-for-everyone, export, and batch download of attachments.
117117
- `forward` mode:
118118
recipient picker for focused normal-mode messages or selected visual-mode messages, with configurable Vim-style movement, slash search, toggle, send, and cancel bindings.
119119
- `command` mode:
@@ -159,6 +159,7 @@ The app should feel closer to `vim` plus `yazi` than to WhatsApp Web: fast keybo
159159
receive/send common attachments,
160160
quoted replies,
161161
own outgoing text edits and own-message revoke,
162+
selected outgoing message revoke from visual mode,
162163
forwarding selected messages from visual mode,
163164
reactions,
164165
read receipts handling,
@@ -277,6 +278,7 @@ The composer, forwarding, and presence polish milestone now has an implemented f
277278
- `Shift+Enter` is the generated default alternate newline binding for insert mode, with `ctrl+j` retained as the portable fallback and all bindings kept editable through config.
278279
- The insert composer soft-wraps long input by display width inside the footer, preserves explicit newlines in the draft/body, and keeps the cursor visible without relying on terminal edge wrapping.
279280
- Normal mode can forward the focused message with `key_normal_forward = "f"`, while visual mode can forward the selected message range through the same recipient picker with `key_visual_forward = "f"`; the picker uses Vim-style `j`/`k` movement and `/` contact search before typing filter text.
281+
- Normal mode can delete the focused outgoing message for everybody with `key_normal_delete_for_everybody = "leader d e"`, while visual mode can apply the same WhatsApp revoke path to the selected outgoing range with `key_visual_delete_for_everybody = "leader d e"` after uppercase-`Y` confirmation; completed deletes stay visible as "This message was deleted" tombstones.
280282
- Forwarding preserves WhatsApp forwarded metadata for received source messages, while self-authored outgoing source messages are resent without the forwarded tag.
281283
- WhatsApp message protobuf payloads are persisted for ingested messages so forwarding can resend the original supported message shape instead of reconstructing from rendered text/media metadata.
282284
- Forwarded messages are persisted locally as outgoing `sending` rows before protocol send, then transition to sent/failed through the same live-update path as other sends.

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ key_insert_remove_attachment = "ctrl+x"
192192

193193
key_visual_yank = "y"
194194
key_visual_forward = "f"
195+
key_visual_delete_for_everybody = "leader d e"
195196

196197
key_forward_send = "enter"
197198
key_forward_toggle = "space"

‎config.example.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ key_visual_move_down = "j"
101101
key_visual_move_up = "k"
102102
key_visual_yank = "y"
103103
key_visual_forward = "f"
104+
key_visual_delete_for_everybody = "leader d e"
104105

105106
# Forward picker
106107
key_forward_cancel = "esc"

‎internal/app/whatsapp_cli_test.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,8 +1304,8 @@ func TestHandleDeleteEveryoneRequestSendsRemoteRevokeBeforeLocalDelete(t *testin
13041304
if err != nil {
13051305
t.Fatalf("ListMessages() error = %v", err)
13061306
}
1307-
if len(messages) != 0 {
1308-
t.Fatalf("messages after delete = %+v, want none", messages)
1307+
if len(messages) != 1 || messages[0].ID != message.ID || messages[0].Body != "" || messages[0].DeletedAt.IsZero() || messages[0].DeletedReason != "everyone" {
1308+
t.Fatalf("messages after delete = %+v, want delete-for-everyone tombstone", messages)
13091309
}
13101310
}
13111311

0 commit comments

Comments
 (0)