Skip to content

Conversation

xsahil03x
Copy link
Member

@xsahil03x xsahil03x commented Aug 8, 2025

Submit a pull request

Fixes: #2346

Description of the pull request

This commit introduces the ability to manage push notification preferences for users and channels.

New Models:

  • PushPreferenceInput: Used for creating or updating preferences.
  • PushPreference: Represents user-level push preferences.
  • ChannelPushPreference: Represents channel-specific push preferences.
  • ChatLevelPushPreference enum: Defines chat notification levels (all, none, mentions, default).
  • CallLevelPushPreference enum: Defines call notification levels (all, none, default).

API Changes:

  • DeviceApi.setPushPreferences(List<PushPreferenceInput> preferences): New method to set user or channel-specific push preferences.
  • UpsertPushPreferencesResponse: New response model for setPushPreferences.

Model Updates:

  • OwnUser: Added pushPreferences field.
  • ChannelState: Added pushPreferences field.

Client Method:

  • StreamChatClient.setPushPreferences(List<PushPreferenceInput> preferences): New client method to interact with the setPushPreferences API.

Summary by CodeRabbit

  • New Features
    • Added ability to configure push notification preferences for the current user, globally or per channel; preferences are preserved across reconnects and user updates.
  • Chores
    • Updated changelog to announce push preference support and public exposure of related types.
  • Bug Fixes
    • No bug fixes included in this release.
  • Tests
    • Added comprehensive tests for the push preference API and models, including serialization, deserialization, and input validation.

Copy link
Contributor

coderabbitai bot commented Aug 8, 2025

Walkthrough

Adds push-preferences support: new models, serialization, API endpoint client, client method setPushPreferences, propagation into user/channel state, exports, changelog entry, and associated tests.

Changes

