Skip to content

Commit 1a21d7d

Browse files
committed
feat(llc): Filter realtime events based on query
Pass the `query` object to all `EventHandler` instances instead of individual properties like `fid`. This allows event handlers to access the query's filter conditions. When a real-time "updated" event is received, the handler now checks if the updated item still matches the filter. If it no longer matches, the item is removed from the local state, ensuring the UI stays consistent with the query's criteria.
1 parent f8e0ec1 commit 1a21d7d

24 files changed

+324
-32
lines changed

packages/stream_feeds/lib/src/state/activity_list.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class ActivityList with Disposable {
3737

3838
// Attach event handlers for real-time updates
3939
final handler = ActivityListEventHandler(
40+
query: query,
4041
state: _stateNotifier,
4142
capabilitiesRepository: capabilitiesRepository,
4243
);

packages/stream_feeds/lib/src/state/bookmark_folder_list.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ class BookmarkFolderList extends Disposable {
3232
);
3333

3434
// Attach event handlers for real-time updates
35-
final handler = BookmarkFolderListEventHandler(state: _stateNotifier);
35+
final handler = BookmarkFolderListEventHandler(
36+
query: query,
37+
state: _stateNotifier,
38+
);
3639

3740
_eventsSubscription = eventsEmitter.listen(handler.handleEvent);
3841
}

packages/stream_feeds/lib/src/state/bookmark_list.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ class BookmarkList with Disposable {
3232
);
3333

3434
// Attach event handlers for real-time updates
35-
final handler = BookmarkListEventHandler(state: _stateNotifier);
35+
final handler = BookmarkListEventHandler(
36+
query: query,
37+
state: _stateNotifier,
38+
);
39+
3640
_eventsSubscription = eventsEmitter.listen(handler.handleEvent);
3741
}
3842

packages/stream_feeds/lib/src/state/bookmark_list_state.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ class BookmarkListStateNotifier extends StateNotifier<BookmarkListState> {
7575

7676
state = state.copyWith(bookmarks: updatedBookmarks);
7777
}
78+
79+
/// Handles the removal of a bookmark by ID.
80+
void onBookmarkRemoved(String bookmarkId) {
81+
final updatedBookmarks = state.bookmarks.where((it) {
82+
return it.id != bookmarkId;
83+
}).toList();
84+
85+
state = state.copyWith(bookmarks: updatedBookmarks);
86+
}
7887
}
7988

8089
/// An observable state object that manages the current state of a bookmark list.

packages/stream_feeds/lib/src/state/comment_list.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ class CommentList extends Disposable {
3131
);
3232

3333
// Attach event handlers for real-time updates
34-
final handler = CommentListEventHandler(state: _stateNotifier);
34+
final handler = CommentListEventHandler(
35+
query: query,
36+
state: _stateNotifier,
37+
);
38+
3539
_eventsSubscription = eventsEmitter.listen(handler.handleEvent);
3640
}
3741

packages/stream_feeds/lib/src/state/event/activity_list_event_handler.dart

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import '../../models/comment_data.dart';
77
import '../../models/feeds_reaction_data.dart';
88
import '../../repository/capabilities_repository.dart';
99
import '../activity_list_state.dart';
10+
import '../query/activities_query.dart';
1011
import 'feed_capabilities_mixin.dart';
1112
import 'state_event_handler.dart';
1213

