[LLC] Add optimistic reaction update
Signed-off-by: Sahil Kumar <[email protected]>
This commit is contained in:
@@ -274,28 +274,107 @@ class Channel {
|
|||||||
bool enforceUnique = false,
|
bool enforceUnique = false,
|
||||||
}) async {
|
}) async {
|
||||||
final messageId = message.id;
|
final messageId = message.id;
|
||||||
|
final now = DateTime.now();
|
||||||
|
final user = _client.state.user;
|
||||||
|
|
||||||
|
final latestReactions = [...message.latestReactions];
|
||||||
|
final ownReactions = [...message.ownReactions];
|
||||||
|
if (enforceUnique) {
|
||||||
|
latestReactions.removeWhere((it) => it.userId == user.id);
|
||||||
|
ownReactions.removeWhere((it) => it.userId == user.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
final newReaction = Reaction(
|
||||||
|
messageId: messageId,
|
||||||
|
createdAt: now,
|
||||||
|
type: type,
|
||||||
|
user: user,
|
||||||
|
score: 1,
|
||||||
|
extraData: extraData,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inserting at the 0th index as it's the latest reaction
|
||||||
|
latestReactions.insert(0, newReaction);
|
||||||
|
ownReactions.add(newReaction);
|
||||||
|
|
||||||
|
final newMessage = message.copyWith(
|
||||||
|
reactionCounts: {...message.reactionCounts}..update(type, (value) {
|
||||||
|
if (enforceUnique) return value;
|
||||||
|
return value + 1;
|
||||||
|
}, ifAbsent: () => 1),
|
||||||
|
reactionScores: {...message.reactionScores}..update(type, (value) {
|
||||||
|
if (enforceUnique) return value;
|
||||||
|
return value + 1;
|
||||||
|
}, ifAbsent: () => 1),
|
||||||
|
latestReactions: latestReactions,
|
||||||
|
ownReactions: ownReactions,
|
||||||
|
);
|
||||||
|
|
||||||
|
state?.addMessage(newMessage);
|
||||||
|
|
||||||
final data = Map<String, dynamic>.from(extraData)
|
final data = Map<String, dynamic>.from(extraData)
|
||||||
..addAll({
|
..addAll({
|
||||||
'type': type,
|
'type': type,
|
||||||
});
|
});
|
||||||
|
|
||||||
final res = await _client.post(
|
try {
|
||||||
'/messages/$messageId/reaction',
|
final res = await _client.post(
|
||||||
data: {
|
'/messages/$messageId/reaction',
|
||||||
'reaction': data,
|
data: {
|
||||||
'enforce_unique': enforceUnique,
|
'reaction': data,
|
||||||
},
|
'enforce_unique': enforceUnique,
|
||||||
);
|
},
|
||||||
return _client.decode(res.data, SendReactionResponse.fromJson);
|
);
|
||||||
|
final reactionResp =
|
||||||
|
_client.decode(res.data, SendReactionResponse.fromJson);
|
||||||
|
state?.addMessage(reactionResp.message);
|
||||||
|
return reactionResp;
|
||||||
|
} catch (error) {
|
||||||
|
if (error is DioError && error.type != DioErrorType.RESPONSE) {
|
||||||
|
// Reset the message if the update fails
|
||||||
|
state?.addMessage(message);
|
||||||
|
}
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete a reaction from this channel
|
/// Delete a reaction from this channel
|
||||||
Future<EmptyResponse> deleteReaction(Message message, Reaction reaction) {
|
Future<EmptyResponse> deleteReaction(
|
||||||
|
Message message, Reaction reaction) async {
|
||||||
_checkInitialized();
|
_checkInitialized();
|
||||||
|
|
||||||
return client
|
final type = reaction.type;
|
||||||
.delete('/messages/${message.id}/reaction/${reaction.type}')
|
|
||||||
.then((res) => _client.decode(res.data, EmptyResponse.fromJson));
|
final reactionCounts = {...message.reactionCounts}
|
||||||
|
..update(type, (value) => value - 1);
|
||||||
|
final reactionScores = {...message.reactionScores}
|
||||||
|
..update(type, (value) => value - 1);
|
||||||
|
|
||||||
|
final removeWhere = (Reaction r) =>
|
||||||
|
r.userId == reaction.userId &&
|
||||||
|
r.type == reaction.type &&
|
||||||
|
r.messageId == reaction.messageId;
|
||||||
|
|
||||||
|
final newMessage = message.copyWith(
|
||||||
|
reactionCounts: reactionCounts..removeWhere((_, value) => value == 0),
|
||||||
|
reactionScores: reactionScores..removeWhere((_, value) => value == 0),
|
||||||
|
latestReactions: [...message.latestReactions]..removeWhere(removeWhere),
|
||||||
|
ownReactions: [...message.ownReactions]..removeWhere(removeWhere),
|
||||||
|
);
|
||||||
|
|
||||||
|
state?.addMessage(newMessage);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final res = await client
|
||||||
|
.delete('/messages/${message.id}/reaction/${reaction.type}');
|
||||||
|
return _client.decode(res.data, EmptyResponse.fromJson);
|
||||||
|
} catch (error) {
|
||||||
|
if (error is DioError && error.type != DioErrorType.RESPONSE) {
|
||||||
|
// Reset the message if the update fails
|
||||||
|
state?.addMessage(message);
|
||||||
|
}
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Edit the channel custom data
|
/// Edit the channel custom data
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ class Reaction {
|
|||||||
this.createdAt,
|
this.createdAt,
|
||||||
this.type,
|
this.type,
|
||||||
this.user,
|
this.user,
|
||||||
this.userId,
|
String userId,
|
||||||
this.score,
|
this.score,
|
||||||
this.extraData,
|
this.extraData,
|
||||||
});
|
}) : userId = userId ?? user?.id;
|
||||||
|
|
||||||
/// Create a new instance from a json
|
/// Create a new instance from a json
|
||||||
factory Reaction.fromJson(Map<String, dynamic> json) {
|
factory Reaction.fromJson(Map<String, dynamic> json) {
|
||||||
@@ -65,4 +65,40 @@ class Reaction {
|
|||||||
return Serialization.moveFromExtraDataToRoot(
|
return Serialization.moveFromExtraDataToRoot(
|
||||||
_$ReactionToJson(this), topLevelFields);
|
_$ReactionToJson(this), topLevelFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a copy of [Reaction] with specified attributes overridden.
|
||||||
|
Reaction copyWith({
|
||||||
|
String messageId,
|
||||||
|
DateTime createdAt,
|
||||||
|
String type,
|
||||||
|
User user,
|
||||||
|
String userId,
|
||||||
|
int score,
|
||||||
|
Map<String, dynamic> extraData,
|
||||||
|
}) {
|
||||||
|
return Reaction(
|
||||||
|
messageId: messageId ?? this.messageId,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
type: type ?? this.type,
|
||||||
|
user: user ?? this.user,
|
||||||
|
userId: userId ?? this.userId,
|
||||||
|
score: score ?? this.score,
|
||||||
|
extraData: extraData ?? this.extraData,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new [Reaction] that is a combination of this reaction and the given
|
||||||
|
/// [other] reaction.
|
||||||
|
Reaction merge(Reaction other) {
|
||||||
|
if (other == null) return this;
|
||||||
|
return copyWith(
|
||||||
|
messageId: other.messageId,
|
||||||
|
createdAt: other.createdAt,
|
||||||
|
type: other.type,
|
||||||
|
user: other.user,
|
||||||
|
userId: other.userId,
|
||||||
|
score: other.score,
|
||||||
|
extraData: other.extraData,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user