Added the display of multi-line messages (#115)

* Added multi-line messages

* Added shutdown method for LoginDialog

* Fixed login bug in LoginDialog

* Added a maximum length for messages

* Implemented update of component list elements on resizing

* Improved visual appearance of some files
This commit is contained in:
delvh 2020-03-14 11:17:43 +01:00 committed by GitHub
parent 9a81fc5b06
commit 198e81608b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 202 additions and 111 deletions

View File

@ -1,8 +1,7 @@
package envoy.client.ui; package envoy.client.ui;
import java.awt.*; import java.awt.*;
import java.awt.event.KeyAdapter; import java.awt.event.*;
import java.awt.event.KeyEvent;
import java.io.IOException; import java.io.IOException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -41,17 +40,25 @@ import envoy.util.EnvoyLog;
*/ */
public class ChatWindow extends JFrame { public class ChatWindow extends JFrame {
/**
* This int defines the maximum amount of chars allowed per message. Currently
* set at 200.
*
* @since Envoy 0.1-beta
*/
public static final int MAX_MESSEAGE_LENGTH = 200;
// User specific objects // User specific objects
private Client client; private Client client;
private WriteProxy writeProxy; private WriteProxy writeProxy;
private LocalDb localDb; private LocalDb localDb;
private Chat currentChat;
// GUI components // GUI components
private JPanel contentPane = new JPanel(); private JPanel contentPane = new JPanel();
private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space); private PrimaryTextArea messageEnterTextArea = new PrimaryTextArea(space);
private JList<User> userList = new JList<>(); private JList<User> userList = new JList<>();
private DefaultListModel<User> userListModel = new DefaultListModel<>(); private DefaultListModel<User> userListModel = new DefaultListModel<>();
private Chat currentChat;
private ComponentList<Message> messageList = new ComponentList<>(new MessageListRenderer()); private ComponentList<Message> messageList = new ComponentList<>(new MessageListRenderer());
private PrimaryScrollPane scrollPane = new PrimaryScrollPane(); private PrimaryScrollPane scrollPane = new PrimaryScrollPane();
private JTextPane textPane = new JTextPane(); private JTextPane textPane = new JTextPane();
@ -64,13 +71,13 @@ public class ChatWindow extends JFrame {
private PrimaryButton addContact = new PrimaryButton("+"); private PrimaryButton addContact = new PrimaryButton("+");
// Search Contacts // Search Contacts
private final JPanel searchPane = new JPanel(); private final JPanel searchPane = new JPanel();
private final PrimaryButton cancelButton = new PrimaryButton("x"); private final PrimaryButton cancelButton = new PrimaryButton("x");
private final PrimaryTextArea searchField = new PrimaryTextArea(space); private final PrimaryTextArea searchField = new PrimaryTextArea(space);
private final PrimaryScrollPane possibleContacts = new PrimaryScrollPane(); private final PrimaryScrollPane scrollForPossibleContacts = new PrimaryScrollPane();
private final ContactsSearchRenderer contactRenderer = new ContactsSearchRenderer(); private final ContactsSearchRenderer contactRenderer = new ContactsSearchRenderer();
private final ComponentListModel<User> contactsModel = new ComponentListModel<>(); private final ComponentListModel<User> contactsModel = new ComponentListModel<>();
private final ComponentList<User> contactList = new ComponentList<>(contactRenderer); private final ComponentList<User> contactList = new ComponentList<>(contactRenderer);
private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class); private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class);
@ -98,13 +105,20 @@ public class ChatWindow extends JFrame {
GridBagLayout gbl_contentPane = new GridBagLayout(); GridBagLayout gbl_contentPane = new GridBagLayout();
gbl_contentPane.columnWidths = new int[] { 1, 1, 1 }; gbl_contentPane.columnWidths = new int[] { 1, 1, 1 };
gbl_contentPane.rowHeights = new int[] { 1, 1, 1, 1 }; gbl_contentPane.rowHeights = new int[] { 1, 1, 1, 1 };
gbl_contentPane.columnWeights = new double[] { 0.3, 1.0, 0.1 }; gbl_contentPane.columnWeights = new double[] { 0.03, 1.0, 0.1 };
gbl_contentPane.rowWeights = new double[] { 0.03, 0.001, 1.0, 0.005 }; gbl_contentPane.rowWeights = new double[] { 0.03, 0.001, 1.0, 0.005 };
contentPane.setLayout(gbl_contentPane); contentPane.setLayout(gbl_contentPane);
messageList.setBorder(new EmptyBorder(space, space, space, space)); messageList.setBorder(new EmptyBorder(space, space, space, space));
scrollPane.setViewportView(messageList); scrollPane.setViewportView(messageList);
scrollPane.addComponentListener(new ComponentAdapter() {
// updates list elements when list is resized
@Override
public void componentResized(ComponentEvent e) { messageList.synchronizeModel(); }
});
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
GridBagConstraints gbc_scrollPane = new GridBagConstraints(); GridBagConstraints gbc_scrollPane = new GridBagConstraints();
gbc_scrollPane.fill = GridBagConstraints.BOTH; gbc_scrollPane.fill = GridBagConstraints.BOTH;
@ -117,7 +131,16 @@ public class ChatWindow extends JFrame {
drawChatBox(gbc_scrollPane); drawChatBox(gbc_scrollPane);
// Message enter field // MessageEnterTextArea
messageEnterTextArea.addInputMethodListener(new InputMethodListener() {
@Override
public void inputMethodTextChanged(InputMethodEvent event) { checkMessageTextLength(); }
@Override
public void caretPositionChanged(InputMethodEvent event) {}
});
messageEnterTextArea.addKeyListener(new KeyAdapter() { messageEnterTextArea.addKeyListener(new KeyAdapter() {
@Override @Override
@ -125,29 +148,31 @@ public class ChatWindow extends JFrame {
if (e.getKeyCode() == KeyEvent.VK_ENTER if (e.getKeyCode() == KeyEvent.VK_ENTER
&& (Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0 || e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK)) && (Settings.getInstance().isEnterToSend() && e.getModifiersEx() == 0 || e.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK))
postMessage(); postMessage();
// Checking if text is too long
checkMessageTextLength();
} }
}); });
GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints(); GridBagConstraints gbc_scrollPaneForTextInput = new GridBagConstraints();
gbc_messageEnterTextfield.fill = GridBagConstraints.BOTH; gbc_scrollPaneForTextInput.fill = GridBagConstraints.BOTH;
gbc_messageEnterTextfield.gridx = 1; gbc_scrollPaneForTextInput.gridx = 1;
gbc_messageEnterTextfield.gridy = 3; gbc_scrollPaneForTextInput.gridy = 3;
gbc_messageEnterTextfield.insets = insets; gbc_scrollPaneForTextInput.insets = insets;
contentPane.add(messageEnterTextArea, gbc_messageEnterTextfield); contentPane.add(messageEnterTextArea, gbc_scrollPaneForTextInput);
// Post Button // Post Button
GridBagConstraints gbc_moveSelectionPostButton = new GridBagConstraints(); GridBagConstraints gbc_postButton = new GridBagConstraints();
gbc_moveSelectionPostButton.fill = GridBagConstraints.BOTH; gbc_postButton.fill = GridBagConstraints.BOTH;
gbc_moveSelectionPostButton.gridx = 2; gbc_postButton.gridx = 2;
gbc_moveSelectionPostButton.gridy = 3; gbc_postButton.gridy = 3;
gbc_moveSelectionPostButton.insets = insets; gbc_postButton.insets = insets;
postButton.addActionListener((evt) -> { postMessage(); }); postButton.addActionListener((evt) -> { postMessage(); });
contentPane.add(postButton, gbc_moveSelectionPostButton); contentPane.add(postButton, gbc_postButton);
// Settings Button // Settings Button
GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints(); GridBagConstraints gbc_moveSelectionSettingsButton = new GridBagConstraints();
@ -180,9 +205,8 @@ public class ChatWindow extends JFrame {
final JList<User> selectedUserList = (JList<User>) listSelectionEvent.getSource(); final JList<User> selectedUserList = (JList<User>) listSelectionEvent.getSource();
final User user = selectedUserList.getSelectedValue(); final User user = selectedUserList.getSelectedValue();
for (int i = 0; i < contentPane.getComponents().length; i++) { for (int i = 0; i < contentPane.getComponents().length; i++)
if (contentPane.getComponent(i).equals(searchPane)) { drawChatBox(gbc_scrollPane); } if (contentPane.getComponent(i).equals(searchPane)) drawChatBox(gbc_scrollPane);
}
if (user != null) { if (user != null) {
// Select current chat // Select current chat
currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get(); currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get();
@ -248,29 +272,23 @@ public class ChatWindow extends JFrame {
@Override @Override
public void removeUpdate(DocumentEvent evt) { public void removeUpdate(DocumentEvent evt) {
if (client.isOnline()) { if (client.isOnline()) if (searchField.getText().isEmpty()) {
if (searchField.getText().isEmpty()) { contactsModel.clear();
contactsModel.clear(); revalidate();
revalidate(); repaint();
repaint(); } else try {
} else { client.sendEvent(new ContactSearchRequest(searchField.getText()));
try { } catch (IOException e) {
client.sendEvent(new ContactSearchRequest(searchField.getText())); e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
} }
@Override @Override
public void insertUpdate(DocumentEvent evt) { public void insertUpdate(DocumentEvent evt) {
if (client.isOnline()) { if (client.isOnline()) try {
try { client.sendEvent(new ContactSearchRequest(searchField.getText()));
client.sendEvent(new ContactSearchRequest(searchField.getText())); } catch (IOException e) {
} catch (IOException e) { e.printStackTrace();
e.printStackTrace();
}
} }
} }
@ -289,8 +307,8 @@ public class ChatWindow extends JFrame {
searchPane.add(cancelButton, gbc_cancelButton); searchPane.add(cancelButton, gbc_cancelButton);
contactList.setModel(contactsModel); contactList.setModel(contactsModel);
possibleContacts.setBorder(new EmptyBorder(space, space, space, space)); scrollForPossibleContacts.setBorder(new EmptyBorder(space, space, space, space));
possibleContacts.setViewportView(contactList); scrollForPossibleContacts.setViewportView(contactList);
GridBagConstraints gbc_possibleContacts = new GridBagConstraints(); GridBagConstraints gbc_possibleContacts = new GridBagConstraints();
gbc_possibleContacts.fill = GridBagConstraints.BOTH; gbc_possibleContacts.fill = GridBagConstraints.BOTH;
@ -300,7 +318,7 @@ public class ChatWindow extends JFrame {
gbc_possibleContacts.insets = insets; gbc_possibleContacts.insets = insets;
searchPane.add(possibleContacts, gbc_possibleContacts); searchPane.add(scrollForPossibleContacts, gbc_possibleContacts);
// Contacts Header // Contacts Header
GridBagConstraints gbc_contactsHeader = new GridBagConstraints(); GridBagConstraints gbc_contactsHeader = new GridBagConstraints();
@ -387,13 +405,15 @@ public class ChatWindow extends JFrame {
}); });
// Listen to contact search results // Listen to contact search results
EventBus.getInstance().register(ContactSearchResult.class, evt -> { EventBus.getInstance()
contactsModel.clear(); .register(ContactSearchResult.class,
final java.util.List<User> contacts = evt.get(); evt -> {
contacts.forEach(contactsModel::add); contactsModel.clear();
revalidate(); final java.util.List<User> contacts = evt.get();
repaint(); contacts.forEach(contactsModel::add);
}); revalidate();
repaint();
});
// Add new contacts to the contact list // Add new contacts to the contact list
EventBus.getInstance().register(ContactOperationEvent.class, evt -> { EventBus.getInstance().register(ContactOperationEvent.class, evt -> {
@ -427,14 +447,11 @@ public class ChatWindow extends JFrame {
contentPane.setBackground(theme.getBackgroundColor()); contentPane.setBackground(theme.getBackgroundColor());
contentPane.setForeground(theme.getUserNameColor()); contentPane.setForeground(theme.getUserNameColor());
// messageList // messageList
// messageList.setSelectionForeground(theme.getUserNameColor()); messageList.setForeground(theme.getMessageTextColor());
// messageList.setSelectionBackground(theme.getSelectionColor());
messageList.setForeground(theme.getMessageColorChat());
messageList.setBackground(theme.getCellColor()); messageList.setBackground(theme.getCellColor());
// scrollPane // scrollPane
scrollPane.applyTheme(theme); scrollPane.applyTheme(theme);
scrollPane.autoscroll(); scrollPane.autoscroll();
// messageEnterTextArea // messageEnterTextArea
messageEnterTextArea.setCaretColor(theme.getTypingMessageColor()); messageEnterTextArea.setCaretColor(theme.getTypingMessageColor());
messageEnterTextArea.setForeground(theme.getTypingMessageColor()); messageEnterTextArea.setForeground(theme.getTypingMessageColor());
@ -465,9 +482,9 @@ public class ChatWindow extends JFrame {
searchField.setForeground(theme.getUserNameColor()); searchField.setForeground(theme.getUserNameColor());
cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setBackground(theme.getInteractableBackgroundColor());
cancelButton.setForeground(theme.getInteractableForegroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor());
contactList.setForeground(theme.getMessageColorChat()); contactList.setForeground(theme.getMessageTextColor());
contactList.setBackground(theme.getCellColor()); contactList.setBackground(theme.getCellColor());
possibleContacts.applyTheme(theme); scrollForPossibleContacts.applyTheme(theme);
} }
private void postMessage() { private void postMessage() {
@ -477,7 +494,7 @@ public class ChatWindow extends JFrame {
} }
if (!messageEnterTextArea.getText().isEmpty()) try { if (!messageEnterTextArea.getText().isEmpty()) try {
checkMessageTextLength();
// Create message // Create message
final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator()) final Message message = new MessageBuilder(localDb.getUser().getId(), currentChat.getRecipient().getId(), localDb.getIdGenerator())
.setText(messageEnterTextArea.getText()) .setText(messageEnterTextArea.getText())
@ -575,4 +592,24 @@ public class ChatWindow extends JFrame {
this.writeProxy = writeProxy; this.writeProxy = writeProxy;
loadUsersAndChats(); loadUsersAndChats();
} }
/**
* Checks whether the length of the text inside messageEnterTextArea >=
* {@link ChatWindow#MAX_MESSEAGE_LENGTH}
* and splits the text into the allowed part, if that is the case.
*
* @since Envoy v0.1-beta
*/
private void checkMessageTextLength() {
String input = messageEnterTextArea.getText();
if (input.length() >= MAX_MESSEAGE_LENGTH) {
messageEnterTextArea.setText(input.substring(0, MAX_MESSEAGE_LENGTH - 1));
// TODO: current notification is like being hit with a hammer, maybe it should
// be replaced with a more subtle notification
JOptionPane.showMessageDialog(messageEnterTextArea,
"the maximum length for a message has been reached",
"maximum message length reached",
JOptionPane.WARNING_MESSAGE);
}
}
} }

View File

@ -3,11 +3,15 @@ package envoy.client.ui;
import java.awt.color.ColorSpace; import java.awt.color.ColorSpace;
/** /**
* Project: <strong>envoy-clientChess</strong><br> * This class further develops {@link java.awt.Color} by adding extra methods
* File: <strong>Color.javaEvent.java</strong><br> * and more default colors.
*
* Project: <strong>envoy-client</strong><br>
* File: <strong>Color.java</strong><br>
* Created: <strong>23.12.2019</strong><br> * Created: <strong>23.12.2019</strong><br>
* *
* @author Kai S. K. Engelbart * @author Kai S. K. Engelbart
* @since Envoy v0.3-alpha
*/ */
@SuppressWarnings("javadoc") @SuppressWarnings("javadoc")
public class Color extends java.awt.Color { public class Color extends java.awt.Color {
@ -98,11 +102,13 @@ public class Color extends java.awt.Color {
/** /**
* @return the inversion of this {@link Color} by replacing the red, green and * @return the inversion of this {@link Color} by replacing the red, green and
* blue values by subtracting them form 255 * blue values by subtracting them form 255
* @since Envoy v0.3-alpha
*/ */
public Color invert() { return new Color(255 - getRed(), 255 - getGreen(), 255 - getBlue()); } public Color invert() { return new Color(255 - getRed(), 255 - getGreen(), 255 - getBlue()); }
/** /**
* @return the hex value of this {@link Color} * @return the hex value of this {@link Color}
* @since Envoy v0.3-alpha
*/ */
public String toHex() { return String.format("#%02x%02x%02x", getRed(), getGreen(), getBlue()); } public String toHex() { return String.format("#%02x%02x%02x", getRed(), getGreen(), getBlue()); }
} }

View File

@ -39,9 +39,8 @@ public class ContactsSearchRenderer implements ComponentListCellRenderer<User> {
panel.setForeground(list.getForeground()); panel.setForeground(list.getForeground());
} }
JLabel display = new JLabel(String.format("<html><p style=\"color:%s\">%s</html>", JLabel display = new JLabel(user.getName());
Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat().toHex(), display.setForeground(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageTextColor());
user.getName()));
display.setAlignmentX(Component.LEFT_ALIGNMENT); display.setAlignmentX(Component.LEFT_ALIGNMENT);
display.setAlignmentY(Component.CENTER_ALIGNMENT); display.setAlignmentY(Component.CENTER_ALIGNMENT);
display.setFont(new Font("Arial", Font.PLAIN, 16)); display.setFont(new Font("Arial", Font.PLAIN, 16));

View File

@ -2,6 +2,8 @@ package envoy.client.ui;
import java.awt.*; import java.awt.*;
import java.awt.event.ItemEvent; import java.awt.event.ItemEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException; import java.io.IOException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.util.Arrays;
@ -80,20 +82,29 @@ public class LoginDialog extends JDialog {
// Prepare handshake // Prepare handshake
localDb.loadIdGenerator(); localDb.loadIdGenerator();
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) { abortLogin(); }
});
initUi(); initUi();
okButton.addActionListener((evt) -> { okButton.addActionListener((evt) -> {
try { try {
if (registerCheckBox.isSelected()) { if (registerCheckBox.isSelected()) {
// Check password equality // Check password equality
if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) if (Arrays.equals(passwordField.getPassword(), repeatPasswordField.getPassword())) {
credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true); credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), true);
else { performHandshake();
JOptionPane.showMessageDialog(this, "The repeated password is not the origional password!"); } else {
JOptionPane.showMessageDialog(this, "The repeated password is not the original password!");
clearPasswordFields(); clearPasswordFields();
} }
} else credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false); } else {
performHandshake(); credentials = new LoginCredentials(textField.getText(), passwordField.getPassword(), false);
performHandshake();
}
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -105,7 +116,7 @@ public class LoginDialog extends JDialog {
evt -> { clearPasswordFields(); errorMessage.setVisible(true); errorMessage.setText(evt.get()); }); evt -> { clearPasswordFields(); errorMessage.setVisible(true); errorMessage.setText(evt.get()); });
// Exit the application when the dialog is cancelled // Exit the application when the dialog is cancelled
cancelButton.addActionListener(evt -> { logger.info("The login process has been cancelled. Exiting..."); System.exit(0); }); cancelButton.addActionListener(evt -> abortLogin());
// Log in directly if configured // Log in directly if configured
if (config.hasLoginCredentials()) { if (config.hasLoginCredentials()) {
@ -320,4 +331,14 @@ public class LoginDialog extends JDialog {
cancelButton.setBackground(theme.getInteractableBackgroundColor()); cancelButton.setBackground(theme.getInteractableBackgroundColor());
cancelButton.setForeground(theme.getInteractableForegroundColor()); cancelButton.setForeground(theme.getInteractableForegroundColor());
} }
/**
* Shuts the system down properly if the login was aborted.
*
* @since Envoy v0.1-beta
*/
private void abortLogin() {
logger.info("The login process has been cancelled. Exiting...");
System.exit(0);
}
} }

View File

@ -1,11 +1,10 @@
package envoy.client.ui; package envoy.client.ui;
import java.awt.Dimension; import java.awt.BorderLayout;
import java.awt.Font;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import javax.swing.BorderFactory; import javax.swing.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import envoy.client.data.Settings; import envoy.client.data.Settings;
import envoy.client.ui.list.ComponentList; import envoy.client.ui.list.ComponentList;
@ -21,46 +20,74 @@ import envoy.data.Message;
* *
* @author Kai S. K. Engelbart * @author Kai S. K. Engelbart
* @author Maximilian K&auml;fer * @author Maximilian K&auml;fer
* @author Leon Hofmeister
* @since Envoy v0.1-alpha * @since Envoy v0.1-alpha
*/ */
public class MessageListRenderer implements ComponentListCellRenderer<Message> { public class MessageListRenderer implements ComponentListCellRenderer<Message> {
private JTextArea messageTextArea;
@Override @Override
public JPanel getListCellComponent(ComponentList<? extends Message> list, Message value, boolean isSelected) { public JPanel getListCellComponent(ComponentList<? extends Message> list, Message value, boolean isSelected) {
final JPanel panel = new JPanel(); final JPanel panel = new JPanel();
final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()); panel.setLayout(new BorderLayout());
final Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
// Panel background // Panel background
panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor()); panel.setBackground(isSelected ? theme.getSelectionColor() : theme.getCellColor());
// TODO: Handle message attachments // TODO: Handle message attachments
final String text = value.getText();
final String state = value.getStatus().toString(); final String state = value.getStatus().toString();
final String date = new SimpleDateFormat("dd.MM.yyyy HH.mm").format(value.getCreationDate()); final String date = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(value.getCreationDate());
final String text = value.getText();
// Message text color // The Label that displays the creation date of a message
String textColor = theme.getMessageColorChat().toHex(); JLabel dateLabel = new JLabel(date);
// Set the date color to be the value of DateColorChat
dateLabel.setForeground(theme.getDateColor());
// Message date color panel.add(dateLabel, BorderLayout.NORTH);
String dateColor = theme.getDateColorChat().toHex();
panel.add(new JLabel(String.format("<html><p style=\"color:%s\"><b><small>%s</b></small><br><p style=\"color:%s\">%s :%s</html>", // The JTextArea that displays the text content of a message and its status
dateColor, messageTextArea = new JTextArea(text + System.getProperty("line.separator"));
date, messageTextArea.setLineWrap(true);
textColor, messageTextArea.setWrapStyleWord(true);
text, messageTextArea.setAlignmentX(0.5f);
state))); messageTextArea.setForeground(theme.getMessageTextColor());
messageTextArea.setBackground(panel.getBackground());
messageTextArea.setEditable(false);
panel.add(messageTextArea, BorderLayout.CENTER);
JLabel statusLabel = new JLabel(state);
statusLabel.setFont(new Font("Arial", Font.BOLD, 14));
Color statusColor;
switch (value.getStatus()) {
case WAITING:
statusColor = Color.gray;
break;
case SENT:
statusColor = Color.blue;
break;
case RECEIVED:
statusColor = Color.yellow;
break;
case READ:
statusColor = Color.green;
break;
default:
statusColor = theme.getMessageTextColor();
break;
}
statusLabel.setForeground(statusColor);
statusLabel.setBackground(panel.getBackground());
panel.add(statusLabel, BorderLayout.SOUTH);
// Define some space to the messages below // Define some space to the messages below
panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder())); panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(), BorderFactory.createEtchedBorder()));
// Set the width to the list width
Dimension size = new Dimension(list.getWidth() - 25, panel.getPreferredSize().height);
panel.setMaximumSize(size);
panel.setMinimumSize(size);
panel.setPreferredSize(size);
return panel; return panel;
} }
} }

View File

@ -51,7 +51,6 @@ public class Startup {
*/ */
public static void main(String[] args) { public static void main(String[] args) {
ClientConfig config = ClientConfig.getInstance(); ClientConfig config = ClientConfig.getInstance();
SwingUtilities.invokeLater(() -> chatWindow = new ChatWindow()); SwingUtilities.invokeLater(() -> chatWindow = new ChatWindow());
try { try {

View File

@ -85,16 +85,18 @@ public class Theme implements Serializable {
public Color getInteractableForegroundColor() { return colors.get("interactableForegroundColor"); } public Color getInteractableForegroundColor() { return colors.get("interactableForegroundColor"); }
/** /**
* @return messageColorChat * @return the {@link Color} in which the text content of a message should be
* displayed
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getMessageColorChat() { return colors.get("messageColorChat"); } public Color getMessageTextColor() { return colors.get("messageColorChat"); }
/** /**
* @return dateColorChat * @return the {@link Color} in which the creation date of a message should be
* displayed
* @since Envoy v0.2-alpha * @since Envoy v0.2-alpha
*/ */
public Color getDateColorChat() { return colors.get("dateColorChat"); } public Color getDateColor() { return colors.get("dateColorChat"); }
/** /**
* @return selectionColor * @return selectionColor

View File

@ -82,6 +82,7 @@ public class ComponentList<E> extends JPanel {
public void synchronizeModel() { public void synchronizeModel() {
removeAll(); removeAll();
if (model != null) model.forEach(this::add); if (model != null) model.forEach(this::add);
revalidate();
} }
/** /**
@ -120,7 +121,7 @@ public class ComponentList<E> extends JPanel {
return new MouseAdapter() { return new MouseAdapter() {
@Override @Override
public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { componentSelected(componentIndex); } } public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) componentSelected(componentIndex); }
}; };
} }
@ -141,7 +142,6 @@ public class ComponentList<E> extends JPanel {
// Clear selection // Clear selection
update(currentSelection, false); update(currentSelection, false);
currentSelection = -1; currentSelection = -1;
} else { } else {
// Remove old selection // Remove old selection
@ -152,7 +152,6 @@ public class ComponentList<E> extends JPanel {
// Update current selection // Update current selection
update(currentSelection, true); update(currentSelection, true);
} }
revalidate(); revalidate();

View File

@ -34,6 +34,7 @@ public final class ComponentListModel<E> implements Iterable<E>, Serializable {
*/ */
public boolean add(E e) { public boolean add(E e) {
if (componentList != null) componentList.add(e); if (componentList != null) componentList.add(e);
componentList.revalidate();
return elements.add(e); return elements.add(e);
} }

View File

@ -181,8 +181,8 @@ public class ThemeCustomizationPanel extends SettingsPanel {
buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2); buildCustomizeElement(theme, theme.getCellColor(), "Cells", "cellColor", 2);
buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3); buildCustomizeElement(theme, theme.getInteractableForegroundColor(), "Interactable Foreground", "interactableForegroundColor", 3);
buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4); buildCustomizeElement(theme, theme.getInteractableBackgroundColor(), "Interactable Background", "interactableBackgroundColor", 4);
buildCustomizeElement(theme, theme.getMessageColorChat(), "Messages Chat", "messageColorChat", 5); buildCustomizeElement(theme, theme.getMessageTextColor(), "Messages Chat", "messageColorChat", 5);
buildCustomizeElement(theme, theme.getDateColorChat(), "Date Chat", "dateColorChat", 6); buildCustomizeElement(theme, theme.getDateColor(), "Date Chat", "dateColorChat", 6);
buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7); buildCustomizeElement(theme, theme.getSelectionColor(), "Selection", "selectionColor", 7);
buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor", 8); buildCustomizeElement(theme, theme.getTypingMessageColor(), "Typing Message", "typingMessageColor", 8);
buildCustomizeElement(theme, theme.getUserNameColor(), "User Names", "userNameColor", 9); buildCustomizeElement(theme, theme.getUserNameColor(), "User Names", "userNameColor", 9);