Skip to content

Commit 00c0b15

Browse files
committed
Merge remote-tracking branch 'origin/master' into v10.0.0
# Conflicts: # packages/stream_chat_persistence/CHANGELOG.md # packages/stream_chat_persistence/lib/src/db/drift_chat_database.dart
2 parents 84b2994 + b82ce14 commit 00c0b15

File tree

16 files changed

+143
-16
lines changed

16 files changed

+143
-16
lines changed

packages/stream_chat/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111

1212
## Upcoming
1313

14+
✅ Added
15+
16+
- Added `avgResponseTime` field to the `User` model to track average response time in seconds.
17+
1418
🐞 Fixed
1519

1620
- Fixed `WebSocket` race condition where reconnection could access null user during disconnect.

packages/stream_chat/lib/src/core/models/own_user.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class OwnUser extends User {
3232
super.teams,
3333
super.language,
3434
super.teamsRole,
35+
super.avgResponseTime,
3536
});
3637

3738
/// Create a new instance from json.
@@ -55,6 +56,7 @@ class OwnUser extends User {
5556
teams: user.teams,
5657
language: user.language,
5758
teamsRole: user.teamsRole,
59+
avgResponseTime: user.avgResponseTime,
5860
);
5961

6062
/// Creates a copy of [OwnUser] with specified attributes overridden.
@@ -81,6 +83,7 @@ class OwnUser extends User {
8183
int? unreadThreads,
8284
String? language,
8385
Map<String, String>? teamsRole,
86+
int? avgResponseTime,
8487
}) =>
8588
OwnUser(
8689
id: id ?? this.id,
@@ -107,6 +110,7 @@ class OwnUser extends User {
107110
blockedUserIds: blockedUserIds ?? this.blockedUserIds,
108111
language: language ?? this.language,
109112
teamsRole: teamsRole ?? this.teamsRole,
113+
avgResponseTime: avgResponseTime ?? this.avgResponseTime,
110114
);
111115

112116
/// Returns a new [OwnUser] that is a combination of this ownUser
@@ -135,6 +139,7 @@ class OwnUser extends User {
135139
updatedAt: other.updatedAt,
136140
language: other.language,
137141
teamsRole: other.teamsRole,
142+
avgResponseTime: other.avgResponseTime,
138143
);
139144
}
140145

