Skip to content

Commit 2448e9a

Browse files
authored
feat(llc, core, ui, localization): threads v2 (#2076)
Co-authored-by: xsahil03x <[email protected]>
1 parent bc4126b commit 2448e9a

File tree

85 files changed

+3677
-495
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+3677
-495
lines changed

melos.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ command:
3737
http_parser: ^4.0.2
3838
image_gallery_saver_plus: ^3.0.5
3939
image_picker: ^1.1.2
40-
image_size_getter: ^2.1.3
40+
image_size_getter: ^2.3.0
4141
jiffy: ^6.2.1
4242
jose: ^0.3.4
4343
json_annotation: ^4.9.0

packages/stream_chat/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## Upcoming
2+
3+
✅ Added
4+
5+
- Added support for Threads v2 feature, which allows users to query all the threads.
6+
17
## 9.0.0
28

39
✅ Added

packages/stream_chat/lib/src/client/channel.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,18 @@ class Channel {
15191519
return response;
15201520
}
15211521

1522+
/// Mark the thread with [threadId] in the channel as read.
1523+
Future<EmptyResponse> markThreadRead(String threadId) {
1524+
_checkInitialized();
1525+
return client.markThreadRead(id!, type, threadId);
1526+
}
1527+
1528+
/// Mark the thread with [threadId] in the channel as unread.
1529+
Future<EmptyResponse> markThreadUnread(String threadId) {
1530+
_checkInitialized();
1531+
return client.markThreadUnread(id!, type, threadId);
1532+
}
1533+
15221534
void _initState(ChannelState channelState) {
15231535
state = ChannelClientState(this, channelState);
15241536

packages/stream_chat/lib/src/client/client.dart

Lines changed: 112 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ class StreamChatClient {
196196

197197
StreamSubscription<ConnectionStatus>? _connectionStatusSubscription;
198198

199-
final _eventController = BehaviorSubject<Event>();
199+
final _eventController = PublishSubject<Event>();
200200

201201
/// Stream of [Event] coming from [_ws] connection
202202
/// Listen to this or use the [on] method to filter specific event types
@@ -491,10 +491,12 @@ class StreamChatClient {
491491
final previousState = wsConnectionStatus;
492492
final currentState = _wsConnectionStatus = status;
493493

494-
handleEvent(Event(
495-
type: EventType.connectionChanged,
496-
online: status == ConnectionStatus.connected,
497-
));
494+
if (previousState != currentState) {
495+
handleEvent(Event(
496+
type: EventType.connectionChanged,
497+
online: status == ConnectionStatus.connected,
498+
));
499+
}
498500

499501
if (currentState == ConnectionStatus.connected &&
500502
previousState != ConnectionStatus.connected) {
@@ -1213,6 +1215,32 @@ class StreamChatClient {
12131215
messageId,
12141216
);
12151217

1218+
/// Mark the thread with [threadId] in the channel with [channelId] of type
1219+
/// [channelType] as read.
1220+
Future<EmptyResponse> markThreadRead(
1221+
String channelId,
1222+
String channelType,
1223+
String threadId,
1224+
) =>
1225+
_chatApi.channel.markThreadRead(
1226+
channelId,
1227+
channelType,
1228+
threadId,
1229+
);
1230+
1231+
/// Mark the thread with [threadId] in the channel with [channelId] of type
1232+
/// [channelType] as unread.
1233+
Future<EmptyResponse> markThreadUnread(
1234+
String channelId,
1235+
String channelType,
1236+
String threadId,
1237+
) =>
1238+
_chatApi.channel.markThreadUnread(
1239+
channelId,
1240+
channelType,
1241+
threadId,
1242+
);
1243+
12161244
/// Creates a new Poll
12171245
Future<CreatePollResponse> createPoll(Poll poll) =>
12181246
_chatApi.polls.createPoll(poll);
@@ -1659,6 +1687,43 @@ class StreamChatClient {
16591687
Future<OGAttachmentResponse> enrichUrl(String url) =>
16601688
_chatApi.general.enrichUrl(url);
16611689

1690+
/// Queries threads with the given [options] and [pagination] params.
1691+
Future<QueryThreadsResponse> queryThreads({
1692+
ThreadOptions options = const ThreadOptions(),
1693+
PaginationParams pagination = const PaginationParams(),
1694+
}) =>
1695+
_chatApi.threads.queryThreads(
1696+
options: options,
1697+
pagination: pagination,
1698+
);
1699+
1700+
/// Retrieves a thread with the given [messageId].
1701+
///
1702+
/// Optionally pass [options] to limit the response.
1703+
Future<GetThreadResponse> getThread(
1704+
String messageId, {
1705+
ThreadOptions options = const ThreadOptions(),
1706+
}) =>
1707+
_chatApi.threads.getThread(
1708+
messageId,
1709+
options: options,
1710+
);
1711+
1712+
/// Partially updates the thread with the given [messageId].
1713+
///
1714+
/// Use [set] to define values to be set.
1715+
/// Use [unset] to define values to be unset.
1716+
Future<UpdateThreadResponse> partialUpdateThread(
1717+
String messageId, {
1718+
Map<String, Object?>? set,
1719+
List<String>? unset,
1720+
}) =>
1721+
_chatApi.threads.partialUpdateThread(
1722+
messageId,
1723+
set: set,
1724+
unset: unset,
1725+
);
1726+
16621727
/// Closes the [_ws] connection and resets the [state]
16631728
/// If [flushChatPersistence] is true the client deletes all offline
16641729
/// user's data.
@@ -1712,30 +1777,32 @@ class ClientState {
17121777
cancelEventSubscription();
17131778
}
17141779

1715-
_eventsSubscription = CompositeSubscription();
1716-
_eventsSubscription!
1717-
..add(_client
1718-
.on()
1719-
.where((event) =>
1720-
event.me != null && event.type != EventType.healthCheck)
1721-
.map((e) => e.me!)
1722-
.listen((user) {
1723-
currentUser = currentUser?.merge(user) ?? user;
1724-
}))
1725-
..add(_client
1726-
.on()
1727-
.map((event) => event.unreadChannels)
1728-
.whereType<int>()
1729-
.listen((count) {
1730-
currentUser = currentUser?.copyWith(unreadChannels: count);
1731-
}))
1732-
..add(_client
1733-
.on()
1734-
.map((event) => event.totalUnreadCount)
1735-
.whereType<int>()
1736-
.listen((count) {
1737-
currentUser = currentUser?.copyWith(totalUnreadCount: count);
1738-
}));
1780+
_eventsSubscription = CompositeSubscription()
1781+
..add(
1782+
_client.on().listen((event) {
1783+
// Update the current user only if the event is not a health check.
1784+
if (event.me case final user?) {
1785+
if (event.type != EventType.healthCheck) {
1786+
currentUser = currentUser?.merge(user) ?? user;
1787+
}
1788+
}
1789+
1790+
// Update the total unread count.
1791+
if (event.totalUnreadCount case final count?) {
1792+
currentUser = currentUser?.copyWith(totalUnreadCount: count);
1793+
}
1794+
1795+
// Update the unread channels count.
1796+
if (event.unreadChannels case final count?) {
1797+
currentUser = currentUser?.copyWith(unreadChannels: count);
1798+
}
1799+
1800+
// Update the unread threads count.
1801+
if (event.unreadThreads case final count?) {
1802+
currentUser = currentUser?.copyWith(unreadThreads: count);
1803+
}
1804+
}),
1805+
);
17391806

17401807
_listenChannelLeft();
17411808

@@ -1873,6 +1940,12 @@ class ClientState {
18731940
/// The current unread channels count as a stream
18741941
Stream<int> get unreadChannelsStream => _unreadChannelsController.stream;
18751942

1943+
/// The current unread thread count.
1944+
int get unreadThreads => _unreadThreadsController.value;
1945+
1946+
/// The current unread threads count as a stream.
1947+
Stream<int> get unreadThreadsStream => _unreadThreadsController.stream;
1948+
18761949
/// The current total unread messages count
18771950
int get totalUnreadCount => _totalUnreadCountController.value;
18781951

@@ -1909,28 +1982,32 @@ class ClientState {
19091982
}
19101983

19111984
void _computeUnreadCounts(OwnUser? user) {
1912-
final totalUnreadCount = user?.totalUnreadCount;
1913-
if (totalUnreadCount != null) {
1914-
_totalUnreadCountController.add(totalUnreadCount);
1985+
if (user?.totalUnreadCount case final count?) {
1986+
_totalUnreadCountController.add(count);
1987+
}
1988+
1989+
if (user?.unreadChannels case final count?) {
1990+
_unreadChannelsController.add(count);
19151991
}
19161992

1917-
final unreadChannels = user?.unreadChannels;
1918-
if (unreadChannels != null) {
1919-
_unreadChannelsController.add(unreadChannels);
1993+
if (user?.unreadThreads case final count?) {
1994+
_unreadThreadsController.add(count);
19201995
}
19211996
}
19221997

19231998
final _channelsController = BehaviorSubject<Map<String, Channel>>.seeded({});
19241999
final _currentUserController = BehaviorSubject<OwnUser?>();
19252000
final _usersController = BehaviorSubject<Map<String, User>>.seeded({});
19262001
final _unreadChannelsController = BehaviorSubject<int>.seeded(0);
2002+
final _unreadThreadsController = BehaviorSubject<int>.seeded(0);
19272003
final _totalUnreadCountController = BehaviorSubject<int>.seeded(0);
19282004

19292005
/// Call this method to dispose this object
19302006
void dispose() {
19312007
cancelEventSubscription();
19322008
_currentUserController.close();
19332009
_unreadChannelsController.close();
2010+
_unreadThreadsController.close();
19342011
_totalUnreadCountController.close();
19352012

19362013
final channels = [...this.channels.keys];

packages/stream_chat/lib/src/core/api/channel_api.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,32 @@ class ChannelApi {
337337
return EmptyResponse.fromJson(response.data);
338338
}
339339

340+
/// Mark the provided [threadId] of the channel as read.
341+
Future<EmptyResponse> markThreadRead(
342+
String channelId,
343+
String channelType,
344+
String threadId,
345+
) async {
346+
final response = await _client.post(
347+
'${_getChannelUrl(channelId, channelType)}/read',
348+
data: {'thread_id': threadId},
349+
);
350+
return EmptyResponse.fromJson(response.data);
351+
}
352+
353+
/// Mark the provided [threadId] of the channel as unread.
354+
Future<EmptyResponse> markThreadUnread(
355+
String channelId,
356+
String channelType,
357+
String threadId,
358+
) async {
359+
final response = await _client.post(
360+
'${_getChannelUrl(channelId, channelType)}/unread',
361+
data: {'thread_id': threadId},
362+
);
363+
return EmptyResponse.fromJson(response.data);
364+
}
365+
340366
/// Stop watching the channel
341367
Future<EmptyResponse> stopWatching(
342368
String channelId,

packages/stream_chat/lib/src/core/api/requests.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,43 @@ class PartialUpdateUserRequest extends Equatable {
207207
@override
208208
List<Object?> get props => [id, set, unset];
209209
}
210+
211+
/// {@template threadOptions}
212+
/// Options for querying threads.
213+
/// {@endtemplate}
214+
@JsonSerializable(createFactory: false)
215+
class ThreadOptions extends Equatable {
216+
/// {@macro threadOptions}
217+
const ThreadOptions({
218+
this.watch = true,
219+
this.replyLimit = 2,
220+
this.participantLimit = 100,
221+
this.memberLimit = 100,
222+
});
223+
224+
/// If true, the client will watch for changes in the thread.
225+
///
226+
/// Defaults to true.
227+
final bool watch;
228+
229+
/// The number of most recent replies to return per thread.
230+
///
231+
/// Defaults to 2.
232+
final int replyLimit;
233+
234+
/// The number of thread participants to return per thread.
235+
///
236+
/// Defaults to 100.
237+
final int participantLimit;
238+
239+
/// The number of members to return per thread.
240+
///
241+
/// Defaults to 100.
242+
final int memberLimit;
243+
244+
/// Serialize model to json
245+
Map<String, dynamic> toJson() => _$ThreadOptionsToJson(this);
246+
247+
@override
248+
List<Object?> get props => [watch, replyLimit, participantLimit, memberLimit];
249+
}

packages/stream_chat/lib/src/core/api/requests.g.dart

Lines changed: 32 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)