Merge branch 'develop' into f/invalid_login
This commit is contained in:
		@@ -127,7 +127,6 @@ public class Settings {
 | 
			
		||||
	 * @param themeName the name to set
 | 
			
		||||
	 * @since Envoy v0.2-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	public void setCurrentTheme(String themeName) { ((SettingsItem<String>) items.get("currentTheme")).set(themeName); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -146,7 +145,6 @@ public class Settings {
 | 
			
		||||
	 *                    conjunction with the {@code Control} key.
 | 
			
		||||
	 * @since Envoy v0.2-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	public void setEnterToSend(boolean enterToSend) { ((SettingsItem<Boolean>) items.get("enterToSend")).set(enterToSend); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -161,7 +159,6 @@ public class Settings {
 | 
			
		||||
	 * @param currentOnCloseMode the on close mode that should be set.
 | 
			
		||||
	 * @since Envoy v0.3-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	public void setCurrentOnCloseMode(boolean currentOnCloseMode) { ((SettingsItem<Boolean>) items.get("onCloseMode")).set(currentOnCloseMode); }
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package envoy.client.event;
 | 
			
		||||
 | 
			
		||||
import envoy.data.Message;
 | 
			
		||||
import envoy.event.Event;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
@@ -10,7 +11,7 @@ import envoy.data.Message;
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @since Envoy v0.2-alpha
 | 
			
		||||
 */
 | 
			
		||||
public class MessageCreationEvent extends MessageEvent {
 | 
			
		||||
public class MessageCreationEvent extends Event<Message> {
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = -6451021678064566774L;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,34 +0,0 @@
 | 
			
		||||
package envoy.client.event;
 | 
			
		||||
 | 
			
		||||
import envoy.data.Message;
 | 
			
		||||
import envoy.event.Event;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
 * File: <strong>MessageCreationEvent.java</strong><br>
 | 
			
		||||
 * Created: <strong>4 Dec 2019</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @since Envoy v0.2-alpha
 | 
			
		||||
 */
 | 
			
		||||
public class MessageEvent implements Event<Message> {
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 7658989461923112804L;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * the {@link Message} attached to this {@link MessageEvent}.
 | 
			
		||||
	 */
 | 
			
		||||
	protected final Message message;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initializes a {@link MessageEvent} conveying information about a
 | 
			
		||||
	 * {@link Message} object.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param message the {@link Message} object to attach to this event
 | 
			
		||||
	 * @since Envoy v0.2-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public MessageEvent(Message message) { this.message = message; }
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Message get() { return message; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package envoy.client.event;
 | 
			
		||||
 | 
			
		||||
import envoy.data.Message;
 | 
			
		||||
import envoy.event.Event;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
@@ -10,7 +11,7 @@ import envoy.data.Message;
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @since Envoy v0.2-alpha
 | 
			
		||||
 */
 | 
			
		||||
public class MessageModificationEvent extends MessageEvent {
 | 
			
		||||
public class MessageModificationEvent extends Event<Message> {
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 4650039506439563116L;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								src/main/java/envoy/client/event/SendEvent.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/main/java/envoy/client/event/SendEvent.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
package envoy.client.event;
 | 
			
		||||
 | 
			
		||||
import envoy.event.Event;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
 * File: <strong>SendEvent.java</strong><br>
 | 
			
		||||
 * Created: <strong>11.02.2020</strong><br>
 | 
			
		||||
 * 
 | 
			
		||||
 * @author: Maximilian Käfer
 | 
			
		||||
 * 
 | 
			
		||||
 * @since Envoy v0.3-alpha
 | 
			
		||||
 */
 | 
			
		||||
public class SendEvent extends Event<Event<?>> {
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 8372746924138839060L;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param value the event to send to the server
 | 
			
		||||
	 */
 | 
			
		||||
	public SendEvent(Event<?> value) { super(value); }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -11,10 +11,9 @@ import envoy.event.Event;
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @since Envoy v0.2-alpha
 | 
			
		||||
 */
 | 
			
		||||
public class ThemeChangeEvent implements Event<Theme> {
 | 
			
		||||
public class ThemeChangeEvent extends Event<Theme> {
 | 
			
		||||
 | 
			
		||||
	private static final long	serialVersionUID	= 6756772448803774547L;
 | 
			
		||||
	private final Theme			theme;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initializes a {@link ThemeChangeEvent} conveying information about the change
 | 
			
		||||
@@ -23,8 +22,5 @@ public class ThemeChangeEvent implements Event<Theme> {
 | 
			
		||||
	 * @param theme the new currently used {@link Theme} object
 | 
			
		||||
	 * @since Envoy v0.2-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public ThemeChangeEvent(Theme theme) { this.theme = theme; }
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public Theme get() { return theme; }
 | 
			
		||||
	public ThemeChangeEvent(Theme theme) { super(theme); }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,9 +12,11 @@ import javax.naming.TimeLimitExceededException;
 | 
			
		||||
import envoy.client.data.Cache;
 | 
			
		||||
import envoy.client.data.Config;
 | 
			
		||||
import envoy.client.data.LocalDb;
 | 
			
		||||
import envoy.client.event.SendEvent;
 | 
			
		||||
import envoy.client.util.EnvoyLog;
 | 
			
		||||
import envoy.data.*;
 | 
			
		||||
import envoy.event.*;
 | 
			
		||||
import envoy.event.ContactOperationEvent.Operation;
 | 
			
		||||
import envoy.util.SerializationUtils;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -109,11 +111,26 @@ public class Client implements Closeable {
 | 
			
		||||
		receiver.registerProcessor(MessageStatusChangeEvent.class, new MessageStatusChangeEventProcessor());
 | 
			
		||||
 | 
			
		||||
		// Process user status changes
 | 
			
		||||
		receiver.registerProcessor(UserStatusChangeEvent.class, new UserStatusChangeProcessor(this));
 | 
			
		||||
		receiver.registerProcessor(UserStatusChangeEvent.class, new UserStatusChangeProcessor(localDb));
 | 
			
		||||
 | 
			
		||||
		// Process message ID generation
 | 
			
		||||
		receiver.registerProcessor(IdGenerator.class, localDb::setIdGenerator);
 | 
			
		||||
 | 
			
		||||
		// Process contact searches
 | 
			
		||||
		receiver.registerProcessor(ContactSearchResult.class, EventBus.getInstance()::dispatch);
 | 
			
		||||
 | 
			
		||||
		receiver.registerProcessor(Contacts.class,
 | 
			
		||||
				contacts -> EventBus.getInstance().dispatch(new ContactOperationEvent(contacts.getContacts().get(0), Operation.ADD)));
 | 
			
		||||
 | 
			
		||||
		// Send event
 | 
			
		||||
		EventBus.getInstance().register(SendEvent.class, evt -> {
 | 
			
		||||
			try {
 | 
			
		||||
				sendEvent(evt.get());
 | 
			
		||||
			} catch (IOException e) {
 | 
			
		||||
				e.printStackTrace();
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		// Request a generator if none is present or the existing one is consumed
 | 
			
		||||
		if (!localDb.hasIdGenerator() || !localDb.getIdGenerator().hasNext()) requestIdGenerator();
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,9 +30,6 @@ public class MessageStatusChangeEventProcessor implements Consumer<MessageStatus
 | 
			
		||||
	@Override
 | 
			
		||||
	public void accept(MessageStatusChangeEvent evt) {
 | 
			
		||||
		if (evt.get().ordinal() < MessageStatus.RECEIVED.ordinal()) logger.info("Received invalid message status change " + evt);
 | 
			
		||||
		else {
 | 
			
		||||
			logger.info("Received " + evt.toString());
 | 
			
		||||
			EventBus.getInstance().dispatch(evt);
 | 
			
		||||
		}
 | 
			
		||||
		else EventBus.getInstance().dispatch(evt);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,6 @@ public class ReceivedMessageProcessor implements Consumer<Message> {
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void accept(Message message) {
 | 
			
		||||
		logger.info("Received message object " + message);
 | 
			
		||||
		if (message.getStatus() != MessageStatus.SENT) logger.warning("The message has the unexpected status " + message.getStatus());
 | 
			
		||||
		else {
 | 
			
		||||
			// Update status to RECEIVED
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,6 @@ public class Receiver implements Runnable {
 | 
			
		||||
	 */
 | 
			
		||||
	public Receiver(InputStream in) { this.in = in; }
 | 
			
		||||
 | 
			
		||||
	@SuppressWarnings("unchecked")
 | 
			
		||||
	@Override
 | 
			
		||||
	public void run() {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,8 @@
 | 
			
		||||
package envoy.client.net;
 | 
			
		||||
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
import envoy.client.util.EnvoyLog;
 | 
			
		||||
import envoy.client.data.LocalDb;
 | 
			
		||||
import envoy.event.EventBus;
 | 
			
		||||
import envoy.event.UserStatusChangeEvent;
 | 
			
		||||
 | 
			
		||||
@@ -17,21 +16,17 @@ import envoy.event.UserStatusChangeEvent;
 | 
			
		||||
 */
 | 
			
		||||
public class UserStatusChangeProcessor implements Consumer<UserStatusChangeEvent> {
 | 
			
		||||
 | 
			
		||||
	private Client client;
 | 
			
		||||
 | 
			
		||||
	private static final Logger logger = EnvoyLog.getLogger(UserStatusChangeProcessor.class.getSimpleName());
 | 
			
		||||
	private final LocalDb localDb;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param client the {@link Client} who receives an
 | 
			
		||||
	 *               {@link UserStatusChangeEvent}
 | 
			
		||||
	 * @param localDb the local database in which status updates will by applied
 | 
			
		||||
	 * @since Envoy v0.3-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public UserStatusChangeProcessor(Client client) { this.client = client; }
 | 
			
		||||
	public UserStatusChangeProcessor(LocalDb localDb) { this.localDb = localDb; }
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public void accept(UserStatusChangeEvent evt) {
 | 
			
		||||
		logger.info("Received " + evt);
 | 
			
		||||
		client.getContacts().getContacts().stream().filter((user) -> user.getId() == evt.getId()).findFirst().get().setStatus(evt.get());
 | 
			
		||||
		localDb.getUsers().values().stream().filter(u -> u.getId() == evt.getId()).findFirst().get().setStatus(evt.get());
 | 
			
		||||
		EventBus.getInstance().dispatch(evt);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -45,12 +45,14 @@ public class WriteProxy {
 | 
			
		||||
		// Initialize cache processors for messages and message status change events
 | 
			
		||||
		localDb.getMessageCache().setProcessor(msg -> {
 | 
			
		||||
			try {
 | 
			
		||||
				logger.info("Sending cached " + msg);
 | 
			
		||||
				client.sendMessage(msg);
 | 
			
		||||
			} catch (IOException e) {
 | 
			
		||||
				logger.log(Level.SEVERE, "Could not send cached message", e);
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
		localDb.getStatusCache().setProcessor(evt -> {
 | 
			
		||||
			logger.info("Sending cached " + evt);
 | 
			
		||||
			try {
 | 
			
		||||
				client.sendEvent(evt);
 | 
			
		||||
			} catch (IOException e) {
 | 
			
		||||
@@ -66,8 +68,6 @@ public class WriteProxy {
 | 
			
		||||
	 * @since Envoy v0.3-alpha
 | 
			
		||||
	 */
 | 
			
		||||
	public void flushCache() {
 | 
			
		||||
		logger.info("Sending cached messages and message status change events...");
 | 
			
		||||
 | 
			
		||||
		// Send messages
 | 
			
		||||
		localDb.getMessageCache().relay();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,8 @@ import java.util.logging.Logger;
 | 
			
		||||
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
import javax.swing.border.EmptyBorder;
 | 
			
		||||
import javax.swing.event.DocumentEvent;
 | 
			
		||||
import javax.swing.event.DocumentListener;
 | 
			
		||||
 | 
			
		||||
import envoy.client.Settings;
 | 
			
		||||
import envoy.client.data.Chat;
 | 
			
		||||
@@ -18,15 +20,14 @@ import envoy.client.event.ThemeChangeEvent;
 | 
			
		||||
import envoy.client.net.Client;
 | 
			
		||||
import envoy.client.net.WriteProxy;
 | 
			
		||||
import envoy.client.ui.list.ComponentList;
 | 
			
		||||
import envoy.client.ui.list.ComponentListModel;
 | 
			
		||||
import envoy.client.ui.settings.SettingsScreen;
 | 
			
		||||
import envoy.client.util.EnvoyLog;
 | 
			
		||||
import envoy.data.Message;
 | 
			
		||||
import envoy.data.Message.MessageStatus;
 | 
			
		||||
import envoy.data.MessageBuilder;
 | 
			
		||||
import envoy.data.User;
 | 
			
		||||
import envoy.event.EventBus;
 | 
			
		||||
import envoy.event.MessageStatusChangeEvent;
 | 
			
		||||
import envoy.event.UserStatusChangeEvent;
 | 
			
		||||
import envoy.event.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
@@ -49,6 +50,7 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
	private JPanel					contentPane				= new JPanel();
 | 
			
		||||
	private PrimaryTextArea			messageEnterTextArea	= new PrimaryTextArea(space);
 | 
			
		||||
	private JList<User>				userList				= new JList<>();
 | 
			
		||||
	private DefaultListModel<User>	userListModel			= new DefaultListModel<>();
 | 
			
		||||
	private Chat					currentChat;
 | 
			
		||||
	private ComponentList<Message>	messageList				= new ComponentList<>(new MessageListRenderer());
 | 
			
		||||
	private PrimaryScrollPane		scrollPane				= new PrimaryScrollPane();
 | 
			
		||||
@@ -56,6 +58,20 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
	private PrimaryButton			postButton				= new PrimaryButton("Post");
 | 
			
		||||
	private PrimaryButton			settingsButton			= new PrimaryButton("Settings");
 | 
			
		||||
 | 
			
		||||
	// Contacts Header
 | 
			
		||||
	private JPanel			contactsHeader	= new JPanel();
 | 
			
		||||
	private JTextPane		contactsDisplay	= new JTextPane();
 | 
			
		||||
	private PrimaryButton	addContact		= new PrimaryButton("+");
 | 
			
		||||
 | 
			
		||||
	// Search Contacts
 | 
			
		||||
	private final JPanel					searchPane			= new JPanel();
 | 
			
		||||
	private final PrimaryButton				cancelButton		= new PrimaryButton("x");
 | 
			
		||||
	private final PrimaryTextArea			searchField			= new PrimaryTextArea(space);
 | 
			
		||||
	private final PrimaryScrollPane			possibleContacts	= new PrimaryScrollPane();
 | 
			
		||||
	private final ContactsSearchRenderer	contactRenderer		= new ContactsSearchRenderer();
 | 
			
		||||
	private final ComponentListModel<User>	contactsModel		= new ComponentListModel<>();
 | 
			
		||||
	private final ComponentList<User>		contactList			= new ComponentList<>(contactRenderer);
 | 
			
		||||
 | 
			
		||||
	private static final Logger logger = EnvoyLog.getLogger(ChatWindow.class.getSimpleName());
 | 
			
		||||
 | 
			
		||||
	// GUI component spacing
 | 
			
		||||
@@ -81,16 +97,11 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
		setContentPane(contentPane);
 | 
			
		||||
		GridBagLayout gbl_contentPane = new GridBagLayout();
 | 
			
		||||
		gbl_contentPane.columnWidths	= new int[] { 1, 1, 1 };
 | 
			
		||||
		gbl_contentPane.rowHeights		= new int[] { 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.rowWeights		= new double[] { 0.05, 1.0, 0.07 };
 | 
			
		||||
		gbl_contentPane.rowWeights		= new double[] { 0.03, 0.001, 1.0, 0.005 };
 | 
			
		||||
		contentPane.setLayout(gbl_contentPane);
 | 
			
		||||
 | 
			
		||||
		// TODO: messageList.setFocusTraversalKeysEnabled(false);
 | 
			
		||||
		// messageList.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
 | 
			
		||||
 | 
			
		||||
		// messageList.setFont(new Font("Arial", Font.PLAIN, 17));
 | 
			
		||||
		// messageList.setFixedCellHeight(60);
 | 
			
		||||
		messageList.setBorder(new EmptyBorder(space, space, space, space));
 | 
			
		||||
 | 
			
		||||
		scrollPane.setViewportView(messageList);
 | 
			
		||||
@@ -98,11 +109,13 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
		GridBagConstraints gbc_scrollPane = new GridBagConstraints();
 | 
			
		||||
		gbc_scrollPane.fill			= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_scrollPane.gridwidth	= 2;
 | 
			
		||||
		gbc_scrollPane.gridheight	= 2;
 | 
			
		||||
		gbc_scrollPane.gridx		= 1;
 | 
			
		||||
		gbc_scrollPane.gridy		= 1;
 | 
			
		||||
 | 
			
		||||
		gbc_scrollPane.insets = insets;
 | 
			
		||||
		contentPane.add(scrollPane, gbc_scrollPane);
 | 
			
		||||
 | 
			
		||||
		drawChatBox(gbc_scrollPane);
 | 
			
		||||
 | 
			
		||||
		// Message enter field
 | 
			
		||||
		messageEnterTextArea.addKeyListener(new KeyAdapter() {
 | 
			
		||||
@@ -118,7 +131,7 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
		GridBagConstraints gbc_messageEnterTextfield = new GridBagConstraints();
 | 
			
		||||
		gbc_messageEnterTextfield.fill	= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_messageEnterTextfield.gridx	= 1;
 | 
			
		||||
		gbc_messageEnterTextfield.gridy	= 2;
 | 
			
		||||
		gbc_messageEnterTextfield.gridy	= 3;
 | 
			
		||||
 | 
			
		||||
		gbc_messageEnterTextfield.insets = insets;
 | 
			
		||||
 | 
			
		||||
@@ -129,7 +142,7 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
 | 
			
		||||
		gbc_moveSelectionPostButton.fill	= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_moveSelectionPostButton.gridx	= 2;
 | 
			
		||||
		gbc_moveSelectionPostButton.gridy	= 2;
 | 
			
		||||
		gbc_moveSelectionPostButton.gridy	= 3;
 | 
			
		||||
 | 
			
		||||
		gbc_moveSelectionPostButton.insets = insets;
 | 
			
		||||
 | 
			
		||||
@@ -145,14 +158,7 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
 | 
			
		||||
		gbc_moveSelectionSettingsButton.insets = insets;
 | 
			
		||||
 | 
			
		||||
		settingsButton.addActionListener((evt) -> {
 | 
			
		||||
			try {
 | 
			
		||||
				new SettingsScreen().setVisible(true);
 | 
			
		||||
			} catch (Exception e) {
 | 
			
		||||
				logger.log(Level.WARNING, "An error occured while opening the settings screen", e);
 | 
			
		||||
				e.printStackTrace();
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
		settingsButton.addActionListener(evt -> new SettingsScreen().setVisible(true));
 | 
			
		||||
		contentPane.add(settingsButton, gbc_moveSelectionSettingsButton);
 | 
			
		||||
 | 
			
		||||
		// Partner name display
 | 
			
		||||
@@ -171,26 +177,30 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
		userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 | 
			
		||||
		userList.addListSelectionListener((listSelectionEvent) -> {
 | 
			
		||||
			if (client != null && localDb != null && !listSelectionEvent.getValueIsAdjusting()) {
 | 
			
		||||
				@SuppressWarnings("unchecked")
 | 
			
		||||
				final JList<User>	selectedUserList	= (JList<User>) listSelectionEvent.getSource();
 | 
			
		||||
				final User			user				= selectedUserList.getSelectedValue();
 | 
			
		||||
 | 
			
		||||
				// Select current chat
 | 
			
		||||
				currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get();
 | 
			
		||||
				for (int i = 0; i < contentPane.getComponents().length; i++) {
 | 
			
		||||
					if (contentPane.getComponent(i).equals(searchPane)) { drawChatBox(gbc_scrollPane); }
 | 
			
		||||
				}
 | 
			
		||||
				if (user != null) {
 | 
			
		||||
					// Select current chat
 | 
			
		||||
					currentChat = localDb.getChats().stream().filter(chat -> chat.getRecipient().getId() == user.getId()).findFirst().get();
 | 
			
		||||
 | 
			
		||||
				// Read current chat
 | 
			
		||||
				readCurrentChat();
 | 
			
		||||
					// Read current chat
 | 
			
		||||
					readCurrentChat();
 | 
			
		||||
 | 
			
		||||
				// Set chat title
 | 
			
		||||
				textPane.setText(currentChat.getRecipient().getName());
 | 
			
		||||
					// Set chat title
 | 
			
		||||
					textPane.setText(currentChat.getRecipient().getName());
 | 
			
		||||
 | 
			
		||||
				// Update model and scroll down
 | 
			
		||||
				messageList.setModel(currentChat.getModel());
 | 
			
		||||
				scrollPane.setChatOpened(true);
 | 
			
		||||
					// Update model and scroll down
 | 
			
		||||
					messageList.setModel(currentChat.getModel());
 | 
			
		||||
					scrollPane.setChatOpened(true);
 | 
			
		||||
 | 
			
		||||
				messageList.synchronizeModel();
 | 
			
		||||
				revalidate();
 | 
			
		||||
				repaint();
 | 
			
		||||
					messageList.synchronizeModel();
 | 
			
		||||
					revalidate();
 | 
			
		||||
					repaint();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
@@ -198,26 +208,151 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
		userList.setBorder(new EmptyBorder(space, space, space, space));
 | 
			
		||||
 | 
			
		||||
		GridBagConstraints gbc_userList = new GridBagConstraints();
 | 
			
		||||
		gbc_userList.fill	= GridBagConstraints.VERTICAL;
 | 
			
		||||
		gbc_userList.gridx	= 0;
 | 
			
		||||
		gbc_userList.gridy	= 1;
 | 
			
		||||
		gbc_userList.anchor	= GridBagConstraints.PAGE_START;
 | 
			
		||||
		gbc_userList.insets	= insets;
 | 
			
		||||
 | 
			
		||||
		applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
 | 
			
		||||
		gbc_userList.fill		= GridBagConstraints.VERTICAL;
 | 
			
		||||
		gbc_userList.gridx		= 0;
 | 
			
		||||
		gbc_userList.gridy		= 2;
 | 
			
		||||
		gbc_userList.gridheight	= 2;
 | 
			
		||||
		gbc_userList.anchor		= GridBagConstraints.PAGE_START;
 | 
			
		||||
		gbc_userList.insets		= insets;
 | 
			
		||||
 | 
			
		||||
		contentPane.add(userList, gbc_userList);
 | 
			
		||||
		contentPane.revalidate();
 | 
			
		||||
 | 
			
		||||
		// Contacts Search
 | 
			
		||||
		GridBagConstraints gbc_searchPane = new GridBagConstraints();
 | 
			
		||||
		gbc_searchPane.fill			= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_searchPane.gridwidth	= 2;
 | 
			
		||||
		gbc_searchPane.gridheight	= 2;
 | 
			
		||||
		gbc_searchPane.gridx		= 1;
 | 
			
		||||
		gbc_searchPane.gridy		= 1;
 | 
			
		||||
 | 
			
		||||
		gbc_searchPane.insets = insets;
 | 
			
		||||
 | 
			
		||||
		GridBagLayout gbl_contactsSearch = new GridBagLayout();
 | 
			
		||||
		gbl_contactsSearch.columnWidths		= new int[] { 1, 1 };
 | 
			
		||||
		gbl_contactsSearch.rowHeights		= new int[] { 1, 1 };
 | 
			
		||||
		gbl_contactsSearch.columnWeights	= new double[] { 1, 0.1 };
 | 
			
		||||
		gbl_contactsSearch.rowWeights		= new double[] { 0.001, 1 };
 | 
			
		||||
		searchPane.setLayout(gbl_contactsSearch);
 | 
			
		||||
 | 
			
		||||
		GridBagConstraints gbc_searchField = new GridBagConstraints();
 | 
			
		||||
		gbc_searchField.fill	= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_searchField.gridx	= 0;
 | 
			
		||||
		gbc_searchField.gridy	= 0;
 | 
			
		||||
		gbc_searchField.insets	= new Insets(7, 4, 4, 4);
 | 
			
		||||
 | 
			
		||||
		searchPane.add(searchField, gbc_searchField);
 | 
			
		||||
 | 
			
		||||
		// Sends event to server, if input has changed
 | 
			
		||||
		searchField.getDocument().addDocumentListener(new DocumentListener() {
 | 
			
		||||
 | 
			
		||||
			@Override
 | 
			
		||||
			public void removeUpdate(DocumentEvent evt) {
 | 
			
		||||
				if (client.isOnline()) {
 | 
			
		||||
					if (searchField.getText().isEmpty()) {
 | 
			
		||||
						contactsModel.clear();
 | 
			
		||||
						revalidate();
 | 
			
		||||
						repaint();
 | 
			
		||||
					} else {
 | 
			
		||||
						try {
 | 
			
		||||
							client.sendEvent(new ContactSearchRequest(searchField.getText()));
 | 
			
		||||
						} catch (IOException e) {
 | 
			
		||||
							e.printStackTrace();
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			@Override
 | 
			
		||||
			public void insertUpdate(DocumentEvent evt) {
 | 
			
		||||
				if (client.isOnline()) {
 | 
			
		||||
					try {
 | 
			
		||||
						client.sendEvent(new ContactSearchRequest(searchField.getText()));
 | 
			
		||||
					} catch (IOException e) {
 | 
			
		||||
						e.printStackTrace();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			@Override
 | 
			
		||||
			public void changedUpdate(DocumentEvent evt) {}
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		GridBagConstraints gbc_cancelButton = new GridBagConstraints();
 | 
			
		||||
		gbc_cancelButton.fill	= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_cancelButton.gridx	= 1;
 | 
			
		||||
		gbc_cancelButton.gridy	= 0;
 | 
			
		||||
		gbc_cancelButton.insets	= new Insets(7, 4, 4, 4);
 | 
			
		||||
 | 
			
		||||
		cancelButton.addActionListener((evt) -> { drawChatBox(gbc_scrollPane); });
 | 
			
		||||
 | 
			
		||||
		searchPane.add(cancelButton, gbc_cancelButton);
 | 
			
		||||
 | 
			
		||||
		contactList.setModel(contactsModel);
 | 
			
		||||
		possibleContacts.setBorder(new EmptyBorder(space, space, space, space));
 | 
			
		||||
		possibleContacts.setViewportView(contactList);
 | 
			
		||||
 | 
			
		||||
		GridBagConstraints gbc_possibleContacts = new GridBagConstraints();
 | 
			
		||||
		gbc_possibleContacts.fill		= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_possibleContacts.gridwidth	= 2;
 | 
			
		||||
		gbc_possibleContacts.gridx		= 0;
 | 
			
		||||
		gbc_possibleContacts.gridy		= 1;
 | 
			
		||||
 | 
			
		||||
		gbc_possibleContacts.insets = insets;
 | 
			
		||||
 | 
			
		||||
		searchPane.add(possibleContacts, gbc_possibleContacts);
 | 
			
		||||
 | 
			
		||||
		// Contacts Header
 | 
			
		||||
		GridBagConstraints gbc_contactsHeader = new GridBagConstraints();
 | 
			
		||||
		gbc_contactsHeader.fill		= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_contactsHeader.gridx	= 0;
 | 
			
		||||
		gbc_contactsHeader.gridy	= 1;
 | 
			
		||||
		gbc_contactsHeader.insets	= insets;
 | 
			
		||||
 | 
			
		||||
		GridBagLayout gbl_contactHeader = new GridBagLayout();
 | 
			
		||||
		gbl_contactHeader.columnWidths	= new int[] { 1, 1 };
 | 
			
		||||
		gbl_contactHeader.rowHeights	= new int[] { 1 };
 | 
			
		||||
		gbl_contactHeader.columnWeights	= new double[] { 1, 1 };
 | 
			
		||||
		gbl_contactHeader.rowWeights	= new double[] { 1 };
 | 
			
		||||
		contactsHeader.setLayout(gbl_contactHeader);
 | 
			
		||||
 | 
			
		||||
		contactsDisplay.setEditable(false);
 | 
			
		||||
		contactsDisplay.setFont(new Font("Arial", Font.PLAIN, 12));
 | 
			
		||||
		contactsDisplay.setText("Contacts");
 | 
			
		||||
 | 
			
		||||
		GridBagConstraints gbc_contactsDisplay = new GridBagConstraints();
 | 
			
		||||
		gbc_contactsDisplay.fill	= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_contactsDisplay.gridx	= 0;
 | 
			
		||||
		gbc_contactsDisplay.gridy	= 0;
 | 
			
		||||
 | 
			
		||||
		contactsHeader.add(contactsDisplay, gbc_contactsDisplay);
 | 
			
		||||
 | 
			
		||||
		addContact.setFont(new Font("Arial", Font.PLAIN, 15));
 | 
			
		||||
 | 
			
		||||
		GridBagConstraints gbc_addContact = new GridBagConstraints();
 | 
			
		||||
		gbc_addContact.fill		= GridBagConstraints.BOTH;
 | 
			
		||||
		gbc_addContact.gridx	= 1;
 | 
			
		||||
		gbc_addContact.gridy	= 0;
 | 
			
		||||
		gbc_addContact.insets	= insets;
 | 
			
		||||
 | 
			
		||||
		addContact.addActionListener((evt) -> { drawContactSearch(gbc_searchPane); });
 | 
			
		||||
 | 
			
		||||
		contactsHeader.add(addContact, gbc_addContact);
 | 
			
		||||
 | 
			
		||||
		applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
 | 
			
		||||
 | 
			
		||||
		contentPane.add(contactsHeader, gbc_contactsHeader);
 | 
			
		||||
		contentPane.revalidate();
 | 
			
		||||
 | 
			
		||||
		// Listen to theme changes
 | 
			
		||||
		EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme((Theme) evt.get()));
 | 
			
		||||
		EventBus.getInstance().register(ThemeChangeEvent.class, evt -> applyTheme(evt.get()));
 | 
			
		||||
 | 
			
		||||
		// Listen to user status changes
 | 
			
		||||
		EventBus.getInstance().register(UserStatusChangeEvent.class, (evt) -> { userList.revalidate(); userList.repaint(); });
 | 
			
		||||
		EventBus.getInstance().register(UserStatusChangeEvent.class, evt -> { userList.revalidate(); userList.repaint(); });
 | 
			
		||||
 | 
			
		||||
		// Listen to received messages
 | 
			
		||||
		EventBus.getInstance().register(MessageCreationEvent.class, (evt) -> {
 | 
			
		||||
			Message	message	= ((MessageCreationEvent) evt).get();
 | 
			
		||||
		EventBus.getInstance().register(MessageCreationEvent.class, evt -> {
 | 
			
		||||
			Message	message	= evt.get();
 | 
			
		||||
			Chat	chat	= localDb.getChats().stream().filter(c -> c.getRecipient().getId() == message.getSenderId()).findFirst().get();
 | 
			
		||||
			chat.appendMessage(message);
 | 
			
		||||
 | 
			
		||||
@@ -229,9 +364,9 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		// Listen to message status changes
 | 
			
		||||
		EventBus.getInstance().register(MessageStatusChangeEvent.class, (evt) -> {
 | 
			
		||||
			final long			id		= ((MessageStatusChangeEvent) evt).getId();
 | 
			
		||||
			final MessageStatus	status	= (MessageStatus) evt.get();
 | 
			
		||||
		EventBus.getInstance().register(MessageStatusChangeEvent.class, evt -> {
 | 
			
		||||
			final long			id		= evt.getId();
 | 
			
		||||
			final MessageStatus	status	= evt.get();
 | 
			
		||||
 | 
			
		||||
			for (Chat c : localDb.getChats())
 | 
			
		||||
				for (Message m : c.getModel())
 | 
			
		||||
@@ -251,7 +386,35 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
			repaint();
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		// Listen to contact search results
 | 
			
		||||
		EventBus.getInstance().register(ContactSearchResult.class, evt -> {
 | 
			
		||||
			contactsModel.clear();
 | 
			
		||||
			final java.util.List<User> contacts = evt.get();
 | 
			
		||||
			logger.info("Received contact search result " + contacts);
 | 
			
		||||
			contacts.forEach(contactsModel::add);
 | 
			
		||||
			revalidate();
 | 
			
		||||
			repaint();
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		// Add new contacts to the contact list
 | 
			
		||||
		EventBus.getInstance().register(ContactOperationEvent.class, evt -> {
 | 
			
		||||
			User contact = evt.get();
 | 
			
		||||
 | 
			
		||||
			// Clearing the search field and the searchResultList
 | 
			
		||||
			searchField.setText("");
 | 
			
		||||
			contactsModel.clear();
 | 
			
		||||
 | 
			
		||||
			// Update LocalDB
 | 
			
		||||
			userListModel.addElement(contact);
 | 
			
		||||
			localDb.getUsers().put(contact.getName(), contact);
 | 
			
		||||
			localDb.getChats().add(new Chat(contact));
 | 
			
		||||
 | 
			
		||||
			revalidate();
 | 
			
		||||
			repaint();
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		revalidate();
 | 
			
		||||
		repaint();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@@ -291,6 +454,21 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
		userList.setSelectionBackground(theme.getSelectionColor());
 | 
			
		||||
		userList.setForeground(theme.getUserNameColor());
 | 
			
		||||
		userList.setBackground(theme.getCellColor());
 | 
			
		||||
		// contacts header
 | 
			
		||||
		contactsHeader.setBackground(theme.getCellColor());
 | 
			
		||||
		contactsDisplay.setBackground(theme.getCellColor());
 | 
			
		||||
		contactsDisplay.setForeground(theme.getUserNameColor());
 | 
			
		||||
		addContact.setBackground(theme.getInteractableBackgroundColor());
 | 
			
		||||
		addContact.setForeground(theme.getInteractableForegroundColor());
 | 
			
		||||
		// SearchPane
 | 
			
		||||
		searchPane.setBackground(theme.getCellColor());
 | 
			
		||||
		searchField.setBackground(theme.getBackgroundColor());
 | 
			
		||||
		searchField.setForeground(theme.getUserNameColor());
 | 
			
		||||
		cancelButton.setBackground(theme.getInteractableBackgroundColor());
 | 
			
		||||
		cancelButton.setForeground(theme.getInteractableForegroundColor());
 | 
			
		||||
		contactList.setForeground(theme.getMessageColorChat());
 | 
			
		||||
		contactList.setBackground(theme.getCellColor());
 | 
			
		||||
		possibleContacts.applyTheme(theme);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void postMessage() {
 | 
			
		||||
@@ -336,7 +514,6 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
	 */
 | 
			
		||||
	private void loadUsersAndChats() {
 | 
			
		||||
		new Thread(() -> {
 | 
			
		||||
			DefaultListModel<User> userListModel = new DefaultListModel<>();
 | 
			
		||||
			localDb.getUsers().values().forEach(user -> {
 | 
			
		||||
				userListModel.addElement(user);
 | 
			
		||||
 | 
			
		||||
@@ -345,6 +522,9 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
					localDb.getChats().add(new Chat(user));
 | 
			
		||||
			});
 | 
			
		||||
			SwingUtilities.invokeLater(() -> userList.setModel(userListModel));
 | 
			
		||||
 | 
			
		||||
			revalidate();
 | 
			
		||||
			repaint();
 | 
			
		||||
		}).start();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -358,6 +538,24 @@ public class ChatWindow extends JFrame {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void drawChatBox(GridBagConstraints gbc_scrollPane) {
 | 
			
		||||
		contentPane.remove(searchPane);
 | 
			
		||||
		contentPane.add(scrollPane, gbc_scrollPane);
 | 
			
		||||
		contentPane.revalidate();
 | 
			
		||||
		contentPane.repaint();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void drawContactSearch(GridBagConstraints gbc_searchPane) {
 | 
			
		||||
		currentChat = null;
 | 
			
		||||
		userList.removeSelectionInterval(0, userList.getModel().getSize() - 1);
 | 
			
		||||
		messageList.setModel(null);
 | 
			
		||||
		textPane.setText("");
 | 
			
		||||
		contentPane.remove(scrollPane);
 | 
			
		||||
		contentPane.add(searchPane, gbc_searchPane);
 | 
			
		||||
		contentPane.revalidate();
 | 
			
		||||
		contentPane.repaint();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Initializes the components responsible server communication and
 | 
			
		||||
	 * persistence.<br>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										78
									
								
								src/main/java/envoy/client/ui/ContactsSearchRenderer.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/main/java/envoy/client/ui/ContactsSearchRenderer.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
			
		||||
package envoy.client.ui;
 | 
			
		||||
 | 
			
		||||
import java.awt.Component;
 | 
			
		||||
import java.awt.Dimension;
 | 
			
		||||
import java.awt.Font;
 | 
			
		||||
 | 
			
		||||
import javax.swing.*;
 | 
			
		||||
 | 
			
		||||
import envoy.client.Settings;
 | 
			
		||||
import envoy.client.event.SendEvent;
 | 
			
		||||
import envoy.client.ui.list.ComponentList;
 | 
			
		||||
import envoy.client.ui.list.ComponentListCellRenderer;
 | 
			
		||||
import envoy.data.User;
 | 
			
		||||
import envoy.event.ContactOperationEvent;
 | 
			
		||||
import envoy.event.EventBus;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Defines how a contact is displayed.<br>
 | 
			
		||||
 * <br>
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
 * File: <strong>ContactsSearchRenderer.java</strong><br>
 | 
			
		||||
 * Created: <strong>08.02.2020</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Maximilian Käfer
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 * @since Envoy v0.3-alpha
 | 
			
		||||
 */
 | 
			
		||||
public class ContactsSearchRenderer implements ComponentListCellRenderer<User> {
 | 
			
		||||
 | 
			
		||||
	@Override
 | 
			
		||||
	public JComponent getListCellComponent(ComponentList<? extends User> list, User user, boolean isSelected) {
 | 
			
		||||
		final JPanel panel = new JPanel();
 | 
			
		||||
		panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
 | 
			
		||||
		if (isSelected) {
 | 
			
		||||
			panel.setBackground(Color.DARK_GRAY);
 | 
			
		||||
			panel.setForeground(Color.RED);
 | 
			
		||||
		} else {
 | 
			
		||||
			panel.setBackground(list.getBackground());
 | 
			
		||||
			panel.setForeground(list.getForeground());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		JLabel display = new JLabel(String.format("<html><p style=\"color:%s\">%s</html>",
 | 
			
		||||
				Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getMessageColorChat().toHex(),
 | 
			
		||||
				user.getName()));
 | 
			
		||||
		display.setAlignmentX(Component.LEFT_ALIGNMENT);
 | 
			
		||||
		display.setAlignmentY(Component.CENTER_ALIGNMENT);
 | 
			
		||||
		display.setFont(new Font("Arial", Font.PLAIN, 16));
 | 
			
		||||
		panel.add(display);
 | 
			
		||||
 | 
			
		||||
		PrimaryButton add = new PrimaryButton("+");
 | 
			
		||||
		add.setFont(new Font("Arial", Font.PLAIN, 19));
 | 
			
		||||
		add.setPreferredSize(new Dimension(45, 45));
 | 
			
		||||
		add.setMinimumSize(new Dimension(45, 45));
 | 
			
		||||
		add.setMaximumSize(new Dimension(45, 45));
 | 
			
		||||
 | 
			
		||||
		add.setBackground(list.getBackground());
 | 
			
		||||
		add.setForeground(list.getForeground());
 | 
			
		||||
 | 
			
		||||
		add.addActionListener(evt -> {
 | 
			
		||||
			ContactOperationEvent contactsOperationEvent = new ContactOperationEvent(user, ContactOperationEvent.Operation.ADD);
 | 
			
		||||
			EventBus.getInstance().dispatch(contactsOperationEvent);
 | 
			
		||||
			EventBus.getInstance().dispatch(new SendEvent(contactsOperationEvent));
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		panel.add(add);
 | 
			
		||||
 | 
			
		||||
		// Define some space to the messages below
 | 
			
		||||
		panel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(0, 0, 15, 0), BorderFactory.createEtchedBorder()));
 | 
			
		||||
 | 
			
		||||
		// Define a maximum height of 50px
 | 
			
		||||
		Dimension size = new Dimension(435, 50);
 | 
			
		||||
		panel.setMaximumSize(size);
 | 
			
		||||
		panel.setMinimumSize(size);
 | 
			
		||||
		panel.setPreferredSize(size);
 | 
			
		||||
 | 
			
		||||
		return panel;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -9,6 +9,7 @@ import javax.swing.*;
 | 
			
		||||
import javax.swing.border.EmptyBorder;
 | 
			
		||||
 | 
			
		||||
import envoy.client.event.HandshakeSuccessfulEvent;
 | 
			
		||||
import envoy.client.Settings;
 | 
			
		||||
import envoy.data.LoginCredentials;
 | 
			
		||||
import envoy.event.EventBus;
 | 
			
		||||
import envoy.event.HandshakeRejectionEvent;
 | 
			
		||||
@@ -24,22 +25,29 @@ import envoy.event.HandshakeRejectionEvent;
 | 
			
		||||
 */
 | 
			
		||||
public class LoginDialog extends JDialog {
 | 
			
		||||
 | 
			
		||||
	private final JPanel contentPanel = new JPanel();
 | 
			
		||||
 | 
			
		||||
	private static final long	serialVersionUID	= 352021600833907468L;
 | 
			
		||||
	private final JPanel	contentPanel;
 | 
			
		||||
	private JTextField			textField;
 | 
			
		||||
	private JPasswordField		passwordField;
 | 
			
		||||
	private JPasswordField		repeatPasswordField;
 | 
			
		||||
 | 
			
		||||
	private JPasswordField	repeatPasswordField;
 | 
			
		||||
	private JLabel			lblRepeatPassword;
 | 
			
		||||
	private JLabel			errorMessage;
 | 
			
		||||
 | 
			
		||||
	private GridBagConstraints	gbc_errorMessage;
 | 
			
		||||
	private JLabel	lblUserName;
 | 
			
		||||
	private JLabel	lblPassword;
 | 
			
		||||
	private JLabel	lblRepeatPassword;
 | 
			
		||||
  private JLabel			errorMessage;
 | 
			
		||||
  
 | 
			
		||||
	private GridBagConstraints	gbc_lblRepeatPassword;
 | 
			
		||||
	private GridBagConstraints	gbc_repeatPasswordField;
 | 
			
		||||
  private GridBagConstraints	gbc_errorMessage;
 | 
			
		||||
 | 
			
		||||
	private JPanel buttonPane;
 | 
			
		||||
	private JTextPane		registerText;
 | 
			
		||||
	private JCheckBox		registerCheckBox;
 | 
			
		||||
	private PrimaryButton	okButton;
 | 
			
		||||
	private PrimaryButton	cancelButton;
 | 
			
		||||
 | 
			
		||||
	private LoginCredentials credentials;
 | 
			
		||||
 | 
			
		||||
	private static final long serialVersionUID = 352021600833907468L;
 | 
			
		||||
	/**
 | 
			
		||||
	 * Displays a dialog enabling the user to enter their user name and password.
 | 
			
		||||
	 *
 | 
			
		||||
@@ -49,6 +57,7 @@ public class LoginDialog extends JDialog {
 | 
			
		||||
		setSize(338, 123);
 | 
			
		||||
		setLocationRelativeTo(null);
 | 
			
		||||
		getContentPane().setLayout(new BorderLayout());
 | 
			
		||||
		contentPanel = new JPanel();
 | 
			
		||||
		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
 | 
			
		||||
		getContentPane().add(contentPanel, BorderLayout.CENTER);
 | 
			
		||||
		GridBagLayout gbl_contentPanel = new GridBagLayout();
 | 
			
		||||
@@ -58,7 +67,7 @@ public class LoginDialog extends JDialog {
 | 
			
		||||
		gbl_contentPanel.rowWeights		= new double[] { 0.0, 0.0, Double.MIN_VALUE };
 | 
			
		||||
		contentPanel.setLayout(gbl_contentPanel);
 | 
			
		||||
		{
 | 
			
		||||
			JLabel				lblUserName		= new JLabel("User name:");
 | 
			
		||||
			lblUserName = new JLabel("Username:");
 | 
			
		||||
			GridBagConstraints	gbc_lblUserName	= new GridBagConstraints();
 | 
			
		||||
			gbc_lblUserName.anchor	= GridBagConstraints.EAST;
 | 
			
		||||
			gbc_lblUserName.insets	= new Insets(0, 0, 5, 5);
 | 
			
		||||
@@ -68,6 +77,7 @@ public class LoginDialog extends JDialog {
 | 
			
		||||
		}
 | 
			
		||||
		{
 | 
			
		||||
			textField = new JTextField();
 | 
			
		||||
			textField.setBorder(null);
 | 
			
		||||
			GridBagConstraints gbc_textField = new GridBagConstraints();
 | 
			
		||||
			gbc_textField.insets	= new Insets(0, 0, 5, 0);
 | 
			
		||||
			gbc_textField.fill		= GridBagConstraints.HORIZONTAL;
 | 
			
		||||
@@ -77,7 +87,7 @@ public class LoginDialog extends JDialog {
 | 
			
		||||
			textField.setColumns(10);
 | 
			
		||||
		}
 | 
			
		||||
		{
 | 
			
		||||
			JLabel				lblPassword		= new JLabel("Password:");
 | 
			
		||||
			lblPassword = new JLabel("Password:");
 | 
			
		||||
			GridBagConstraints	gbc_lblPassword	= new GridBagConstraints();
 | 
			
		||||
			gbc_lblPassword.anchor	= GridBagConstraints.EAST;
 | 
			
		||||
			gbc_lblPassword.insets	= new Insets(0, 0, 0, 5);
 | 
			
		||||
@@ -87,6 +97,7 @@ public class LoginDialog extends JDialog {
 | 
			
		||||
		}
 | 
			
		||||
		{
 | 
			
		||||
			passwordField = new JPasswordField();
 | 
			
		||||
			passwordField.setBorder(null);
 | 
			
		||||
			GridBagConstraints gbc_passwordField = new GridBagConstraints();
 | 
			
		||||
			gbc_passwordField.fill	= GridBagConstraints.HORIZONTAL;
 | 
			
		||||
			gbc_passwordField.gridx	= 1;
 | 
			
		||||
@@ -124,22 +135,23 @@ public class LoginDialog extends JDialog {
 | 
			
		||||
			});
 | 
			
		||||
		}
 | 
			
		||||
		{
 | 
			
		||||
			JPanel buttonPane = new JPanel();
 | 
			
		||||
			buttonPane = new JPanel();
 | 
			
		||||
 | 
			
		||||
			JTextPane registerText = new JTextPane();
 | 
			
		||||
			registerText = new JTextPane();
 | 
			
		||||
			registerText.setEditable(false);
 | 
			
		||||
			registerText.setText("Register?");
 | 
			
		||||
			registerText.setFont(new Font("Arial", Font.BOLD, 12));
 | 
			
		||||
			registerText.setAlignmentX(LEFT_ALIGNMENT);
 | 
			
		||||
			buttonPane.add(registerText);
 | 
			
		||||
 | 
			
		||||
			JCheckBox registerCheckBox = new JCheckBox();
 | 
			
		||||
			registerCheckBox = new JCheckBox();
 | 
			
		||||
			registerCheckBox.setAlignmentX(LEFT_ALIGNMENT);
 | 
			
		||||
			registerCheckBox.addItemListener(e -> {
 | 
			
		||||
				switch (e.getStateChange()) {
 | 
			
		||||
					case ItemEvent.SELECTED:
 | 
			
		||||
						contentPanel.add(lblRepeatPassword, gbc_lblRepeatPassword);
 | 
			
		||||
						contentPanel.add(repeatPasswordField, gbc_repeatPasswordField);
 | 
			
		||||
						setSize(338, 160);
 | 
			
		||||
						setSize(338, 148);
 | 
			
		||||
						break;
 | 
			
		||||
 | 
			
		||||
					case ItemEvent.DESELECTED:
 | 
			
		||||
@@ -158,7 +170,7 @@ public class LoginDialog extends JDialog {
 | 
			
		||||
			buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
 | 
			
		||||
			getContentPane().add(buttonPane, BorderLayout.SOUTH);
 | 
			
		||||
			{
 | 
			
		||||
				JButton okButton = new JButton("OK");
 | 
			
		||||
				okButton = new PrimaryButton("OK");
 | 
			
		||||
				okButton.addActionListener((evt) -> {
 | 
			
		||||
					try {
 | 
			
		||||
						if (registerCheckBox.isSelected()) {
 | 
			
		||||
@@ -179,12 +191,13 @@ public class LoginDialog extends JDialog {
 | 
			
		||||
				getRootPane().setDefaultButton(okButton);
 | 
			
		||||
			}
 | 
			
		||||
			{
 | 
			
		||||
				JButton cancelButton = new JButton("Cancel");
 | 
			
		||||
				cancelButton = new PrimaryButton("Cancel");
 | 
			
		||||
				cancelButton.addActionListener((evt) -> dispose());
 | 
			
		||||
				cancelButton.setActionCommand("Cancel");
 | 
			
		||||
				buttonPane.add(cancelButton);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		setTheme();
 | 
			
		||||
 | 
			
		||||
		setModal(true);
 | 
			
		||||
		setVisible(true);
 | 
			
		||||
@@ -201,6 +214,50 @@ public class LoginDialog extends JDialog {
 | 
			
		||||
		repeatPasswordField.setText(null);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void setTheme() {
 | 
			
		||||
		Theme theme = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme());
 | 
			
		||||
 | 
			
		||||
		// Panels
 | 
			
		||||
		contentPanel.setBackground(theme.getBackgroundColor());
 | 
			
		||||
		contentPanel.setForeground(theme.getBackgroundColor());
 | 
			
		||||
 | 
			
		||||
		buttonPane.setBackground(theme.getBackgroundColor());
 | 
			
		||||
		buttonPane.setForeground(theme.getBackgroundColor());
 | 
			
		||||
 | 
			
		||||
		// Input Fields
 | 
			
		||||
		textField.setBackground(theme.getCellColor());
 | 
			
		||||
		textField.setForeground(theme.getUserNameColor());
 | 
			
		||||
 | 
			
		||||
		passwordField.setBackground(theme.getCellColor());
 | 
			
		||||
		passwordField.setForeground(theme.getUserNameColor());
 | 
			
		||||
 | 
			
		||||
		repeatPasswordField.setBackground(theme.getCellColor());
 | 
			
		||||
		repeatPasswordField.setForeground(theme.getUserNameColor());
 | 
			
		||||
 | 
			
		||||
		// JLabels
 | 
			
		||||
		lblUserName.setBackground(theme.getCellColor());
 | 
			
		||||
		lblUserName.setForeground(theme.getUserNameColor());
 | 
			
		||||
 | 
			
		||||
		lblPassword.setBackground(theme.getCellColor());
 | 
			
		||||
		lblPassword.setForeground(theme.getUserNameColor());
 | 
			
		||||
 | 
			
		||||
		lblRepeatPassword.setBackground(theme.getCellColor());
 | 
			
		||||
		lblRepeatPassword.setForeground(theme.getUserNameColor());
 | 
			
		||||
 | 
			
		||||
		// Register
 | 
			
		||||
		registerText.setBackground(theme.getCellColor());
 | 
			
		||||
		registerText.setForeground(theme.getUserNameColor());
 | 
			
		||||
 | 
			
		||||
		registerCheckBox.setBackground(theme.getCellColor());
 | 
			
		||||
 | 
			
		||||
		// Buttons
 | 
			
		||||
		okButton.setBackground(theme.getInteractableBackgroundColor());
 | 
			
		||||
		okButton.setForeground(theme.getInteractableForegroundColor());
 | 
			
		||||
 | 
			
		||||
		cancelButton.setBackground(theme.getInteractableBackgroundColor());
 | 
			
		||||
		cancelButton.setForeground(theme.getInteractableForegroundColor());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return the {@link LoginCredentials} entered by the user, or {@code null} if
 | 
			
		||||
	 *         the dialog has been cancelled
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ import envoy.data.Message;
 | 
			
		||||
 * Defines how a message is displayed.<br>
 | 
			
		||||
 * <br>
 | 
			
		||||
 * Project: <strong>envoy-client</strong><br>
 | 
			
		||||
 * File: <strong>UserListRenderer.java</strong><br>
 | 
			
		||||
 * File: <strong>MessageListRenderer.java</strong><br>
 | 
			
		||||
 * Created: <strong>19 Oct 2019</strong><br>
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kai S. K. Engelbart
 | 
			
		||||
 
 | 
			
		||||
@@ -163,7 +163,7 @@ public class Startup {
 | 
			
		||||
				chatWindow.initContent(client, localDb, writeProxy);
 | 
			
		||||
 | 
			
		||||
				// Relay unread messages from cache
 | 
			
		||||
				if (cache != null) cache.relay();
 | 
			
		||||
				if (cache != null && client.isOnline()) cache.relay();
 | 
			
		||||
 | 
			
		||||
				try {
 | 
			
		||||
					new StatusTrayIcon(chatWindow).show();
 | 
			
		||||
 
 | 
			
		||||
@@ -74,13 +74,10 @@ public class StatusTrayIcon {
 | 
			
		||||
		trayIcon.addActionListener((evt) -> { focusTarget.setVisible(true); focusTarget.requestFocus(); });
 | 
			
		||||
 | 
			
		||||
		// Start processing message events
 | 
			
		||||
		// TODO: Handle other message types
 | 
			
		||||
		EventBus.getInstance()
 | 
			
		||||
			.register(MessageCreationEvent.class,
 | 
			
		||||
					(evt) -> {
 | 
			
		||||
						// TODO: Handle other message types
 | 
			
		||||
						if (displayMessages)
 | 
			
		||||
							trayIcon.displayMessage("New message received", ((MessageCreationEvent) evt).get().getText(), MessageType.INFO);
 | 
			
		||||
					});
 | 
			
		||||
					evt -> { if (displayMessages) trayIcon.displayMessage("New message received", evt.get().getText(), MessageType.INFO); });
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package envoy.client.ui;
 | 
			
		||||
 | 
			
		||||
import java.awt.Component;
 | 
			
		||||
import java.awt.Dimension;
 | 
			
		||||
 | 
			
		||||
import javax.swing.JLabel;
 | 
			
		||||
import javax.swing.JList;
 | 
			
		||||
@@ -41,6 +42,8 @@ public class UserListRenderer extends JLabel implements ListCellRenderer<User> {
 | 
			
		||||
		final String		name	= value.getName();
 | 
			
		||||
		final UserStatus	status	= value.getStatus();
 | 
			
		||||
 | 
			
		||||
		this.setPreferredSize(new Dimension(100, 35));
 | 
			
		||||
 | 
			
		||||
		// Getting the UserNameColor of the current theme
 | 
			
		||||
		String textColor = null;
 | 
			
		||||
		textColor = Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()).getUserNameColor().toHex();
 | 
			
		||||
 
 | 
			
		||||
@@ -62,8 +62,10 @@ public class ComponentList<E> extends JPanel {
 | 
			
		||||
 | 
			
		||||
		// Synchronize with new model
 | 
			
		||||
		this.model = model;
 | 
			
		||||
		this.model.setComponentList(this);
 | 
			
		||||
		synchronizeModel();
 | 
			
		||||
		if (model != null) {
 | 
			
		||||
			this.model.setComponentList(this);
 | 
			
		||||
			synchronizeModel();
 | 
			
		||||
		} else removeAll();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
 
 | 
			
		||||
@@ -159,7 +159,7 @@ public class SettingsScreen extends JDialog {
 | 
			
		||||
		applyTheme(Settings.getInstance().getThemes().get(Settings.getInstance().getCurrentTheme()));
 | 
			
		||||
 | 
			
		||||
		// Respond to theme changes
 | 
			
		||||
		EventBus.getInstance().register(ThemeChangeEvent.class, (evt) -> applyTheme(((ThemeChangeEvent) evt).get()));
 | 
			
		||||
		EventBus.getInstance().register(ThemeChangeEvent.class, evt -> applyTheme(evt.get()));
 | 
			
		||||
 | 
			
		||||
		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 | 
			
		||||
		setModal(true);
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ public class ThemeCustomizationPanel extends SettingsPanel {
 | 
			
		||||
	 * Initializes a {@link ThemeCustomizationPanel} that enables the user to change
 | 
			
		||||
	 * the current {@link Theme} and create new themes as part of the
 | 
			
		||||
	 * {@link SettingsScreen}.
 | 
			
		||||
	 * 
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param parent the {@link SettingsScreen} as a part of which this
 | 
			
		||||
	 *               {@link SettingsPanel} is displayed
 | 
			
		||||
	 * @since Envoy v0.2-alpha
 | 
			
		||||
@@ -119,8 +119,8 @@ public class ThemeCustomizationPanel extends SettingsPanel {
 | 
			
		||||
		// Respond to theme changes
 | 
			
		||||
		EventBus.getInstance()
 | 
			
		||||
			.register(ThemeChangeEvent.class,
 | 
			
		||||
					(evt) -> {
 | 
			
		||||
						final Theme currentTheme = ((ThemeChangeEvent) evt).get();
 | 
			
		||||
					evt -> {
 | 
			
		||||
						final Theme currentTheme = evt.get();
 | 
			
		||||
						temporaryTheme = new Theme("temporaryTheme", currentTheme);
 | 
			
		||||
						applyTheme(currentTheme);
 | 
			
		||||
					});
 | 
			
		||||
@@ -130,7 +130,7 @@ public class ThemeCustomizationPanel extends SettingsPanel {
 | 
			
		||||
	public ActionListener getOkButtonAction() {
 | 
			
		||||
		return (evt) -> {
 | 
			
		||||
			if (themeChanged) {
 | 
			
		||||
				new NewThemeScreen(parent, (name) -> {
 | 
			
		||||
				new NewThemeScreen(parent, name -> {
 | 
			
		||||
					// Create new theme
 | 
			
		||||
					logger.log(Level.FINEST, name);
 | 
			
		||||
					Settings.getInstance().addNewThemeToMap(new Theme(name, temporaryTheme));
 | 
			
		||||
@@ -140,12 +140,12 @@ public class ThemeCustomizationPanel extends SettingsPanel {
 | 
			
		||||
 | 
			
		||||
					// Select new theme name
 | 
			
		||||
					themes.setSelectedIndex(themesModel.getSize() - 1);
 | 
			
		||||
				}, (name) -> {
 | 
			
		||||
				}, name -> {
 | 
			
		||||
					// Modify theme
 | 
			
		||||
					Settings.getInstance().getThemes().replace(name, new Theme(name, temporaryTheme));
 | 
			
		||||
					if(themes.getSelectedItem().equals(name)) {
 | 
			
		||||
					if (themes.getSelectedItem().equals(name)) {
 | 
			
		||||
						EventBus.getInstance().dispatch(new ThemeChangeEvent(Settings.getInstance().getTheme(name)));
 | 
			
		||||
					}else {
 | 
			
		||||
					} else {
 | 
			
		||||
						themes.setSelectedItem(name);
 | 
			
		||||
					}
 | 
			
		||||
				}).setVisible(true);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user