Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/stream_chat/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
an `User` instance.
- Fixed `Client.currentUser` specific fields getting reset on `user.updated` events.

✅ Added

- Added support for `Client.setPushPreferences` which allows setting PushPreferences for the
current user or for a specific channel.

## 9.15.0

✅ Added
Expand Down
1 change: 1 addition & 0 deletions packages/stream_chat/lib/src/client/channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3320,6 +3320,7 @@ class ChannelClientState {
read: newReads,
draft: updatedState.draft,
pinnedMessages: updatedState.pinnedMessages,
pushPreferences: updatedState.pushPreferences,
);
}

Expand Down
50 changes: 50 additions & 0 deletions packages/stream_chat/lib/src/client/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import 'package:stream_chat/src/core/models/own_user.dart';
import 'package:stream_chat/src/core/models/poll.dart';
import 'package:stream_chat/src/core/models/poll_option.dart';
import 'package:stream_chat/src/core/models/poll_vote.dart';
import 'package:stream_chat/src/core/models/push_preference.dart';
import 'package:stream_chat/src/core/models/thread.dart';
import 'package:stream_chat/src/core/models/user.dart';
import 'package:stream_chat/src/core/util/utils.dart';
Expand Down Expand Up @@ -989,6 +990,54 @@ class StreamChatClient {
Future<EmptyResponse> removeDevice(String id) =>
_chatApi.device.removeDevice(id);

/// Set push preferences for the current user.
///
/// This method allows you to configure push notification settings
/// at both global and channel-specific levels.
///
/// [preferences] - List of push preferences to apply
///
/// Returns [UpsertPushPreferencesResponse] with the updated preferences.
///
/// Example:
/// ```dart
/// // Set global push preferences
/// await client.setPushPreferences([
/// const PushPreferenceInput(
/// chatLevel: ChatLevelPushPreference.mentions,
/// callLevel: CallLevelPushPreference.all,
/// ),
/// ]);
///
/// // Set channel-specific preferences
/// await client.setPushPreferences([
/// const PushPreferenceInput.channel(
/// channelCid: 'messaging:general',
/// chatLevel: ChatLevelPushPreference.none,
/// ),
/// const PushPreferenceInput.channel(
/// channelCid: 'messaging:support',
/// chatLevel: ChatLevelPushPreference.mentions,
/// ),
/// ]);
///
/// // Mix global and channel-specific preferences
/// await client.setPushPreferences([
/// const PushPreferenceInput(
/// chatLevel: ChatLevelPushPreference.all,
/// ), // Global default
/// const PushPreferenceInput.channel(
/// channelCid: 'messaging:spam',
/// chatLevel: ChatLevelPushPreference.none,
/// ),
/// ]);
/// ```
Future<UpsertPushPreferencesResponse> setPushPreferences(
List<PushPreferenceInput> preferences,
) {
return _chatApi.device.setPushPreferences(preferences);
}

/// Get a development token
Token devToken(String userId) => Token.development(userId);

Expand Down Expand Up @@ -2139,6 +2188,7 @@ class ClientState {
unreadChannels: currentUser?.unreadChannels,
unreadThreads: currentUser?.unreadThreads,
blockedUserIds: currentUser?.blockedUserIds,
pushPreferences: currentUser?.pushPreferences,
);
}

Expand Down
33 changes: 33 additions & 0 deletions packages/stream_chat/lib/src/core/api/device_api.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import 'dart:convert';

import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
import 'package:stream_chat/src/core/models/push_preference.dart';

/// Provider used to send push notifications.
enum PushProvider {
Expand Down Expand Up @@ -57,4 +60,34 @@ class DeviceApi {
);
return EmptyResponse.fromJson(response.data);
}

/// Set push preferences for the current user.
///
/// This method allows you to configure push notification settings
/// at both global and channel-specific levels.
///
/// [preferences] - List of [PushPreferenceInput] to apply. Use the default
/// constructor for user-level preferences or [PushPreferenceInput.channel]
/// for channel-specific preferences.
///
/// Returns [UpsertPushPreferencesResponse] with the updated preferences.
///
/// Throws [ArgumentError] if preferences list is empty.
Future<UpsertPushPreferencesResponse> setPushPreferences(
List<PushPreferenceInput> preferences,
) async {
if (preferences.isEmpty) {
throw ArgumentError.value(
preferences,
'preferences',
'Cannot be empty. At least one preference must be provided.',
);
}

final response = await _client.post(
'/push_preferences',
data: jsonEncode({'preferences': preferences}),
);
return UpsertPushPreferencesResponse.fromJson(response.data);
}
}
17 changes: 17 additions & 0 deletions packages/stream_chat/lib/src/core/api/responses.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:stream_chat/src/core/models/message_reminder.dart';
import 'package:stream_chat/src/core/models/poll.dart';
import 'package:stream_chat/src/core/models/poll_option.dart';
import 'package:stream_chat/src/core/models/poll_vote.dart';
import 'package:stream_chat/src/core/models/push_preference.dart';
import 'package:stream_chat/src/core/models/reaction.dart';
import 'package:stream_chat/src/core/models/read.dart';
import 'package:stream_chat/src/core/models/thread.dart';
Expand Down Expand Up @@ -829,3 +830,19 @@ class GetUnreadCountResponse extends _BaseResponse {
static GetUnreadCountResponse fromJson(Map<String, dynamic> json) =>
_$GetUnreadCountResponseFromJson(json);
}

