Merge branch 'develop' into develop

This commit is contained in:
Simon Eckerstorfer
2022-02-18 17:09:30 +01:00
committed by GitHub
11 changed files with 177 additions and 21 deletions
+10 -4
View File
@@ -2,20 +2,26 @@
✅ Added ✅ Added
- You can now pass `score` to `client.sendReaction` and `channel.sendReaction` functions - You can now pass `score` to `client.sendReaction` and `channel.sendReaction` functions.
- Added new `client.partialUpdateUsers` function in order to partially update users.
🐞 Fixed 🐞 Fixed
- [[#890]](https://github.com/GetStream/stream-chat-flutter/pull/890). Fixed Reactions not updating on thread messages. Thanks [bstolinski](https://github.com/bstolinski). - [[#890]](https://github.com/GetStream/stream-chat-flutter/pull/890) Fixed Reactions not updating on thread messages.
Thanks [bstolinski](https://github.com/bstolinski).
- [[#897]](https://github.com/GetStream/stream-chat-flutter/issues/897) Fixed error type mis-match in `AuthInterceptor`.
## 3.4.0 ## 3.4.0
🐞 Fixed 🐞 Fixed
- [[#857]](https://github.com/GetStream/stream-chat-flutter/issues/857) Channel now listens for member ban/unban and - [[#857]](https://github.com/GetStream/stream-chat-flutter/issues/857) Channel now listens for member ban/unban and
updates the channel state with the latest data. updates the channel state with the latest data.
- [[#748]](https://github.com/GetStream/stream-chat-flutter/issues/748) `Message.user` is now also included while saving users in persistence. - [[#748]](https://github.com/GetStream/stream-chat-flutter/issues/748) `Message.user` is now also included while saving
users in persistence.
- [[#871]](https://github.com/GetStream/stream-chat-flutter/issues/871) Fixed thread message deletion. - [[#871]](https://github.com/GetStream/stream-chat-flutter/issues/871) Fixed thread message deletion.
- [[#846]](https://github.com/GetStream/stream-chat-flutter/issues/846) Fixed `message.ownReactions` getting truncated when receiving a reaction event. - [[#846]](https://github.com/GetStream/stream-chat-flutter/issues/846) Fixed `message.ownReactions` getting truncated
when receiving a reaction event.
- Add check for invalid image URLs - Add check for invalid image URLs
- Fix `channelState.pinnedMessagesStream` getting reset to `0` after a channel update. - Fix `channelState.pinnedMessagesStream` getting reset to `0` after a channel update.
- Fixed `unreadCount` after removing user from a channel. - Fixed `unreadCount` after removing user from a channel.
@@ -1073,6 +1073,28 @@ class StreamChatClient {
Future<UpdateUsersResponse> updateUsers(List<User> users) => Future<UpdateUsersResponse> updateUsers(List<User> users) =>
_chatApi.user.updateUsers(users); _chatApi.user.updateUsers(users);
/// Partially update the given user with [id].
/// Use [set] to define values to be set.
/// Use [unset] to define values to be unset.
Future<UpdateUsersResponse> partialUpdateUser(
String id, {
Map<String, Object?>? set,
List<String>? unset,
}) {
final user = PartialUpdateUserRequest(
id: id,
set: set,
unset: unset,
);
return partialUpdateUsers([user]);
}
/// Batch partial updates the [users].
Future<UpdateUsersResponse> partialUpdateUsers(
List<PartialUpdateUserRequest> users,
) =>
_chatApi.user.partialUpdateUsers(users);
/// Bans a user from all channels /// Bans a user from all channels
Future<EmptyResponse> banUser( Future<EmptyResponse> banUser(
String targetUserId, [ String targetUserId, [
@@ -156,3 +156,29 @@ class PaginationParams extends Equatable {
lessThanOrEqual, lessThanOrEqual,
]; ];
} }
/// Request model for the [client.partialUpdateUser] api call.
@JsonSerializable(createFactory: false)
class PartialUpdateUserRequest extends Equatable {
/// Creates a new PartialUpdateUserRequest instance.
const PartialUpdateUserRequest({
required this.id,
this.set,
this.unset,
});
/// User ID.
final String id;
/// Fields to set.
final Map<String, Object?>? set;
/// Fields to unset.
final List<String>? unset;
/// Serialize model to json
Map<String, dynamic> toJson() => _$PartialUpdateUserRequestToJson(this);
@override
List<Object?> get props => [id, set, unset];
}
@@ -54,3 +54,14 @@ Map<String, dynamic> _$PaginationParamsToJson(PaginationParams instance) {
writeNotNull('id_lte', instance.lessThanOrEqual); writeNotNull('id_lte', instance.lessThanOrEqual);
return val; return val;
} }
Map<String, dynamic> _$PartialUpdateUserRequestToJson(
PartialUpdateUserRequest instance) =>
<String, dynamic>{
'stringify': instance.stringify,
'hash_code': instance.hashCode,
'id': instance.id,
'set': instance.set,
'unset': instance.unset,
'props': instance.props,
};
@@ -46,4 +46,17 @@ class UserApi {
); );
return UpdateUsersResponse.fromJson(response.data); return UpdateUsersResponse.fromJson(response.data);
} }
/// Batch partial update of [users].
Future<UpdateUsersResponse> partialUpdateUsers(
List<PartialUpdateUserRequest> users,
) async {
final response = await _client.patch(
'/users',
data: {
'users': users,
},
);
return UpdateUsersResponse.fromJson(response.data);
}
} }
@@ -49,10 +49,13 @@ class AuthInterceptor extends Interceptor {
DioError err, DioError err,
ErrorInterceptorHandler handler, ErrorInterceptorHandler handler,
) async { ) async {
ErrorResponse? error;
final data = err.response?.data; final data = err.response?.data;
if (data != null) error = ErrorResponse.fromJson(data); if (data == null || data is! Map<String, dynamic>) {
if (error?.code == ChatErrorCode.tokenExpired.code) { return handler.next(err);
}
final error = ErrorResponse.fromJson(data);
if (error.code == ChatErrorCode.tokenExpired.code) {
if (_tokenManager.isStatic) return handler.next(err); if (_tokenManager.isStatic) return handler.next(err);
_client.lock(); _client.lock();
await _tokenManager.loadToken(refresh: true); await _tokenManager.loadToken(refresh: true);
@@ -21,7 +21,7 @@ ChannelState _$ChannelStateFromJson(Map<String, dynamic> json) => ChannelState(
pinnedMessages: (json['pinned_messages'] as List<dynamic>?) pinnedMessages: (json['pinned_messages'] as List<dynamic>?)
?.map((e) => Message.fromJson(e as Map<String, dynamic>)) ?.map((e) => Message.fromJson(e as Map<String, dynamic>))
.toList() ?? .toList() ??
const [], _emptyPinnedMessages,
watcherCount: json['watcher_count'] as int?, watcherCount: json['watcher_count'] as int?,
watchers: (json['watchers'] as List<dynamic>?) watchers: (json['watchers'] as List<dynamic>?)
?.map((e) => User.fromJson(e as Map<String, dynamic>)) ?.map((e) => User.fromJson(e as Map<String, dynamic>))
@@ -1772,6 +1772,46 @@ void main() {
verifyNoMoreInteractions(api.user); verifyNoMoreInteractions(api.user);
}); });
test('`.partialUpdateUser`', () async {
const userId = 'test-user-id';
final set = {'color': 'yellow'};
final unset = <String>[];
final partialUpdateRequest = PartialUpdateUserRequest(
id: userId,
set: set,
unset: unset,
);
final updatedUser = User(
id: userId,
extraData: {'color': set['color']},
);
when(() => api.user.partialUpdateUsers([partialUpdateRequest]))
.thenAnswer(
(_) async => UpdateUsersResponse()
..users = {
updatedUser.id: updatedUser,
},
);
final res = await client.partialUpdateUser(
userId,
set: set,
unset: unset,
);
expect(res, isNotNull);
expect(res.users, {updatedUser.id: updatedUser});
verify(
() => api.user.partialUpdateUsers([partialUpdateRequest]),
).called(1);
verifyNoMoreInteractions(api.user);
});
test('`.banUser`', () async { test('`.banUser`', () async {
const userId = 'test-user-id'; const userId = 'test-user-id';
@@ -82,4 +82,37 @@ void main() {
verify(() => client.post(path, data: any(named: 'data'))).called(1); verify(() => client.post(path, data: any(named: 'data'))).called(1);
verifyNoMoreInteractions(client); verifyNoMoreInteractions(client);
}); });
test('partialUpdateUsers', () async {
const user = PartialUpdateUserRequest(
id: 'test-user-id',
set: {'color': 'yellow'},
);
const path = '/users';
final updatedUser = {user.id: User(id: user.id, extraData: user.set!)};
when(() => client.patch(path, data: {
'users': [user],
})).thenAnswer(
(_) async => successResponse(
path,
data: {
'users':
updatedUser.map((key, value) => MapEntry(key, value.toJson()))
},
),
);
final res = await userApi.partialUpdateUsers([user]);
expect(res, isNotNull);
expect(res.users.length, updatedUser.length);
verify(() => client.patch(path, data: {
'users': [user]
})).called(1);
verifyNoMoreInteractions(client);
});
} }
@@ -4,6 +4,7 @@
- [[#888]](https://github.com/GetStream/stream-chat-flutter/issues/888) Fix `unban` command not working in `MessageInput`. - [[#888]](https://github.com/GetStream/stream-chat-flutter/issues/888) Fix `unban` command not working in `MessageInput`.
- [[#805]](https://github.com/GetStream/stream-chat-flutter/issues/805) Updated chewie dependency version to 1.3.0 - [[#805]](https://github.com/GetStream/stream-chat-flutter/issues/805) Updated chewie dependency version to 1.3.0
- Fix `showScrollToBottom` in `MessageListView` not respecting false value.
## 3.4.0 ## 3.4.0
- Updated `stream_chat_flutter_core` dependency to [`3.4.0`](https://pub.dev/packages/stream_chat_flutter_core/changelog). - Updated `stream_chat_flutter_core` dependency to [`3.4.0`](https://pub.dev/packages/stream_chat_flutter_core/changelog).
@@ -712,20 +712,21 @@ class _MessageListViewState extends State<MessageListView> {
); );
}, },
), ),
BetterStreamBuilder<bool>( if (widget.showScrollToBottom)
stream: streamChannel!.channel.state!.isUpToDateStream, BetterStreamBuilder<bool>(
initialData: streamChannel!.channel.state!.isUpToDate, stream: streamChannel!.channel.state!.isUpToDateStream,
builder: (context, snapshot) => ValueListenableBuilder<bool>( initialData: streamChannel!.channel.state!.isUpToDate,
valueListenable: _showScrollToBottom, builder: (context, snapshot) => ValueListenableBuilder<bool>(
child: _buildScrollToBottom(), valueListenable: _showScrollToBottom,
builder: (context, value, child) { child: _buildScrollToBottom(),
if (!snapshot || value) { builder: (context, value, child) {
return child!; if (!snapshot || value) {
} return child!;
return const Offstage(); }
}, return const Offstage();
},
),
), ),
),
if (widget.showFloatingDateDivider) if (widget.showFloatingDateDivider)
_buildFloatingDateDivider(itemCount), _buildFloatingDateDivider(itemCount),
], ],