Skip to content

Commit

Permalink
Reduce chat tab dependencies (#3086)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sheikah45 authored Dec 16, 2023
1 parent 2827411 commit 7e1f13d
Show file tree
Hide file tree
Showing 22 changed files with 302 additions and 508 deletions.
1 change: 1 addition & 0 deletions .idea/codeStyles/Project.xml

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

3 changes: 1 addition & 2 deletions src/main/java/com/faforever/client/audio/AudioService.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public class AudioService implements InitializingBean {
private static final String FRIEND_OFFLINE_SOUND = "theme/sounds/friendOfflineSound.mp3";
private static final String FRIEND_JOINS_GAME_SOUND = "theme/sounds/friendJoinsGameSound.mp3";
private static final String FRIEND_PLAYS_GAME_SOUND = "theme/sounds/friendPlaysGameSound.mp3";
private static final long MILLISECONDS_SILENT_AFTER_SOUND = 30000;

private final AudioClipPlayer audioClipPlayer;
private final ThemeService themeService;
Expand Down Expand Up @@ -155,7 +154,7 @@ private void playSound(AudioClip audioClip) {
}

long currentTimeMillis = System.currentTimeMillis();
if (currentTimeMillis - lastPlayedSoundTime < MILLISECONDS_SILENT_AFTER_SOUND) {
if (currentTimeMillis - lastPlayedSoundTime < notificationPrefs.getSilenceBetweenSounds()) {
return;
}
lastPlayedSoundTime = currentTimeMillis;
Expand Down
148 changes: 65 additions & 83 deletions src/main/java/com/faforever/client/chat/AbstractChatTabController.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@
import com.faforever.client.fx.TabController;
import com.faforever.client.fx.WebViewConfigurer;
import com.faforever.client.i18n.I18n;
import com.faforever.client.navigation.NavigationHandler;
import com.faforever.client.notification.NotificationService;
import com.faforever.client.player.CountryFlagService;
import com.faforever.client.player.PlayerService;
import com.faforever.client.preferences.ChatPrefs;
import com.faforever.client.preferences.NotificationPrefs;
import com.faforever.client.theme.ThemeService;
import com.faforever.client.theme.UiService;
import com.faforever.client.ui.StageHolder;
import com.faforever.client.user.LoginService;
import com.faforever.client.util.ConcurrentUtil;
import com.faforever.client.util.PopupUtil;
import com.faforever.client.util.TimeService;
Expand All @@ -28,6 +24,7 @@
import com.google.common.io.CharStreams;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
Expand All @@ -43,11 +40,9 @@
import javafx.scene.control.skin.TabPaneSkin;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Popup;
import javafx.stage.PopupWindow;
import javafx.stage.PopupWindow.AnchorLocation;
import javafx.stage.Window;
import lombok.RequiredArgsConstructor;
Expand All @@ -60,7 +55,6 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
Expand Down Expand Up @@ -121,9 +115,7 @@ public abstract class AbstractChatTabController extends TabController {
private static final String ACTION_CSS_CLASS = "action";
private static final String MESSAGE_CSS_CLASS = "message";

protected final LoginService loginService;
protected final ChatService chatService;
protected final PlayerService playerService;
protected final TimeService timeService;
protected final I18n i18n;
protected final NotificationService notificationService;
Expand All @@ -133,9 +125,7 @@ public abstract class AbstractChatTabController extends TabController {
protected final EmoticonService emoticonService;
protected final CountryFlagService countryFlagService;
protected final ChatPrefs chatPrefs;
protected final NotificationPrefs notificationPrefs;
protected final FxApplicationThreadExecutor fxApplicationThreadExecutor;
protected final NavigationHandler navigationHandler;

/**
* Messages that arrived before the web view was ready. Those are appended as soon as it is ready.
Expand All @@ -145,17 +135,19 @@ public abstract class AbstractChatTabController extends TabController {
private final IntegerProperty unreadMessagesCount = new SimpleIntegerProperty();
protected final ObjectProperty<ChatChannel> chatChannel = new SimpleObjectProperty<>();
protected final ObservableValue<String> channelName = chatChannel.map(ChatChannel::getName);
private final ReadOnlyStringWrapper chatMessageTextHtml = new ReadOnlyStringWrapper();
private final ReadOnlyStringWrapper chatMessageSectionHtml = new ReadOnlyStringWrapper();

private final Consumer<ChatMessage> messageListener = this::onChatMessage;
private int lastEntryId;
private boolean isChatReady;

public Button emoticonsButton;
@VisibleForTesting
protected WeakReference<Popup> emoticonsPopupWindowWeakReference;

private ChatMessage lastMessage;
private WebEngine engine;
private Popup emoticonsPopup;

private String currentUserMessage = "";
private int curMessageHistoryIndex = 0;

Expand All @@ -165,7 +157,41 @@ public abstract class AbstractChatTabController extends TabController {
@Override
protected void onInitialize() {
mentionPattern = Pattern.compile(
"(^|[^A-Za-z0-9-])" + Pattern.quote(loginService.getUsername()) + "([^A-Za-z0-9-]|$)", CASE_INSENSITIVE);
"(^|[^A-Za-z0-9-])" + Pattern.quote(chatService.getCurrentUsername()) + "([^A-Za-z0-9-]|$)", CASE_INSENSITIVE);

chatMessageTextHtml.bind(chatPrefs.chatFormatProperty().map(chatFormat -> switch (chatFormat) {
case COMPACT -> CHAT_TEXT_COMPACT;
case EXTENDED -> CHAT_TEXT_EXTENDED;
}).map(themeFile -> {
try {
return themeService.getThemeFileUrl(themeFile);
} catch (IOException e) {
return null;
}
}).map(url -> {
try (Reader reader = new InputStreamReader(url.openStream())) {
return CharStreams.toString(reader);
} catch (IOException e) {
return null;
}
}).orElse(""));

chatMessageSectionHtml.bind(chatPrefs.chatFormatProperty().map(chatFormat -> switch (chatFormat) {
case COMPACT -> CHAT_SECTION_COMPACT;
case EXTENDED -> CHAT_SECTION_EXTENDED;
}).map(themeFile -> {
try {
return themeService.getThemeFileUrl(themeFile);
} catch (IOException e) {
return null;
}
}).map(url -> {
try (Reader reader = new InputStreamReader(url.openStream())) {
return CharStreams.toString(reader);
} catch (IOException e) {
return null;
}
}).orElse(""));

initChatView();

Expand Down Expand Up @@ -196,6 +222,11 @@ protected void onInitialize() {
unreadMessagesCount.subscribe(
(oldValue, newValue) -> incrementUnreadMessageCount(newValue.intValue() - oldValue.intValue()));
getRoot().setOnClosed(this::onClosed);

EmoticonsWindowController controller = uiService.loadFxml("theme/chat/emoticons/emoticons_window.fxml");
controller.setTextInputControl(messageTextField());
emoticonsPopup = PopupUtil.createPopup(AnchorLocation.WINDOW_BOTTOM_RIGHT, controller.getRoot());
emoticonsPopup.setConsumeAutoHidingEvents(false);
}

@Override
Expand Down Expand Up @@ -405,7 +436,7 @@ public void onSendMessage() {
}

if(userMessageHistory.size() >= 50) {
userMessageHistory.remove(0);
userMessageHistory.removeFirst();
userMessageHistory.add(text);
} else {
userMessageHistory.add(text);
Expand All @@ -427,12 +458,7 @@ public void onSendMessage() {
}

private void hideEmoticonsWindow() {
if (emoticonsPopupWindowWeakReference != null) {
PopupWindow window = emoticonsPopupWindowWeakReference.get();
if (window != null && window.isShowing()) {
window.hide();
}
}
emoticonsPopup.hide();
}

private void sendMessage() {
Expand Down Expand Up @@ -510,6 +536,10 @@ private void removeTopmostMessages() {
* entry.
*/
private void addMessage(ChatMessage chatMessage) {
if (mentionPattern.matcher(chatMessage.message()).find()) {
onMention(chatMessage);
}

JavaFxUtil.assertApplicationThread();
try {
if (requiresNewChatSection(chatMessage)) {
Expand All @@ -527,7 +557,7 @@ private boolean requiresNewChatSection(ChatMessage chatMessage) {
if (lastMessage == null) {
return true;
}
if (!lastMessage.username().equals(chatMessage.username())) {
if (!lastMessage.sender().getUsername().equals(chatMessage.sender().getUsername())) {
return true;
}
if (lastMessage.time().isBefore(chatMessage.time().minus(1, MINUTES))) {
Expand All @@ -537,40 +567,23 @@ private boolean requiresNewChatSection(ChatMessage chatMessage) {
}

private void appendMessage(ChatMessage chatMessage) throws IOException {
URL themeFileUrl;
if (chatPrefs.getChatFormat() == ChatFormat.COMPACT) {
themeFileUrl = themeService.getThemeFileUrl(CHAT_TEXT_COMPACT);
} else {
themeFileUrl = themeService.getThemeFileUrl(CHAT_TEXT_EXTENDED);
}

String html = renderHtml(chatMessage, themeFileUrl, null);
String html = fillTemplateHtml(chatMessage, chatMessageTextHtml.get(), null);

insertIntoContainer(html, "chat-section-" + lastEntryId);
}

private void appendChatMessageSection(ChatMessage chatMessage) throws IOException {
URL themeFileURL;
if (chatPrefs.getChatFormat() == ChatFormat.COMPACT) {
themeFileURL = themeService.getThemeFileUrl(CHAT_SECTION_COMPACT);
} else {
themeFileURL = themeService.getThemeFileUrl(CHAT_SECTION_EXTENDED);
}

String html = renderHtml(chatMessage, themeFileURL, ++lastEntryId);
String html = fillTemplateHtml(chatMessage, chatMessageSectionHtml.get(), ++lastEntryId);
insertIntoContainer(html, MESSAGE_CONTAINER_ID);
appendMessage(chatMessage);
}

private String renderHtml(ChatMessage chatMessage, URL themeFileUrl, @Nullable Integer sectionId) throws IOException {
String html;
try (Reader reader = new InputStreamReader(themeFileUrl.openStream())) {
html = CharStreams.toString(reader);
}

String username = chatMessage.username();
private String fillTemplateHtml(ChatMessage chatMessage, String htmlTemplate,
@Nullable Integer sectionId) throws IOException {
ChatChannelUser sender = chatMessage.sender();
String username = sender.getUsername();

Optional<PlayerBean> playerOptional = playerService.getPlayerByNameIfOnline(chatMessage.username());
Optional<PlayerBean> playerOptional = sender.getPlayer();
Optional<String> clanOptional = playerOptional.map(PlayerBean::getClan);

String avatarUrl = playerOptional.map(PlayerBean::getAvatar).map(AvatarBean::getUrl).map(URL::toString).orElse("");
Expand All @@ -582,7 +595,7 @@ private String renderHtml(ChatMessage chatMessage, URL themeFileUrl, @Nullable I
String decoratedClanTag = clanOptional.map(tag -> i18n.get("chat.clanTagFormat", tag)).orElse("");

String timeString = timeService.asShortTime(chatMessage.time());
html = html.replace("{time}", timeString)
String html = htmlTemplate.replace("{time}", timeString)
.replace("{avatar}", avatarUrl)
.replace("{username}", username)
.replace("{clan-tag}", clanTag)
Expand All @@ -591,17 +604,16 @@ private String renderHtml(ChatMessage chatMessage, URL themeFileUrl, @Nullable I
.replace("{section-id}", String.valueOf(sectionId));

Collection<String> cssClasses = new ArrayList<>();
cssClasses.add(String.format("user-%s", chatMessage.username()));
cssClasses.add(String.format("user-%s", username));
if (chatMessage.action()) {
cssClasses.add(ACTION_CSS_CLASS);
} else {
cssClasses.add(MESSAGE_CSS_CLASS);
}
sender.getCategories().stream().sorted().map(ChatUserCategory::getCssClass).findFirst().ifPresent(cssClasses::add);

html = html.replace("{css-classes}", Joiner.on(' ').join(cssClasses));

Optional.ofNullable(getMessageCssClass(username)).ifPresent(cssClasses::add);

String text = htmlEscaper().escape(chatMessage.message()).replace("\\", "\\\\");
text = convertUrlsToHyperlinks(text);
text = replaceChannelNamesWithHyperlinks(text);
Expand All @@ -610,11 +622,9 @@ private String renderHtml(ChatMessage chatMessage, URL themeFileUrl, @Nullable I
Matcher matcher = mentionPattern.matcher(text);
if (matcher.find()) {
text = matcher.replaceAll("<span class='self'>" + matcher.group() + "</span>");
onMention(chatMessage);
}

return html.replace("{css-classes}", Joiner.on(' ').join(cssClasses))
.replace("{inline-style}", getInlineStyle(username))
return html.replace("{inline-style}", getInlineStyle(sender))
// Always replace text last in case the message contains one of the placeholders.
.replace("{text}", text);
}
Expand Down Expand Up @@ -645,25 +655,11 @@ protected void onMention(ChatMessage chatMessage) {
// Default implementation does nothing
}

protected String getMessageCssClass(String login) {
Optional<PlayerBean> playerOptional = playerService.getPlayerByNameIfOnline(login);
if (playerOptional.isEmpty()) {
return CSS_CLASS_CHAT_ONLY;
}

return playerOptional.get().getSocialStatus().getCssClass();
}

protected String getInlineStyle(String username) {
protected String getInlineStyle(ChatChannelUser chatChannelUser) {
// To be overridden by subclasses
return "";
}

@VisibleForTesting
String createInlineStyleFromColor(Color messageColor) {
return String.format("color: %s;", JavaFxUtil.toRgbCode(messageColor));
}

protected String convertUrlsToHyperlinks(String text) {
JavaFxUtil.assertApplicationThread();
return (String) engine.executeScript("link('" + text.replace("'", "\\'") + "')");
Expand All @@ -686,22 +682,8 @@ public void openEmoticonsPopupWindow() {
double anchorX = screenBounds.getMaxX() - 5;
double anchorY = screenBounds.getMinY() - 5;

if (emoticonsPopupWindowWeakReference != null) {
PopupWindow window = emoticonsPopupWindowWeakReference.get();
if (window != null) {
window.show(emoticonsButton.getScene().getWindow(), anchorX, anchorY);
messageTextField().requestFocus();
return;
}
}

EmoticonsWindowController controller = uiService.loadFxml("theme/chat/emoticons/emoticons_window.fxml");
controller.setTextInputControl(messageTextField());
messageTextField().requestFocus();
Popup window = PopupUtil.createPopup(AnchorLocation.WINDOW_BOTTOM_RIGHT, controller.getRoot());
window.setConsumeAutoHidingEvents(false);
window.show(emoticonsButton.getScene().getWindow(), anchorX, anchorY);
emoticonsPopupWindowWeakReference = new WeakReference<>(window);
emoticonsPopup.show(emoticonsButton.getScene().getWindow(), anchorX, anchorY);
}

@VisibleForTesting
Expand Down
Loading

0 comments on commit 7e1f13d

Please sign in to comment.