fix(zaps): collapse same-actor zap spam in notifications and post drawer#557
Open
dmnyc wants to merge 2 commits into
Open
fix(zaps): collapse same-actor zap spam in notifications and post drawer#557dmnyc wants to merge 2 commits into
dmnyc wants to merge 2 commits into
Conversation
Mirrors iOS PR barrydeen/wisp-ios#161 on the Android side. A sender spamming many small zaps against the same note used to push everything else off the Notifications tab — one row per zap receipt. This change folds same-actor + same-note zaps into a single row. - `FlatNotificationItem` gains a `mergedZaps: List<FlatNotificationItem>` field (defaulted to empty so the repo-side ingest path is unchanged) and a `totalZapSats` computed property summing primary + merged. - `NotificationsViewModel.collapseSameActorZapSpam` runs after the existing filter pass: walks newest-first, dedupes `NotificationType.ZAP` items by `(actorPubkey, referencedEventId)`, folds duplicates into the primary's `mergedZaps`. DM_ZAP and PROFILE_ZAP don't participate — they have no `referencedEventId` to dedupe against. - `NotificationTypeIcon`'s bolt label now reads `totalZapSats` so the surfaced amount reflects the combined contribution. - `ZenNotificationRow` shows a `+N more` pill next to the actor name when duplicates were folded. - New `MergedZapsBreakdown` composable renders below the embedded referenced note (matching the iOS NotificationRowView caption flow): shows `N zaps · total sats` then one line per individual zap with amount + comment.
Mirrors iOS PR barrydeen/wisp-ios#161 on the Android side. The in-post engagement drawer (`ReactionDetailsSection`) rendered one `ZapRow` per individual `ZapDetail`, so an actor spamming N small zaps against a single note took up N rows and pushed legitimate zappers off the screen. Groups `[ZapDetail]` by `pubkey` before rendering: each group shows the combined sat total and a `(×N)` count suffix on the label when N > 1. The first non-empty zap message becomes the row label (falls back to display name / shortened npub when no message exists, same as the per-zap default). Distinct zappers still get their own rows; sort order stays "highest combined sats first." Long-press inspect on a collapsed row routes to the first individual receipt in the group.
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Android counterpart to iOS PR barrydeen/wisp-ios#161.
A sender spamming many small zaps against the same note used to push everything else off-screen — both in the Notifications tab (one row per zap receipt) and in the in-post engagement drawer (one row per individual zapper). This change folds same-actor + same-note zaps into a single row in both surfaces.
Notifications tab
FlatNotificationItemgainsmergedZaps: List<FlatNotificationItem>(defaulted empty so the ingest path is unchanged) and atotalZapSatscomputed property summing the primary + every merged duplicate.NotificationsViewModel.collapseSameActorZapSpamruns after the existing filter pass. Walks the newest-first list, dedupesNotificationType.ZAPentries by(actorPubkey, referencedEventId), and folds duplicates into the primary'smergedZaps. DM_ZAP / PROFILE_ZAP don't participate — they have noreferencedEventIdto dedupe against.NotificationTypeIconbolt-icon label usestotalZapSatsso the surfaced amount is the combined contribution from this actor on this note.ZenNotificationRowshows a+N morepill next to the actor name when duplicates were folded.MergedZapsBreakdowncomposable renders below the embedded referenced note (matching the iOS NotificationRowView caption order):N zaps · total satsheader, then one line per individual zap with amount + comment.Post-engagement drawer
ReactionDetailsSectionnow groups[ZapDetail]bypubkeybefore rendering. Each group renders oneZapRowwith the combined sat total and a(×N)count suffix on the label when N > 1. The first non-empty zap message becomes the row label (falls back to display name / shortened npub same as the per-zap default).Test plan
+N morepill; expanding the row shows the embedded note followed by the per-zap breakdown (N zaps · total sats+ one line per zap with amount and comment).referencedEventId) still render as individual rows.(×N)after the label and the combined sat total on the right.