fix(mobile): read only shown events from filtered Activity rows

With Threads, Mentions or a People/Agents filter active, a row holds only
part of its conversation. Marking it read advanced the thread or channel
marker through its latest event, which also read the replies the filter
hid. Filtered rows now write msg: marks for just the events they show,
as filtered DM rows already did.

Follow-up to #9213 (review comment r4497322772).

Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tom Brow <tomb@squareup.com>
This commit is contained in:
Tom Brow
2026-11-06 12:42:15 -08:00
parent 597a8d1970
commit bee88f70a3
2 changed files with 57 additions and 3 deletions

View File

@@ -186,8 +186,6 @@ class ActivityPage extends HookConsumerWidget {
(channelById[id]?.isDm ?? false) ||
ref.read(channelsProvider.notifier).hiddenDmIds.contains(id),
);
// A filtered DM row holds only part of its conversation, so the DM
// channel marker would also read events this view hides.
final rowsArePartial =
filter.value == InboxFilter.thread ||
filter.value == InboxFilter.mention ||
@@ -220,8 +218,10 @@ class ActivityPage extends HookConsumerWidget {
ref
.read(inboxLocalStateProvider.notifier)
.clearUnread(groupedInboxItemIds(item));
// A filtered row holds only part of its conversation, so channel and
// thread markers would also read events this view hides.
final isDmRow = item.conversationId.startsWith('dm:');
if (isDmRow && rowsArePartial) {
if (rowsArePartial && item.item.channelId != null) {
for (final e in {item.item, ...item.groupItems}) {
notifier.markContextRead(msgContextKey(e.id), e.createdAt);
}

View File

@@ -879,6 +879,60 @@ void main() {
},
);
testWidgets(
'reading a thread row under People leaves hidden agent replies unread',
(tester) async {
FeedItem threadEvent(String id, String pubkey, int age) => FeedItem(
id: id,
kind: 9,
pubkey: pubkey,
content: 'body $id',
createdAt: now - age,
channelId: 'ch1',
channelName: 'general',
tags: const [
['e', threadIdRoot1, '', 'root'],
['e', threadIdRoot1, '', 'reply'],
],
category: 'mention',
);
await tester.pumpWidget(
await buildTestable(
knownAgentPubkeys: const {'agent_pk'},
feed: HomeFeedResponse(
mentions: [
threadEvent('g1', 'agent_pk', 300),
threadEvent('p1', 'bob_pk', 200),
],
needsAction: const [],
activity: const [],
agentActivity: const [],
),
),
);
await tester.pumpAndSettle();
Future<void> chooseSender(String label) async {
await tester.tap(find.byKey(const ValueKey('activity-sender-menu')));
await tester.pumpAndSettle();
await tester.tap(find.text(label).last);
await tester.pumpAndSettle();
}
await chooseSender('People');
await tester.drag(
find.byKey(const ValueKey('inbox-row-p1')),
const Offset(-500, 0),
);
await tester.pumpAndSettle();
expect(find.byKey(const ValueKey('inbox-unread-dot-p1')), findsNothing);
await chooseSender('Anyone');
expect(find.byKey(const ValueKey('inbox-unread-dot-p1')), findsOneWidget);
},
);
testWidgets('sender filter preloads authors hidden under newer rows', (
tester,
) async {