Skip to content

Commit 848d233

Browse files
committed
unreads: Track per-stream unread counts
This won't help UI code that wants to filter out muted messages, but otherwise it should let the caller conveniently know how many unreads there are in a stream, without worrying about performance and dropped frames.
1 parent ad074b2 commit 848d233

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

lib/model/unreads.dart

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,12 @@ class Unreads extends ChangeNotifier {
4848
for (final unreadStreamSnapshot in initial.streams) {
4949
final streamId = unreadStreamSnapshot.streamId;
5050
final topic = unreadStreamSnapshot.topic;
51-
(streams[streamId] ??= StreamUnreads.empty())
52-
.topics[topic] = QueueList.from(unreadStreamSnapshot.unreadMessageIds);
53-
totalCount += unreadStreamSnapshot.unreadMessageIds.length;
51+
final streamUnreads = streams[streamId] ??= StreamUnreads.empty();
52+
final unreadInTopic = unreadStreamSnapshot.unreadMessageIds.length;
53+
streamUnreads
54+
..topics[topic] = QueueList.from(unreadStreamSnapshot.unreadMessageIds)
55+
..count += unreadInTopic;
56+
totalCount += unreadInTopic;
5457
}
5558

5659
for (final unreadDmSnapshot in initial.dms) {
@@ -337,6 +340,7 @@ class Unreads extends ChangeNotifier {
337340
void _addLastInStreamTopic(int messageId, int streamId, String topic) {
338341
final streamUnreads = streams[streamId] ??= StreamUnreads.empty();
339342
(streamUnreads.topics[topic] ??= QueueList()).addLast(messageId);
343+
streamUnreads.count++;
340344
_totalCount += 1;
341345
}
342346

@@ -358,19 +362,23 @@ class Unreads extends ChangeNotifier {
358362
return result;
359363
},
360364
);
365+
streamUnreads.count += numAdded;
361366
_totalCount += numAdded;
362367
}
363368

364369
// TODO use efficient model lookups
365370
void _slowRemoveAllInStreams(Set<int> idsToRemove) {
366-
int numRemoved = 0;
371+
int totalRemoved = 0;
367372
final newlyEmptyStreams = [];
368373
for (final MapEntry(key: streamId, value: streamUnreads) in streams.entries) {
374+
int removedInStream = 0;
369375
final newlyEmptyTopics = [];
370376
for (final MapEntry(key: topic, value: messageIds) in streamUnreads.topics.entries) {
371377
final lengthBefore = messageIds.length;
372378
messageIds.removeWhere((id) => idsToRemove.contains(id));
373-
numRemoved += lengthBefore - messageIds.length;
379+
final removedInTopic = lengthBefore - messageIds.length;
380+
removedInStream += removedInTopic;
381+
totalRemoved += removedInTopic;
374382
if (messageIds.isEmpty) {
375383
newlyEmptyTopics.add(topic);
376384
}
@@ -381,11 +389,12 @@ class Unreads extends ChangeNotifier {
381389
if (streamUnreads.topics.isEmpty) {
382390
newlyEmptyStreams.add(streamId);
383391
}
392+
streamUnreads.count -= removedInStream;
384393
}
385394
for (final streamId in newlyEmptyStreams) {
386395
streams.remove(streamId);
387396
}
388-
_totalCount -= numRemoved;
397+
_totalCount -= totalRemoved;
389398
}
390399

391400
void _removeAllInStreamTopic(Set<int> incomingMessageIds, int streamId, String topic) {
@@ -397,7 +406,9 @@ class Unreads extends ChangeNotifier {
397406
// ([QueueList] doesn't have a `removeAll`)
398407
final lengthBefore = messageIds.length;
399408
messageIds.removeWhere((id) => incomingMessageIds.contains(id));
400-
_totalCount -= lengthBefore - messageIds.length;
409+
final numRemoved = lengthBefore - messageIds.length;
410+
streamUnreads.count -= numRemoved;
411+
_totalCount -= numRemoved;
401412
if (messageIds.isEmpty) {
402413
streamUnreads.topics.remove(topic);
403414
if (streamUnreads.topics.isEmpty) {
@@ -456,11 +467,18 @@ class Unreads extends ChangeNotifier {
456467
}
457468

458469
class StreamUnreads {
459-
StreamUnreads({required this.topics});
460-
StreamUnreads.empty() : topics = {};
470+
StreamUnreads({required this.count, required this.topics});
471+
StreamUnreads.empty()
472+
: count = 0,
473+
topics = {};
474+
475+
/// Total unread messages in this stream.
476+
///
477+
/// Prefer this when possible over traversing [topics] to make a sum.
478+
int count;
461479

462480
Map<String, QueueList<int>> topics;
463481

464482
@visibleForTesting
465-
Map<String, dynamic> toJson() => {'topics': topics};
483+
Map<String, dynamic> toJson() => {'count': count, 'topics': topics};
466484
}

test/model/unreads_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ void main() {
6666
final streamUnreads = expectedStreams[message.streamId] ??= StreamUnreads.empty();
6767
final messageIds = streamUnreads.topics[message.subject] ??= QueueList();
6868
messageIds.add(message.id);
69+
streamUnreads.count++;
6970
case DmMessage():
7071
final narrow = DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId);
7172
final messageIds = expectedDms[narrow] ??= QueueList();

0 commit comments

Comments
 (0)