-
Notifications
You must be signed in to change notification settings - Fork 367
feat(llc): add local events for push preference updates #2387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This commit introduces two new local event types: - `push_preference.updated`: Fired when global push notification preferences are updated. - `channel.push_preference.updated`: Fired when channel-specific push notification preferences are updated. The `setPushPreferences` method in the `StreamChatClient` now emits these events after successfully updating preferences. Additionally: - The `StreamChatClient` now updates the `currentUser.pushPreferences` when a `push_preference.updated` event is received. - The `ChannelController` now listens for `channel.push_preference.updated` events and updates the `channelState.pushPreferences` accordingly. - The `Event` model has been updated to include `pushPreference` and `channelPushPreference` fields to carry this data.
WalkthroughAdds push-preference support: new Event fields and event types, client.setPushPreferences now awaits API and emits user/channel push-preference events, client and channel state subscribe to those events to update user and channel push preferences, JSON serialization updated, and tests added. Changes
Sequence Diagram(s)sequenceDiagram
participant App
participant Client
participant API as PushPrefsAPI
participant Events as EventBus
participant State as Client/ChannelState
App->>Client: setPushPreferences(preferences)
Client->>API: upsertPushPreferences(preferences)
API-->>Client: UpsertPushPreferencesResponse
Client->>Events: emit push_preference.updated (user) %% new/changed
Client->>Events: loop emit channel.push_preference.updated (per cid) %% new/changed
Events->>State: push_preference.updated -> update currentUser.pushPreferences
Events->>State: channel.push_preference.updated -> update Channel.pushPreferences
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
packages/stream_chat/lib/src/client/channel.dart (1)
3502-3518
: Avoid redundant state writes when preference hasn’t changedAdd a cheap equality/identity guard to prevent no‑op updates and unnecessary persistence writes.
void _listenChannelPushPreferenceUpdated() { _subscriptions.add( _channel.on(EventType.channelPushPreferenceUpdated).listen( (event) { final pushPreferences = event.channelPushPreference; if (pushPreferences == null) return; + // No-op if nothing changed + if (identical(pushPreferences, channelState.pushPreferences) || + pushPreferences == channelState.pushPreferences) { + return; + } updateChannelState( channelState.copyWith( pushPreferences: pushPreferences, ), ); }, ), ); }packages/stream_chat/test/src/client/client_test.dart (2)
1245-1296
: Strengthen assertions: validate payload details (cid and levels), not just event typesVerifying payloads makes the test more robust and guards regressions in emitted event shape.
- expect( - client.eventStream, - emitsInOrder([ - isA<Event>().having( - (e) => e.type, - 'push_preference.updated event', - EventType.pushPreferenceUpdated, - ), - isA<Event>().having( - (e) => e.type, - 'channel.push_preference.updated event', - EventType.channelPushPreferenceUpdated, - ), - ]), - ); + expect( + client.eventStream, + emitsInOrder([ + isA<Event>() + .having((e) => e.type, 'type', EventType.pushPreferenceUpdated) + .having((e) => e.pushPreference?.chatLevel, 'chatLevel', + ChatLevel.mentions), + isA<Event>() + .having((e) => e.type, 'type', + EventType.channelPushPreferenceUpdated) + .having((e) => e.cid, 'cid', channelCid) + .having((e) => e.channelPushPreference?.chatLevel, 'chatLevel', + ChatLevel.mentions), + ]), + );
1298-1325
: Prefer waiting on currentUserStream instead of a microtask delayListen for the next OwnUser emission to avoid timing flakiness.
- // Trigger the event - client.handleEvent(event); - - // Wait for the event to get processed - await Future.delayed(Duration.zero); - - // Should update currentUser.pushPreferences - final pushPreferences = client.state.currentUser?.pushPreferences; - expect(pushPreferences, isNotNull); - expect(pushPreferences?.chatLevel, ChatLevel.mentions); - expect(pushPreferences?.callLevel, CallLevel.all); - expect(pushPreferences?.disabledUntil, pushPreference.disabledUntil); + // Trigger the event + client.handleEvent(event); + + // Wait for the user update and assert + final updatedUser = await client.state.currentUserStream + .where((u) => u?.pushPreferences != null) + .first; + expect(updatedUser!.pushPreferences!.chatLevel, ChatLevel.mentions); + expect(updatedUser.pushPreferences!.callLevel, CallLevel.all); + expect(updatedUser.pushPreferences!.disabledUntil, + pushPreference.disabledUntil);packages/stream_chat/lib/src/client/client.dart (1)
1037-1069
: Emit events + eagerly update local state; avoid Dart 3‑only pattern destructuring
- Recommend updating
state.currentUser.pushPreferences
immediately (in addition to emitting the local event) to avoid UI races where callers read stale state right afterawait setPushPreferences(...)
.- The
for (final MapEntry(:key, :value) ...)
pattern requires recent Dart pattern‑matching syntax. If your min SDK isn’t high enough, prefer a classicfor (final entry in ...)
loop.Suggested diff:
Future<UpsertPushPreferencesResponse> setPushPreferences( List<PushPreferenceInput> preferences, ) async { final res = await _chatApi.device.setPushPreferences(preferences); final currentUser = state.currentUser; final currentUserId = currentUser?.id; if (currentUserId == null) return res; // Emit events for updated preferences final updatedPushPreference = res.userPreferences[currentUserId]; if (updatedPushPreference != null) { - final pushPreferenceUpdatedEvent = Event( - type: EventType.pushPreferenceUpdated, - pushPreference: updatedPushPreference, - ); - handleEvent(pushPreferenceUpdatedEvent); + // Eager local update to prevent brief UI staleness. + state.currentUser = + state.currentUser?.copyWith(pushPreferences: updatedPushPreference); + handleEvent(Event( + type: EventType.pushPreferenceUpdated, + pushPreference: updatedPushPreference, + )); } // Emit events for updated channel-specific preferences final channelPushPreferences = res.userChannelPreferences[currentUserId]; if (channelPushPreferences != null) { - for (final MapEntry(:key, :value) in channelPushPreferences.entries) { - final pushPreferenceUpdatedEvent = Event( - type: EventType.channelPushPreferenceUpdated, - cid: key, - channelPushPreference: value, - ); - handleEvent(pushPreferenceUpdatedEvent); - } + for (final entry in channelPushPreferences.entries) { + final cid = entry.key; + final pref = entry.value; + handleEvent(Event( + type: EventType.channelPushPreferenceUpdated, + cid: cid, + channelPushPreference: pref, + )); + } } return res; }Also, please confirm the map keys in
res.userChannelPreferences[currentUserId]
are CIDs (e.g.,type:id
) as expected by listeners consumingevent.cid
. If they are channel IDs instead, state updates won’t route correctly.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
packages/stream_chat/lib/src/client/channel.dart
(2 hunks)packages/stream_chat/lib/src/client/client.dart
(2 hunks)packages/stream_chat/lib/src/core/models/event.dart
(5 hunks)packages/stream_chat/lib/src/core/models/event.g.dart
(2 hunks)packages/stream_chat/lib/src/event_type.dart
(1 hunks)packages/stream_chat/test/src/client/channel_test.dart
(1 hunks)packages/stream_chat/test/src/client/client_test.dart
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: stream_chat_flutter
- GitHub Check: stream_chat_localizations
- GitHub Check: analyze_legacy_versions
- GitHub Check: stream_chat_flutter_core
- GitHub Check: stream_chat_persistence
- GitHub Check: test
- GitHub Check: build (android)
- GitHub Check: build (ios)
- GitHub Check: analyze
🔇 Additional comments (8)
packages/stream_chat/lib/src/event_type.dart (1)
173-179
: New local event types look goodNames and string values are consistent with existing conventions.
packages/stream_chat/lib/src/client/channel.dart (2)
2182-2183
: Good: registering the channel push preference listener during state initHooks in at the right point in the constructor and will be disposed via the existing CompositeSubscription.
3502-3518
: Resolved — setPushPreferences emits channel events with cidsetPushPreferences creates Event(type: EventType.channelPushPreferenceUpdated, cid: key, channelPushPreference: value) and calls handleEvent, so Channel.on(...) filtering by cid will receive them.
packages/stream_chat/lib/src/core/models/event.g.dart (2)
71-78
: JSON parsing for new fields looks correctKeys and constructors align with PushPreference and ChannelPushPreference.
123-126
: Ensure codegen is up to dateSince this is generated, please re-run codegen to avoid drift with event.dart after merging.
Run locally:
- dart run build_runner build --delete-conflicting-outputs
packages/stream_chat/lib/src/client/client.dart (1)
2164-2167
: LGTM: client state now reacts to push preference eventsThe
currentUser = currentUser?.copyWith(pushPreferences: preferences)
hook is correct and minimal. Ensure a companion test exists that assertscurrentUser.pushPreferences
updates afterpush_preference.updated
.packages/stream_chat/test/src/client/channel_test.dart (1)
4818-4909
: LGTM: solid coverage for channel.push_preference.updated
- Good assertions for both initial set and updating existing prefs.
- Using
Future.delayed(Duration.zero)
is a pragmatic way to yield to the event loop for handlers to run.packages/stream_chat/lib/src/core/models/event.dart (1)
44-46
: LGTM — push preference fields wired & serializedVerified: packages/stream_chat/lib/src/core/models/event.g.dart contains (de)serialization for 'push_preference' and 'channel_push_preference'; EventType.pushPreferenceUpdated and EventType.channelPushPreferenceUpdated exist in packages/stream_chat/lib/src/event_type.dart. No further action required.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2387 +/- ##
==========================================
+ Coverage 63.81% 63.85% +0.03%
==========================================
Files 413 413
Lines 25837 25858 +21
==========================================
+ Hits 16488 16511 +23
+ Misses 9349 9347 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Submit a pull request
Fixes: #2356
Description of the pull request
This commit introduces two new local event types:
push_preference.updated
: Fired when global push notification preferences are updated.channel.push_preference.updated
: Fired when channel-specific push notification preferences are updated.The
setPushPreferences
method in theStreamChatClient
now emits these events after successfully updating preferences.Additionally:
StreamChatClient
now updates thecurrentUser.pushPreferences
when apush_preference.updated
event is received.ChannelController
now listens forchannel.push_preference.updated
events and updates thechannelState.pushPreferences
accordingly.Event
model has been updated to includepushPreference
andchannelPushPreference
fields to carry this data.Summary by CodeRabbit
New Features
Improvements
Tests
Documentation