mirror of
https://github.com/block/buzz.git
synced 2026-11-10 11:21:05 +00:00
fix(mobile): let the synced marker catch up after filtered reads
Advance a filtered row's thread or channel marker through every event that is now read, not just up to the row's own latest event, so replies read under one filter sync once the hidden ones are read under another. 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:
@@ -1,7 +1,7 @@
|
|||||||
import 'package:buzz/shared/widgets/feedback_snackbar.dart';
|
import 'package:buzz/shared/widgets/feedback_snackbar.dart';
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:math' show max, min;
|
import 'dart:math' show max;
|
||||||
|
|
||||||
import '../../shared/widgets/ios_message_create_button.dart';
|
import '../../shared/widgets/ios_message_create_button.dart';
|
||||||
import '../../shared/widgets/ios_glass_navigation_button.dart';
|
import '../../shared/widgets/ios_glass_navigation_button.dart';
|
||||||
@@ -213,9 +213,11 @@ class ActivityPage extends HookConsumerWidget {
|
|||||||
return null;
|
return null;
|
||||||
}, [preloadPubkeysKey]);
|
}, [preloadPubkeysKey]);
|
||||||
|
|
||||||
// A filtered row holds only part of its conversation. Advance its synced
|
// A filtered row holds only part of its conversation. Its synced thread
|
||||||
// thread or channel marker only up to the first unread event the filter
|
// or channel marker is one watermark, so advance it through every event
|
||||||
// hides, and give shown events past that point local per-message marks.
|
// that is now read (shown here, or already read) and stop just before the
|
||||||
|
// first unread event the filter hides. Shown events past that point get
|
||||||
|
// local per-message marks until the hidden one is read too.
|
||||||
void markPartialRowRead(
|
void markPartialRowRead(
|
||||||
InboxItem item,
|
InboxItem item,
|
||||||
String channelId, {
|
String channelId, {
|
||||||
@@ -231,21 +233,30 @@ class ActivityPage extends HookConsumerWidget {
|
|||||||
(rootId == null ||
|
(rootId == null ||
|
||||||
(isThreadReply(e.tags) &&
|
(isThreadReply(e.tags) &&
|
||||||
threadReferenceOf(e.tags).rootId == rootId));
|
threadReferenceOf(e.tags).rootId == rootId));
|
||||||
var cap = item.latestActivityAt;
|
final events = {
|
||||||
for (final e in allItems.expand((i) => i.groupItems)) {
|
for (final e in [
|
||||||
if (shown.containsKey(e.id) ||
|
...allItems.expand((i) => i.groupItems),
|
||||||
!inContext(e) ||
|
...shown.values,
|
||||||
isInboxEventRead(e, markerOf: markerOf)) {
|
])
|
||||||
continue;
|
if (inContext(e)) e.id: e,
|
||||||
|
}.values.toList()..sort((a, b) => a.createdAt.compareTo(b.createdAt));
|
||||||
|
int? cap;
|
||||||
|
for (final e in events) {
|
||||||
|
if (!shown.containsKey(e.id) &&
|
||||||
|
!isInboxEventRead(e, markerOf: markerOf)) {
|
||||||
|
cap = e.createdAt - 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
cap = min(cap, e.createdAt - 1);
|
cap = e.createdAt;
|
||||||
|
}
|
||||||
|
if (cap != null) {
|
||||||
|
notifier.markContextRead(
|
||||||
|
rootId == null ? channelId : threadContextKey(rootId),
|
||||||
|
cap,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
notifier.markContextRead(
|
|
||||||
rootId == null ? channelId : threadContextKey(rootId),
|
|
||||||
cap,
|
|
||||||
);
|
|
||||||
for (final e in shown.values) {
|
for (final e in shown.values) {
|
||||||
if (inContext(e) && e.createdAt <= cap) continue;
|
if (inContext(e) && cap != null && e.createdAt <= cap) continue;
|
||||||
notifier.markContextRead(msgContextKey(e.id), e.createdAt);
|
notifier.markContextRead(msgContextKey(e.id), e.createdAt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -943,7 +943,8 @@ void main() {
|
|||||||
const Offset(-500, 0),
|
const Offset(-500, 0),
|
||||||
);
|
);
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(threadMarker(), now - 300);
|
// With the agent reply read too, the synced marker covers both.
|
||||||
|
expect(threadMarker(), now - 200);
|
||||||
await chooseSender('Anyone');
|
await chooseSender('Anyone');
|
||||||
expect(find.byKey(const ValueKey('inbox-unread-dot-p1')), findsNothing);
|
expect(find.byKey(const ValueKey('inbox-unread-dot-p1')), findsNothing);
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user