diff --git a/mobile/lib/features/channels/channel_messages_provider.dart b/mobile/lib/features/channels/channel_messages_provider.dart index 7f657f4b7c..0e442d88d5 100644 --- a/mobile/lib/features/channels/channel_messages_provider.dart +++ b/mobile/lib/features/channels/channel_messages_provider.dart @@ -220,7 +220,6 @@ class ChannelMessagesNotifier extends Notifier>> { ), ); } - if (!_isBroadcastReply(event)) return false; } if (!isTimelineRow && !EventKind.channelAuxEventKinds.contains(event.kind)) { @@ -461,12 +460,6 @@ class ChannelMessagesNotifier extends Notifier>> { } } -bool _isBroadcastReply(NostrEvent event) { - return event.tags.any( - (tag) => tag.length >= 2 && tag[0] == 'broadcast' && tag[1] == '1', - ); -} - int _currentUnixSeconds() => DateTime.now().millisecondsSinceEpoch ~/ 1000; final channelMessagesProvider = diff --git a/mobile/test/features/channels/channel_messages_provider_test.dart b/mobile/test/features/channels/channel_messages_provider_test.dart index 6620c8c506..89b6b597e8 100644 --- a/mobile/test/features/channels/channel_messages_provider_test.dart +++ b/mobile/test/features/channels/channel_messages_provider_test.dart @@ -7,6 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:buzz/features/channels/channel_messages_provider.dart'; import 'package:buzz/features/channels/pending_local_messages_provider.dart'; import 'package:buzz/features/channels/thread_replies_provider.dart'; +import 'package:buzz/features/channels/timeline_message.dart'; import 'package:buzz/shared/relay/relay.dart'; void main() { @@ -282,6 +283,79 @@ void main() { ); }); + test('live non-broadcast reply updates its parent thread summary', () async { + final relaySession = _RecordingRelaySessionNotifier( + queryResults: [ + [_event(id: 'root', createdAt: 10), _bounds()], + ], + ); + final container = _buildContainer(relaySession); + addTearDown(container.dispose); + + container.read(channelMessagesProvider(_channelId)); + await relaySession.subscribed; + await _pumpEventQueue(); + + relaySession.emit( + _event( + id: 'reply', + createdAt: 20, + extraTags: const [ + ['e', 'root', '', 'reply'], + ], + ), + ); + await _pumpEventQueue(); + + final notifier = container.read( + channelMessagesProvider(_channelId).notifier, + ); + final events = container.read(channelMessagesProvider(_channelId)).value!; + final entries = buildMainTimelineEntries( + formatTimeline(events), + relaySummaries: notifier.threadSummaries, + ); + + expect(entries.single.summary?.replyCount, 1); + }); + + test( + 'live non-broadcast reply stays out of the top-level timeline', + () async { + final relaySession = _RecordingRelaySessionNotifier( + queryResults: [ + [_event(id: 'root', createdAt: 10), _bounds()], + ], + ); + final container = _buildContainer(relaySession); + addTearDown(container.dispose); + + container.read(channelMessagesProvider(_channelId)); + await relaySession.subscribed; + await _pumpEventQueue(); + + relaySession.emit( + _event( + id: 'reply', + createdAt: 20, + extraTags: const [ + ['e', 'root', '', 'reply'], + ], + ), + ); + await _pumpEventQueue(); + + final events = container.read(channelMessagesProvider(_channelId)).value!; + expect(events.map((event) => event.id), ['root', 'reply']); + expect( + buildMainTimelineEntries( + formatTimeline(events), + ).map((entry) => entry.message.id), + ['root'], + ); + }, + ); + test( 'thread replies are inserted, deduped, and rolled back locally', () async {