packages/stream_chat/lib/src/core/models/own_user.g.dart

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/stream_chat/lib/src/core/models/user.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class User extends Equatable implements ComparableFieldProvider {
4747
this.teams = const [],
4848
this.language,
4949
this.teamsRole,
50+
this.avgResponseTime,
5051
}) :
5152
// For backwards compatibility, set 'name', 'image' in [extraData].
5253
extraData = {
@@ -74,6 +75,7 @@ class User extends Equatable implements ComparableFieldProvider {
7475
'teams',
7576
'language',
7677
'teams_role',
78+
'avg_response_time',
7779
];
7880

7981
/// User id.
@@ -143,6 +145,10 @@ class User extends Equatable implements ComparableFieldProvider {
143145
@JsonKey(includeIfNull: false)
144146
final Map< /*Team*/ String, /*Role*/ String>? teamsRole;
145147

148+
/// The average response time of the user in seconds.
149+
@JsonKey(includeToJson: false)
150+
final int? avgResponseTime;
151+
146152
/// Map of custom user extraData.
147153
final Map<String, Object?> extraData;
148154

@@ -171,6 +177,7 @@ class User extends Equatable implements ComparableFieldProvider {
171177
List<String>? teams,
172178
String? language,
173179
Map<String, String>? teamsRole,
180+
int? avgResponseTime,
174181
}) =>
175182
User(
176183
id: id ?? this.id,
@@ -190,6 +197,7 @@ class User extends Equatable implements ComparableFieldProvider {
190197
teams: teams ?? this.teams,
191198
language: language ?? this.language,
192199
teamsRole: teamsRole ?? this.teamsRole,
200+
avgResponseTime: avgResponseTime ?? this.avgResponseTime,
193201
);
194202

195203
@override
@@ -204,6 +212,7 @@ class User extends Equatable implements ComparableFieldProvider {
204212
teams,
205213
language,
206214
teamsRole,
215+
avgResponseTime,
207216
];
208217

209218
@override

packages/stream_chat/lib/src/core/models/user.g.dart

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/stream_chat/test/fixtures/user.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@
1313
"created_at": "2021-08-03 12:39:21.817646",
1414
"updated_at": "2021-08-04 12:39:21.817646",
1515
"last_active" : "2021-08-05 12:39:21.817646",
16-
"language": "en"
16+
"language": "en",
17+
"teams_role": {"team-1": "admin", "team-2": "member"},
18+
"avg_response_time": 120
1719
}

packages/stream_chat/test/src/core/models/user_test.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ void main() {
1818
const online = true;
1919
const banned = true;
2020
const teams = ['team-1', 'team-2'];
21+
const teamsRole = {'team-1': 'admin', 'team-2': 'member'};
22+
const avgResponseTime = 120;
2123
const createdAtString = '2021-08-03 12:39:21.817646';
2224
const updatedAtString = '2021-08-04 12:39:21.817646';
2325
const lastActiveString = '2021-08-05 12:39:21.817646';
@@ -41,6 +43,8 @@ void main() {
4143
expect(user.updatedAt, DateTime.parse(updatedAtString));
4244
expect(user.lastActive, DateTime.parse(lastActiveString));
4345
expect(user.language, 'en');
46+
expect(user.teamsRole, teamsRole);
47+
expect(user.avgResponseTime, avgResponseTime);
4448
});
4549

4650
test('should serialize to json correctly', () {
@@ -62,6 +66,8 @@ void main() {
6266
online: banned,
6367
teams: const ['team-1', 'team-2'],
6468
language: 'fr',
69+
teamsRole: teamsRole,
70+
avgResponseTime: avgResponseTime,
6571
);
6672

6773
expect(user.toJson(), {
@@ -73,6 +79,7 @@ void main() {
7379
'extraDataDoubleTest': extraDataDoubleTest,
7480
'extraDataBoolTest': extraDataBoolTest,
7581
'language': 'fr',
82+
'teams_role': teamsRole,
7683
});
7784
});
7885

@@ -91,6 +98,8 @@ void main() {
9198
expect(newUser.updatedAt, user.updatedAt);
9299
expect(newUser.lastActive, user.lastActive);
93100
expect(newUser.language, user.language);
101+
expect(newUser.teamsRole, user.teamsRole);
102+
expect(newUser.avgResponseTime, user.avgResponseTime);
94103

95104
newUser = user.copyWith(
96105
id: 'test',
@@ -104,6 +113,8 @@ void main() {
104113
updatedAt: DateTime.parse('2021-05-04 12:39:21.817646'),
105114
lastActive: DateTime.parse('2021-05-06 12:39:21.817646'),
106115
language: 'it',
116+
teamsRole: {'new-team1': 'admin', 'new-team2': 'member'},
117+
avgResponseTime: 60,
107118
);
108119

109120
expect(newUser.id, 'test');
@@ -118,6 +129,8 @@ void main() {
118129
expect(newUser.updatedAt, DateTime.parse('2021-05-04 12:39:21.817646'));
119130
expect(newUser.lastActive, DateTime.parse('2021-05-06 12:39:21.817646'));
120131
expect(newUser.language, 'it');
132+
expect(newUser.teamsRole, {'new-team1': 'admin', 'new-team2': 'member'});
133+
expect(newUser.avgResponseTime, 60);
121134
});
122135

123136
test('name property and extraData manipulation', () {
@@ -202,6 +215,8 @@ void main() {
202215
expect(user.lastActive, null);
203216
expect(user.createdAt, null);
204217
expect(user.updatedAt, null);
218+
expect(user.teamsRole, null);
219+
expect(user.avgResponseTime, null);
205220
});
206221

207222
test('default values, parse json', () {
@@ -218,6 +233,8 @@ void main() {
218233
expect(user.lastActive, null);
219234
expect(user.createdAt, null);
220235
expect(user.updatedAt, null);
236+
expect(user.teamsRole, null);
237+
expect(user.avgResponseTime, null);
221238
});
222239

223240
group('ComparableFieldProvider', () {
@@ -449,6 +466,8 @@ User createTestUser({
449466
bool? banned,
450467
DateTime? lastActive,
451468
Map<String, Object?>? extraData,
469+
Map<String, String>? teamsRole,
470+
int? avgResponseTime,
452471
}) {
453472
return User(
454473
id: id,
@@ -457,5 +476,7 @@ User createTestUser({
457476
banned: banned ?? false,
458477
lastActive: lastActive,
459478
extraData: extraData ?? {},
479+
teamsRole: teamsRole,
480+
avgResponseTime: avgResponseTime,
460481
);
461482
}

packages/stream_chat_flutter_core/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
- Fixed `MessageListCore.dispose()` crash when channel reload fails due to insufficient permissions.
1111
- Fixed incorrect parent message comparison in `MessageListCore.didUpdateWidget()`.
12+
- Ensure `StreamChannel` future builder completes after channel
13+
initialization. [[#2323]](https://github.com/GetStream/stream-chat-flutter/issues/2323)
1214

1315
## 10.0.0-beta.3
1416

packages/stream_chat_flutter_core/lib/src/stream_channel.dart

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,24 @@ class StreamChannel extends StatefulWidget {
8181
StackTrace? stackTrace,
8282
) {
8383
final backgroundColor = _getDefaultBackgroundColor(context);
84+
85+
Object? unwrapParallelError(Object error) {
86+
if (error case ParallelWaitError(:final List<AsyncError?> errors)) {
87+
return errors.firstWhereOrNull((it) => it != null)?.error;
88+
}
89+
90+
return error;
91+
}
92+
93+
final exception = unwrapParallelError(error);
8494
return Material(
8595
color: backgroundColor,
8696
child: Center(
87-
child: switch (error) {
97+
child: switch (exception) {
8898
DioException(type: DioExceptionType.badResponse) =>
89-
Text(error.message ?? 'Bad response'),
99+
Text(exception.message ?? 'Bad response'),
90100
DioException() => const Text('Check your connection and retry'),
91-
_ => Text(error.toString()),
101+
_ => Text(exception.toString()),
92102
},
93103
),
94104
);
@@ -728,12 +738,12 @@ class StreamChannelState extends State<StreamChannel> {
728738
if (channel.state?.isUpToDate == false) return loadChannelAtMessage(null);
729739
}
730740

731-
late Future<void> _channelInitFuture;
741+
late Future<List<void>> _channelInitFuture;
732742

733743
@override
734744
void initState() {
735745
super.initState();
736-
_channelInitFuture = _maybeInitChannel();
746+
_channelInitFuture = [_maybeInitChannel(), channel.initialized].wait;
737747
}
738748

739749
@override
@@ -742,7 +752,7 @@ class StreamChannelState extends State<StreamChannel> {
742752
if (oldWidget.channel.cid != widget.channel.cid ||
743753
oldWidget.initialMessageId != widget.initialMessageId) {
744754
// Re-initialize channel if the channel CID or initial message ID changes.
745-
_channelInitFuture = _maybeInitChannel();
755+
_channelInitFuture = [_maybeInitChannel(), channel.initialized].wait;
746756
}
747757
}
748758

packages/stream_chat_flutter_core/test/message_list_core_test.dart

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ void main() {
9292
);
9393

9494
final mockChannel = MockChannel();
95-
when(() => mockChannel.initialized).thenAnswer((_) => Future.value(true));
9695
when(() => mockChannel.state.unreadCount).thenReturn(0);
9796
when(() => mockChannel.state.isUpToDate).thenReturn(true);
9897
when(() => mockChannel.state.messagesStream)
@@ -135,7 +134,6 @@ void main() {
135134
when(() => mockChannel.state.messagesStream)
136135
.thenAnswer((_) => Stream.value([]));
137136
when(() => mockChannel.state.messages).thenReturn([]);
138-
when(() => mockChannel.initialized).thenAnswer((_) => Future.value(true));
139137

140138
await tester.pumpWidget(
141139
StreamChannel(
@@ -178,7 +176,6 @@ void main() {
178176
when(() => mockChannel.state.messagesStream)
179177
.thenAnswer((_) => Stream.value(messages));
180178
when(() => mockChannel.state.messages).thenReturn(messages);
181-
when(() => mockChannel.initialized).thenAnswer((_) => Future.value(true));
182179

183180
await tester.pumpWidget(
184181
StreamChannel(
@@ -224,7 +221,6 @@ void main() {
224221
final mockChannel = MockChannel();
225222

226223
when(() => mockChannel.state.isUpToDate).thenReturn(true);
227-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
228224

229225
const error = 'Error! Error! Error!';
230226
when(() => mockChannel.state.messagesStream)
@@ -266,7 +262,6 @@ void main() {
266262
final mockChannel = MockChannel();
267263

268264
when(() => mockChannel.state.isUpToDate).thenReturn(true);
269-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
270265

271266
const messages = <Message>[];
272267
when(() => mockChannel.state.messagesStream)
@@ -307,7 +302,6 @@ void main() {
307302
final mockChannel = MockChannel();
308303

309304
when(() => mockChannel.state.isUpToDate).thenReturn(false);
310-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
311305
when(() => mockChannel.query(
312306
state: any(named: 'state'),
313307
watch: any(named: 'watch'),
@@ -362,7 +356,6 @@ void main() {
362356
final mockChannel = MockChannel();
363357

364358
when(() => mockChannel.state.isUpToDate).thenReturn(true);
365-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
366359

367360
final messages = _generateMessages();
368361
when(() => mockChannel.state.messagesStream)
@@ -411,7 +404,6 @@ void main() {
411404
final mockChannel = MockChannel();
412405

413406
when(() => mockChannel.state.isUpToDate).thenReturn(true);
414-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
415407

416408
final threads = {parentMessage.id: messages};
417409

0 commit comments

Comments
 (0)