@@ -18,24 +19,37 @@ class ActivityListEventHandler
1819
with FeedCapabilitiesMixin
1920
implements StateEventHandler {
2021
const ActivityListEventHandler({
22+
required this.query,
2123
required this.state,
2224
required this.capabilitiesRepository,
2325
});
2426

27+
final ActivitiesQuery query;
2528
final ActivityListStateNotifier state;
29+
2630
@override
2731
final CapabilitiesRepository capabilitiesRepository;
2832

2933
@override
3034
Future<void> handleEvent(WsEvent event) async {
35+
bool matchesQueryFilter(ActivityData activity) {
36+
final filter = query.filter;
37+
if (filter == null) return true;
38+
return filter.matches(activity);
39+
}
40+
3141
if (event is api.ActivityUpdatedEvent) {
3242
final activity = event.activity.toModel();
43+
if (!matchesQueryFilter(activity)) {
44+
// If the updated activity no longer matches the filter, remove it
45+
return state.onActivityRemoved(activity);
46+
}
47+
3348
state.onActivityUpdated(activity);
3449

3550
final updatedActivity = await withUpdatedFeedCapabilities(activity);
36-
if (updatedActivity != null) {
37-
state.onActivityUpdated(updatedActivity);
38-
}
51+
if (updatedActivity != null) state.onActivityUpdated(updatedActivity);
52+
3953
return;
4054
}
4155

@@ -44,26 +58,57 @@ class ActivityListEventHandler
4458
}
4559

4660
if (event is api.ActivityReactionAddedEvent) {
61+
final activity = event.activity.toModel();
62+
if (!matchesQueryFilter(activity)) {
63+
// If the reaction's activity no longer matches the filter, remove it
64+
return state.onActivityRemoved(activity);
65+
}
66+
4767
return state.onReactionAdded(event.reaction.toModel());
4868
}
4969

5070
if (event is api.ActivityReactionDeletedEvent) {
71+
final activity = event.activity.toModel();
72+
if (!matchesQueryFilter(activity)) {
73+
// If the reaction's activity no longer matches the filter, remove it
74+
return state.onActivityRemoved(activity);
75+
}
76+
5177
return state.onReactionRemoved(event.reaction.toModel());
5278
}
5379

5480
if (event is api.BookmarkAddedEvent) {
81+
final activity = event.bookmark.activity.toModel();
82+
if (!matchesQueryFilter(activity)) {
83+
// If the bookmark's activity no longer matches the filter, remove it
84+
return state.onActivityRemoved(activity);
85+
}
86+
5587
return state.onBookmarkAdded(event.bookmark.toModel());
5688
}
5789

5890
if (event is api.BookmarkDeletedEvent) {
91+
final activity = event.bookmark.activity.toModel();
92+
if (!matchesQueryFilter(activity)) {
93+
// If the bookmark's activity no longer matches the filter, remove it
94+
return state.onActivityRemoved(activity);
95+
}
96+
5997
return state.onBookmarkRemoved(event.bookmark.toModel());
6098
}
6199

62100
if (event is api.CommentAddedEvent) {
101+
final activity = event.activity.toModel();
102+
if (!matchesQueryFilter(activity)) {
103+
// If the comment's activity no longer matches the filter, remove it
104+
return state.onActivityRemoved(activity);
105+
}
106+
63107
return state.onCommentAdded(event.comment.toModel());
64108
}
65109

66110
if (event is api.CommentDeletedEvent) {
111+
// TODO: Match event activity against filter once available in the event
67112
return state.onCommentRemoved(event.comment.toModel());
68113
}
69114

packages/stream_feeds/lib/src/state/event/bookmark_folder_list_event_handler.dart

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:stream_core/stream_core.dart';
33
import '../../generated/api/models.dart' as api;
44
import '../../models/bookmark_folder_data.dart';
55
import '../bookmark_folder_list_state.dart';
6+
import '../query/bookmark_folders_query.dart';
67
import 'state_event_handler.dart';
78

89
/// Event handler for bookmark folder list real-time updates.
@@ -11,19 +12,33 @@ import 'state_event_handler.dart';
1112
/// and updates the bookmark folder list state accordingly.
1213
class BookmarkFolderListEventHandler implements StateEventHandler {
1314
const BookmarkFolderListEventHandler({
15+
required this.query,
1416
required this.state,
1517
});
1618

19+
final BookmarkFoldersQuery query;
1720
final BookmarkFolderListStateNotifier state;
1821

1922
@override
2023
void handleEvent(WsEvent event) {
24+
bool matchesQueryFilter(BookmarkFolderData bookmarkFolder) {
25+
final filter = query.filter;
26+
if (filter == null) return true;
27+
return filter.matches(bookmarkFolder);
28+
}
29+
2130
if (event is api.BookmarkFolderDeletedEvent) {
2231
return state.onBookmarkFolderRemoved(event.bookmarkFolder.id);
2332
}
2433

2534
if (event is api.BookmarkFolderUpdatedEvent) {
26-
return state.onBookmarkFolderUpdated(event.bookmarkFolder.toModel());
35+
final bookmarkFolder = event.bookmarkFolder.toModel();
36+
if (!matchesQueryFilter(bookmarkFolder)) {
37+
// If the updated bookmark folder no longer matches the filter, remove it
38+
return state.onBookmarkFolderRemoved(bookmarkFolder.id);
39+
}
40+
41+
return state.onBookmarkFolderUpdated(bookmarkFolder);
2742
}
2843

2944
// Handle other bookmark folder list events if needed

packages/stream_feeds/lib/src/state/event/bookmark_list_event_handler.dart

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import '../../generated/api/models.dart' as api;
44
import '../../models/bookmark_data.dart';
55
import '../../models/bookmark_folder_data.dart';
66
import '../bookmark_list_state.dart';
7+
import '../query/bookmarks_query.dart';
78
import 'state_event_handler.dart';
89

910
/// Event handler for bookmark list real-time updates.
@@ -12,13 +13,21 @@ import 'state_event_handler.dart';
1213
/// and updates the bookmark list state accordingly.
1314
class BookmarkListEventHandler implements StateEventHandler {
1415
const BookmarkListEventHandler({
16+
required this.query,
1517
required this.state,
1618
});
1719

20+
final BookmarksQuery query;
1821
final BookmarkListStateNotifier state;
1922

2023
@override
2124
void handleEvent(WsEvent event) {
25+
bool matchesQueryFilter(BookmarkData bookmark) {
26+
final filter = query.filter;
27+
if (filter == null) return true;
28+
return filter.matches(bookmark);
29+
}
30+
2231
if (event is api.BookmarkFolderDeletedEvent) {
2332
return state.onBookmarkFolderRemoved(event.bookmarkFolder.id);
2433
}
@@ -28,7 +37,13 @@ class BookmarkListEventHandler implements StateEventHandler {
2837
}
2938

3039
if (event is api.BookmarkUpdatedEvent) {
31-
return state.onBookmarkUpdated(event.bookmark.toModel());
40+
final bookmark = event.bookmark.toModel();
41+
if (!matchesQueryFilter(bookmark)) {
42+
// If the updated bookmark no longer matches the filter, remove it
43+
return state.onBookmarkRemoved(bookmark.id);
44+
}
45+
46+
return state.onBookmarkUpdated(bookmark);
3247
}
3348

3449
// Handle other bookmark list events if needed

packages/stream_feeds/lib/src/state/event/comment_list_event_handler.dart

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,37 @@ import '../../generated/api/models.dart' as api;
44

55
import '../../models/comment_data.dart';
66
import '../comment_list_state.dart';
7+
import '../query/comments_query.dart';
78
import 'state_event_handler.dart';
89

910
/// Event handler for comment list real-time updates.
1011
///
1112
/// Processes WebSocket events and updates the comment list state accordingly.
1213
class CommentListEventHandler implements StateEventHandler {
1314
const CommentListEventHandler({
15+
required this.query,
1416
required this.state,
1517
});
1618

19+
final CommentsQuery query;
1720
final CommentListStateNotifier state;
1821

1922
@override
2023
void handleEvent(WsEvent event) {
24+
bool matchesQueryFilter(CommentData comment) {
25+
final filter = query.filter;
26+
if (filter == null) return true;
27+
return filter.matches(comment);
28+
}
29+
2130
if (event is api.CommentUpdatedEvent) {
22-
return state.onCommentUpdated(event.comment.toModel());
31+
final comment = event.comment.toModel();
32+
if (!matchesQueryFilter(comment)) {
33+
// If the updated comment no longer matches the filter, remove it
34+
return state.onCommentRemoved(comment.id);
35+
}
36+
37+
return state.onCommentUpdated(comment);
2338
}
2439

2540
if (event is api.CommentDeletedEvent) {

0 commit comments

Comments
 (0)