/// Model response for [StreamChatClient.setPushPreferences] api call
@JsonSerializable(createToJson: false)
class UpsertPushPreferencesResponse extends _BaseResponse {
/// Mapping of user IDs to their push preferences
@JsonKey(defaultValue: {})
late Map<String, PushPreference> userPreferences;

/// Mapping of user IDs to their channel-specific push preferences
@JsonKey(defaultValue: {})
late Map<String, Map<String, ChannelPushPreference>> userChannelPreferences;

/// Create a new instance from a json
static UpsertPushPreferencesResponse fromJson(Map<String, dynamic> json) =>
_$UpsertPushPreferencesResponseFromJson(json);
}
23 changes: 23 additions & 0 deletions packages/stream_chat/lib/src/core/api/responses.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion packages/stream_chat/lib/src/core/models/channel_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:stream_chat/src/core/models/comparable_field.dart';
import 'package:stream_chat/src/core/models/draft.dart';
import 'package:stream_chat/src/core/models/member.dart';
import 'package:stream_chat/src/core/models/message.dart';
import 'package:stream_chat/src/core/models/push_preference.dart';
import 'package:stream_chat/src/core/models/read.dart';
import 'package:stream_chat/src/core/models/user.dart';

Expand All @@ -19,7 +20,7 @@ const _nullConst = _NullConst();
@JsonSerializable()
class ChannelState implements ComparableFieldProvider {
/// Constructor used for json serialization
ChannelState({
const ChannelState({
this.channel,
this.messages,
this.members,
Expand All @@ -29,6 +30,7 @@ class ChannelState implements ComparableFieldProvider {
this.read,
this.membership,
this.draft,
this.pushPreferences,
});

/// The channel to which this state belongs
Expand Down Expand Up @@ -58,6 +60,9 @@ class ChannelState implements ComparableFieldProvider {
/// The draft message for this channel if it exists.
final Draft? draft;

/// The push preferences for this channel if it exists.
final ChannelPushPreference? pushPreferences;

/// Create a new instance from a json
static ChannelState fromJson(Map<String, dynamic> json) =>
_$ChannelStateFromJson(json);
Expand All @@ -76,6 +81,7 @@ class ChannelState implements ComparableFieldProvider {
List<Read>? read,
Member? membership,
Object? draft = _nullConst,
ChannelPushPreference? pushPreferences,
}) =>
ChannelState(
channel: channel ?? this.channel,
Expand All @@ -87,6 +93,7 @@ class ChannelState implements ComparableFieldProvider {
read: read ?? this.read,
membership: membership ?? this.membership,
draft: draft == _nullConst ? this.draft : draft as Draft?,
pushPreferences: pushPreferences ?? this.pushPreferences,
);

@override
Expand Down
5 changes: 5 additions & 0 deletions packages/stream_chat/lib/src/core/models/channel_state.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions packages/stream_chat/lib/src/core/models/own_user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class OwnUser extends User {
this.channelMutes = const [],
this.unreadThreads = 0,
this.blockedUserIds = const [],
this.pushPreferences,
required super.id,
super.role,
super.name,
Expand Down Expand Up @@ -68,6 +69,7 @@ class OwnUser extends User {
unreadChannels: user.extraData['unread_channels'].safeCast(),
unreadThreads: user.extraData['unread_threads'].safeCast(),
blockedUserIds: user.extraData['blocked_user_ids'].safeCast(),
pushPreferences: user.extraData['push_preferences'].safeCast(),
);

// Once we are done working with the extraData, we have to clean it up
Expand Down Expand Up @@ -112,6 +114,7 @@ class OwnUser extends User {
String? language,
Map<String, String>? teamsRole,
int? avgResponseTime,
PushPreference? pushPreferences,
}) =>
OwnUser(
id: id ?? this.id,
Expand Down Expand Up @@ -139,6 +142,7 @@ class OwnUser extends User {
language: language ?? this.language,
teamsRole: teamsRole ?? this.teamsRole,
avgResponseTime: avgResponseTime ?? this.avgResponseTime,
pushPreferences: pushPreferences ?? this.pushPreferences,
);

/// Returns a new [OwnUser] that is a combination of this ownUser
Expand Down Expand Up @@ -168,6 +172,7 @@ class OwnUser extends User {
language: other.language,
teamsRole: other.teamsRole,
avgResponseTime: other.avgResponseTime,
pushPreferences: other.pushPreferences,
);
}

Expand Down Expand Up @@ -199,6 +204,10 @@ class OwnUser extends User {
@JsonKey(includeIfNull: false)
final List<String> blockedUserIds;

/// Push preferences for the user if set.
@JsonKey(includeIfNull: false)
final PushPreference? pushPreferences;

/// Known top level fields.
///
/// Useful for [Serializer] methods.
Expand All @@ -210,6 +219,7 @@ class OwnUser extends User {
'channel_mutes',
'unread_threads',
'blocked_user_ids',
'push_preferences',
...User.topLevelFields,
];
}
4 changes: 4 additions & 0 deletions packages/stream_chat/lib/src/core/models/own_user.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading