Skip to content

Commit 7408264

Browse files
committed
feat: add poll event handlers
1 parent 92928c6 commit 7408264

File tree

8 files changed

+399
-51
lines changed

8 files changed

+399
-51
lines changed

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

Lines changed: 211 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import 'dart:async';
22
import 'dart:math';
33

4-
import 'package:collection/collection.dart'
5-
show IterableExtension, ListEquality;
4+
import 'package:collection/collection.dart';
65
import 'package:rxdart/rxdart.dart';
76
import 'package:stream_chat/src/client/retry_queue.dart';
87
import 'package:stream_chat/src/core/util/utils.dart';
@@ -1800,6 +1799,24 @@ class ChannelClientState {
18001799

18011800
_listenReactionDeleted();
18021801

1802+
/* Start of poll events */
1803+
1804+
_listenPollUpdated();
1805+
1806+
_listenPollClosed();
1807+
1808+
_listenPollAnswerCasted();
1809+
1810+
_listenPollVoteCasted();
1811+
1812+
_listenPollVoteChanged();
1813+
1814+
_listenPollAnswerRemoved();
1815+
1816+
_listenPollVoteRemoved();
1817+
1818+
/* End of poll events */
1819+
18031820
_listenReadEvents();
18041821

18051822
_listenUnreadEvents();
@@ -2052,6 +2069,198 @@ class ChannelClientState {
20522069
_retryQueue.add(failedMessages);
20532070
}
20542071

2072+
Message? _findPollMessage(String pollId) {
2073+
final message = messages.firstWhereOrNull((it) => it.pollId == pollId);
2074+
if (message != null) return message;
2075+
2076+
final threadMessage = threads.values.flattened.firstWhereOrNull((it) {
2077+
return it.pollId == pollId;
2078+
});
2079+
2080+
return threadMessage;
2081+
}
2082+
2083+
void _listenPollUpdated() {
2084+
_subscriptions.add(_channel.on(EventType.pollUpdated).listen((event) {
2085+
final eventPoll = event.poll;
2086+
if (eventPoll == null) return;
2087+
2088+
final pollMessage = _findPollMessage(eventPoll.id);
2089+
if (pollMessage == null) return;
2090+
2091+
final oldPoll = pollMessage.poll;
2092+
2093+
final answers = oldPoll?.answers ?? eventPoll.answers;
2094+
final ownVotesAndAnswers =
2095+
oldPoll?.ownVotesAndAnswers ?? eventPoll.ownVotesAndAnswers;
2096+
2097+
final poll = eventPoll.copyWith(
2098+
answers: answers,
2099+
ownVotesAndAnswers: ownVotesAndAnswers,
2100+
);
2101+
2102+
final message = pollMessage.copyWith(poll: poll);
2103+
updateMessage(message);
2104+
}));
2105+
}
2106+
2107+
void _listenPollClosed() {
2108+
_subscriptions.add(_channel.on(EventType.pollClosed).listen((event) {
2109+
final eventPoll = event.poll;
2110+
if (eventPoll == null) return;
2111+
2112+
final pollMessage = _findPollMessage(eventPoll.id);
2113+
if (pollMessage == null) return;
2114+
2115+
final oldPoll = pollMessage.poll;
2116+
final poll = oldPoll?.copyWith(isClosed: true) ?? eventPoll;
2117+
2118+
final message = pollMessage.copyWith(poll: poll);
2119+
updateMessage(message);
2120+
}));
2121+
}
2122+
2123+
void _listenPollAnswerCasted() {
2124+
_subscriptions.add(_channel.on(EventType.pollAnswerCasted).listen((event) {
2125+
final (eventPoll, eventPollVote) = (event.poll, event.pollVote);
2126+
if (eventPoll == null || eventPollVote == null) return;
2127+
2128+
final pollMessage = _findPollMessage(eventPoll.id);
2129+
if (pollMessage == null) return;
2130+
2131+
final oldPoll = pollMessage.poll;
2132+
2133+
final answers = <String, PollVote>{
2134+
for (final ans in oldPoll?.answers ?? []) ans.id: ans,
2135+
eventPollVote.id!: eventPollVote,
2136+
};
2137+
2138+
final currentUserId = _channel.client.state.currentUser?.id;
2139+
final ownVotesAndAnswers = <String, PollVote>{
2140+
for (final vote in oldPoll?.ownVotesAndAnswers ?? []) vote.id: vote,
2141+
if (eventPollVote.userId == currentUserId)
2142+
eventPollVote.id!: eventPollVote,
2143+
};
2144+
2145+
final poll = eventPoll.copyWith(
2146+
answers: [...answers.values],
2147+
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
2148+
);
2149+
2150+
final message = pollMessage.copyWith(poll: poll);
2151+
updateMessage(message);
2152+
}));
2153+
}
2154+
2155+
void _listenPollVoteCasted() {
2156+
_subscriptions.add(_channel.on(EventType.pollVoteCasted).listen((event) {
2157+
final (eventPoll, eventPollVote) = (event.poll, event.pollVote);
2158+
if (eventPoll == null || eventPollVote == null) return;
2159+
2160+
final pollMessage = _findPollMessage(eventPoll.id);
2161+
if (pollMessage == null) return;
2162+
2163+
final oldPoll = pollMessage.poll;
2164+
2165+
final answers = oldPoll?.answers ?? eventPoll.answers;
2166+
final currentUserId = _channel.client.state.currentUser?.id;
2167+
final ownVotesAndAnswers = <String, PollVote>{
2168+
for (final vote in oldPoll?.ownVotesAndAnswers ?? []) vote.id: vote,
2169+
if (eventPollVote.userId == currentUserId)
2170+
eventPollVote.id!: eventPollVote,
2171+
};
2172+
2173+
final poll = eventPoll.copyWith(
2174+
answers: answers,
2175+
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
2176+
);
2177+
2178+
final message = pollMessage.copyWith(poll: poll);
2179+
updateMessage(message);
2180+
}));
2181+
}
2182+
2183+
void _listenPollAnswerRemoved() {
2184+
_subscriptions.add(_channel.on(EventType.pollAnswerRemoved).listen((event) {
2185+
final (eventPoll, eventPollVote) = (event.poll, event.pollVote);
2186+
if (eventPoll == null || eventPollVote == null) return;
2187+
2188+
final pollMessage = _findPollMessage(eventPoll.id);
2189+
if (pollMessage == null) return;
2190+
2191+
final oldPoll = pollMessage.poll;
2192+
2193+
final answers = <String, PollVote>{
2194+
for (final ans in oldPoll?.answers ?? []) ans.id: ans,
2195+
}..remove(eventPollVote.id);
2196+
2197+
final ownVotesAndAnswers = <String, PollVote>{
2198+
for (final vote in oldPoll?.ownVotesAndAnswers ?? []) vote.id: vote,
2199+
}..remove(eventPollVote.id);
2200+
2201+
final poll = eventPoll.copyWith(
2202+
answers: [...answers.values],
2203+
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
2204+
);
2205+
2206+
final message = pollMessage.copyWith(poll: poll);
2207+
updateMessage(message);
2208+
}));
2209+
}
2210+
2211+
void _listenPollVoteRemoved() {
2212+
_subscriptions.add(_channel.on(EventType.pollVoteRemoved).listen((event) {
2213+
final (eventPoll, eventPollVote) = (event.poll, event.pollVote);
2214+
if (eventPoll == null || eventPollVote == null) return;
2215+
2216+
final pollMessage = _findPollMessage(eventPoll.id);
2217+
if (pollMessage == null) return;
2218+
2219+
final oldPoll = pollMessage.poll;
2220+
2221+
final answers = oldPoll?.answers ?? eventPoll.answers;
2222+
final ownVotesAndAnswers = <String, PollVote>{
2223+
for (final vote in oldPoll?.ownVotesAndAnswers ?? []) vote.id: vote,
2224+
}..remove(eventPollVote.id);
2225+
2226+
final poll = eventPoll.copyWith(
2227+
answers: answers,
2228+
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
2229+
);
2230+
2231+
final message = pollMessage.copyWith(poll: poll);
2232+
updateMessage(message);
2233+
}));
2234+
}
2235+
2236+
void _listenPollVoteChanged() {
2237+
_subscriptions.add(_channel.on(EventType.pollVoteChanged).listen((event) {
2238+
final (eventPoll, eventPollVote) = (event.poll, event.pollVote);
2239+
if (eventPoll == null || eventPollVote == null) return;
2240+
2241+
final pollMessage = _findPollMessage(eventPoll.id);
2242+
if (pollMessage == null) return;
2243+
2244+
final oldPoll = pollMessage.poll;
2245+
2246+
final answers = oldPoll?.answers ?? eventPoll.answers;
2247+
final currentUserId = _channel.client.state.currentUser?.id;
2248+
final ownVotesAndAnswers = <String, PollVote>{
2249+
for (final vote in oldPoll?.ownVotesAndAnswers ?? []) vote.id: vote,
2250+
if (eventPollVote.userId == currentUserId)
2251+
eventPollVote.id!: eventPollVote,
2252+
};
2253+
2254+
final poll = eventPoll.copyWith(
2255+
answers: answers,
2256+
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
2257+
);
2258+
2259+
final message = pollMessage.copyWith(poll: poll);
2260+
updateMessage(message);
2261+
}));
2262+
}
2263+
20552264
void _listenReactionDeleted() {
20562265
_subscriptions.add(_channel.on(EventType.reactionDeleted).listen((event) {
20572266
final oldMessage =

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,17 @@ class StreamChatClient {
200200

201201
/// Stream of [Event] coming from [_ws] connection
202202
/// Listen to this or use the [on] method to filter specific event types
203-
Stream<Event> get eventStream => _eventController.stream;
203+
Stream<Event> get eventStream => _eventController.stream.map(
204+
// If the poll vote is an answer, we should emit a different event
205+
// to make it easier to handle in the state.
206+
(event) => switch ((event.type, event.pollVote?.isAnswer == true)) {
207+
(EventType.pollVoteCasted || EventType.pollVoteChanged, true) =>
208+
event.copyWith(type: EventType.pollAnswerCasted),
209+
(EventType.pollVoteRemoved, true) =>
210+
event.copyWith(type: EventType.pollAnswerRemoved),
211+
_ => event,
212+
},
213+
);
204214

205215
final _wsConnectionStatusController =
206216
BehaviorSubject.seeded(ConnectionStatus.disconnected);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ class Event {
180180
OwnUser? me,
181181
User? user,
182182
Message? message,
183+
Poll? poll,
184+
PollVote? pollVote,
183185
EventChannel? channel,
184186
Member? member,
185187
Reaction? reaction,
@@ -201,6 +203,8 @@ class Event {
201203
me: me ?? this.me,
202204
user: user ?? this.user,
203205
message: message ?? this.message,
206+
poll: poll ?? this.poll,
207+
pollVote: pollVote ?? this.pollVote,
204208
totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount,
205209
unreadChannels: unreadChannels ?? this.unreadChannels,
206210
reaction: reaction ?? this.reaction,

0 commit comments

Comments
 (0)