Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui, core, localization): Add Poll attachment interactor #2052

Merged
merged 61 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
10968f1
feat: add support for polls api
xsahil03x Oct 25, 2024
678806a
chore: fix analysis
xsahil03x Oct 25, 2024
9468141
Merge branch 'master' into feat/message-polls-apis
deven98 Oct 25, 2024
08029a2
test: fix test
xsahil03x Oct 25, 2024
a9261b9
Merge remote-tracking branch 'origin/feat/message-polls-apis' into fe…
xsahil03x Oct 25, 2024
cd26fbc
revert: revert state changes
xsahil03x Oct 25, 2024
921086d
test: fix test
xsahil03x Oct 25, 2024
33c5a75
chore: fix lints
xsahil03x Oct 25, 2024
b5d3fe5
chore: improve cast poll vote api
xsahil03x Oct 28, 2024
2d429da
feat: add poll event handlers
xsahil03x Oct 29, 2024
4d68b56
Add Poll attachment composer
xsahil03x Nov 11, 2024
06e6be1
add poll creator theme appBarElevation
xsahil03x Nov 12, 2024
d00b542
Add poll creator widget tests
xsahil03x Nov 12, 2024
818f10b
add StreamPollController test
xsahil03x Nov 12, 2024
a5fd7f6
add translations for poll creator
xsahil03x Nov 12, 2024
ceee773
add pollVotingMode, additional poll extensions
xsahil03x Nov 19, 2024
e13d0e1
fix llc tests
xsahil03x Nov 19, 2024
562bc46
add StreamPollVoteListController
xsahil03x Nov 19, 2024
ff8f0d6
move poll creator into a separate directory
xsahil03x Nov 19, 2024
ef256c8
add StreamPollVoteListView
xsahil03x Nov 19, 2024
8466d3c
add poll message preview text
xsahil03x Nov 19, 2024
086a418
add poll related methods to channel
xsahil03x Nov 19, 2024
de36e29
add StreamPollInteractor widget and PollMessage
xsahil03x Nov 21, 2024
758afaa
fix lints
xsahil03x Nov 21, 2024
0b50637
revert maxVisibleOptionCount
xsahil03x Nov 21, 2024
4c506a2
add ui tests and minor changes
xsahil03x Nov 22, 2024
f373927
add refresh indicator to vote list
xsahil03x Nov 22, 2024
e82dda1
fix StreamPollVoteListView additional state texts
xsahil03x Nov 22, 2024
5cd11a3
fix poll comments visibility
xsahil03x Nov 22, 2024
bce5c21
Disallow editing, adding polls in threads
xsahil03x Nov 22, 2024
1315ae1
add locks to poll and vote methods
xsahil03x Nov 25, 2024
8e2a19d
add more tests
xsahil03x Nov 25, 2024
b59f8fb
feat(localization): add new poll interactor strings
xsahil03x Dec 9, 2024
8329d53
feat: add support for polls api
xsahil03x Oct 25, 2024
4653c7a
chore: fix analysis
xsahil03x Oct 25, 2024
b5893cf
test: fix test
xsahil03x Oct 25, 2024
c3cc1d7
revert: revert state changes
xsahil03x Oct 25, 2024
a6fd19b
test: fix test
xsahil03x Oct 25, 2024
9a8626f
chore: fix lints
xsahil03x Oct 25, 2024
8fd289a
chore: improve cast poll vote api
xsahil03x Oct 28, 2024
f9e7664
feat: add poll event handlers
xsahil03x Oct 29, 2024
822ca86
Merge remote-tracking branch 'origin/feat/message-polls-apis' into fe…
xsahil03x Dec 9, 2024
611560e
Merge remote-tracking branch 'origin/feat/polls-attachment-composer' …
xsahil03x Dec 9, 2024
91b1ff8
Merge remote-tracking branch 'origin/master' into feat/poll-message-w…
xsahil03x Dec 12, 2024
0ec3c7d
chore: merge fixes
xsahil03x Dec 12, 2024
6067df0
chore: update CHANGELOG.md
xsahil03x Dec 12, 2024
bfc5c38
chore: ignore line length lint for tests
xsahil03x Dec 12, 2024
ef2b2bf
revert: testing changes
xsahil03x Dec 12, 2024
d14ef7b
test: regenerate goldens
xsahil03x Dec 13, 2024
413d0e4
test: fix golden tests date
xsahil03x Dec 13, 2024
16035d1
test: fix golden tests date
xsahil03x Dec 13, 2024
08dc23e
add StreamPollOptionsDialogThemeData to StreamTheme
xsahil03x Dec 23, 2024
768fc62
Merge remote-tracking branch 'origin/master' into feat/poll-message-w…
xsahil03x Dec 24, 2024
8ee56a8
migrate the new golden tests to alchemist
xsahil03x Dec 24, 2024
0abc7a9
remove previous goldens
xsahil03x Dec 24, 2024
c4d8d7c
update action
xsahil03x Dec 24, 2024
7fb14dc
temp test
xsahil03x Dec 24, 2024
ebfc2d6
chore: Update Goldens
xsahil03x Dec 24, 2024
fdcdc02
revert test changes
xsahil03x Dec 24, 2024
cc3a5f1
remove fetch depth
xsahil03x Dec 24, 2024
c3f9988
apply review suggestions.
xsahil03x Dec 24, 2024
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
138 changes: 119 additions & 19 deletions packages/stream_chat/lib/src/client/channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,8 @@ class Channel {
return _client.sendEvent(id!, type, event);
}

