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

Add reaction and reply capability to chat messages #3111

Merged
merged 4 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@
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 @@
return Optional.ofNullable(usernameToChatUser.get(username));
}

public Optional<ChatMessage> getMessage(String id) {
return Optional.ofNullable(messagesById.get(id));

Check warning on line 153 in src/main/java/com/faforever/client/chat/ChatChannel.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/chat/ChatChannel.java#L153

Added line #L153 was not covered by tests
}

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;

Check warning on line 164 in src/main/java/com/faforever/client/chat/ChatChannel.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/chat/ChatChannel.java#L164

Added line #L164 was not covered by tests
}

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 @@
pruneMessages();
}

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

Check warning on line 183 in src/main/java/com/faforever/client/chat/ChatChannel.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/chat/ChatChannel.java#L183

Added line #L183 was not covered by tests
}

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();

Check warning on line 59 in src/main/java/com/faforever/client/chat/ChatMessage.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/chat/ChatMessage.java#L59

Added line #L59 was not covered by tests
}

public BooleanProperty openProperty() {
return open;
}

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

Check warning on line 68 in src/main/java/com/faforever/client/chat/ChatMessage.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/faforever/client/chat/ChatMessage.java#L67-L68

Added lines #L67 - L68 were not covered by tests

public enum Type {
MESSAGE, ACTION, PENDING
Expand Down