Cohort / File(s) Change Summary
Client Push Preferences API
packages/stream_chat/lib/src/client/client.dart, packages/stream_chat/CHANGELOG.md, packages/stream_chat/lib/stream_chat.dart
Added StreamChatClient.setPushPreferences API, exported push preference model, and updated changelog. Client preserves push preferences on user updates.
Device API Support
packages/stream_chat/lib/src/core/api/device_api.dart
Added DeviceApi.setPushPreferences to POST /push_preferences, validate non-empty input, and parse response.
API Response Models
packages/stream_chat/lib/src/core/api/responses.dart, .../responses.g.dart
Added UpsertPushPreferencesResponse with userPreferences and userChannelPreferences fields and JSON deserializer.
Push Preference Models
packages/stream_chat/lib/src/core/models/push_preference.dart, .../push_preference.g.dart
New models: PushPreferenceInput, PushPreference, ChannelPushPreference, plus ChatLevel and CallLevel string enums and generated (de)serialization.
Channel State Integration
packages/stream_chat/lib/src/core/models/channel_state.dart, .../channel_state.g.dart, packages/stream_chat/lib/src/client/channel.dart
Added ChannelState.pushPreferences field, included in constructor/copyWith and JSON (de)serialization; channel state update now carries pushPreferences.
OwnUser Integration
packages/stream_chat/lib/src/core/models/own_user.dart, .../own_user.g.dart
Added OwnUser.pushPreferences field, JSON handling, copyWith/merge propagation, and populating from extraData['push_preferences'].
Tests — Device API & Responses
packages/stream_chat/test/src/core/api/device_api_test.dart, packages/stream_chat/test/src/core/api/responses_test.dart
Added tests for setPushPreferences behavior (valid/empty inputs, channel-specific) and for UpsertPushPreferencesResponse JSON parsing.
Tests — Models & Fixtures
packages/stream_chat/test/src/core/models/push_preference_test.dart, packages/stream_chat/test/fixtures/channel_state_to_json.json, packages/stream_chat/test/src/core/models/channel_state_test.dart
Added model tests for push preference classes; updated fixture and channel state serialization tests to include push_preferences.
Test Mocks / Const updates
packages/stream_chat/test/src/db/chat_persistence_client_test.dart, packages/stream_chat_flutter/test/src/mocks.dart, packages/stream_chat_flutter_core/test/*, packages/stream_chat_flutter_core/test/stream_channel_test.dart
Replaced several runtime ChannelState() instances with const ChannelState() in mocks/tests to match new const constructor and fields.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant StreamChatClient
    participant DeviceApi
    participant Server

    App->>StreamChatClient: setPushPreferences(preferences)
    StreamChatClient->>DeviceApi: setPushPreferences(preferences)
    DeviceApi->>Server: POST /push_preferences (body: preferences)
    Server-->>DeviceApi: 200 + payload (user_preferences, user_channel_preferences)
    DeviceApi-->>StreamChatClient: UpsertPushPreferencesResponse
    StreamChatClient-->>App: UpsertPushPreferencesResponse
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Add upsertPushPreferences method to the client (#2346)
Support global and channel-specific push notification preferences (#2346)
Provide models and serialization for push preference data (#2346)
Add tests for push preferences API and models (#2346)

Possibly related PRs

Suggested reviewers

  • renefloor

Poem

"I nibbled through code all day and night,
Pushed preferences now set just right,
Channels and users in tidy array,
Tests hop in to keep bugs away,
A rabbit's work—soft, swift, and bright. 🐇"

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/upsert-push-preferences

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (8)
packages/stream_chat/lib/src/client/channel.dart (1)

3305-3306: Propagating channel pushPreferences in state updates — LGTM

This correctly threads ChannelState.pushPreferences through updateChannelState. With copyWith using pushPreferences ?? this.pushPreferences, nulls won’t inadvertently clear existing values.

Optional: expose convenience accessors on Channel to keep API parity with other fields.

Example (outside the shown lines):

// In class Channel:
ChannelPushPreference? get pushPreferences {
  _checkInitialized();
  return state?._channelState.pushPreferences;
}

Stream<ChannelPushPreference?> get pushPreferencesStream {
  _checkInitialized();
  return state!.channelStateStream.map((cs) => cs.pushPreferences);
}
packages/stream_chat/CHANGELOG.md (1)

8-12: Use consistent API naming in CHANGELOG

Elsewhere the doc uses client.methodName() or StreamChatClient.methodName. Here it says Client.setPushPreferences. Recommend aligning for consistency and clarity.

Apply:

- - Added support for `Client.setPushPreferences` which allows setting PushPreferences for the
-   current user or for a specific channel.
+ - Added support for `client.setPushPreferences()` which allows setting push notification
+   preferences for the current user or for a specific channel.
packages/stream_chat/lib/src/core/models/channel_state.dart (1)

7-7: ChannelState gains pushPreferences — LGTM; consider allowing explicit unsetting

The field, constructor, and copyWith wiring look correct and consistent with other fields. Current copyWith uses pushPreferences ?? this.pushPreferences, which preserves existing values if null is passed.

Optional: If you foresee clearing this value (setting it to null) via copyWith, mirror the sentinel approach used for draft:

-  ChannelState copyWith({
+  ChannelState copyWith({
     ChannelModel? channel,
     List<Message>? messages,
     List<Member>? members,
     List<Message>? pinnedMessages,
     int? watcherCount,
     List<User>? watchers,
     List<Read>? read,
     Member? membership,
-    Object? draft = _nullConst,
-    ChannelPushPreference? pushPreferences,
+    Object? draft = _nullConst,
+    Object? pushPreferences = _nullConst,
   }) =>
       ChannelState(
         channel: channel ?? this.channel,
         messages: messages ?? this.messages,
         members: members ?? this.members,
         pinnedMessages: pinnedMessages ?? this.pinnedMessages,
         watcherCount: watcherCount ?? this.watcherCount,
         watchers: watchers ?? this.watchers,
         read: read ?? this.read,
         membership: membership ?? this.membership,
         draft: draft == _nullConst ? this.draft : draft as Draft?,
-        pushPreferences: pushPreferences ?? this.pushPreferences,
+        pushPreferences: pushPreferences == _nullConst
+            ? this.pushPreferences
+            : pushPreferences as ChannelPushPreference?,
       );

Also applies to: 23-34, 63-65, 84-85, 96-97

packages/stream_chat/lib/src/core/api/device_api.dart (1)

1-1: Remove unused import

After removing jsonEncode, dart:convert is no longer needed.

-import 'dart:convert';
packages/stream_chat/lib/src/client/client.dart (1)

1035-1039: Optionally update in-memory state after upsert

Consider updating state.currentUser.pushPreferences from the response to keep local state in sync without waiting for a user-updated event.

-  Future<UpsertPushPreferencesResponse> setPushPreferences(
-    List<PushPreferenceInput> preferences,
-  ) {
-    return _chatApi.device.setPushPreferences(preferences);
-  }
+  Future<UpsertPushPreferencesResponse> setPushPreferences(
+    List<PushPreferenceInput> preferences,
+  ) async {
+    final res = await _chatApi.device.setPushPreferences(preferences);
+    final uid = state.currentUser?.id;
+    if (uid != null) {
+      final pref = res.userPreferences[uid];
+      if (pref != null) {
+        state.currentUser = state.currentUser?.copyWith(pushPreferences: pref);
+      }
+    }
+    return res;
+  }
packages/stream_chat/test/src/core/api/device_api_test.dart (1)

136-210: Reset mock between tests to avoid leakage

All tests share the same MockHttpClient instance.
Although mocktail clears recorded interactions after each verify*, the stubs themselves accumulate, which can lead to surprising behaviour when later tests stub the same method/args combo.

setUp(() {
-  deviceApi = DeviceApi(client);
+  reset(client);          // clear stubs & interactions
+  deviceApi = DeviceApi(client);
});
packages/stream_chat/lib/src/core/models/push_preference.dart (2)

45-51: Constrain invalid combinations in the input constructors.

To prevent ambiguous payloads:

  • removeDisable should not be used together with disabledUntil.
  • For channel-scoped input, callLevel is likely not supported (server typically only supports chat-level per channel).
   const PushPreferenceInput({
     this.callLevel,
     this.chatLevel,
     this.disabledUntil,
     this.removeDisable,
-  }) : channelCid = null;
+  })  : channelCid = null,
+        assert(!(removeDisable == true && disabledUntil != null),
+            'removeDisable and disabledUntil are mutually exclusive');
@@
   const PushPreferenceInput.channel({
     required String this.channelCid,
     this.callLevel,
     this.chatLevel,
     this.disabledUntil,
     this.removeDisable,
-  });
+  }) : assert(!(removeDisable == true && disabledUntil != null),
+            'removeDisable and disabledUntil are mutually exclusive'),
+       assert(callLevel == null,
+            'callLevel is not supported for channel-scoped preferences');

If the backend actually allows callLevel per-channel, drop the second assert and update docs to clarify supported combos.

Also applies to: 54-61


74-76: Clarify the removeDisable docstring.

-  /// Temporary flag for resetting disabledUntil
+  /// When true, clears any existing [disabledUntil] on the server (resets snooze).
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d666475 and 6e74ec6.

📒 Files selected for processing (16)
  • packages/stream_chat/CHANGELOG.md (1 hunks)
  • packages/stream_chat/lib/src/client/channel.dart (1 hunks)
  • packages/stream_chat/lib/src/client/client.dart (2 hunks)
  • packages/stream_chat/lib/src/core/api/device_api.dart (2 hunks)
  • packages/stream_chat/lib/src/core/api/responses.dart (2 hunks)
  • packages/stream_chat/lib/src/core/api/responses.g.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/channel_state.dart (6 hunks)
  • packages/stream_chat/lib/src/core/models/channel_state.g.dart (2 hunks)
  • packages/stream_chat/lib/src/core/models/own_user.dart (6 hunks)
  • packages/stream_chat/lib/src/core/models/own_user.g.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/push_preference.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/push_preference.g.dart (1 hunks)
  • packages/stream_chat/lib/stream_chat.dart (1 hunks)
  • packages/stream_chat/test/src/core/api/device_api_test.dart (1 hunks)
  • packages/stream_chat/test/src/core/api/responses_test.dart (1 hunks)
  • packages/stream_chat/test/src/core/models/push_preference_test.dart (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-08T14:27:59.609Z
Learnt from: xsahil03x
PR: GetStream/stream-chat-flutter#2348
File: packages/stream_chat_flutter_core/lib/src/stream_channel.dart:383-406
Timestamp: 2025-08-08T14:27:59.609Z
Learning: In stream_chat_flutter_core/lib/src/stream_channel.dart, threads (replies) do not support around-anchor loading. Thread replies are fetched as: initial latest page via StreamChannelState.getReplies(), and further pagination via StreamChannelState.queryReplies(parentId, direction: top|bottom). Anchored loads apply only to channel messages, not to threads.

Applied to files:

  • packages/stream_chat/lib/src/client/client.dart
  • packages/stream_chat/lib/src/core/api/responses.dart
🪛 GitHub Actions: legacy_version_analyze
packages/stream_chat/lib/src/core/models/push_preference.dart

[error] 84-84: Missing documentation for a public member. Try adding documentation for the member. (public_member_api_docs)


[error] 113-113: Missing documentation for a public member. Try adding documentation for the member. (public_member_api_docs)

⏰ 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: test
  • GitHub Check: build (ios)
  • GitHub Check: build (android)
  • GitHub Check: analyze
  • GitHub Check: stream_chat_flutter_core
  • GitHub Check: stream_chat_localizations
  • GitHub Check: stream_chat_flutter
  • GitHub Check: stream_chat
  • GitHub Check: stream_chat_persistence
🔇 Additional comments (9)
packages/stream_chat/lib/stream_chat.dart (1)

57-57: Export push_preference.dart — LGTM

Models are now publicly accessible through the main library. No issues.

packages/stream_chat/lib/src/core/models/own_user.g.dart (1)

29-33: Incorrect suggestion on toJson generation for OwnUser

The deserialization of push_preferences is correct, but the OwnUser model is annotated with

@JsonSerializable(createToJson: false)

which explicitly disables any generated toJson method. As a result, there is no toJson counterpart in the .g.dart file and no fields—pushPreferences or otherwise—will be serialized.

If you do need to serialize OwnUser (including pushPreferences), you should remove or change the createToJson: false setting on @JsonSerializable. Otherwise, the absence of a toJson implementation is intentional.

Likely an incorrect or invalid review comment.

packages/stream_chat/lib/src/client/client.dart (1)

34-34: Import looks good

The import exposes the new types to the client API; consistent with other model imports.

packages/stream_chat/lib/src/core/models/own_user.dart (1)

21-22: OwnUser pushPreferences wiring looks correct

  • Field added with proper JSON key and null exclusion.
  • Propagated through copyWith, merge, and topLevelFields.
  • Matches the new push preference model types.

Also applies to: 88-89, 116-117, 178-181, 193-194

packages/stream_chat/test/src/core/api/responses_test.dart (1)

4449-4521: Great addition – covers the critical deserialization paths

The new test exercises both user-level and channel-level preference maps and enumerations – nice job.

packages/stream_chat/test/src/core/models/push_preference_test.dart (1)

1-103: Model tests look solid

Thorough round-trip checks for enum mapping and date handling – nothing to add.

packages/stream_chat/lib/src/core/models/push_preference.g.dart (1)

9-22: No action required: Dart SDK constraint already enforces Dart 3
pubspec.yaml declares environment: sdk: ^3.6.2, which satisfies the Dart 3 requirement for collection if-case pattern syntax.

packages/stream_chat/lib/src/core/models/push_preference.dart (2)

6-23: Enums look solid; JSON mappings are correct.

Good choice using defaultValue mapped to "default" to avoid the reserved keyword while keeping wire format stable.

Also applies to: 25-38


71-76: Confirm DateTime serialization consistency

PushPreference.disabledUntil (lines 71–76, 99–101, 124–126) is using the default toIso8601String/DateTime.parse behavior, just like all other models (e.g. Read, UnreadCounts). There is currently no shared UTC converter in the repo.

• If your backend requires UTC-only timestamps, consider introducing a DateTimeUtcConverter and annotating each disabledUntil field:

  • packages/stream_chat/lib/src/core/models/push_preference.dart (lines 71–76)
  • packages/stream_chat/lib/src/core/models/push_preference.dart (lines 99–101)
  • packages/stream_chat/lib/src/core/models/push_preference.dart (lines 124–126)

• Otherwise, the default ISO8601 serialization is consistent with the rest of the codebase.

Copy link

codecov bot commented Aug 8, 2025

Codecov Report

❌ Patch coverage is 75.00000% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.81%. Comparing base (8ce9fae) to head (9e926c9).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...ream_chat/lib/src/core/models/push_preference.dart 66.66% 5 Missing ⚠️
packages/stream_chat/lib/src/client/client.dart 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2350      +/-   ##
==========================================
+ Coverage   63.80%   63.81%   +0.01%     
==========================================
  Files         411      412       +1     
  Lines       25793    25824      +31     
==========================================
+ Hits        16457    16480      +23     
- Misses       9336     9344       +8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69f748a and 69236ca.

📒 Files selected for processing (9)
  • packages/stream_chat/lib/src/core/api/responses.dart (2 hunks)
  • packages/stream_chat/lib/src/core/api/responses.g.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/push_preference.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/push_preference.g.dart (1 hunks)
  • packages/stream_chat/test/fixtures/channel_state_to_json.json (1 hunks)
  • packages/stream_chat/test/src/core/api/device_api_test.dart (1 hunks)
  • packages/stream_chat/test/src/core/api/responses_test.dart (1 hunks)
  • packages/stream_chat/test/src/core/models/channel_state_test.dart (1 hunks)
  • packages/stream_chat/test/src/core/models/push_preference_test.dart (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/stream_chat/test/fixtures/channel_state_to_json.json
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/stream_chat/lib/src/core/api/responses.g.dart
  • packages/stream_chat/test/src/core/api/device_api_test.dart
  • packages/stream_chat/test/src/core/models/push_preference_test.dart
  • packages/stream_chat/lib/src/core/api/responses.dart
  • packages/stream_chat/test/src/core/api/responses_test.dart
  • packages/stream_chat/lib/src/core/models/push_preference.g.dart
  • packages/stream_chat/lib/src/core/models/push_preference.dart
⏰ 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)
  • GitHub Check: stream_chat_localizations
  • GitHub Check: stream_chat_flutter
  • GitHub Check: stream_chat_persistence
  • GitHub Check: stream_chat_flutter_core
  • GitHub Check: stream_chat
  • GitHub Check: build (android)
  • GitHub Check: build (ios)
  • GitHub Check: analyze
  • GitHub Check: test
  • GitHub Check: analyze_legacy_versions

This commit introduces the ability to manage push notification preferences for users and channels.

**New Models:**
- `PushPreferenceInput`: Used for creating or updating preferences.
- `PushPreference`: Represents user-level push preferences.
- `ChannelPushPreference`: Represents channel-specific push preferences.
- `ChatLevelPushPreference` enum: Defines chat notification levels (all, none, mentions, default).
- `CallLevelPushPreference` enum: Defines call notification levels (all, none, default).

**API Changes:**
- `DeviceApi.setPushPreferences(List<PushPreferenceInput> preferences)`: New method to set user or channel-specific push preferences.
- `UpsertPushPreferencesResponse`: New response model for `setPushPreferences`.

**Model Updates:**
- `OwnUser`: Added `pushPreferences` field.
- `ChannelState`: Added `pushPreferences` field.

**Client Method:**
- `StreamChatClient.setPushPreferences(List<PushPreferenceInput> preferences)`: New client method to interact with the `setPushPreferences` API.
This commit replaces the `enum` types for `ChatLevelPushPreference` and `CallLevelPushPreference` with `extension type`s named `ChatLevel` and `CallLevel` respectively.

This change allows for more flexibility in how these values are handled, particularly in JSON serialization and deserialization, while maintaining type safety.

Key changes:
- `ChatLevelPushPreference` and `CallLevelPushPreference` enums are removed.
- `ChatLevel` and `CallLevel` extension types are introduced.
- JSON serialization and deserialization logic for `PushPreference`, `ChannelPushPreference`, and `PushPreferenceInput` has been updated to use the new extension types directly as `String` values, removing the need for `EnumMap` lookups.
- `UpsertPushPreferencesResponse` now includes a `defaultValue` of `{}` for `userPreferences` and `userChannelPreferences` to prevent potential null issues during deserialization.
- Tests have been updated to reflect these changes.
@xsahil03x xsahil03x force-pushed the feat/upsert-push-preferences branch from 69236ca to 9e926c9 Compare August 11, 2025 10:36
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

♻️ Duplicate comments (3)
packages/stream_chat/test/src/core/models/channel_state_test.dart (1)

62-65: Add deserialization test for pushPreferences in ChannelState

The past review comment about adding a deserialization test is still applicable. While the serialization test correctly verifies toJson() includes pushPreferences, we also need to test that ChannelState.fromJson() properly deserializes the push_preferences field.

packages/stream_chat/lib/src/core/models/push_preference.dart (2)

35-36: Enforce snake_case JSON field naming for PushPreference models

The past review comment about adding fieldRename: FieldRename.snake to the @JsonSerializable annotations is still valid and should be addressed to ensure proper JSON field naming consistency with the Stream API.


88-95: Consider adding unknownEnumValue handling for robust enum deserialization

The past review comment about adding unknownEnumValue handling for enum fields is a good defensive programming practice that should be considered to prevent crashes when the API returns new enum values in the future.

🧹 Nitpick comments (2)
packages/stream_chat/test/src/db/chat_persistence_client_test.dart (2)

253-256: Await the async call or make the test sync

The test body is async but the Future from updateChannelState isn’t awaited. Prefer awaiting to ensure the operation completes before the test ends (or drop async if not needed).

Option A (await the call):

-    test('updateChannelState', () async {
-      const channelState = ChannelState();
-      persistenceClient.updateChannelState(channelState);
-    });
+    test('updateChannelState', () async {
+      const channelState = ChannelState();
+      await persistenceClient.updateChannelState(channelState);
+    });

Option B (make test synchronous if the method is sync):

-    test('updateChannelState', () async {
+    test('updateChannelState', () {
       const channelState = ChannelState();
       persistenceClient.updateChannelState(channelState);
     });

253-256: Add coverage for pushPreferences in ChannelState

Given the PR adds ChannelState.pushPreferences, consider extending this or the updateChannelStates test to include a ChannelState with pushPreferences populated to exercise persistence/serialization pathways.

Happy to draft a test snippet once the final shape of ChannelPushPreference and related enums is confirmed.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69236ca and 9e926c9.

📒 Files selected for processing (22)
  • packages/stream_chat/CHANGELOG.md (1 hunks)
  • packages/stream_chat/lib/src/client/channel.dart (1 hunks)
  • packages/stream_chat/lib/src/client/client.dart (3 hunks)
  • packages/stream_chat/lib/src/core/api/device_api.dart (2 hunks)
  • packages/stream_chat/lib/src/core/api/responses.dart (2 hunks)
  • packages/stream_chat/lib/src/core/api/responses.g.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/channel_state.dart (6 hunks)
  • packages/stream_chat/lib/src/core/models/channel_state.g.dart (2 hunks)
  • packages/stream_chat/lib/src/core/models/own_user.dart (7 hunks)
  • packages/stream_chat/lib/src/core/models/own_user.g.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/push_preference.dart (1 hunks)
  • packages/stream_chat/lib/src/core/models/push_preference.g.dart (1 hunks)
  • packages/stream_chat/lib/stream_chat.dart (1 hunks)
  • packages/stream_chat/test/fixtures/channel_state_to_json.json (1 hunks)
  • packages/stream_chat/test/src/core/api/device_api_test.dart (1 hunks)
  • packages/stream_chat/test/src/core/api/responses_test.dart (1 hunks)
  • packages/stream_chat/test/src/core/models/channel_state_test.dart (1 hunks)
  • packages/stream_chat/test/src/core/models/push_preference_test.dart (1 hunks)
  • packages/stream_chat/test/src/db/chat_persistence_client_test.dart (1 hunks)
  • packages/stream_chat_flutter/test/src/mocks.dart (1 hunks)
  • packages/stream_chat_flutter_core/test/message_list_core_test.dart (1 hunks)
  • packages/stream_chat_flutter_core/test/stream_channel_test.dart (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (18)
  • packages/stream_chat/test/src/core/api/device_api_test.dart
  • packages/stream_chat/lib/src/core/api/device_api.dart
  • packages/stream_chat/test/fixtures/channel_state_to_json.json
  • packages/stream_chat/test/src/core/api/responses_test.dart
  • packages/stream_chat/lib/src/core/models/push_preference.g.dart
  • packages/stream_chat/lib/stream_chat.dart
  • packages/stream_chat/lib/src/core/api/responses.g.dart
  • packages/stream_chat_flutter_core/test/message_list_core_test.dart
  • packages/stream_chat_flutter/test/src/mocks.dart
  • packages/stream_chat/lib/src/client/channel.dart
  • packages/stream_chat/CHANGELOG.md
  • packages/stream_chat_flutter_core/test/stream_channel_test.dart
  • packages/stream_chat/lib/src/core/api/responses.dart
  • packages/stream_chat/lib/src/core/models/channel_state.g.dart
  • packages/stream_chat/lib/src/core/models/own_user.dart
  • packages/stream_chat/lib/src/core/models/own_user.g.dart
  • packages/stream_chat/lib/src/client/client.dart
  • packages/stream_chat/lib/src/core/models/channel_state.dart
⏰ 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)
  • GitHub Check: stream_chat_flutter
  • GitHub Check: stream_chat
  • GitHub Check: stream_chat_localizations
  • GitHub Check: stream_chat_flutter_core
  • GitHub Check: stream_chat_persistence
  • GitHub Check: analyze_legacy_versions
  • GitHub Check: build (ios)
  • GitHub Check: analyze
  • GitHub Check: build (android)
  • GitHub Check: test
🔇 Additional comments (4)
packages/stream_chat/test/src/db/chat_persistence_client_test.dart (1)

254-254: LGTM on using const ChannelState()

This aligns with the const constructor for ChannelState and encourages immutability and canonicalization.

packages/stream_chat/test/src/core/models/push_preference_test.dart (1)

1-103: Excellent test coverage for push preference models

The test suite provides comprehensive coverage of all three push preference models:

  • Thorough serialization testing for both user-level and channel-specific preferences
  • Proper verification of enum handling including default values
  • DateTime serialization/deserialization testing
  • Good test organization with logical grouping

The tests correctly verify JSON field naming (snake_case) and cover all the key use cases for the push preference functionality.

packages/stream_chat/lib/src/core/models/push_preference.dart (2)

7-31: Well-designed extension types for type-safe enums

The use of extension types for ChatLevel and CallLevel provides excellent type safety while maintaining String compatibility. The enum values are well-chosen:

  • ChatLevel: all, none, mentions, defaultValue
  • CallLevel: all, none, defaultValue (appropriately excludes mentions)

This approach is more type-safe than plain String constants and integrates well with JSON serialization.


36-72: Good design for flexible preference input

The PushPreferenceInput class design is well thought out:

  • Default constructor for user-level preferences
  • Named .channel() constructor for channel-specific preferences
  • Appropriate field validation through the constructor design
  • createFactory: false is correct since this is input-only

The API design makes it clear when you're setting user vs channel preferences.

@xsahil03x xsahil03x merged commit 21206e8 into master Aug 11, 2025
19 checks passed
@xsahil03x xsahil03x deleted the feat/upsert-push-preferences branch August 11, 2025 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add upsertPushPreferences method to the client
2 participants