Skip to content

Commit

Permalink
Add reaction and reply capability to chat messages (#3111)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sheikah45 authored Jan 10, 2024
1 parent e9285eb commit dc1c11a
Show file tree
Hide file tree
Showing 64 changed files with 1,738 additions and 543 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import java.util.Arrays;
import java.util.List;

import static com.faforever.client.fx.PlatformService.URL_REGEX_PATTERN;
import static com.faforever.client.fx.PlatformService.STRICT_URL_REGEX_PATTERN;

@Slf4j
@Component
Expand Down Expand Up @@ -116,7 +116,7 @@ private void setChannelTopic(String content) {
boolean notBlank = StringUtils.isNotBlank(content);
if (notBlank) {
Arrays.stream(content.split("\\s")).forEach(word -> {
if (URL_REGEX_PATTERN.matcher(word).matches()) {
if (STRICT_URL_REGEX_PATTERN.matcher(word).matches()) {
Hyperlink link = new Hyperlink(word);
link.setOnAction(event -> platformService.showDocument(word));
children.add(link);
Expand Down
32 changes: 32 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 @@ -145,6 +149,24 @@ public Optional<ChatChannelUser> getUser(String username) {
return Optional.ofNullable(usernameToChatUser.get(username));
}

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 @@ -155,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
51 changes: 50 additions & 1 deletion src/main/java/com/faforever/client/chat/ChatMessage.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.faforever.client.chat;

import com.faforever.client.chat.emoticons.Emoticon;
import com.faforever.client.chat.emoticons.Reaction;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
Expand All @@ -8,15 +14,58 @@

@RequiredArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Getter
public class ChatMessage {

@EqualsAndHashCode.Include
@Getter
private final String id;
@Getter
private final Instant time;
@Getter
private final ChatChannelUser sender;
@Getter
private final String content;
@Getter
private final Type type;
@Getter
private final ChatMessage targetMessage;

private final BooleanProperty open = new SimpleBooleanProperty();
private final ObservableMap<Emoticon, ObservableMap<String, String>> reactions = FXCollections.synchronizedObservableMap(
FXCollections.observableHashMap());
private final ObservableMap<Emoticon, ObservableMap<String, String>> unmodifiableReactions = FXCollections.unmodifiableObservableMap(
reactions);

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

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 boolean isOpen() {
return open.get();
}

public BooleanProperty openProperty() {
return open;
}

public void setOpen(boolean open) {
this.open.set(open);
}

public enum Type {
MESSAGE, ACTION, PENDING
Expand Down
Loading

0 comments on commit dc1c11a

Please sign in to comment.