Skip to content

Commit

Permalink
Add ability to remove reactions
Browse files Browse the repository at this point in the history
  • Loading branch information
Sheikah45 committed Jan 10, 2024
1 parent a237c4d commit 426a539
Show file tree
Hide file tree
Showing 16 changed files with 577 additions and 167 deletions.
28 changes: 28 additions & 0 deletions src/main/java/com/faforever/client/chat/ChatChannel.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.faforever.client.chat;

import com.faforever.client.chat.ChatMessage.Type;
import com.faforever.client.chat.emoticons.Reaction;
import com.faforever.client.fx.JavaFxUtil;
import com.google.common.annotations.VisibleForTesting;
import javafx.beans.Observable;
Expand All @@ -21,7 +22,9 @@

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

@EqualsAndHashCode(onlyExplicitlyIncluded = true)
Expand All @@ -48,6 +51,7 @@ public class ChatChannel {
private final ObjectProperty<ChannelTopic> topic = new SimpleObjectProperty<>(new ChannelTopic(null, ""));
private final ObservableMap<String, ChatMessage> messagesById = FXCollections.synchronizedObservableMap(
FXCollections.observableHashMap());
private final Map<String, Reaction> reactionsById = new ConcurrentHashMap<>();
private final ObservableList<ChatMessage> rawMessages = JavaFxUtil.attachListToMap(
FXCollections.synchronizedObservableList(FXCollections.observableArrayList()), messagesById);
private final ObservableList<ChatMessage> messages = FXCollections.synchronizedObservableList(
Expand Down Expand Up @@ -149,6 +153,20 @@ public Optional<ChatMessage> getMessage(String id) {
return Optional.ofNullable(messagesById.get(id));
}

public void removeMessage(String messageId) {
messagesById.remove(messageId);
Reaction removedReaction = reactionsById.remove(messageId);
if (removedReaction == null) {
return;
}
ChatMessage reactedToMessage = messagesById.get(removedReaction.targetMessageId());
if (reactedToMessage == null) {
return;
}

reactedToMessage.removeReaction(removedReaction);
}

public void removePendingMessage(String messageId) {
messagesById.computeIfPresent(messageId,
(ignored, chatMessage) -> chatMessage.getType() == Type.PENDING ? null : chatMessage);
Expand All @@ -159,6 +177,16 @@ public void addMessage(ChatMessage message) {
pruneMessages();
}

public void addReaction(Reaction reaction) {
ChatMessage targetMessage = messagesById.get(reaction.targetMessageId());
if (targetMessage == null) {
return;
}

targetMessage.addReaction(reaction);
reactionsById.put(reaction.messageId(), reaction);
}

public ObservableList<ChatMessage> getMessages() {
return messages;
}
Expand Down
25 changes: 17 additions & 8 deletions src/main/java/com/faforever/client/chat/ChatMessage.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.faforever.client.chat;

import com.faforever.client.chat.emoticons.Emoticon;
import com.faforever.client.chat.emoticons.Reaction;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import javafx.collections.ObservableSet;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
Expand All @@ -28,19 +28,28 @@ public class ChatMessage {
@Getter
private final ChatMessage targetMessage;

private final ObservableMap<Emoticon, ObservableSet<String>> reactions = FXCollections.synchronizedObservableMap(
private final ObservableMap<Emoticon, ObservableMap<String, String>> reactions = FXCollections.synchronizedObservableMap(
FXCollections.observableHashMap());
private final ObservableMap<Emoticon, ObservableSet<String>> unmodifiableReactions = FXCollections.unmodifiableObservableMap(
private final ObservableMap<Emoticon, ObservableMap<String, String>> unmodifiableReactions = FXCollections.unmodifiableObservableMap(
reactions);

public ObservableMap<Emoticon, ObservableSet<String>> getReactions() {
public ObservableMap<Emoticon, ObservableMap<String, String>> getReactions() {
return unmodifiableReactions;
}

public void addReaction(Emoticon reaction, ChatChannelUser reactor) {
reactions.computeIfAbsent(reaction,
ignored -> FXCollections.synchronizedObservableSet(FXCollections.observableSet()))
.add(reactor.getUsername());
public void addReaction(Reaction reaction) {
reactions.computeIfAbsent(reaction.emoticon(),
ignored -> FXCollections.synchronizedObservableMap(FXCollections.observableHashMap()))
.put(reaction.reactorName(), reaction.messageId());
}

public void removeReaction(Reaction reaction) {
ObservableMap<String, String> reactors = reactions.getOrDefault(reaction.emoticon(),
FXCollections.emptyObservableMap());
reactors.remove(reaction.reactorName());
if (reactors.isEmpty()) {
reactions.remove(reaction.emoticon());
}
}

public enum Type {
Expand Down
54 changes: 35 additions & 19 deletions src/main/java/com/faforever/client/chat/ChatMessageController.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableSet;
import javafx.collections.ObservableMap;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
Expand Down Expand Up @@ -103,7 +103,7 @@ public class ChatMessageController extends NodeController<VBox> {
private final ObjectProperty<Consumer<ChatMessage>> onReplyButtonClicked = new SimpleObjectProperty<>();
private final ObjectProperty<Consumer<ChatMessage>> onReplyClicked = new SimpleObjectProperty<>();

private final MapChangeListener<Emoticon, ObservableSet<String>> reactionChangeListener = this::onReactionChange;
private final MapChangeListener<Emoticon, ObservableMap<String, String>> reactionChangeListener = this::onReactionChange;

private final Map<Emoticon, HBox> reactionNodeMap = new HashMap<>();

Expand Down Expand Up @@ -176,8 +176,7 @@ protected void onInitialize() {
}
});

reactionsContainer.visibleProperty()
.bind(chatMessage.map(ChatMessage::getReactions).flatMap(Bindings::isNotEmpty).when(showing));
reactionsContainer.visibleProperty().bind(Bindings.isNotEmpty(reactionsContainer.getChildren()).when(showing));
replyButton.onActionProperty().bind(chatMessage.flatMap(message -> onReplyButtonClicked.map(
onReplyClicked -> (EventHandler<ActionEvent>) event -> onReplyClicked.accept(message)))
.when(showing));
Expand All @@ -196,7 +195,8 @@ protected void onInitialize() {
.when(showing));
}

private void onReactionChange(MapChangeListener.Change<? extends Emoticon, ? extends ObservableSet<String>> change) {
private void onReactionChange(
MapChangeListener.Change<? extends Emoticon, ? extends ObservableMap<String, String>> change) {
Emoticon reaction = change.getKey();
if (change.wasRemoved()) {
HBox reactionRoot = reactionNodeMap.remove(reaction);
Expand All @@ -208,18 +208,25 @@ private void onReactionChange(MapChangeListener.Change<? extends Emoticon, ? ext
}
}

private void addReaction(Emoticon reaction, ObservableSet<String> reactors) {
private void addReaction(Emoticon reaction, ObservableMap<String, String> reactors) {
ReactionController reactionController = uiService.loadFxml("theme/chat/emoticons/reaction.fxml");
reactionController.setReaction(reaction);
reactionController.setReactors(reactors);
reactionController.onReactionClickedProperty()
.bind(chatMessage.map(target -> react -> {
if (target != null && !target.getReactions()
.getOrDefault(react, FXCollections.emptyObservableSet())
.contains(chatService.getCurrentUsername())) {
chatService.reactToMessageInBackground(target, react);
}
}));
reactionController.onReactionClickedProperty().bind(chatMessage.map(target -> emoticon -> {
if (target == null) {
return;
}

ObservableMap<String, String> emoticonReactions = target.getReactions()
.getOrDefault(emoticon,
FXCollections.emptyObservableMap());
String currentUsername = chatService.getCurrentUsername();
if (!emoticonReactions.containsKey(currentUsername)) {
chatService.reactToMessageInBackground(target, emoticon);
} else {
chatService.redactMessageInBackground(target.getSender().getChannel(), emoticonReactions.get(currentUsername));
}
}));
HBox reactionRoot = reactionController.getRoot();
reactionNodeMap.put(reaction, reactionRoot);
fxApplicationThreadExecutor.execute(() -> reactionsContainer.getChildren().add(reactionRoot));
Expand Down Expand Up @@ -292,12 +299,21 @@ public void onReactButtonClicked() {
emoticonsPopup.setConsumeAutoHidingEvents(false);
emoticonsWindowController.setOnEmoticonClicked(emoticon -> {
ChatMessage target = getChatMessage();
if (target != null && !target.getReactions()
.getOrDefault(emoticon, FXCollections.emptyObservableSet())
.contains(chatService.getCurrentUsername())) {
chatService.reactToMessageInBackground(target, emoticon);
}
emoticonsPopup.hide();

if (target == null) {
return;
}

ObservableMap<String, String> emoticonReactions = target.getReactions()
.getOrDefault(emoticon,
FXCollections.emptyObservableMap());
String currentUsername = chatService.getCurrentUsername();
if (emoticonReactions.containsKey(currentUsername)) {
return;
}

chatService.reactToMessageInBackground(target, emoticon);
});

Bounds bounds = reactButton.localToScreen(reactButton.getBoundsInLocal());
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/faforever/client/chat/ChatService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public interface ChatService {

void disconnect();

CompletableFuture<Void> redactMessageInBackground(ChatChannel chatChannel, String messageId);

CompletableFuture<Void> reactToMessageInBackground(ChatMessage targetMessage, Emoticon reaction);

CompletableFuture<Void> sendReplyInBackground(ChatMessage targetMessage, String message);
Expand Down
Loading

0 comments on commit 426a539

Please sign in to comment.