final _pollLock = Lock();

/// Send a message with a poll to this channel.
///
/// Optionally provide a [messageText] to send a message along with the poll.
Expand All @@ -1043,7 +1045,7 @@ class Channel {
String messageText = '',
}) async {
_checkInitialized();
final res = await _client.createPoll(poll);
final res = await _pollLock.synchronized(() => _client.createPoll(poll));
return sendMessage(
Message(
text: messageText,
Expand All @@ -1056,13 +1058,109 @@ class Channel {
/// Updates the [poll] in this channel.
Future<UpdatePollResponse> updatePoll(Poll poll) {
_checkInitialized();
return _client.updatePoll(poll);
return _pollLock.synchronized(() => _client.updatePoll(poll));
}

/// Deletes the given [poll] from this channel.
Future<EmptyResponse> deletePoll(Poll poll) {
_checkInitialized();
return _pollLock.synchronized(() => _client.deletePoll(poll.id));
}

/// Close the given [poll].
Future<UpdatePollResponse> closePoll(Poll poll) {
_checkInitialized();
return _pollLock.synchronized(() => _client.closePoll(poll.id));
}

/// Deletes the poll with the given [pollId] from this channel.
Future<EmptyResponse> deletePoll(String pollId) {
/// Create a new poll option for the given [poll].
Future<CreatePollOptionResponse> createPollOption(
Poll poll,
PollOption option,
) {
_checkInitialized();
return _pollLock.synchronized(
() => _client.createPollOption(poll.id, option),
);
}

final _pollVoteLock = Lock();

/// Cast a vote on the given [poll] with the given [option].
Future<CastPollVoteResponse> castPollVote(
Message message,
Poll poll,
PollOption option,
) async {
_checkInitialized();
return _client.deletePoll(pollId);

final optionId = option.id;
if (optionId == null) {
throw ArgumentError('Option id cannot be null');
}

return _pollVoteLock.synchronized(
() => _client.castPollVote(
message.id,
poll.id,
optionId: optionId,
),
);
}

/// Add a new answer to the given [poll].
Future<CastPollVoteResponse> addPollAnswer(
Message message,
Poll poll, {
required String answerText,
}) {
_checkInitialized();
return _pollVoteLock.synchronized(
() => _client.addPollAnswer(
message.id,
poll.id,
answerText: answerText,
),
);
}

/// Remove a vote on the given [poll] with the given [vote].
Future<RemovePollVoteResponse> removePollVote(
Message message,
Poll poll,
PollVote vote,
) {
_checkInitialized();

final voteId = vote.id;
if (voteId == null) {
throw ArgumentError('Vote id cannot be null');
}

return _pollVoteLock.synchronized(
() => _client.removePollVote(
message.id,
poll.id,
voteId,
),
);
}

/// Query the poll votes for the given [pollId] with the given [filter] and
/// [sort] options.
Future<QueryPollVotesResponse> queryPollVotes(
String pollId, {
Filter? filter,
List<SortOption>? sort,
PaginationParams pagination = const PaginationParams(),
}) {
_checkInitialized();
return _client.queryPollVotes(
pollId,
filter: filter,
sort: sort,
pagination: pagination,
);
}

/// Send a reaction to this channel.
Expand Down Expand Up @@ -2120,12 +2218,12 @@ class ChannelClientState {

final oldPoll = pollMessage.poll;

final answers = oldPoll?.answers ?? eventPoll.answers;
final latestAnswers = oldPoll?.latestAnswers ?? eventPoll.latestAnswers;
final ownVotesAndAnswers =
oldPoll?.ownVotesAndAnswers ?? eventPoll.ownVotesAndAnswers;

final poll = eventPoll.copyWith(
answers: answers,
latestAnswers: latestAnswers,
ownVotesAndAnswers: ownVotesAndAnswers,
);

Expand Down Expand Up @@ -2160,8 +2258,8 @@ class ChannelClientState {

final oldPoll = pollMessage.poll;

final answers = <String, PollVote>{
for (final ans in oldPoll?.answers ?? []) ans.id: ans,
final latestAnswers = <String, PollVote>{
for (final ans in oldPoll?.latestAnswers ?? []) ans.id: ans,
eventPollVote.id!: eventPollVote,
};

Expand All @@ -2173,7 +2271,7 @@ class ChannelClientState {
};

final poll = eventPoll.copyWith(
answers: [...answers.values],
latestAnswers: [...latestAnswers.values],
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
);

Expand All @@ -2192,7 +2290,7 @@ class ChannelClientState {

final oldPoll = pollMessage.poll;

final answers = oldPoll?.answers ?? eventPoll.answers;
final latestAnswers = oldPoll?.latestAnswers ?? eventPoll.latestAnswers;
final currentUserId = _channel.client.state.currentUser?.id;
final ownVotesAndAnswers = <String, PollVote>{
for (final vote in oldPoll?.ownVotesAndAnswers ?? []) vote.id: vote,
Expand All @@ -2201,7 +2299,7 @@ class ChannelClientState {
};

final poll = eventPoll.copyWith(
answers: answers,
latestAnswers: latestAnswers,
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
);

Expand All @@ -2220,16 +2318,16 @@ class ChannelClientState {

final oldPoll = pollMessage.poll;

final answers = <String, PollVote>{
for (final ans in oldPoll?.answers ?? []) ans.id: ans,
final latestAnswers = <String, PollVote>{
for (final ans in oldPoll?.latestAnswers ?? []) ans.id: ans,
}..remove(eventPollVote.id);

final ownVotesAndAnswers = <String, PollVote>{
for (final vote in oldPoll?.ownVotesAndAnswers ?? []) vote.id: vote,
}..remove(eventPollVote.id);

final poll = eventPoll.copyWith(
answers: [...answers.values],
latestAnswers: [...latestAnswers.values],
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
);

Expand All @@ -2248,13 +2346,13 @@ class ChannelClientState {

final oldPoll = pollMessage.poll;

final answers = oldPoll?.answers ?? eventPoll.answers;
final latestAnswers = oldPoll?.latestAnswers ?? eventPoll.latestAnswers;
final ownVotesAndAnswers = <String, PollVote>{
for (final vote in oldPoll?.ownVotesAndAnswers ?? []) vote.id: vote,
}..remove(eventPollVote.id);

final poll = eventPoll.copyWith(
answers: answers,
latestAnswers: latestAnswers,
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
);

Expand All @@ -2273,7 +2371,7 @@ class ChannelClientState {

final oldPoll = pollMessage.poll;

final answers = oldPoll?.answers ?? eventPoll.answers;
final latestAnswers = oldPoll?.latestAnswers ?? eventPoll.latestAnswers;
final currentUserId = _channel.client.state.currentUser?.id;
final ownVotesAndAnswers = <String, PollVote>{
for (final vote in oldPoll?.ownVotesAndAnswers ?? []) vote.id: vote,
Expand All @@ -2282,7 +2380,7 @@ class ChannelClientState {
};

final poll = eventPoll.copyWith(
answers: answers,
latestAnswers: latestAnswers,
ownVotesAndAnswers: [...ownVotesAndAnswers.values],
);

Expand Down Expand Up @@ -2338,6 +2436,8 @@ class ChannelClientState {
threads[event.message?.parentId]
?.firstWhereOrNull((e) => e.id == event.message?.id);
final message = event.message!.copyWith(
poll: oldMessage?.poll,
pollId: oldMessage?.pollId,
ownReactions: oldMessage?.ownReactions,
);
updateMessage(message);
Expand Down
46 changes: 31 additions & 15 deletions packages/stream_chat/lib/src/core/models/poll.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ class Poll extends Equatable {
this.enforceUniqueVote = true,
this.maxVotesAllowed,
this.allowAnswers = false,
this.answers = const [],
this.latestAnswers = const [],
this.answersCount = 0,
this.allowUserSuggestedOptions = false,
this.isClosed = false,
DateTime? createdAt,
DateTime? updatedAt,
this.voteCountsByOption = const {},
this.voteCount = 0,
this.votesByOption = const {},
this.latestVotesByOption = const {},
this.createdById,
this.createdBy,
this.ownVotesAndAnswers = const [],
Expand Down Expand Up @@ -109,20 +109,20 @@ class Poll extends Equatable {
final Map<String, int> voteCountsByOption;

/// Map of latest votes by option.
@JsonKey(name: 'latest_votes_by_option', includeToJson: false)
final Map<String, List<PollVote>> votesByOption;
@JsonKey(includeToJson: false)
final Map<String, List<PollVote>> latestVotesByOption;

/// List of votes received by the poll.
///
/// Note: This does not include the answers provided by the users,
/// see [answers] for that.
List<PollVote> get votes => [
...votesByOption.values.flattened.where((it) => !it.isAnswer),
/// see [latestAnswers] for that.
List<PollVote> get latestVotes => [
...latestVotesByOption.values.flattened.where((it) => !it.isAnswer),
xsahil03x marked this conversation as resolved.
Show resolved Hide resolved
];

/// List of latest answers received by the poll.
@JsonKey(name: 'latest_answers', includeToJson: false)
final List<PollVote> answers;
@JsonKey(includeToJson: false)
final List<PollVote> latestAnswers;

/// List of votes casted by the current user.
///
Expand All @@ -134,6 +134,22 @@ class Poll extends Equatable {
@JsonKey(includeToJson: false)
final int voteCount;

/// List of votes casted by the current user.
///
/// Note: This does not include the answers provided by the user,
/// see [ownAnswers] for that.
List<PollVote> get ownVotes => [
...ownVotesAndAnswers.where((it) => !it.isAnswer),
];

/// List of answers provided by the current user.
///
/// Note: This does not include the votes casted by the user,
/// see [ownVotes] for that.
List<PollVote> get ownAnswers => [
...ownVotesAndAnswers.where((it) => it.isAnswer),
];

/// The id of the user who created the poll.
@JsonKey(includeToJson: false)
final String? createdById;
Expand Down Expand Up @@ -173,8 +189,8 @@ class Poll extends Equatable {
List<PollVote>? ownVotesAndAnswers,
int? voteCount,
int? answersCount,
Map<String, List<PollVote>>? votesByOption,
List<PollVote>? answers,
Map<String, List<PollVote>>? latestVotesByOption,
List<PollVote>? latestAnswers,
String? createdById,
User? createdBy,
DateTime? createdAt,
Expand All @@ -199,8 +215,8 @@ class Poll extends Equatable {
ownVotesAndAnswers: ownVotesAndAnswers ?? this.ownVotesAndAnswers,
voteCount: voteCount ?? this.voteCount,
answersCount: answersCount ?? this.answersCount,
votesByOption: votesByOption ?? this.votesByOption,
answers: answers ?? this.answers,
latestVotesByOption: latestVotesByOption ?? this.latestVotesByOption,
latestAnswers: latestAnswers ?? this.latestAnswers,
createdById: createdById ?? this.createdById,
createdBy: createdBy ?? this.createdBy,
createdAt: createdAt ?? this.createdAt,
Expand Down Expand Up @@ -251,8 +267,8 @@ class Poll extends Equatable {
ownVotesAndAnswers,
voteCount,
answersCount,
votesByOption,
answers,
latestVotesByOption,
latestAnswers,
createdById,
createdBy,
createdAt,
Expand Down
21 changes: 11 additions & 10 deletions packages/stream_chat/lib/src/core/models/poll.g.dart

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

Loading
Loading