Fixed Bug Regarding Incorrect Pending MessageStatuses in LoginCredentialsProcessor #61
@@ -9,16 +9,17 @@ import envoy.client.ui.Startup;
 | 
				
			|||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * To allow Maven shading, the main method has to be separated from the
 | 
					 * To allow Maven shading, the main method has to be separated from the
 | 
				
			||||||
 * {@link Startup} class which extends {@link Application}.
 | 
					 * {@link Startup} class which extends {@link Application}.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Main.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>05.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public final class Main {
 | 
					public final class Main {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * A funny debug switch put in by {@code delvh} to enable easy debugging.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	private static final boolean debug = false;
 | 
						private static final boolean debug = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,14 @@
 | 
				
			|||||||
package envoy.client.data;
 | 
					package envoy.client.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.Serializable;
 | 
					import java.io.Serializable;
 | 
				
			||||||
import java.util.LinkedList;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.Queue;
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.*;
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.util.EnvoyLog;
 | 
					import envoy.util.EnvoyLog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Stores elements in a queue to process them later.
 | 
					 * Stores elements in a queue to process them later.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Cache.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>6 Feb 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param <T> the type of cached elements
 | 
					 * @param <T> the type of cached elements
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
@@ -62,4 +56,11 @@ public final class Cache<T> implements Consumer<T>, Serializable {
 | 
				
			|||||||
		elements.forEach(processor::accept);
 | 
							elements.forEach(processor::accept);
 | 
				
			||||||
		elements.clear();
 | 
							elements.clear();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Clears this cache of all stored elements.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void clear() { elements.clear(); }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,11 @@
 | 
				
			|||||||
package envoy.client.data;
 | 
					package envoy.client.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.Serializable;
 | 
					import java.io.Serializable;
 | 
				
			||||||
import java.util.HashMap;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.Map;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Stores a heterogeneous map of {@link Cache} objects with different type
 | 
					 * Stores a heterogeneous map of {@link Cache} objects with different type
 | 
				
			||||||
 * parameters.
 | 
					 * parameters.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>CacheMap.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>09.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
@@ -52,7 +47,7 @@ public final class CacheMap implements Serializable {
 | 
				
			|||||||
	public <T> Cache<? super T> getApplicable(Class<T> key) {
 | 
						public <T> Cache<? super T> getApplicable(Class<T> key) {
 | 
				
			||||||
		Cache<? super T> cache = get(key);
 | 
							Cache<? super T> cache = get(key);
 | 
				
			||||||
		if (cache == null)
 | 
							if (cache == null)
 | 
				
			||||||
			for (var e : map.entrySet())
 | 
								for (final var e : map.entrySet())
 | 
				
			||||||
				if (e.getKey().isAssignableFrom(key))
 | 
									if (e.getKey().isAssignableFrom(key))
 | 
				
			||||||
					cache = (Cache<? super T>) e.getValue();
 | 
										cache = (Cache<? super T>) e.getValue();
 | 
				
			||||||
		return cache;
 | 
							return cache;
 | 
				
			||||||
@@ -63,4 +58,11 @@ public final class CacheMap implements Serializable {
 | 
				
			|||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public Map<Class<?>, Cache<?>> getMap() { return map; }
 | 
						public Map<Class<?>, Cache<?>> getMap() { return map; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Clears the caches of this map of any values.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void clear() { map.values().forEach(Cache::clear); }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,18 @@
 | 
				
			|||||||
package envoy.client.data;
 | 
					package envoy.client.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.*;
 | 
				
			||||||
import java.io.Serializable;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.ArrayList;
 | 
					
 | 
				
			||||||
import java.util.List;
 | 
					import javafx.collections.*;
 | 
				
			||||||
import java.util.Objects;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.net.WriteProxy;
 | 
					import envoy.client.net.WriteProxy;
 | 
				
			||||||
import envoy.data.Contact;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.data.Message;
 | 
					 | 
				
			||||||
import envoy.data.Message.MessageStatus;
 | 
					import envoy.data.Message.MessageStatus;
 | 
				
			||||||
import envoy.data.User;
 | 
					 | 
				
			||||||
import envoy.event.MessageStatusChange;
 | 
					import envoy.event.MessageStatusChange;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents a chat between two {@link User}s
 | 
					 * Represents a chat between two {@link User}s
 | 
				
			||||||
 * as a list of {@link Message} objects.
 | 
					 * as a list of {@link Message} objects.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Chat.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>19 Oct 2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
@@ -29,7 +22,8 @@ import envoy.event.MessageStatusChange;
 | 
				
			|||||||
public class Chat implements Serializable {
 | 
					public class Chat implements Serializable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected final Contact recipient;
 | 
						protected final Contact recipient;
 | 
				
			||||||
	protected final List<Message>	messages	= new ArrayList<>();
 | 
					
 | 
				
			||||||
 | 
						protected transient ObservableList<Message> messages = FXCollections.observableArrayList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected int unreadAmount;
 | 
						protected int unreadAmount;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,7 +32,7 @@ public class Chat implements Serializable {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected transient long lastWritingEvent;
 | 
						protected transient long lastWritingEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static final long serialVersionUID = 1L;
 | 
						private static final long serialVersionUID = 2L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Provides the list of messages that the recipient receives.
 | 
						 * Provides the list of messages that the recipient receives.
 | 
				
			||||||
@@ -50,8 +44,18 @@ public class Chat implements Serializable {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public Chat(Contact recipient) { this.recipient = recipient; }
 | 
						public Chat(Contact recipient) { this.recipient = recipient; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException {
 | 
				
			||||||
 | 
							stream.defaultReadObject();
 | 
				
			||||||
 | 
							messages = FXCollections.observableList((List<Message>) stream.readObject());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void writeObject(ObjectOutputStream stream) throws IOException {
 | 
				
			||||||
 | 
							stream.defaultWriteObject();
 | 
				
			||||||
 | 
							stream.writeObject(new ArrayList<>(messages));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public String toString() { return String.format("Chat[recipient=%s,messages=%d]", recipient, messages.size()); }
 | 
						public String toString() { return String.format("%s[recipient=%s,messages=%d]", getClass().getSimpleName(), recipient, messages.size()); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Generates a hash code based on the recipient.
 | 
						 * Generates a hash code based on the recipient.
 | 
				
			||||||
@@ -81,11 +85,9 @@ public class Chat implements Serializable {
 | 
				
			|||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param writeProxy the write proxy instance used to notify the server about
 | 
						 * @param writeProxy the write proxy instance used to notify the server about
 | 
				
			||||||
	 *                   the message status changes
 | 
						 *                   the message status changes
 | 
				
			||||||
	 * @throws IOException if a {@link MessageStatusChange} could not be
 | 
					 | 
				
			||||||
	 *                     delivered to the server
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void read(WriteProxy writeProxy) throws IOException {
 | 
						public void read(WriteProxy writeProxy) {
 | 
				
			||||||
		for (int i = messages.size() - 1; i >= 0; --i) {
 | 
							for (int i = messages.size() - 1; i >= 0; --i) {
 | 
				
			||||||
			final Message m = messages.get(i);
 | 
								final Message m = messages.get(i);
 | 
				
			||||||
			if (m.getSenderID() == recipient.getID()) if (m.getStatus() == MessageStatus.READ) break;
 | 
								if (m.getSenderID() == recipient.getID()) if (m.getStatus() == MessageStatus.READ) break;
 | 
				
			||||||
@@ -136,7 +138,7 @@ public class Chat implements Serializable {
 | 
				
			|||||||
	 * @return all messages in the current chat
 | 
						 * @return all messages in the current chat
 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public List<Message> getMessages() { return messages; }
 | 
						public ObservableList<Message> getMessages() { return messages; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return the recipient of a message
 | 
						 * @return the recipient of a message
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,10 +7,6 @@ import envoy.data.Config;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Implements a configuration specific to the Envoy Client with default values
 | 
					 * Implements a configuration specific to the Envoy Client with default values
 | 
				
			||||||
 * and convenience methods.
 | 
					 * and convenience methods.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ClientConfig.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>01.03.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,16 +2,11 @@ package envoy.client.data;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import javafx.stage.Stage;
 | 
					import javafx.stage.Stage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.net.Client;
 | 
					import envoy.client.net.*;
 | 
				
			||||||
import envoy.client.net.WriteProxy;
 | 
					 | 
				
			||||||
import envoy.client.ui.SceneContext;
 | 
					import envoy.client.ui.SceneContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides access to commonly used objects.
 | 
					 * Provides access to commonly used objects.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Context.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>01.09.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,15 @@
 | 
				
			|||||||
package envoy.client.data;
 | 
					package envoy.client.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
import java.time.Instant;
 | 
					import java.time.Instant;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.net.WriteProxy;
 | 
					import envoy.client.net.WriteProxy;
 | 
				
			||||||
import envoy.data.Contact;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.data.GroupMessage;
 | 
					 | 
				
			||||||
import envoy.data.Message.MessageStatus;
 | 
					import envoy.data.Message.MessageStatus;
 | 
				
			||||||
import envoy.data.User;
 | 
					 | 
				
			||||||
import envoy.event.GroupMessageStatusChange;
 | 
					import envoy.event.GroupMessageStatusChange;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents a chat between a user and a group
 | 
					 * Represents a chat between a user and a group
 | 
				
			||||||
 * as a list of messages.
 | 
					 * as a list of messages.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GroupChat.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>05.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
@@ -38,7 +31,7 @@ public final class GroupChat extends Chat {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public void read(WriteProxy writeProxy) throws IOException {
 | 
						public void read(WriteProxy writeProxy) {
 | 
				
			||||||
		for (int i = messages.size() - 1; i >= 0; --i) {
 | 
							for (int i = messages.size() - 1; i >= 0; --i) {
 | 
				
			||||||
			final GroupMessage gmsg = (GroupMessage) messages.get(i);
 | 
								final GroupMessage gmsg = (GroupMessage) messages.get(i);
 | 
				
			||||||
			if (gmsg.getSenderID() != sender.getID()) if (gmsg.getMemberStatuses().get(sender.getID()) == MessageStatus.READ) break;
 | 
								if (gmsg.getSenderID() != sender.getID()) if (gmsg.getMemberStatuses().get(sender.getID()) == MessageStatus.READ) break;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,13 @@ import java.nio.channels.*;
 | 
				
			|||||||
import java.nio.file.StandardOpenOption;
 | 
					import java.nio.file.StandardOpenOption;
 | 
				
			||||||
import java.time.Instant;
 | 
					import java.time.Instant;
 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.event.EnvoyCloseEvent;
 | 
					import javafx.collections.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import envoy.client.event.*;
 | 
				
			||||||
import envoy.data.*;
 | 
					import envoy.data.*;
 | 
				
			||||||
 | 
					import envoy.data.Message.MessageStatus;
 | 
				
			||||||
import envoy.event.*;
 | 
					import envoy.event.*;
 | 
				
			||||||
import envoy.exception.EnvoyException;
 | 
					import envoy.exception.EnvoyException;
 | 
				
			||||||
import envoy.util.*;
 | 
					import envoy.util.*;
 | 
				
			||||||
@@ -22,10 +25,6 @@ import dev.kske.eventbus.EventListener;
 | 
				
			|||||||
 * For message ID generation a {@link IDGenerator} is stored as well.
 | 
					 * For message ID generation a {@link IDGenerator} is stored as well.
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * The managed objects are stored inside a folder in the local file system.
 | 
					 * The managed objects are stored inside a folder in the local file system.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>LocalDB.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>3 Feb 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.3-alpha
 | 
					 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
@@ -35,11 +34,15 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
	// Data
 | 
						// Data
 | 
				
			||||||
	private User					user;
 | 
						private User					user;
 | 
				
			||||||
	private Map<String, User>		users		= Collections.synchronizedMap(new HashMap<>());
 | 
						private Map<String, User>		users		= Collections.synchronizedMap(new HashMap<>());
 | 
				
			||||||
	private List<Chat>			chats		= Collections.synchronizedList(new ArrayList<>());
 | 
						private ObservableList<Chat>	chats		= FXCollections.observableArrayList();
 | 
				
			||||||
	private IDGenerator				idGenerator;
 | 
						private IDGenerator				idGenerator;
 | 
				
			||||||
	private CacheMap				cacheMap	= new CacheMap();
 | 
						private CacheMap				cacheMap	= new CacheMap();
 | 
				
			||||||
	private String					authToken;
 | 
						private String					authToken;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Auto save timer
 | 
				
			||||||
 | 
						private Timer	autoSaver;
 | 
				
			||||||
 | 
						private boolean	autoSaveRestart	= true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// State management
 | 
						// State management
 | 
				
			||||||
	private Instant lastSync = Instant.EPOCH;
 | 
						private Instant lastSync = Instant.EPOCH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,6 +52,8 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	private final File dbDir, idGeneratorFile, lastLoginFile, usersFile;
 | 
						private final File dbDir, idGeneratorFile, lastLoginFile, usersFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final Logger logger = EnvoyLog.getLogger(LocalDB.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Constructs an empty local database.
 | 
						 * Constructs an empty local database.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
@@ -130,7 +135,7 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
		if (user == null) throw new IllegalStateException("Client user is null, cannot initialize user storage");
 | 
							if (user == null) throw new IllegalStateException("Client user is null, cannot initialize user storage");
 | 
				
			||||||
		userFile = new File(dbDir, user.getID() + ".db");
 | 
							userFile = new File(dbDir, user.getID() + ".db");
 | 
				
			||||||
		try (var in = new ObjectInputStream(new FileInputStream(userFile))) {
 | 
							try (var in = new ObjectInputStream(new FileInputStream(userFile))) {
 | 
				
			||||||
			chats		= (List<Chat>) in.readObject();
 | 
								chats		= FXCollections.observableList((List<Chat>) in.readObject());
 | 
				
			||||||
			cacheMap	= (CacheMap) in.readObject();
 | 
								cacheMap	= (CacheMap) in.readObject();
 | 
				
			||||||
			lastSync	= (Instant) in.readObject();
 | 
								lastSync	= (Instant) in.readObject();
 | 
				
			||||||
		} finally {
 | 
							} finally {
 | 
				
			||||||
@@ -167,7 +172,14 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
	 * @since Envoy Client v0.2-beta
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void initAutoSave() {
 | 
						public void initAutoSave() {
 | 
				
			||||||
		new Timer("LocalDB Autosave", true).schedule(new TimerTask() {
 | 
					
 | 
				
			||||||
 | 
							// A logout happened so the timer should be restarted
 | 
				
			||||||
 | 
							if (autoSaveRestart) {
 | 
				
			||||||
 | 
								autoSaver		= new Timer("LocalDB Autosave", true);
 | 
				
			||||||
 | 
								autoSaveRestart	= false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							autoSaver.schedule(new TimerTask() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			@Override
 | 
								@Override
 | 
				
			||||||
			public void run() { save(); }
 | 
								public void run() { save(); }
 | 
				
			||||||
@@ -190,8 +202,8 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
			SerializationUtils.write(usersFile, users);
 | 
								SerializationUtils.write(usersFile, users);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Save user data and last sync time stamp
 | 
								// Save user data and last sync time stamp
 | 
				
			||||||
			if (user != null)
 | 
								if (user != null) SerializationUtils
 | 
				
			||||||
				SerializationUtils.write(userFile, chats, cacheMap, Context.getInstance().getClient().isOnline() ? Instant.now() : lastSync);
 | 
									.write(userFile, new ArrayList<>(chats), cacheMap, Context.getInstance().getClient().isOnline() ? Instant.now() : lastSync);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Save last login information
 | 
								// Save last login information
 | 
				
			||||||
			if (authToken != null) SerializationUtils.write(lastLoginFile, user, authToken);
 | 
								if (authToken != null) SerializationUtils.write(lastLoginFile, user, authToken);
 | 
				
			||||||
@@ -203,6 +215,37 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Event(priority = 150)
 | 
				
			||||||
 | 
						private void onMessage(Message msg) { if (msg.getStatus() == MessageStatus.SENT) msg.nextStatus(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Event(priority = 150)
 | 
				
			||||||
 | 
						private void onGroupMessage(GroupMessage msg) {
 | 
				
			||||||
 | 
							// TODO: Cancel event once EventBus is updated
 | 
				
			||||||
 | 
							if (msg.getStatus() == MessageStatus.WAITING || msg.getStatus() == MessageStatus.READ)
 | 
				
			||||||
 | 
								logger.warning("The groupMessage has the unexpected status " + msg.getStatus());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Event(priority = 150)
 | 
				
			||||||
 | 
						private void onMessageStatusChange(MessageStatusChange evt) { getMessage(evt.getID()).ifPresent(msg -> msg.setStatus(evt.get())); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Event(priority = 150)
 | 
				
			||||||
 | 
						private void onGroupMessageStatusChange(GroupMessageStatusChange evt) {
 | 
				
			||||||
 | 
							this.<GroupMessage>getMessage(evt.getID()).ifPresent(msg -> msg.getMemberStatuses().replace(evt.getMemberID(), evt.get()));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Event(priority = 150)
 | 
				
			||||||
 | 
						private void onUserStatusChange(UserStatusChange evt) {
 | 
				
			||||||
 | 
							this.getChat(evt.getID()).map(Chat::getRecipient).map(User.class::cast).ifPresent(u -> u.setStatus(evt.get()));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Event(priority = 150)
 | 
				
			||||||
 | 
						private void onGroupResize(GroupResize evt) { getChat(evt.getGroupID()).map(Chat::getRecipient).map(Group.class::cast).ifPresent(evt::apply); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Event(priority = 150)
 | 
				
			||||||
 | 
						private void onNameChange(NameChange evt) {
 | 
				
			||||||
 | 
							chats.stream().map(Chat::getRecipient).filter(c -> c.getID() == evt.getID()).findAny().ifPresent(c -> c.setName(evt.get()));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Stores a new authentication token.
 | 
						 * Stores a new authentication token.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
@@ -212,6 +255,24 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
	@Event
 | 
						@Event
 | 
				
			||||||
	private void onNewAuthToken(NewAuthToken evt) { authToken = evt.get(); }
 | 
						private void onNewAuthToken(NewAuthToken evt) { authToken = evt.get(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Deletes all associations to the current user.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						@Event(eventType = Logout.class, priority = 100)
 | 
				
			||||||
 | 
						private void onLogout() {
 | 
				
			||||||
 | 
							autoSaver.cancel();
 | 
				
			||||||
 | 
							autoSaveRestart = true;
 | 
				
			||||||
 | 
							lastLoginFile.delete();
 | 
				
			||||||
 | 
							userFile	= null;
 | 
				
			||||||
 | 
							user		= null;
 | 
				
			||||||
 | 
							authToken	= null;
 | 
				
			||||||
 | 
							chats.clear();
 | 
				
			||||||
 | 
							lastSync = Instant.EPOCH;
 | 
				
			||||||
 | 
							cacheMap.clear();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return a {@code Map<String, User>} of all users stored locally with their
 | 
						 * @return a {@code Map<String, User>} of all users stored locally with their
 | 
				
			||||||
	 *         user names as keys
 | 
						 *         user names as keys
 | 
				
			||||||
@@ -219,17 +280,32 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public Map<String, User> getUsers() { return users; }
 | 
						public Map<String, User> getUsers() { return users; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Searches for a message by ID.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param id the ID of the message to search for
 | 
				
			||||||
 | 
						 * @return an optional containing the message
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public <T extends Message> Optional<T> getMessage(long id) {
 | 
				
			||||||
 | 
							return (Optional<T>) chats.stream().map(Chat::getMessages).flatMap(List::stream).filter(m -> m.getID() == id).findAny();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Searches for a chat by recipient ID.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param recipientID the ID of the chat's recipient
 | 
				
			||||||
 | 
						 * @return an optional containing the chat
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Optional<Chat> getChat(long recipientID) { return chats.stream().filter(c -> c.getRecipient().getID() == recipientID).findAny(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return all saved {@link Chat} objects that list the client user as the
 | 
						 * @return all saved {@link Chat} objects that list the client user as the
 | 
				
			||||||
	 *         sender
 | 
						 *         sender
 | 
				
			||||||
	 * @since Envoy Client v0.1-alpha
 | 
						 * @since Envoy Client v0.1-alpha
 | 
				
			||||||
	 **/
 | 
						 **/
 | 
				
			||||||
	public List<Chat> getChats() { return chats; }
 | 
						public ObservableList<Chat> getChats() { return chats; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @param chats the chats to set
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void setChats(List<Chat> chats) { this.chats = chats; }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return the {@link User} who initialized the local database
 | 
						 * @return the {@link User} who initialized the local database
 | 
				
			||||||
@@ -253,6 +329,7 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
	 * @param idGenerator the message ID generator to set
 | 
						 * @param idGenerator the message ID generator to set
 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						@Event(priority = 150)
 | 
				
			||||||
	public void setIDGenerator(IDGenerator idGenerator) { this.idGenerator = idGenerator; }
 | 
						public void setIDGenerator(IDGenerator idGenerator) { this.idGenerator = idGenerator; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -278,59 +355,4 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
	 * @since Envoy Client v0.2-beta
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public String getAuthToken() { return authToken; }
 | 
						public String getAuthToken() { return authToken; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Searches for a message by ID.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param id the ID of the message to search for
 | 
					 | 
				
			||||||
	 * @return an optional containing the message
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public Optional<Message> getMessage(long id) {
 | 
					 | 
				
			||||||
		return chats.stream().map(Chat::getMessages).flatMap(List::stream).filter(m -> m.getID() == id).findAny();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Searches for a chat by recipient ID.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param recipientID the ID of the chat's recipient
 | 
					 | 
				
			||||||
	 * @return an optional containing the chat
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public Optional<Chat> getChat(long recipientID) { return chats.stream().filter(c -> c.getRecipient().getID() == recipientID).findAny(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Performs a contact name change if the corresponding contact is present.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param event the {@link NameChange} to process
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void replaceContactName(NameChange event) {
 | 
					 | 
				
			||||||
		chats.stream().map(Chat::getRecipient).filter(c -> c.getID() == event.getID()).findAny().ifPresent(c -> c.setName(event.get()));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Performs a group resize operation if the corresponding group is present.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param event the {@link GroupResize} to process
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void updateGroup(GroupResize event) {
 | 
					 | 
				
			||||||
		chats.stream()
 | 
					 | 
				
			||||||
			.map(Chat::getRecipient)
 | 
					 | 
				
			||||||
			.filter(Group.class::isInstance)
 | 
					 | 
				
			||||||
			.filter(g -> g.getID() == event.getGroupID() && g.getID() != user.getID())
 | 
					 | 
				
			||||||
			.map(Group.class::cast)
 | 
					 | 
				
			||||||
			.findAny()
 | 
					 | 
				
			||||||
			.ifPresent(group -> {
 | 
					 | 
				
			||||||
				switch (event.getOperation()) {
 | 
					 | 
				
			||||||
					case ADD:
 | 
					 | 
				
			||||||
						group.getContacts().add(event.get());
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
					case REMOVE:
 | 
					 | 
				
			||||||
						group.getContacts().remove(event.get());
 | 
					 | 
				
			||||||
						break;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			});
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,10 +15,6 @@ import dev.kske.eventbus.EventListener;
 | 
				
			|||||||
 * Manages all application settings, which are different objects that can be
 | 
					 * Manages all application settings, which are different objects that can be
 | 
				
			||||||
 * changed during runtime and serialized them by using either the file system or
 | 
					 * changed during runtime and serialized them by using either the file system or
 | 
				
			||||||
 * the {@link Preferences} API.
 | 
					 * the {@link Preferences} API.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Settings.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>11 Nov 2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
@@ -92,6 +88,8 @@ public final class Settings implements EventListener {
 | 
				
			|||||||
				new SettingsItem<>(new File(System.getProperty("user.home") + "/Downloads/"), "Download location",
 | 
									new SettingsItem<>(new File(System.getProperty("user.home") + "/Downloads/"), "Download location",
 | 
				
			||||||
						"The location where files will be saved to"));
 | 
											"The location where files will be saved to"));
 | 
				
			||||||
		items.putIfAbsent("autoSaveDownloads", new SettingsItem<>(false, "Save without asking?", "Should downloads be saved without asking?"));
 | 
							items.putIfAbsent("autoSaveDownloads", new SettingsItem<>(false, "Save without asking?", "Should downloads be saved without asking?"));
 | 
				
			||||||
 | 
							items.putIfAbsent("askForConfirmation",
 | 
				
			||||||
 | 
									new SettingsItem<>(true, "Ask for confirmation", "Will ask for confirmation before doing certain things"));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -182,6 +180,25 @@ public final class Settings implements EventListener {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void setHideOnClose(boolean hideOnClose) { ((SettingsItem<Boolean>) items.get("hideOnClose")).set(hideOnClose); }
 | 
						public void setHideOnClose(boolean hideOnClose) { ((SettingsItem<Boolean>) items.get("hideOnClose")).set(hideOnClose); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @return whether a confirmation dialog should be displayed before certain
 | 
				
			||||||
 | 
						 *         actions
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-alpha
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Boolean isAskForConfirmation() { return (Boolean) items.get("askForConfirmation").get(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Changes the behavior of calling certain functionality by displaying a
 | 
				
			||||||
 | 
						 * confirmation dialog before executing it.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param askForConfirmation whether confirmation dialogs should be displayed
 | 
				
			||||||
 | 
						 *                           before certain actions
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-alpha
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void setAskForConfirmation(boolean askForConfirmation) {
 | 
				
			||||||
 | 
							((SettingsItem<Boolean>) items.get("askForConfirmation")).set(askForConfirmation);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return the items
 | 
						 * @return the items
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,6 @@ import javax.swing.JComponent;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Encapsulates a persistent value that is directly or indirectly mutable by the
 | 
					 * Encapsulates a persistent value that is directly or indirectly mutable by the
 | 
				
			||||||
 * user.
 | 
					 * user.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>SettingsItem.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>23.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param <T> the type of this {@link SettingsItem}'s value
 | 
					 * @param <T> the type of this {@link SettingsItem}'s value
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,10 +6,6 @@ import envoy.exception.EnvoyException;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Plays back audio from a byte array.
 | 
					 * Plays back audio from a byte array.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>AudioPlayer.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>05.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,7 @@
 | 
				
			|||||||
package envoy.client.data.audio;
 | 
					package envoy.client.data.audio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.nio.file.Files;
 | 
					import java.nio.file.*;
 | 
				
			||||||
import java.nio.file.Path;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.sound.sampled.*;
 | 
					import javax.sound.sampled.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -10,10 +9,6 @@ import envoy.exception.EnvoyException;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Records audio and exports it as a byte array.
 | 
					 * Records audio and exports it as a byte array.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>AudioRecorder.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>02.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,5 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Contains classes related to recording and playing back audio clips.
 | 
					 * Contains classes related to recording and playing back audio clips.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>package-info.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>05.07.2020</strong><br>
 | 
					 | 
				
			||||||
 * 
 | 
					 * 
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,6 @@ import java.util.function.Supplier;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This interface defines an action that should be performed when a system
 | 
					 * This interface defines an action that should be performed when a system
 | 
				
			||||||
 * command gets called.
 | 
					 * command gets called.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>OnCall.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>23.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,7 @@
 | 
				
			|||||||
package envoy.client.data.commands;
 | 
					package envoy.client.data.commands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.function.*;
 | 
				
			||||||
import java.util.Objects;
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					 | 
				
			||||||
import java.util.function.Supplier;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This class is the base class of all {@code SystemCommands} and contains an
 | 
					 * This class is the base class of all {@code SystemCommands} and contains an
 | 
				
			||||||
@@ -16,10 +13,6 @@ import java.util.function.Supplier;
 | 
				
			|||||||
 * function. This approach has one limitation:<br>
 | 
					 * function. This approach has one limitation:<br>
 | 
				
			||||||
 * <b>Order matters!</b> Changing the order of arguments will likely result in
 | 
					 * <b>Order matters!</b> Changing the order of arguments will likely result in
 | 
				
			||||||
 * unexpected behavior.
 | 
					 * unexpected behavior.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>SystemCommand.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>16.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,10 @@
 | 
				
			|||||||
package envoy.client.data.commands;
 | 
					package envoy.client.data.commands;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This class acts as a builder for {@link SystemCommand}s.
 | 
					 * This class acts as a builder for {@link SystemCommand}s.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>SystemCommandBuilder.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>23.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
@@ -22,6 +17,22 @@ public final class SystemCommandBuilder {
 | 
				
			|||||||
	private String					description;
 | 
						private String					description;
 | 
				
			||||||
	private int						relevance;
 | 
						private int						relevance;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private final SystemCommandMap commandsMap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates a new {@code SystemCommandsBuilder} without underlying
 | 
				
			||||||
 | 
						 * {@link SystemCommandMap}.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SystemCommandBuilder() { this(null); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @param commandsMap the map to use when calling build (optional)
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SystemCommandBuilder(SystemCommandMap commandsMap) { this.commandsMap = commandsMap; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @param numberOfArguments the numberOfArguments to set
 | 
						 * @param numberOfArguments the numberOfArguments to set
 | 
				
			||||||
	 * @return this {@code SystemCommandBuilder}
 | 
						 * @return this {@code SystemCommandBuilder}
 | 
				
			||||||
@@ -125,6 +136,7 @@ public final class SystemCommandBuilder {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Builds a {@code SystemCommand} based upon the previously entered data.<br>
 | 
						 * Builds a {@code SystemCommand} based upon the previously entered data.<br>
 | 
				
			||||||
 | 
						 * Automatically adds the built object to the given map.
 | 
				
			||||||
	 * At the end, this {@code SystemCommandBuilder} <b>can</b> be reset but must
 | 
						 * At the end, this {@code SystemCommandBuilder} <b>can</b> be reset but must
 | 
				
			||||||
	 * not be.
 | 
						 * not be.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
@@ -141,4 +153,78 @@ public final class SystemCommandBuilder {
 | 
				
			|||||||
		if (reset) reset();
 | 
							if (reset) reset();
 | 
				
			||||||
		return sc;
 | 
							return sc;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Builds a {@code SystemCommand} based upon the previously entered data.
 | 
				
			||||||
 | 
						 * Automatically adds the built object to the given map.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param command the command under which to store the SystemCommand in the
 | 
				
			||||||
 | 
						 *                {@link SystemCommandMap}
 | 
				
			||||||
 | 
						 * @return the built {@code SystemCommand}
 | 
				
			||||||
 | 
						 * @throws NullPointerException if no map has been assigned to this builder
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SystemCommand build(String command) { return build(command, true); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Builds a {@code SystemCommand} based upon the previously entered data.<br>
 | 
				
			||||||
 | 
						 * Automatically adds the built object to the given map.
 | 
				
			||||||
 | 
						 * {@code SystemCommand#numberOfArguments} will be set to 0, regardless of the
 | 
				
			||||||
 | 
						 * previous value.<br>
 | 
				
			||||||
 | 
						 * At the end, this {@code SystemCommandBuilder} will be reset.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param command the command under which to store the SystemCommand in the
 | 
				
			||||||
 | 
						 *                {@link SystemCommandMap}
 | 
				
			||||||
 | 
						 * @return the built {@code SystemCommand}
 | 
				
			||||||
 | 
						 * @throws NullPointerException if no map has been assigned to this builder
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SystemCommand buildNoArg(String command) {
 | 
				
			||||||
 | 
							numberOfArguments = 0;
 | 
				
			||||||
 | 
							return build(command, true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Builds a {@code SystemCommand} based upon the previously entered data.<br>
 | 
				
			||||||
 | 
						 * Automatically adds the built object to the given map.
 | 
				
			||||||
 | 
						 * {@code SystemCommand#numberOfArguments} will be set to use the rest of the
 | 
				
			||||||
 | 
						 * string as argument, regardless of the previous value.<br>
 | 
				
			||||||
 | 
						 * At the end, this {@code SystemCommandBuilder} will be reset.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param command the command under which to store the SystemCommand in the
 | 
				
			||||||
 | 
						 *                {@link SystemCommandMap}
 | 
				
			||||||
 | 
						 * @return the built {@code SystemCommand}
 | 
				
			||||||
 | 
						 * @throws NullPointerException if no map has been assigned to this builder
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SystemCommand buildRemainingArg(String command) {
 | 
				
			||||||
 | 
							numberOfArguments = -1;
 | 
				
			||||||
 | 
							return build(command, true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Builds a {@code SystemCommand} based upon the previously entered data.<br>
 | 
				
			||||||
 | 
						 * Automatically adds the built object to the given map.
 | 
				
			||||||
 | 
						 * At the end, this {@code SystemCommandBuilder} <b>can</b> be reset but must
 | 
				
			||||||
 | 
						 * not be.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param command the command under which to store the SystemCommand in the
 | 
				
			||||||
 | 
						 *                {@link SystemCommandMap}
 | 
				
			||||||
 | 
						 * @param reset   whether this {@code SystemCommandBuilder} should be reset
 | 
				
			||||||
 | 
						 *                afterwards.<br>
 | 
				
			||||||
 | 
						 *                This can be useful if another command wants to execute
 | 
				
			||||||
 | 
						 *                something
 | 
				
			||||||
 | 
						 *                similar
 | 
				
			||||||
 | 
						 * @return the built {@code SystemCommand}
 | 
				
			||||||
 | 
						 * @throws NullPointerException if no map has been assigned to this builder
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SystemCommand build(String command, boolean reset) {
 | 
				
			||||||
 | 
							final var sc = new SystemCommand(action, numberOfArguments, defaults, description);
 | 
				
			||||||
 | 
							sc.setRelevance(relevance);
 | 
				
			||||||
 | 
							if (commandsMap != null) commandsMap.add(command, sc);
 | 
				
			||||||
 | 
							else throw new NullPointerException("No map in SystemCommandsBuilder present");
 | 
				
			||||||
 | 
							if (reset) reset();
 | 
				
			||||||
 | 
							return sc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,21 +10,17 @@ import envoy.util.EnvoyLog;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This class stores all {@link SystemCommand}s used.
 | 
					 * This class stores all {@link SystemCommand}s used.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>SystemCommandsMap.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>17.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public final class SystemCommandsMap {
 | 
					public final class SystemCommandMap {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private final Map<String, SystemCommand> systemCommands = new HashMap<>();
 | 
						private final Map<String, SystemCommand> systemCommands = new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private final Pattern commandPattern = Pattern.compile("^[a-zA-Z0-9_:!\\(\\)\\?\\.\\,\\;\\-]+$");
 | 
						private final Pattern commandPattern = Pattern.compile("^[a-zA-Z0-9_:!\\(\\)\\?\\.\\,\\;\\-]+$");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static final Logger logger = EnvoyLog.getLogger(SystemCommandsMap.class);
 | 
						private static final Logger logger = EnvoyLog.getLogger(SystemCommandMap.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Adds a new command to the map if the command name is valid.
 | 
						 * Adds a new command to the map if the command name is valid.
 | 
				
			||||||
@@ -33,7 +29,7 @@ public final class SystemCommandsMap {
 | 
				
			|||||||
	 *                      given action
 | 
						 *                      given action
 | 
				
			||||||
	 * @param systemCommand the command to add - can be built using
 | 
						 * @param systemCommand the command to add - can be built using
 | 
				
			||||||
	 *                      {@link SystemCommandBuilder}
 | 
						 *                      {@link SystemCommandBuilder}
 | 
				
			||||||
	 * @see SystemCommandsMap#isValidKey(String)
 | 
						 * @see SystemCommandMap#isValidKey(String)
 | 
				
			||||||
	 * @since Envoy Client v0.2-beta
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void add(String command, SystemCommand systemCommand) {
 | 
						public void add(String command, SystemCommand systemCommand) {
 | 
				
			||||||
@@ -48,7 +44,7 @@ public final class SystemCommandsMap {
 | 
				
			|||||||
	 * map).
 | 
						 * map).
 | 
				
			||||||
	 * <p>
 | 
						 * <p>
 | 
				
			||||||
	 * Usage example:<br>
 | 
						 * Usage example:<br>
 | 
				
			||||||
	 * {@code SystemCommandsMap systemCommands = new SystemCommandsMap();}<br>
 | 
						 * {@code SystemCommandMap systemCommands = new SystemCommandMap();}<br>
 | 
				
			||||||
	 * {@code Button button = new  Button();}
 | 
						 * {@code Button button = new  Button();}
 | 
				
			||||||
	 * {@code systemCommands.add("example", text -> button.setText(text.get(0), 1);}<br>
 | 
						 * {@code systemCommands.add("example", text -> button.setText(text.get(0), 1);}<br>
 | 
				
			||||||
	 * {@code ....}<br>
 | 
						 * {@code ....}<br>
 | 
				
			||||||
@@ -132,7 +128,7 @@ public final class SystemCommandsMap {
 | 
				
			|||||||
	 * map).
 | 
						 * map).
 | 
				
			||||||
	 * <p>
 | 
						 * <p>
 | 
				
			||||||
	 * Usage example:<br>
 | 
						 * Usage example:<br>
 | 
				
			||||||
	 * {@code SystemCommandsMap systemCommands = new SystemCommandsMap();}<br>
 | 
						 * {@code SystemCommandMap systemCommands = new SystemCommandMap();}<br>
 | 
				
			||||||
	 * {@code Button button = new Button();}<br>
 | 
						 * {@code Button button = new Button();}<br>
 | 
				
			||||||
	 * {@code systemCommands.add("example", (words)-> button.setText(words.get(0), 1);}<br>
 | 
						 * {@code systemCommands.add("example", (words)-> button.setText(words.get(0), 1);}<br>
 | 
				
			||||||
	 * {@code ....}<br>
 | 
						 * {@code ....}<br>
 | 
				
			||||||
@@ -1,10 +1,6 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This package contains all classes that can be used as system commands.<br>
 | 
					 * This package contains all classes that can be used as system commands.<br>
 | 
				
			||||||
 * Every system command can be called using a specific syntax:"/<command>"
 | 
					 * Every system command can be called using a specific syntax:"/<command>"
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>package-info.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>16.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,12 +3,8 @@ package envoy.client.event;
 | 
				
			|||||||
import envoy.event.Event.Valueless;
 | 
					import envoy.event.Event.Valueless;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This event serves the purpose to trigger the tab change to tab 0 in
 | 
					 * This event serves the purpose of triggering the tab change to tab 0 in
 | 
				
			||||||
 * {@link envoy.client.ui.controller.ChatScene}.
 | 
					 * {@link envoy.client.ui.controller.ChatScene}.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>BackEvent.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>23.08.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,9 @@ package envoy.client.event;
 | 
				
			|||||||
import envoy.event.Event.Valueless;
 | 
					import envoy.event.Event.Valueless;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This event will be sent once Envoy is <strong>really</strong> closed.
 | 
					 * This event notifies various Envoy components of the application being about
 | 
				
			||||||
 * Its purpose is to forcefully stop other threads peacefully so that the VM can
 | 
					 * to shut down. This allows the graceful closing of connections, persisting
 | 
				
			||||||
 * shutdown too.
 | 
					 * local data etc.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								client/src/main/java/envoy/client/event/Logout.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								client/src/main/java/envoy/client/event/Logout.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					package envoy.client.event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import envoy.event.Event.Valueless;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Indicates that a logout has been requested.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public final class Logout extends Valueless {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final long serialVersionUID = 1L;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,22 +0,0 @@
 | 
				
			|||||||
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 Client v0.3-alpha
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public final class SendEvent extends Event<Event<?>> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static final long serialVersionUID = 0L;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @param value the event to send to the server
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public SendEvent(Event<?> value) { super(value); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -3,9 +3,7 @@ package envoy.client.event;
 | 
				
			|||||||
import envoy.event.Event;
 | 
					import envoy.event.Event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Notifies UI components of a theme change.
 | 
				
			||||||
 * File: <strong>ThemeChangeEvent.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>15 Dec 2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.2-alpha
 | 
					 * @since Envoy Client v0.2-alpha
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										36
									
								
								client/src/main/java/envoy/client/helper/AlertHelper.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								client/src/main/java/envoy/client/helper/AlertHelper.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					package envoy.client.helper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import envoy.client.data.Settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Provides methods that are commonly used for alerts.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public final class AlertHelper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private AlertHelper() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Asks for a confirmation dialog if {@link Settings#isAskForConfirmation()}
 | 
				
			||||||
 | 
						 * returns {@code true}.
 | 
				
			||||||
 | 
						 * Immediately executes the action if no dialog was requested or the dialog was
 | 
				
			||||||
 | 
						 * exited with a confirmation.
 | 
				
			||||||
 | 
						 * Does nothing if the dialog was closed without clicking on OK.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param alert  the (customized) alert to show. <strong>Should not be shown
 | 
				
			||||||
 | 
						 *               already</strong>
 | 
				
			||||||
 | 
						 * @param action the action to perform in case of success
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static void confirmAction(Alert alert, Runnable action) {
 | 
				
			||||||
 | 
							alert.setHeight(225);
 | 
				
			||||||
 | 
							alert.setWidth(400);
 | 
				
			||||||
 | 
							alert.setHeaderText("");
 | 
				
			||||||
 | 
							if (Settings.getInstance().isAskForConfirmation()) alert.showAndWait().filter(ButtonType.OK::equals).ifPresent(bu -> action.run());
 | 
				
			||||||
 | 
							else action.run();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										57
									
								
								client/src/main/java/envoy/client/helper/ShutdownHelper.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								client/src/main/java/envoy/client/helper/ShutdownHelper.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					package envoy.client.helper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.logging.Level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javafx.scene.control.Alert;
 | 
				
			||||||
 | 
					import javafx.scene.control.Alert.AlertType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import envoy.client.data.*;
 | 
				
			||||||
 | 
					import envoy.client.event.*;
 | 
				
			||||||
 | 
					import envoy.client.ui.SceneContext.SceneInfo;
 | 
				
			||||||
 | 
					import envoy.util.EnvoyLog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.kske.eventbus.EventBus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Simplifies shutdown actions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public final class ShutdownHelper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ShutdownHelper() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Exits Envoy or minimizes it, depending on the current state of
 | 
				
			||||||
 | 
						 * {@link Settings#isHideOnClose()}.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static void exit() {
 | 
				
			||||||
 | 
							if (Settings.getInstance().isHideOnClose()) Context.getInstance().getStage().setIconified(true);
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								EventBus.getInstance().dispatch(new EnvoyCloseEvent());
 | 
				
			||||||
 | 
								System.exit(0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Logs the current user out and reopens
 | 
				
			||||||
 | 
						 * {@link envoy.client.ui.controller.LoginScene}.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static void logout() {
 | 
				
			||||||
 | 
							final var alert = new Alert(AlertType.CONFIRMATION);
 | 
				
			||||||
 | 
							alert.setTitle("Logout?");
 | 
				
			||||||
 | 
							alert.setContentText("Are you sure you want to log out?");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							AlertHelper.confirmAction(alert, () -> {
 | 
				
			||||||
 | 
								EnvoyLog.getLogger(ShutdownHelper.class).log(Level.INFO, "A logout was requested");
 | 
				
			||||||
 | 
								EventBus.getInstance().dispatch(new EnvoyCloseEvent());
 | 
				
			||||||
 | 
								EventBus.getInstance().dispatch(new Logout());
 | 
				
			||||||
 | 
								Context.getInstance().getSceneContext().load(SceneInfo.LOGIN_SCENE);
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Provides helper methods that reduce boilerplate code.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 | 
					 * @author Kai S. K. Engelbert
 | 
				
			||||||
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package envoy.client.helper;
 | 
				
			||||||
@@ -6,22 +6,17 @@ import java.util.concurrent.TimeoutException;
 | 
				
			|||||||
import java.util.logging.*;
 | 
					import java.util.logging.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.*;
 | 
					import envoy.client.data.*;
 | 
				
			||||||
import envoy.client.event.*;
 | 
					import envoy.client.event.EnvoyCloseEvent;
 | 
				
			||||||
import envoy.data.*;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.event.*;
 | 
					import envoy.event.*;
 | 
				
			||||||
import envoy.event.Event;
 | 
					 | 
				
			||||||
import envoy.event.contact.*;
 | 
					 | 
				
			||||||
import envoy.util.*;
 | 
					import envoy.util.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.kske.eventbus.*;
 | 
					import dev.kske.eventbus.*;
 | 
				
			||||||
 | 
					import dev.kske.eventbus.Event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Establishes a connection to the server, performs a handshake and delivers
 | 
					 * Establishes a connection to the server, performs a handshake and delivers
 | 
				
			||||||
 * certain objects to the server.
 | 
					 * certain objects to the server.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Client.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>28 Sep 2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
@@ -79,8 +74,6 @@ public final class Client implements EventListener, Closeable {
 | 
				
			|||||||
		// authentication token
 | 
							// authentication token
 | 
				
			||||||
		receiver.registerProcessor(User.class, sender -> this.sender = sender);
 | 
							receiver.registerProcessor(User.class, sender -> this.sender = sender);
 | 
				
			||||||
		receiver.registerProcessors(cacheMap.getMap());
 | 
							receiver.registerProcessors(cacheMap.getMap());
 | 
				
			||||||
		receiver.registerProcessor(HandshakeRejection.class, evt -> { rejected = true; eventBus.dispatch(evt); });
 | 
					 | 
				
			||||||
		receiver.registerProcessor(NewAuthToken.class, eventBus::dispatch);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rejected = false;
 | 
							rejected = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -107,7 +100,6 @@ public final class Client implements EventListener, Closeable {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		online = true;
 | 
							online = true;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		logger.log(Level.INFO, "Handshake completed.");
 | 
							logger.log(Level.INFO, "Handshake completed.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -128,129 +120,86 @@ public final class Client implements EventListener, Closeable {
 | 
				
			|||||||
		// Remove all processors as they are only used during the handshake
 | 
							// Remove all processors as they are only used during the handshake
 | 
				
			||||||
		receiver.removeAllProcessors();
 | 
							receiver.removeAllProcessors();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Process incoming messages
 | 
					 | 
				
			||||||
		final var	receivedMessageProcessor			= new ReceivedMessageProcessor();
 | 
					 | 
				
			||||||
		final var	receivedGroupMessageProcessor		= new ReceivedGroupMessageProcessor();
 | 
					 | 
				
			||||||
		final var	messageStatusChangeProcessor		= new MessageStatusChangeProcessor();
 | 
					 | 
				
			||||||
		final var	groupMessageStatusChangeProcessor	= new GroupMessageStatusChangeProcessor();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		receiver.registerProcessor(GroupMessage.class, receivedGroupMessageProcessor);
 | 
					 | 
				
			||||||
		receiver.registerProcessor(Message.class, receivedMessageProcessor);
 | 
					 | 
				
			||||||
		receiver.registerProcessor(MessageStatusChange.class, messageStatusChangeProcessor);
 | 
					 | 
				
			||||||
		receiver.registerProcessor(GroupMessageStatusChange.class, groupMessageStatusChangeProcessor);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Relay cached messages and message status changes
 | 
							// Relay cached messages and message status changes
 | 
				
			||||||
		cacheMap.get(Message.class).setProcessor(receivedMessageProcessor);
 | 
							cacheMap.get(Message.class).setProcessor(eventBus::dispatch);
 | 
				
			||||||
		cacheMap.get(GroupMessage.class).setProcessor(receivedGroupMessageProcessor);
 | 
							cacheMap.get(GroupMessage.class).setProcessor(eventBus::dispatch);
 | 
				
			||||||
		cacheMap.get(MessageStatusChange.class).setProcessor(messageStatusChangeProcessor);
 | 
							cacheMap.get(MessageStatusChange.class).setProcessor(eventBus::dispatch);
 | 
				
			||||||
		cacheMap.get(GroupMessageStatusChange.class).setProcessor(groupMessageStatusChangeProcessor);
 | 
							cacheMap.get(GroupMessageStatusChange.class).setProcessor(eventBus::dispatch);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process user status changes
 | 
					 | 
				
			||||||
		receiver.registerProcessor(UserStatusChange.class, eventBus::dispatch);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process message ID generation
 | 
					 | 
				
			||||||
		receiver.registerProcessor(IDGenerator.class, localDB::setIDGenerator);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process name changes
 | 
					 | 
				
			||||||
		receiver.registerProcessor(NameChange.class, evt -> { localDB.replaceContactName(evt); eventBus.dispatch(evt); });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process contact searches
 | 
					 | 
				
			||||||
		receiver.registerProcessor(UserSearchResult.class, eventBus::dispatch);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process contact operations
 | 
					 | 
				
			||||||
		receiver.registerProcessor(ContactOperation.class, eventBus::dispatch);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process group size changes
 | 
					 | 
				
			||||||
		receiver.registerProcessor(GroupResize.class, evt -> { localDB.updateGroup(evt); eventBus.dispatch(evt); });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process IsTyping events
 | 
					 | 
				
			||||||
		receiver.registerProcessor(IsTyping.class, eventBus::dispatch);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process PasswordChangeResults
 | 
					 | 
				
			||||||
		receiver.registerProcessor(PasswordChangeResult.class, eventBus::dispatch);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process ProfilePicChanges
 | 
					 | 
				
			||||||
		receiver.registerProcessor(ProfilePicChange.class, eventBus::dispatch);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process requests to not send any more attachments as they will not be shown
 | 
					 | 
				
			||||||
		// to other users
 | 
					 | 
				
			||||||
		receiver.registerProcessor(NoAttachments.class, eventBus::dispatch);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Process group creation results - they might have been disabled on the server
 | 
					 | 
				
			||||||
		receiver.registerProcessor(GroupCreationResult.class, eventBus::dispatch);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Request a generator if none is present or the existing one is consumed
 | 
							// Request a generator if none is present or the existing one is consumed
 | 
				
			||||||
		if (!localDB.hasIDGenerator() || !localDB.getIDGenerator().hasNext()) requestIdGenerator();
 | 
							if (!localDB.hasIDGenerator() || !localDB.getIDGenerator().hasNext()) requestIDGenerator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Relay caches
 | 
							// Relay caches
 | 
				
			||||||
		cacheMap.getMap().values().forEach(Cache::relay);
 | 
							cacheMap.getMap().values().forEach(Cache::relay);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sends an object to the server.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param obj the object to send
 | 
				
			||||||
 | 
						 * @throws IllegalStateException if the client is not online
 | 
				
			||||||
 | 
						 * @throws RuntimeException      if the object serialization failed
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void send(Serializable obj) throws IllegalStateException, RuntimeException {
 | 
				
			||||||
 | 
							checkOnline();
 | 
				
			||||||
 | 
							logger.log(Level.FINE, "Sending " + obj);
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								SerializationUtils.writeBytesWithLength(obj, socket.getOutputStream());
 | 
				
			||||||
 | 
							} catch (IOException e) {
 | 
				
			||||||
 | 
								throw new RuntimeException(e);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Sends a message to the server. The message's status will be incremented once
 | 
						 * Sends a message to the server. The message's status will be incremented once
 | 
				
			||||||
	 * it was delivered successfully.
 | 
						 * it was delivered successfully.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param message the message to send
 | 
						 * @param message the message to send
 | 
				
			||||||
	 * @throws IOException if the message does not reach the server
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void sendMessage(Message message) throws IOException {
 | 
						public void sendMessage(Message message) {
 | 
				
			||||||
		writeObject(message);
 | 
							send(message);
 | 
				
			||||||
		message.nextStatus();
 | 
							message.nextStatus();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Sends an event to the server.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param evt the event to send
 | 
					 | 
				
			||||||
	 * @throws IOException if the event did not reach the server
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void sendEvent(Event<?> evt) throws IOException { if (online) writeObject(evt); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Requests a new {@link IDGenerator} from the server.
 | 
						 * Requests a new {@link IDGenerator} from the server.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @throws IOException if the request does not reach the server
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void requestIdGenerator() throws IOException {
 | 
						public void requestIDGenerator() {
 | 
				
			||||||
		logger.log(Level.INFO, "Requesting new id generator...");
 | 
							logger.log(Level.INFO, "Requesting new id generator...");
 | 
				
			||||||
		writeObject(new IDGeneratorRequest());
 | 
							send(new IDGeneratorRequest());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						@Event(eventType = HandshakeRejection.class, priority = 1000)
 | 
				
			||||||
	 * Sends the value of a send event to the server.
 | 
						private void onHandshakeRejection() { rejected = true; }
 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param evt the send event to extract the value from
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.2-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	@dev.kske.eventbus.Event
 | 
					 | 
				
			||||||
	private void onSendEvent(SendEvent evt) {
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			sendEvent(evt.get());
 | 
					 | 
				
			||||||
		} catch (final IOException e) {
 | 
					 | 
				
			||||||
			logger.log(Level.WARNING, "An error occurred when trying to send " + evt, e);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	@dev.kske.eventbus.Event(eventType = EnvoyCloseEvent.class, priority = 800)
 | 
						@Event(eventType = EnvoyCloseEvent.class, priority = 800)
 | 
				
			||||||
	public void close() {
 | 
						public void close() {
 | 
				
			||||||
		if (online) {
 | 
							if (online) {
 | 
				
			||||||
			logger.log(Level.INFO, "Closing connection...");
 | 
								logger.log(Level.INFO, "Closing connection...");
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// The sender must be reset as otherwise the handshake is immediately closed
 | 
				
			||||||
 | 
									sender	= null;
 | 
				
			||||||
 | 
									online	= false;
 | 
				
			||||||
				socket.close();
 | 
									socket.close();
 | 
				
			||||||
			} catch (final IOException e) {}
 | 
								} catch (final IOException e) {
 | 
				
			||||||
 | 
									logger.log(Level.WARNING, "Failed to close socket: ", e);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void writeObject(Object obj) throws IOException {
 | 
						/**
 | 
				
			||||||
		checkOnline();
 | 
						 * Ensured that the client is online.
 | 
				
			||||||
		logger.log(Level.FINE, "Sending " + obj);
 | 
						 *
 | 
				
			||||||
		SerializationUtils.writeBytesWithLength(obj, socket.getOutputStream());
 | 
						 * @throws IllegalStateException if the client is not online
 | 
				
			||||||
	}
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	private void checkOnline() { if (!online) throw new IllegalStateException("Client is not online"); }
 | 
						private void checkOnline() throws IllegalStateException { if (!online) throw new IllegalStateException("Client is not online"); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return the {@link User} as which this client is logged in
 | 
						 * @return the {@link User} as which this client is logged in
 | 
				
			||||||
@@ -268,6 +217,7 @@ public final class Client implements EventListener, Closeable {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return the {@link Receiver} used by this {@link Client}
 | 
						 * @return the {@link Receiver} used by this {@link Client}
 | 
				
			||||||
 | 
						 * @since v0.2-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public Receiver getReceiver() { return receiver; }
 | 
						public Receiver getReceiver() { return receiver; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,29 +0,0 @@
 | 
				
			|||||||
package envoy.client.net;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import envoy.data.Message.MessageStatus;
 | 
					 | 
				
			||||||
import envoy.event.GroupMessageStatusChange;
 | 
					 | 
				
			||||||
import envoy.util.EnvoyLog;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dev.kske.eventbus.EventBus;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GroupMessageStatusChangePocessor.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>03.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public final class GroupMessageStatusChangeProcessor implements Consumer<GroupMessageStatusChange> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static final Logger logger = EnvoyLog.getLogger(GroupMessageStatusChangeProcessor.class);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void accept(GroupMessageStatusChange evt) {
 | 
					 | 
				
			||||||
		if (evt.get().ordinal() < MessageStatus.RECEIVED.ordinal()) logger.warning("Received invalid group message status change " + evt);
 | 
					 | 
				
			||||||
		else EventBus.getInstance().dispatch(evt);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,36 +0,0 @@
 | 
				
			|||||||
package envoy.client.net;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import envoy.data.Message.MessageStatus;
 | 
					 | 
				
			||||||
import envoy.event.MessageStatusChange;
 | 
					 | 
				
			||||||
import envoy.util.EnvoyLog;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dev.kske.eventbus.EventBus;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>MessageStatusChangeProcessor.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>4 Feb 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.3-alpha
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public final class MessageStatusChangeProcessor implements Consumer<MessageStatusChange> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static final Logger logger = EnvoyLog.getLogger(MessageStatusChangeProcessor.class);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Dispatches a {@link MessageStatusChange} if the status is
 | 
					 | 
				
			||||||
	 * {@code RECEIVED} or {@code READ}.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param evt the status change event
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void accept(MessageStatusChange evt) {
 | 
					 | 
				
			||||||
		if (evt.get().ordinal() < MessageStatus.RECEIVED.ordinal()) logger.warning("Received invalid message status change " + evt);
 | 
					 | 
				
			||||||
		else EventBus.getInstance().dispatch(evt);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,33 +0,0 @@
 | 
				
			|||||||
package envoy.client.net;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import envoy.data.GroupMessage;
 | 
					 | 
				
			||||||
import envoy.data.Message.MessageStatus;
 | 
					 | 
				
			||||||
import envoy.util.EnvoyLog;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dev.kske.eventbus.EventBus;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ReceivedGroupMessageProcessor.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>13.06.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public final class ReceivedGroupMessageProcessor implements Consumer<GroupMessage> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private static final Logger logger = EnvoyLog.getLogger(ReceivedGroupMessageProcessor.class);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void accept(GroupMessage groupMessage) {
 | 
					 | 
				
			||||||
		if (groupMessage.getStatus() == MessageStatus.WAITING || groupMessage.getStatus() == MessageStatus.READ)
 | 
					 | 
				
			||||||
			logger.warning("The groupMessage has the unexpected status " + groupMessage.getStatus());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Dispatch event
 | 
					 | 
				
			||||||
		EventBus.getInstance().dispatch(groupMessage);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,28 +0,0 @@
 | 
				
			|||||||
package envoy.client.net;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.function.Consumer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import envoy.data.Message;
 | 
					 | 
				
			||||||
import envoy.data.Message.MessageStatus;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import dev.kske.eventbus.EventBus;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ReceivedMessageProcessor.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>31.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.3-alpha
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public final class ReceivedMessageProcessor implements Consumer<Message> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Override
 | 
					 | 
				
			||||||
	public void accept(Message message) {
 | 
					 | 
				
			||||||
		// Update status to RECEIVED
 | 
					 | 
				
			||||||
		if (message.getStatus() == MessageStatus.SENT) message.nextStatus();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// Dispatch message
 | 
					 | 
				
			||||||
		EventBus.getInstance().dispatch(message);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -8,13 +8,11 @@ import java.util.logging.*;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import envoy.util.*;
 | 
					import envoy.util.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.kske.eventbus.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Receives objects from the server and passes them to processor objects based
 | 
					 * Receives objects from the server and passes them to processor objects based
 | 
				
			||||||
 * on their class.
 | 
					 * on their class.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Receiver.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>30.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.3-alpha
 | 
					 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
@@ -26,6 +24,7 @@ public final class Receiver extends Thread {
 | 
				
			|||||||
	private final InputStream					in;
 | 
						private final InputStream					in;
 | 
				
			||||||
	private final Map<Class<?>, Consumer<?>>	processors	= new HashMap<>();
 | 
						private final Map<Class<?>, Consumer<?>>	processors	= new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final EventBus	eventBus	= EventBus.getInstance();
 | 
				
			||||||
	private static final Logger		logger		= EnvoyLog.getLogger(Receiver.class);
 | 
						private static final Logger		logger		= EnvoyLog.getLogger(Receiver.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -37,6 +36,7 @@ public final class Receiver extends Thread {
 | 
				
			|||||||
	public Receiver(InputStream in) {
 | 
						public Receiver(InputStream in) {
 | 
				
			||||||
		super("Receiver");
 | 
							super("Receiver");
 | 
				
			||||||
		this.in = in;
 | 
							this.in = in;
 | 
				
			||||||
 | 
							setDaemon(true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -81,9 +81,14 @@ public final class Receiver extends Thread {
 | 
				
			|||||||
					// Get appropriate processor
 | 
										// Get appropriate processor
 | 
				
			||||||
					@SuppressWarnings("rawtypes")
 | 
										@SuppressWarnings("rawtypes")
 | 
				
			||||||
					final Consumer processor = processors.get(obj.getClass());
 | 
										final Consumer processor = processors.get(obj.getClass());
 | 
				
			||||||
					if (processor == null)
 | 
					
 | 
				
			||||||
						logger.log(Level.WARNING, String.format("The received object has the %s for which no processor is defined.", obj.getClass()));
 | 
										// Dispatch to the processor if present
 | 
				
			||||||
					else processor.accept(obj);
 | 
										if (processor != null) processor.accept(obj);
 | 
				
			||||||
 | 
										// Dispatch to the event bus if the object is an event without a processor
 | 
				
			||||||
 | 
										else if (obj instanceof IEvent) eventBus.dispatch((IEvent) obj);
 | 
				
			||||||
 | 
										// Notify if no processor could be located
 | 
				
			||||||
 | 
										else logger.log(Level.WARNING,
 | 
				
			||||||
 | 
												String.format("The received object has the %s for which no processor is defined.", obj.getClass()));
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (final SocketException | EOFException e) {
 | 
								} catch (final SocketException | EOFException e) {
 | 
				
			||||||
				// Connection probably closed by client.
 | 
									// Connection probably closed by client.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,8 @@
 | 
				
			|||||||
package envoy.client.net;
 | 
					package envoy.client.net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.util.logging.*;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.Cache;
 | 
					import envoy.client.data.*;
 | 
				
			||||||
import envoy.client.data.LocalDB;
 | 
					 | 
				
			||||||
import envoy.data.Message;
 | 
					import envoy.data.Message;
 | 
				
			||||||
import envoy.event.MessageStatusChange;
 | 
					import envoy.event.MessageStatusChange;
 | 
				
			||||||
import envoy.util.EnvoyLog;
 | 
					import envoy.util.EnvoyLog;
 | 
				
			||||||
@@ -14,10 +11,6 @@ import envoy.util.EnvoyLog;
 | 
				
			|||||||
 * Implements methods to send {@link Message}s and
 | 
					 * Implements methods to send {@link Message}s and
 | 
				
			||||||
 * {@link MessageStatusChange}s to the server or cache them inside a
 | 
					 * {@link MessageStatusChange}s to the server or cache them inside a
 | 
				
			||||||
 * {@link LocalDB} depending on the online status.
 | 
					 * {@link LocalDB} depending on the online status.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>WriteProxy.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>6 Feb 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.3-alpha
 | 
					 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
@@ -44,20 +37,12 @@ public final class WriteProxy {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Initialize cache processors for messages and message status change events
 | 
							// Initialize cache processors for messages and message status change events
 | 
				
			||||||
		localDB.getCacheMap().get(Message.class).setProcessor(msg -> {
 | 
							localDB.getCacheMap().get(Message.class).setProcessor(msg -> {
 | 
				
			||||||
			try {
 | 
					 | 
				
			||||||
			logger.log(Level.FINER, "Sending cached " + msg);
 | 
								logger.log(Level.FINER, "Sending cached " + msg);
 | 
				
			||||||
			client.sendMessage(msg);
 | 
								client.sendMessage(msg);
 | 
				
			||||||
			} catch (final IOException e) {
 | 
					 | 
				
			||||||
				logger.log(Level.SEVERE, "Could not send cached message: ", e);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
		localDB.getCacheMap().get(MessageStatusChange.class).setProcessor(evt -> {
 | 
							localDB.getCacheMap().get(MessageStatusChange.class).setProcessor(evt -> {
 | 
				
			||||||
			logger.log(Level.FINER, "Sending cached " + evt);
 | 
								logger.log(Level.FINER, "Sending cached " + evt);
 | 
				
			||||||
			try {
 | 
								client.send(evt);
 | 
				
			||||||
				client.sendEvent(evt);
 | 
					 | 
				
			||||||
			} catch (final IOException e) {
 | 
					 | 
				
			||||||
				logger.log(Level.SEVERE, "Could not send cached message status change event: ", e);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -74,10 +59,9 @@ public final class WriteProxy {
 | 
				
			|||||||
	 * inside the local database.
 | 
						 * inside the local database.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param message the message to send
 | 
						 * @param message the message to send
 | 
				
			||||||
	 * @throws IOException if the message could not be sent
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void writeMessage(Message message) throws IOException {
 | 
						public void writeMessage(Message message) {
 | 
				
			||||||
		if (client.isOnline()) client.sendMessage(message);
 | 
							if (client.isOnline()) client.sendMessage(message);
 | 
				
			||||||
		else localDB.getCacheMap().getApplicable(Message.class).accept(message);
 | 
							else localDB.getCacheMap().getApplicable(Message.class).accept(message);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -87,11 +71,10 @@ public final class WriteProxy {
 | 
				
			|||||||
	 * event is cached inside the local database.
 | 
						 * event is cached inside the local database.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param evt the event to send
 | 
						 * @param evt the event to send
 | 
				
			||||||
	 * @throws IOException if the event could not be sent
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.3-alpha
 | 
						 * @since Envoy Client v0.3-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void writeMessageStatusChange(MessageStatusChange evt) throws IOException {
 | 
						public void writeMessageStatusChange(MessageStatusChange evt) {
 | 
				
			||||||
		if (client.isOnline()) client.sendEvent(evt);
 | 
							if (client.isOnline()) client.send(evt);
 | 
				
			||||||
		else localDB.getCacheMap().getApplicable(MessageStatusChange.class).accept(evt);
 | 
							else localDB.getCacheMap().getApplicable(MessageStatusChange.class).accept(evt);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,169 +0,0 @@
 | 
				
			|||||||
package envoy.client.ui;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javafx.beans.property.BooleanProperty;
 | 
					 | 
				
			||||||
import javafx.beans.property.ObjectProperty;
 | 
					 | 
				
			||||||
import javafx.beans.property.StringProperty;
 | 
					 | 
				
			||||||
import javafx.event.ActionEvent;
 | 
					 | 
				
			||||||
import javafx.event.EventHandler;
 | 
					 | 
				
			||||||
import javafx.scene.control.*;
 | 
					 | 
				
			||||||
import javafx.scene.image.ImageView;
 | 
					 | 
				
			||||||
import javafx.scene.layout.Background;
 | 
					 | 
				
			||||||
import javafx.scene.layout.ColumnConstraints;
 | 
					 | 
				
			||||||
import javafx.scene.layout.GridPane;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * This class offers a text field that is automatically equipped with a clear
 | 
					 | 
				
			||||||
 * button.
 | 
					 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ClearableTextField.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>25.06.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public final class ClearableTextField extends GridPane {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private final TextField textField;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private final Button clearButton;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Constructs a new {@code ClearableTextField} with no initial text and icon
 | 
					 | 
				
			||||||
	 * size 16.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public ClearableTextField() { this("", 16); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Constructs a new {@code ClearableTextField} with initial text and a
 | 
					 | 
				
			||||||
	 * predetermined icon size.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param text the text that should be displayed by default
 | 
					 | 
				
			||||||
	 * @param size the size of the icon
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public ClearableTextField(String text, int size) {
 | 
					 | 
				
			||||||
		// initializing the textField and the button
 | 
					 | 
				
			||||||
		textField	= new TextField(text);
 | 
					 | 
				
			||||||
		clearButton	= new Button("", new ImageView(IconUtil.loadIconThemeSensitive("clear_button", size)));
 | 
					 | 
				
			||||||
		clearButton.setOnAction(e -> textField.clear());
 | 
					 | 
				
			||||||
		clearButton.setFocusTraversable(false);
 | 
					 | 
				
			||||||
		clearButton.getStyleClass().clear();
 | 
					 | 
				
			||||||
		clearButton.setBackground(Background.EMPTY);
 | 
					 | 
				
			||||||
		// Adding the two elements to the GridPane
 | 
					 | 
				
			||||||
		add(textField, 0, 0, 2, 1);
 | 
					 | 
				
			||||||
		add(clearButton, 1, 0, 1, 1);
 | 
					 | 
				
			||||||
		// Setting the percent - widths of the two columns.
 | 
					 | 
				
			||||||
		// Used to locate the button on the right.
 | 
					 | 
				
			||||||
		final var columnConstraints = new ColumnConstraints();
 | 
					 | 
				
			||||||
		columnConstraints.setPercentWidth(90);
 | 
					 | 
				
			||||||
		getColumnConstraints().add(columnConstraints);
 | 
					 | 
				
			||||||
		final var columnConstraints2 = new ColumnConstraints();
 | 
					 | 
				
			||||||
		columnConstraints2.setPercentWidth(10);
 | 
					 | 
				
			||||||
		getColumnConstraints().add(columnConstraints2);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return the underlying {@code textField}
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public TextField getTextField() { return textField; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * This method offers the freedom to perform custom actions when the
 | 
					 | 
				
			||||||
	 * {@code clearButton} has been pressed.
 | 
					 | 
				
			||||||
	 * <p>
 | 
					 | 
				
			||||||
	 * The default is
 | 
					 | 
				
			||||||
	 * <b><code>  e -> {clearableTextField.getTextField().clear();}</code></b>
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param onClearButtonAction the action that should be performed
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void setClearButtonListener(EventHandler<ActionEvent> onClearButtonAction) { clearButton.setOnAction(onClearButtonAction); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return the current property of the prompt text
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.TextInputControl#promptTextProperty()
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public StringProperty promptTextProperty() { return textField.promptTextProperty(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return the current prompt text
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.TextInputControl#getPromptText()
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public String getPromptText() { return textField.getPromptText(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @param value the prompt text to display
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.TextInputControl#setPromptText(java.lang.String)
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void setPromptText(String value) { textField.setPromptText(value); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return the current property of the tooltip
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.Control#tooltipProperty()
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public ObjectProperty<Tooltip> tooltipProperty() { return textField.tooltipProperty(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @param value the new tooltip
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.Control#setTooltip(javafx.scene.control.Tooltip)
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void setTooltip(Tooltip value) { textField.setTooltip(value); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return the current tooltip
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.Control#getTooltip()
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public Tooltip getTooltip() { return textField.getTooltip(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return the current property of the context menu
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.Control#contextMenuProperty()
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public ObjectProperty<ContextMenu> contextMenuProperty() { return textField.contextMenuProperty(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @param value the new context menu
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.Control#setContextMenu(javafx.scene.control.ContextMenu)
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void setContextMenu(ContextMenu value) { textField.setContextMenu(value); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return the current context menu
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.Control#getContextMenu()
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public ContextMenu getContextMenu() { return textField.getContextMenu(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @param value whether this ClearableTextField should be editable
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.TextInputControl#setEditable(boolean)
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public void setEditable(boolean value) { textField.setEditable(value); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return the current property whether this ClearableTextField is editable
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.TextInputControl#editableProperty()
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public BooleanProperty editableProperty() { return textField.editableProperty(); }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * @return whether this {@code ClearableTextField} is editable
 | 
					 | 
				
			||||||
	 * @see javafx.scene.control.TextInputControl#isEditable()
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public boolean isEditable() { return textField.isEditable(); }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,36 +0,0 @@
 | 
				
			|||||||
package envoy.client.ui;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javafx.scene.control.ListCell;
 | 
					 | 
				
			||||||
import javafx.scene.control.ListView;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * This is a utility class that provides access to a refreshing mechanism for
 | 
					 | 
				
			||||||
 * elements that were added without notifying the underlying {@link ListView}.
 | 
					 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ListViewRefresh.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>16.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public final class ListViewRefresh {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private ListViewRefresh() {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 * Deeply refreshes a {@code listview}, meaning it recomputes every single of
 | 
					 | 
				
			||||||
	 * its {@link ListCell}s.
 | 
					 | 
				
			||||||
	 * <p>
 | 
					 | 
				
			||||||
	 * While it does work, it is <b>not the most efficient algorithm</b> possible.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @param toRefresh the listView to refresh
 | 
					 | 
				
			||||||
	 * @param <T>       the type of its {@code listcells}
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	public static <T> void deepRefresh(ListView<T> toRefresh) {
 | 
					 | 
				
			||||||
		final var items = toRefresh.getItems();
 | 
					 | 
				
			||||||
		toRefresh.setItems(null);
 | 
					 | 
				
			||||||
		toRefresh.setItems(items);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -3,10 +3,6 @@ package envoy.client.ui;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This interface defines an action that should be performed when a scene gets
 | 
					 * This interface defines an action that should be performed when a scene gets
 | 
				
			||||||
 * restored from the scene stack in {@link SceneContext}.
 | 
					 * restored from the scene stack in {@link SceneContext}.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Restorable.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>03.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import javafx.stage.Stage;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.Settings;
 | 
					import envoy.client.data.Settings;
 | 
				
			||||||
import envoy.client.event.*;
 | 
					import envoy.client.event.*;
 | 
				
			||||||
 | 
					import envoy.client.helper.ShutdownHelper;
 | 
				
			||||||
import envoy.util.EnvoyLog;
 | 
					import envoy.util.EnvoyLog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.kske.eventbus.*;
 | 
					import dev.kske.eventbus.*;
 | 
				
			||||||
@@ -23,10 +24,6 @@ import dev.kske.eventbus.*;
 | 
				
			|||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * When a scene is loaded, the style sheet for the current theme is applied to
 | 
					 * When a scene is loaded, the style sheet for the current theme is applied to
 | 
				
			||||||
 * it.
 | 
					 * it.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>SceneContext.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>06.06.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
@@ -96,6 +93,7 @@ public final class SceneContext implements EventListener {
 | 
				
			|||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public void load(SceneInfo sceneInfo) {
 | 
						public void load(SceneInfo sceneInfo) {
 | 
				
			||||||
 | 
							EnvoyLog.getLogger(SceneContext.class).log(Level.FINER, "Loading scene " + sceneInfo);
 | 
				
			||||||
		loader.setRoot(null);
 | 
							loader.setRoot(null);
 | 
				
			||||||
		loader.setController(null);
 | 
							loader.setController(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -107,18 +105,17 @@ public final class SceneContext implements EventListener {
 | 
				
			|||||||
			sceneStack.push(scene);
 | 
								sceneStack.push(scene);
 | 
				
			||||||
			stage.setScene(scene);
 | 
								stage.setScene(scene);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Adding the option to exit Linux-like with "Control" + "Q"
 | 
								// Add the option to exit Linux-like with "Control" + "Q"
 | 
				
			||||||
			scene.getAccelerators()
 | 
								scene.getAccelerators().put(new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN), ShutdownHelper::exit);
 | 
				
			||||||
				.put(new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN),
 | 
					
 | 
				
			||||||
						() -> {
 | 
								// Add the option to logout using "Control"+"Shift"+"L" if not in login scene
 | 
				
			||||||
							// Presumably no Settings are loaded in the login scene, hence Envoy is closed
 | 
								if (sceneInfo != SceneInfo.LOGIN_SCENE) scene.getAccelerators()
 | 
				
			||||||
							// directly
 | 
									.put(new KeyCodeCombination(KeyCode.L, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN), ShutdownHelper::logout);
 | 
				
			||||||
							if (sceneInfo != SceneInfo.LOGIN_SCENE && settings.isHideOnClose()) stage.setIconified(true);
 | 
					
 | 
				
			||||||
							else {
 | 
								// Add the option to open the settings scene with "Control"+"S", if being in
 | 
				
			||||||
								EventBus.getInstance().dispatch(new EnvoyCloseEvent());
 | 
								// chat scene
 | 
				
			||||||
								System.exit(0);
 | 
								if (sceneInfo.equals(SceneInfo.CHAT_SCENE))
 | 
				
			||||||
							}
 | 
									scene.getAccelerators().put(new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN), () -> load(SceneInfo.SETTINGS_SCENE));
 | 
				
			||||||
						});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// The LoginScene is the only scene not intended to be resized
 | 
								// The LoginScene is the only scene not intended to be resized
 | 
				
			||||||
			// As strange as it seems, this is needed as otherwise the LoginScene won't be
 | 
								// As strange as it seems, this is needed as otherwise the LoginScene won't be
 | 
				
			||||||
@@ -167,6 +164,12 @@ public final class SceneContext implements EventListener {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Event(eventType = Logout.class, priority = 150)
 | 
				
			||||||
 | 
						private void onLogout() {
 | 
				
			||||||
 | 
							sceneStack.clear();
 | 
				
			||||||
 | 
							controllerStack.clear();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Event(priority = 150, eventType = ThemeChangeEvent.class)
 | 
						@Event(priority = 150, eventType = ThemeChangeEvent.class)
 | 
				
			||||||
	private void onThemeChange() { applyCSS(); }
 | 
						private void onThemeChange() { applyCSS(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,24 +11,19 @@ import javafx.scene.control.Alert.AlertType;
 | 
				
			|||||||
import javafx.stage.Stage;
 | 
					import javafx.stage.Stage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.*;
 | 
					import envoy.client.data.*;
 | 
				
			||||||
import envoy.client.event.EnvoyCloseEvent;
 | 
					import envoy.client.helper.ShutdownHelper;
 | 
				
			||||||
import envoy.client.net.Client;
 | 
					import envoy.client.net.Client;
 | 
				
			||||||
import envoy.client.ui.SceneContext.SceneInfo;
 | 
					import envoy.client.ui.SceneContext.SceneInfo;
 | 
				
			||||||
import envoy.client.ui.controller.LoginScene;
 | 
					import envoy.client.ui.controller.LoginScene;
 | 
				
			||||||
 | 
					import envoy.client.util.IconUtil;
 | 
				
			||||||
import envoy.data.*;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.data.User.UserStatus;
 | 
					import envoy.data.User.UserStatus;
 | 
				
			||||||
import envoy.event.*;
 | 
					import envoy.event.*;
 | 
				
			||||||
import envoy.exception.EnvoyException;
 | 
					import envoy.exception.EnvoyException;
 | 
				
			||||||
import envoy.util.EnvoyLog;
 | 
					import envoy.util.EnvoyLog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.kske.eventbus.EventBus;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Handles application startup and shutdown.
 | 
					 * Handles application startup.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Startup.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>26.03.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
@@ -58,6 +53,8 @@ public final class Startup extends Application {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public void start(Stage stage) throws Exception {
 | 
						public void start(Stage stage) throws Exception {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Initialize config and logger
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			config.loadAll(Startup.class, "client.properties", getParameters().getRaw().toArray(new String[0]));
 | 
								config.loadAll(Startup.class, "client.properties", getParameters().getRaw().toArray(new String[0]));
 | 
				
			||||||
			EnvoyLog.initialize(config);
 | 
								EnvoyLog.initialize(config);
 | 
				
			||||||
@@ -70,7 +67,7 @@ public final class Startup extends Application {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Initialize the local database
 | 
							// Initialize the local database
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			var localDBFile = new File(config.getHomeDirectory(), config.getServer());
 | 
								final var localDBFile = new File(config.getHomeDirectory(), config.getServer());
 | 
				
			||||||
			logger.info("Initializing LocalDB at " + localDBFile);
 | 
								logger.info("Initializing LocalDB at " + localDBFile);
 | 
				
			||||||
			localDB = new LocalDB(localDBFile);
 | 
								localDB = new LocalDB(localDBFile);
 | 
				
			||||||
		} catch (IOException | EnvoyException e) {
 | 
							} catch (IOException | EnvoyException e) {
 | 
				
			||||||
@@ -117,7 +114,6 @@ public final class Startup extends Application {
 | 
				
			|||||||
		cacheMap.put(MessageStatusChange.class, new Cache<MessageStatusChange>());
 | 
							cacheMap.put(MessageStatusChange.class, new Cache<MessageStatusChange>());
 | 
				
			||||||
		cacheMap.put(GroupMessageStatusChange.class, new Cache<GroupMessageStatusChange>());
 | 
							cacheMap.put(GroupMessageStatusChange.class, new Cache<GroupMessageStatusChange>());
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			final var client = context.getClient();
 | 
					 | 
				
			||||||
			client.performHandshake(credentials, cacheMap);
 | 
								client.performHandshake(credentials, cacheMap);
 | 
				
			||||||
			if (client.isOnline()) {
 | 
								if (client.isOnline()) {
 | 
				
			||||||
				loadChatScene();
 | 
									loadChatScene();
 | 
				
			||||||
@@ -211,13 +207,8 @@ public final class Startup extends Application {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		if (StatusTrayIcon.isSupported()) {
 | 
							if (StatusTrayIcon.isSupported()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Configure hide on close
 | 
								// Exit or minimize the stage when a close request occurs
 | 
				
			||||||
			stage.setOnCloseRequest(e -> {
 | 
								stage.setOnCloseRequest(e -> { ShutdownHelper.exit(); if (Settings.getInstance().isHideOnClose()) e.consume(); });
 | 
				
			||||||
				if (Settings.getInstance().isHideOnClose()) {
 | 
					 | 
				
			||||||
					stage.setIconified(true);
 | 
					 | 
				
			||||||
					e.consume();
 | 
					 | 
				
			||||||
				} else EventBus.getInstance().dispatch(new EnvoyCloseEvent());
 | 
					 | 
				
			||||||
			});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Initialize status tray icon
 | 
								// Initialize status tray icon
 | 
				
			||||||
			final var trayIcon = new StatusTrayIcon(stage);
 | 
								final var trayIcon = new StatusTrayIcon(stage);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,16 +6,14 @@ import java.awt.TrayIcon.MessageType;
 | 
				
			|||||||
import javafx.application.Platform;
 | 
					import javafx.application.Platform;
 | 
				
			||||||
import javafx.stage.Stage;
 | 
					import javafx.stage.Stage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import envoy.client.helper.ShutdownHelper;
 | 
				
			||||||
 | 
					import envoy.client.util.IconUtil;
 | 
				
			||||||
import envoy.data.Message;
 | 
					import envoy.data.Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.kske.eventbus.*;
 | 
					import dev.kske.eventbus.*;
 | 
				
			||||||
import dev.kske.eventbus.Event;
 | 
					import dev.kske.eventbus.Event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>StatusTrayIcon.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>3 Dec 2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.2-alpha
 | 
					 * @since Envoy Client v0.2-alpha
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -32,7 +30,7 @@ public final class StatusTrayIcon implements EventListener {
 | 
				
			|||||||
	 * A received {@link Message} is only displayed as a system tray notification if
 | 
						 * A received {@link Message} is only displayed as a system tray notification if
 | 
				
			||||||
	 * this variable is set to {@code true}.
 | 
						 * this variable is set to {@code true}.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	private boolean displayMessages = false;
 | 
						private boolean displayMessages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return {@code true} if the status tray icon is supported on this platform
 | 
						 * @return {@code true} if the status tray icon is supported on this platform
 | 
				
			||||||
@@ -56,7 +54,7 @@ public final class StatusTrayIcon implements EventListener {
 | 
				
			|||||||
		final PopupMenu popup = new PopupMenu();
 | 
							final PopupMenu popup = new PopupMenu();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		final MenuItem exitMenuItem = new MenuItem("Exit");
 | 
							final MenuItem exitMenuItem = new MenuItem("Exit");
 | 
				
			||||||
		exitMenuItem.addActionListener(evt -> { Platform.exit(); System.exit(0); });
 | 
							exitMenuItem.addActionListener(evt -> ShutdownHelper.exit());
 | 
				
			||||||
		popup.add(exitMenuItem);
 | 
							popup.add(exitMenuItem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		trayIcon.setPopupMenu(popup);
 | 
							trayIcon.setPopupMenu(popup);
 | 
				
			||||||
@@ -90,10 +88,10 @@ public final class StatusTrayIcon implements EventListener {
 | 
				
			|||||||
	public void hide() { SystemTray.getSystemTray().remove(trayIcon); }
 | 
						public void hide() { SystemTray.getSystemTray().remove(trayIcon); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Event
 | 
						@Event
 | 
				
			||||||
	private void onMessage(Message evt) {
 | 
						private void onMessage(Message message) {
 | 
				
			||||||
		if (displayMessages) trayIcon.displayMessage(
 | 
							if (displayMessages) trayIcon.displayMessage(
 | 
				
			||||||
				evt.hasAttachment() ? "New " + evt.getAttachment().getType().toString().toLowerCase() + " message received" : "New message received",
 | 
									message.hasAttachment() ? "New " + message.getAttachment().getType().toString().toLowerCase() + " message received" : "New message received",
 | 
				
			||||||
				evt.getText(),
 | 
									message.getText(),
 | 
				
			||||||
				MessageType.INFO);
 | 
									MessageType.INFO);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,9 @@
 | 
				
			|||||||
package envoy.client.ui;
 | 
					package envoy.client.ui.control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.*;
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.scene.control.Alert;
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
import javafx.scene.control.Alert.AlertType;
 | 
					import javafx.scene.control.Alert.AlertType;
 | 
				
			||||||
import javafx.scene.control.Button;
 | 
					 | 
				
			||||||
import javafx.scene.layout.HBox;
 | 
					import javafx.scene.layout.HBox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.audio.AudioPlayer;
 | 
					import envoy.client.data.audio.AudioPlayer;
 | 
				
			||||||
@@ -14,10 +12,6 @@ import envoy.util.EnvoyLog;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Enables the play back of audio clips through a button.
 | 
					 * Enables the play back of audio clips through a button.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>AudioControl.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>05.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
@@ -1,23 +1,17 @@
 | 
				
			|||||||
package envoy.client.ui.listcell;
 | 
					package envoy.client.ui.control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.geometry.Insets;
 | 
					import javafx.geometry.*;
 | 
				
			||||||
import javafx.geometry.Pos;
 | 
					 | 
				
			||||||
import javafx.scene.control.Label;
 | 
					import javafx.scene.control.Label;
 | 
				
			||||||
import javafx.scene.image.ImageView;
 | 
					import javafx.scene.image.*;
 | 
				
			||||||
import javafx.scene.layout.*;
 | 
					import javafx.scene.layout.*;
 | 
				
			||||||
import javafx.scene.shape.Rectangle;
 | 
					import javafx.scene.shape.Rectangle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.Chat;
 | 
					import envoy.client.data.*;
 | 
				
			||||||
import envoy.client.ui.IconUtil;
 | 
					import envoy.client.util.IconUtil;
 | 
				
			||||||
import envoy.data.Group;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Displays a chat using a contact control for the recipient and a label for the
 | 
					 * Displays a chat using a contact control for the recipient and a label for the
 | 
				
			||||||
 * unread message count.
 | 
					 * unread message count.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ContactControl.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>01.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @see ContactControl
 | 
					 * @see ContactControl
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
@@ -25,6 +19,9 @@ import envoy.data.Group;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
public final class ChatControl extends HBox {
 | 
					public final class ChatControl extends HBox {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final Image userIcon = IconUtil.loadIconThemeSensitive("user_icon", 32),
 | 
				
			||||||
 | 
								groupIcon = IconUtil.loadIconThemeSensitive("group_icon", 32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @param chat the chat to display
 | 
						 * @param chat the chat to display
 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
@@ -32,10 +29,9 @@ public final class ChatControl extends HBox {
 | 
				
			|||||||
	public ChatControl(Chat chat) {
 | 
						public ChatControl(Chat chat) {
 | 
				
			||||||
		setAlignment(Pos.CENTER_LEFT);
 | 
							setAlignment(Pos.CENTER_LEFT);
 | 
				
			||||||
		setPadding(new Insets(0, 0, 3, 0));
 | 
							setPadding(new Insets(0, 0, 3, 0));
 | 
				
			||||||
		// profile pic
 | 
					
 | 
				
			||||||
		ImageView contactProfilePic;
 | 
							// Profile picture
 | 
				
			||||||
		if (chat.getRecipient() instanceof Group) contactProfilePic = new ImageView(IconUtil.loadIconThemeSensitive("group_icon", 32));
 | 
							ImageView	contactProfilePic	= new ImageView(chat instanceof GroupChat ? groupIcon : userIcon);
 | 
				
			||||||
		else contactProfilePic = new ImageView(IconUtil.loadIconThemeSensitive("user_icon", 32));
 | 
					 | 
				
			||||||
		final var clip = new Rectangle();
 | 
							final var clip = new Rectangle();
 | 
				
			||||||
		clip.setWidth(32);
 | 
							clip.setWidth(32);
 | 
				
			||||||
		clip.setHeight(32);
 | 
							clip.setHeight(32);
 | 
				
			||||||
@@ -43,14 +39,17 @@ public final class ChatControl extends HBox {
 | 
				
			|||||||
		clip.setArcWidth(32);
 | 
							clip.setArcWidth(32);
 | 
				
			||||||
		contactProfilePic.setClip(clip);
 | 
							contactProfilePic.setClip(clip);
 | 
				
			||||||
		getChildren().add(contactProfilePic);
 | 
							getChildren().add(contactProfilePic);
 | 
				
			||||||
		// spacing
 | 
					
 | 
				
			||||||
 | 
							// Spacing
 | 
				
			||||||
		final var leftSpacing = new Region();
 | 
							final var leftSpacing = new Region();
 | 
				
			||||||
		leftSpacing.setPrefSize(8, 0);
 | 
							leftSpacing.setPrefSize(8, 0);
 | 
				
			||||||
		leftSpacing.setMinSize(8, 0);
 | 
							leftSpacing.setMinSize(8, 0);
 | 
				
			||||||
		leftSpacing.setMaxSize(8, 0);
 | 
							leftSpacing.setMaxSize(8, 0);
 | 
				
			||||||
		getChildren().add(leftSpacing);
 | 
							getChildren().add(leftSpacing);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Contact control
 | 
							// Contact control
 | 
				
			||||||
		getChildren().add(new ContactControl(chat.getRecipient()));
 | 
							getChildren().add(new ContactControl(chat.getRecipient()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Unread messages
 | 
							// Unread messages
 | 
				
			||||||
		if (chat.getUnreadAmount() != 0) {
 | 
							if (chat.getUnreadAmount() != 0) {
 | 
				
			||||||
			final var spacing = new Region();
 | 
								final var spacing = new Region();
 | 
				
			||||||
@@ -58,12 +57,12 @@ public final class ChatControl extends HBox {
 | 
				
			|||||||
			getChildren().add(spacing);
 | 
								getChildren().add(spacing);
 | 
				
			||||||
			final var unreadMessagesLabel = new Label(Integer.toString(chat.getUnreadAmount()));
 | 
								final var unreadMessagesLabel = new Label(Integer.toString(chat.getUnreadAmount()));
 | 
				
			||||||
			unreadMessagesLabel.setMinSize(15, 15);
 | 
								unreadMessagesLabel.setMinSize(15, 15);
 | 
				
			||||||
			final var vBox2 = new VBox();
 | 
								final var vbox = new VBox();
 | 
				
			||||||
			vBox2.setAlignment(Pos.CENTER_RIGHT);
 | 
								vbox.setAlignment(Pos.CENTER_RIGHT);
 | 
				
			||||||
			unreadMessagesLabel.setAlignment(Pos.CENTER);
 | 
								unreadMessagesLabel.setAlignment(Pos.CENTER);
 | 
				
			||||||
			unreadMessagesLabel.getStyleClass().add("unread-messages-amount");
 | 
								unreadMessagesLabel.getStyleClass().add("unread-messages-amount");
 | 
				
			||||||
			vBox2.getChildren().add(unreadMessagesLabel);
 | 
								vbox.getChildren().add(unreadMessagesLabel);
 | 
				
			||||||
			getChildren().add(vBox2);
 | 
								getChildren().add(vbox);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		getStyleClass().add("list-element");
 | 
							getStyleClass().add("list-element");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -1,19 +1,14 @@
 | 
				
			|||||||
package envoy.client.ui.listcell;
 | 
					package envoy.client.ui.control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.scene.control.Label;
 | 
					import javafx.scene.control.Label;
 | 
				
			||||||
import javafx.scene.layout.VBox;
 | 
					import javafx.scene.layout.VBox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.data.Contact;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.data.User;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Displays information about a contact in two rows. The first row contains the
 | 
					 * Displays information about a contact in two rows. The first row contains the
 | 
				
			||||||
 * name. The second row contains the online status (user) or the member count
 | 
					 * name. The second row contains the online status (user) or the member count
 | 
				
			||||||
 * (group).
 | 
					 * (group).
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ContactControl.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>13.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package envoy.client.ui.listcell;
 | 
					package envoy.client.ui.control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.awt.Toolkit;
 | 
					import java.awt.Toolkit;
 | 
				
			||||||
import java.awt.datatransfer.StringSelection;
 | 
					import java.awt.datatransfer.StringSelection;
 | 
				
			||||||
@@ -6,37 +6,23 @@ import java.io.*;
 | 
				
			|||||||
import java.time.ZoneId;
 | 
					import java.time.ZoneId;
 | 
				
			||||||
import java.time.format.DateTimeFormatter;
 | 
					import java.time.format.DateTimeFormatter;
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.*;
 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.geometry.Insets;
 | 
					import javafx.geometry.*;
 | 
				
			||||||
import javafx.geometry.Pos;
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
import javafx.scene.control.ContextMenu;
 | 
					import javafx.scene.image.*;
 | 
				
			||||||
import javafx.scene.control.Label;
 | 
					 | 
				
			||||||
import javafx.scene.control.MenuItem;
 | 
					 | 
				
			||||||
import javafx.scene.image.Image;
 | 
					 | 
				
			||||||
import javafx.scene.image.ImageView;
 | 
					 | 
				
			||||||
import javafx.scene.layout.*;
 | 
					import javafx.scene.layout.*;
 | 
				
			||||||
import javafx.stage.FileChooser;
 | 
					import javafx.stage.FileChooser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.Context;
 | 
					import envoy.client.data.*;
 | 
				
			||||||
import envoy.client.data.LocalDB;
 | 
					import envoy.client.ui.*;
 | 
				
			||||||
import envoy.client.data.Settings;
 | 
					import envoy.client.util.IconUtil;
 | 
				
			||||||
import envoy.client.ui.AudioControl;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.client.ui.IconUtil;
 | 
					 | 
				
			||||||
import envoy.client.ui.SceneContext;
 | 
					 | 
				
			||||||
import envoy.data.GroupMessage;
 | 
					 | 
				
			||||||
import envoy.data.Message;
 | 
					 | 
				
			||||||
import envoy.data.Message.MessageStatus;
 | 
					import envoy.data.Message.MessageStatus;
 | 
				
			||||||
import envoy.data.User;
 | 
					 | 
				
			||||||
import envoy.util.EnvoyLog;
 | 
					import envoy.util.EnvoyLog;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This class formats a single {@link Message} into a UI component.
 | 
					 * This class transforms a single {@link Message} into a UI component.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>MessageControl.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>01.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
@@ -95,6 +81,7 @@ public final class MessageControl extends Label {
 | 
				
			|||||||
		contextMenu.getItems().addAll(copyMenuItem, deleteMenuItem, forwardMenuItem, quoteMenuItem, infoMenuItem);
 | 
							contextMenu.getItems().addAll(copyMenuItem, deleteMenuItem, forwardMenuItem, quoteMenuItem, infoMenuItem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Handling message attachment display
 | 
							// Handling message attachment display
 | 
				
			||||||
 | 
							// TODO: Add missing attachment types
 | 
				
			||||||
		if (message.hasAttachment()) {
 | 
							if (message.hasAttachment()) {
 | 
				
			||||||
			switch (message.getAttachment().getType()) {
 | 
								switch (message.getAttachment().getType()) {
 | 
				
			||||||
				case PICTURE:
 | 
									case PICTURE:
 | 
				
			||||||
@@ -1,15 +1,10 @@
 | 
				
			|||||||
package envoy.client.ui.custom;
 | 
					package envoy.client.ui.control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.scene.image.Image;
 | 
					import javafx.scene.image.*;
 | 
				
			||||||
import javafx.scene.image.ImageView;
 | 
					 | 
				
			||||||
import javafx.scene.shape.Rectangle;
 | 
					import javafx.scene.shape.Rectangle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides a set of convenience constructors for images that are displayed as profile pictures.
 | 
					 * Provides a set of convenience constructors for images that are displayed as profile pictures.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ProfilePicImageView.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>30.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package envoy.client.ui.custom;
 | 
					package envoy.client.ui.control;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.function.Consumer;
 | 
					import java.util.function.Consumer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,10 +21,6 @@ import javafx.scene.input.Clipboard;
 | 
				
			|||||||
 * <li>clear</li>
 | 
					 * <li>clear</li>
 | 
				
			||||||
 * <li>Select all</li>
 | 
					 * <li>Select all</li>
 | 
				
			||||||
 * </ul>
 | 
					 * </ul>
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>TextInputContextMenu.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>20.09.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Defines custom UI controls.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					package envoy.client.ui.control;
 | 
				
			||||||
@@ -11,7 +11,7 @@ import java.util.logging.*;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import javafx.animation.RotateTransition;
 | 
					import javafx.animation.RotateTransition;
 | 
				
			||||||
import javafx.application.Platform;
 | 
					import javafx.application.Platform;
 | 
				
			||||||
import javafx.collections.*;
 | 
					import javafx.collections.ObservableList;
 | 
				
			||||||
import javafx.collections.transformation.FilteredList;
 | 
					import javafx.collections.transformation.FilteredList;
 | 
				
			||||||
import javafx.fxml.*;
 | 
					import javafx.fxml.*;
 | 
				
			||||||
import javafx.scene.control.*;
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
@@ -28,11 +28,13 @@ import envoy.client.data.*;
 | 
				
			|||||||
import envoy.client.data.audio.AudioRecorder;
 | 
					import envoy.client.data.audio.AudioRecorder;
 | 
				
			||||||
import envoy.client.data.commands.*;
 | 
					import envoy.client.data.commands.*;
 | 
				
			||||||
import envoy.client.event.*;
 | 
					import envoy.client.event.*;
 | 
				
			||||||
 | 
					import envoy.client.helper.ShutdownHelper;
 | 
				
			||||||
import envoy.client.net.*;
 | 
					import envoy.client.net.*;
 | 
				
			||||||
import envoy.client.ui.*;
 | 
					import envoy.client.ui.*;
 | 
				
			||||||
import envoy.client.ui.custom.TextInputContextMenu;
 | 
					import envoy.client.ui.SceneContext.SceneInfo;
 | 
				
			||||||
 | 
					import envoy.client.ui.control.*;
 | 
				
			||||||
import envoy.client.ui.listcell.*;
 | 
					import envoy.client.ui.listcell.*;
 | 
				
			||||||
import envoy.client.util.ReflectionUtil;
 | 
					import envoy.client.util.*;
 | 
				
			||||||
import envoy.data.*;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.data.Attachment.AttachmentType;
 | 
					import envoy.data.Attachment.AttachmentType;
 | 
				
			||||||
import envoy.data.Message.MessageStatus;
 | 
					import envoy.data.Message.MessageStatus;
 | 
				
			||||||
@@ -45,9 +47,7 @@ import dev.kske.eventbus.*;
 | 
				
			|||||||
import dev.kske.eventbus.Event;
 | 
					import dev.kske.eventbus.Event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Controller for the chat scene.
 | 
				
			||||||
 * File: <strong>ChatSceneController.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>26.03.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
@@ -144,7 +144,7 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
	private final WriteProxy		writeProxy				= context.getWriteProxy();
 | 
						private final WriteProxy		writeProxy				= context.getWriteProxy();
 | 
				
			||||||
	private final SceneContext		sceneContext			= context.getSceneContext();
 | 
						private final SceneContext		sceneContext			= context.getSceneContext();
 | 
				
			||||||
	private final AudioRecorder		recorder				= new AudioRecorder();
 | 
						private final AudioRecorder		recorder				= new AudioRecorder();
 | 
				
			||||||
	private final SystemCommandsMap	messageTextAreaCommands	= new SystemCommandsMap();
 | 
						private final SystemCommandMap	messageTextAreaCommands	= new SystemCommandMap();
 | 
				
			||||||
	private final Tooltip			onlyIfOnlineTooltip		= new Tooltip("You need to be online to do this");
 | 
						private final Tooltip			onlyIfOnlineTooltip		= new Tooltip("You need to be online to do this");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static Image DEFAULT_ATTACHMENT_VIEW_IMAGE = IconUtil.loadIconThemeSensitive("attachment_present", 20);
 | 
						private static Image DEFAULT_ATTACHMENT_VIEW_IMAGE = IconUtil.loadIconThemeSensitive("attachment_present", 20);
 | 
				
			||||||
@@ -169,7 +169,8 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
		messageList.setCellFactory(MessageListCell::new);
 | 
							messageList.setCellFactory(MessageListCell::new);
 | 
				
			||||||
		chatList.setCellFactory(new ListCellFactory<>(ChatControl::new));
 | 
							chatList.setCellFactory(new ListCellFactory<>(ChatControl::new));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// JavaFX provides an internal way of populating the context menu of a textarea.
 | 
							// JavaFX provides an internal way of populating the context menu of a text
 | 
				
			||||||
 | 
							// area.
 | 
				
			||||||
		// We, however, need additional functionality.
 | 
							// We, however, need additional functionality.
 | 
				
			||||||
		messageTextArea.setContextMenu(new TextInputContextMenu(messageTextArea, e -> checkKeyCombination(null)));
 | 
							messageTextArea.setContextMenu(new TextInputContextMenu(messageTextArea, e -> checkKeyCombination(null)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -188,7 +189,7 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
		clip.setArcWidth(43);
 | 
							clip.setArcWidth(43);
 | 
				
			||||||
		clientProfilePic.setClip(clip);
 | 
							clientProfilePic.setClip(clip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		chatList.setItems(chats = new FilteredList<>(FXCollections.observableList(localDB.getChats())));
 | 
							chatList.setItems(chats = new FilteredList<>(localDB.getChats()));
 | 
				
			||||||
		contactLabel.setText(localDB.getUser().getName());
 | 
							contactLabel.setText(localDB.getUser().getName());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		initializeSystemCommandsMap();
 | 
							initializeSystemCommandsMap();
 | 
				
			||||||
@@ -203,8 +204,8 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
				Tooltip.uninstall(contactSpecificOnlineOperations, onlyIfOnlineTooltip);
 | 
									Tooltip.uninstall(contactSpecificOnlineOperations, onlyIfOnlineTooltip);
 | 
				
			||||||
				contactSearchTab.setContent(new FXMLLoader().load(getClass().getResourceAsStream("/fxml/ContactSearchTab.fxml")));
 | 
									contactSearchTab.setContent(new FXMLLoader().load(getClass().getResourceAsStream("/fxml/ContactSearchTab.fxml")));
 | 
				
			||||||
				groupCreationTab.setContent(new FXMLLoader().load(getClass().getResourceAsStream("/fxml/GroupCreationTab.fxml")));
 | 
									groupCreationTab.setContent(new FXMLLoader().load(getClass().getResourceAsStream("/fxml/GroupCreationTab.fxml")));
 | 
				
			||||||
			} catch (final IOException e2) {
 | 
								} catch (final IOException e) {
 | 
				
			||||||
				logger.log(Level.SEVERE, "An error occurred when attempting to load tabs: ", e2);
 | 
									logger.log(Level.SEVERE, "An error occurred when attempting to load tabs: ", e);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else {
 | 
								else {
 | 
				
			||||||
				Tooltip.install(contactSpecificOnlineOperations, onlyIfOnlineTooltip);
 | 
									Tooltip.install(contactSpecificOnlineOperations, onlyIfOnlineTooltip);
 | 
				
			||||||
@@ -230,12 +231,8 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Read current chat or increment unread amount
 | 
								// Read current chat or increment unread amount
 | 
				
			||||||
			if (chat.equals(currentChat)) {
 | 
								if (chat.equals(currentChat)) {
 | 
				
			||||||
				try {
 | 
					 | 
				
			||||||
				currentChat.read(writeProxy);
 | 
									currentChat.read(writeProxy);
 | 
				
			||||||
				} catch (final IOException e) {
 | 
									Platform.runLater(this::scrollToMessageListEnd);
 | 
				
			||||||
					logger.log(Level.WARNING, "Could not read current chat: ", e);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				Platform.runLater(() -> { ListViewRefresh.deepRefresh(messageList); scrollToMessageListEnd(); });
 | 
					 | 
				
			||||||
			} else if (!ownMessage && message.getStatus() != MessageStatus.READ) chat.incrementUnreadAmount();
 | 
								} else if (!ownMessage && message.getStatus() != MessageStatus.READ) chat.incrementUnreadAmount();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Move chat with most recent unread messages to the top
 | 
								// Move chat with most recent unread messages to the top
 | 
				
			||||||
@@ -250,33 +247,16 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	@Event
 | 
						@Event
 | 
				
			||||||
	private void onMessageStatusChange(MessageStatusChange evt) {
 | 
						private void onMessageStatusChange(MessageStatusChange evt) {
 | 
				
			||||||
		localDB.getMessage(evt.getID()).ifPresent(message -> {
 | 
					
 | 
				
			||||||
			message.setStatus(evt.get());
 | 
					 | 
				
			||||||
		// Update UI if in current chat and the current user was the sender of the
 | 
							// Update UI if in current chat and the current user was the sender of the
 | 
				
			||||||
		// message
 | 
							// message
 | 
				
			||||||
			if (currentChat != null && message.getSenderID() == client.getSender().getID()) Platform.runLater(messageList::refresh);
 | 
							if (currentChat != null) localDB.getMessage(evt.getID())
 | 
				
			||||||
		});
 | 
								.filter(msg -> msg.getSenderID() == client.getSender().getID())
 | 
				
			||||||
 | 
								.ifPresent(msg -> Platform.runLater(messageList::refresh));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Event
 | 
						@Event(eventType = UserStatusChange.class)
 | 
				
			||||||
	private void onGroupMessageStatusChange(GroupMessageStatusChange evt) {
 | 
						private void onUserStatusChange() { Platform.runLater(chatList::refresh); }
 | 
				
			||||||
		localDB.getMessage(evt.getID()).ifPresent(groupMessage -> {
 | 
					 | 
				
			||||||
			((GroupMessage) groupMessage).getMemberStatuses().replace(evt.getMemberID(), evt.get());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// Update UI if in current chat
 | 
					 | 
				
			||||||
			if (currentChat != null && groupMessage.getRecipientID() == currentChat.getRecipient().getID()) Platform.runLater(messageList::refresh);
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@Event
 | 
					 | 
				
			||||||
	private void onUserStatusChange(UserStatusChange evt) {
 | 
					 | 
				
			||||||
		chats.getSource()
 | 
					 | 
				
			||||||
			.stream()
 | 
					 | 
				
			||||||
			.filter(c -> c.getRecipient().getID() == evt.getID())
 | 
					 | 
				
			||||||
			.findAny()
 | 
					 | 
				
			||||||
			.map(Chat::getRecipient)
 | 
					 | 
				
			||||||
			.ifPresent(u -> { ((User) u).setStatus(evt.get()); Platform.runLater(() -> ListViewRefresh.deepRefresh(chatList)); });
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Event
 | 
						@Event
 | 
				
			||||||
	private void onContactOperation(ContactOperation operation) {
 | 
						private void onContactOperation(ContactOperation operation) {
 | 
				
			||||||
@@ -320,24 +300,42 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
		clientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
 | 
							clientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
 | 
				
			||||||
		chatList.setCellFactory(new ListCellFactory<>(ChatControl::new));
 | 
							chatList.setCellFactory(new ListCellFactory<>(ChatControl::new));
 | 
				
			||||||
		messageList.setCellFactory(MessageListCell::new);
 | 
							messageList.setCellFactory(MessageListCell::new);
 | 
				
			||||||
 | 
							// TODO: cache image
 | 
				
			||||||
		if (currentChat.getRecipient() instanceof User) recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
 | 
							if (currentChat.getRecipient() instanceof User) recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("user_icon", 43));
 | 
				
			||||||
		else recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43));
 | 
							else recipientProfilePic.setImage(IconUtil.loadIconThemeSensitive("group_icon", 43));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@Event(eventType = Logout.class, priority = 200)
 | 
				
			||||||
 | 
						private void onLogout() { eventBus.removeListener(this); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Initializes all {@code SystemCommands} used in {@code ChatScene}.
 | 
						 * Initializes all {@code SystemCommands} used in {@code ChatScene}.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @since Envoy Client v0.2-beta
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	private void initializeSystemCommandsMap() {
 | 
						private void initializeSystemCommandsMap() {
 | 
				
			||||||
		final var builder = new SystemCommandBuilder();
 | 
							final var builder = new SystemCommandBuilder(messageTextAreaCommands);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Do A Barrel roll initialization
 | 
							// Do A Barrel roll initialization
 | 
				
			||||||
		final var random = new Random();
 | 
							final var random = new Random();
 | 
				
			||||||
		builder.setAction(text -> doABarrelRoll(Integer.parseInt(text.get(0)), Double.parseDouble(text.get(1))))
 | 
							builder.setAction(text -> doABarrelRoll(Integer.parseInt(text.get(0)), Double.parseDouble(text.get(1))))
 | 
				
			||||||
			.setDefaults(Integer.toString(random.nextInt(3) + 1), Double.toString(random.nextDouble() * 3 + 1))
 | 
								.setDefaults(Integer.toString(random.nextInt(3) + 1), Double.toString(random.nextDouble() * 3 + 1))
 | 
				
			||||||
			.setDescription("See for yourself :)")
 | 
								.setDescription("See for yourself :)")
 | 
				
			||||||
			.setNumberOfArguments(2);
 | 
								.setNumberOfArguments(2)
 | 
				
			||||||
		messageTextAreaCommands.add("DABR", builder.build());
 | 
								.build("dabr");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Logout initialization
 | 
				
			||||||
 | 
							builder.setAction(text -> ShutdownHelper.logout()).setNumberOfArguments(0).setDescription("Logs you out.").build("logout");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Exit initialization
 | 
				
			||||||
 | 
							builder.setAction(text -> ShutdownHelper.exit()).setNumberOfArguments(0).setDescription("Exits the program").build("exit", false);
 | 
				
			||||||
 | 
							builder.build("q");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Open settings scene initialization
 | 
				
			||||||
 | 
							builder.setAction(text -> sceneContext.load(SceneInfo.SETTINGS_SCENE))
 | 
				
			||||||
 | 
								.setNumberOfArguments(0)
 | 
				
			||||||
 | 
								.setDescription("Opens the settings screen")
 | 
				
			||||||
 | 
								.build("settings");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
@@ -360,18 +358,14 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
			// Load the chat
 | 
								// Load the chat
 | 
				
			||||||
			currentChat = localDB.getChat(user.getID()).get();
 | 
								currentChat = localDB.getChat(user.getID()).get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			messageList.setItems(FXCollections.observableList(currentChat.getMessages()));
 | 
								messageList.setItems(currentChat.getMessages());
 | 
				
			||||||
			final var scrollIndex = messageList.getItems().size() - currentChat.getUnreadAmount();
 | 
								final var scrollIndex = messageList.getItems().size() - currentChat.getUnreadAmount();
 | 
				
			||||||
			messageList.scrollTo(scrollIndex);
 | 
								messageList.scrollTo(scrollIndex);
 | 
				
			||||||
			logger.log(Level.FINEST, "Loading chat with " + user + " at index " + scrollIndex);
 | 
								logger.log(Level.FINEST, "Loading chat with " + user + " at index " + scrollIndex);
 | 
				
			||||||
			deleteContactMenuItem.setText("Delete " + user.getName());
 | 
								deleteContactMenuItem.setText("Delete " + user.getName());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Read the current chat
 | 
								// Read the current chat
 | 
				
			||||||
			try {
 | 
					 | 
				
			||||||
			currentChat.read(writeProxy);
 | 
								currentChat.read(writeProxy);
 | 
				
			||||||
			} catch (final IOException e) {
 | 
					 | 
				
			||||||
				logger.log(Level.WARNING, "Could not read current chat.", e);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Discard the pending attachment
 | 
								// Discard the pending attachment
 | 
				
			||||||
			if (recorder.isRecording()) {
 | 
								if (recorder.isRecording()) {
 | 
				
			||||||
@@ -555,8 +549,8 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Sending an IsTyping event if none has been sent for
 | 
							// Sending an IsTyping event if none has been sent for
 | 
				
			||||||
		// IsTyping#millisecondsActive
 | 
							// IsTyping#millisecondsActive
 | 
				
			||||||
		if (currentChat.getLastWritingEvent() + IsTyping.millisecondsActive <= System.currentTimeMillis()) {
 | 
							if (client.isOnline() && currentChat.getLastWritingEvent() + IsTyping.millisecondsActive <= System.currentTimeMillis()) {
 | 
				
			||||||
			eventBus.dispatch(new SendEvent(new IsTyping(getChatID(), currentChat.getRecipient().getID())));
 | 
								client.send(new IsTyping(getChatID(), currentChat.getRecipient().getID()));
 | 
				
			||||||
			currentChat.lastWritingEventWasNow();
 | 
								currentChat.lastWritingEventWasNow();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -665,7 +659,7 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		final var text = messageTextArea.getText().strip();
 | 
							final var text = messageTextArea.getText().strip();
 | 
				
			||||||
		if (!messageTextAreaCommands.executeIfAnyPresent(text)) try {
 | 
							if (!messageTextAreaCommands.executeIfAnyPresent(text)) {
 | 
				
			||||||
			// Creating the message and its metadata
 | 
								// Creating the message and its metadata
 | 
				
			||||||
			final var builder = new MessageBuilder(localDB.getUser().getID(), currentChat.getRecipient().getID(), localDB.getIDGenerator())
 | 
								final var builder = new MessageBuilder(localDB.getUser().getID(), currentChat.getRecipient().getID(), localDB.getIDGenerator())
 | 
				
			||||||
				.setText(text);
 | 
									.setText(text);
 | 
				
			||||||
@@ -692,15 +686,10 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
				localDB.getChats().remove(currentChat);
 | 
									localDB.getChats().remove(currentChat);
 | 
				
			||||||
				localDB.getChats().add(0, currentChat);
 | 
									localDB.getChats().add(0, currentChat);
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
			ListViewRefresh.deepRefresh(messageList);
 | 
					 | 
				
			||||||
			scrollToMessageListEnd();
 | 
								scrollToMessageListEnd();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Request a new ID generator if all IDs were used
 | 
								// Request a new ID generator if all IDs were used
 | 
				
			||||||
			if (!localDB.getIDGenerator().hasNext() && client.isOnline()) client.requestIdGenerator();
 | 
								if (!localDB.getIDGenerator().hasNext() && client.isOnline()) client.requestIDGenerator();
 | 
				
			||||||
 | 
					 | 
				
			||||||
		} catch (final IOException e) {
 | 
					 | 
				
			||||||
			logger.log(Level.SEVERE, "Error while sending message: ", e);
 | 
					 | 
				
			||||||
			new Alert(AlertType.ERROR, "An error occured while sending the message!").showAndWait();
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Clear text field and disable post button
 | 
							// Clear text field and disable post button
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,12 @@ import javafx.fxml.FXML;
 | 
				
			|||||||
import javafx.scene.control.*;
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
import javafx.scene.control.Alert.AlertType;
 | 
					import javafx.scene.control.Alert.AlertType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.event.*;
 | 
					import envoy.client.data.Context;
 | 
				
			||||||
import envoy.client.ui.listcell.*;
 | 
					import envoy.client.event.BackEvent;
 | 
				
			||||||
 | 
					import envoy.client.helper.AlertHelper;
 | 
				
			||||||
 | 
					import envoy.client.net.Client;
 | 
				
			||||||
 | 
					import envoy.client.ui.control.ContactControl;
 | 
				
			||||||
 | 
					import envoy.client.ui.listcell.ListCellFactory;
 | 
				
			||||||
import envoy.data.User;
 | 
					import envoy.data.User;
 | 
				
			||||||
import envoy.event.ElementOperation;
 | 
					import envoy.event.ElementOperation;
 | 
				
			||||||
import envoy.event.contact.*;
 | 
					import envoy.event.contact.*;
 | 
				
			||||||
@@ -25,10 +29,6 @@ import dev.kske.eventbus.*;
 | 
				
			|||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * To create a group, a button is available that loads the
 | 
					 * To create a group, a button is available that loads the
 | 
				
			||||||
 * {@link GroupCreationTab}.
 | 
					 * {@link GroupCreationTab}.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ContactSearchScene.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>07.06.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
@@ -46,6 +46,7 @@ public class ContactSearchTab implements EventListener {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	private final Alert alert = new Alert(AlertType.CONFIRMATION);
 | 
						private final Alert alert = new Alert(AlertType.CONFIRMATION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final Client		client		= Context.getInstance().getClient();
 | 
				
			||||||
	private static final EventBus	eventBus	= EventBus.getInstance();
 | 
						private static final EventBus	eventBus	= EventBus.getInstance();
 | 
				
			||||||
	private static final Logger		logger		= EnvoyLog.getLogger(ChatScene.class);
 | 
						private static final Logger		logger		= EnvoyLog.getLogger(ChatScene.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,6 +54,7 @@ public class ContactSearchTab implements EventListener {
 | 
				
			|||||||
	private void initialize() {
 | 
						private void initialize() {
 | 
				
			||||||
		eventBus.registerListener(this);
 | 
							eventBus.registerListener(this);
 | 
				
			||||||
		userList.setCellFactory(new ListCellFactory<>(ContactControl::new));
 | 
							userList.setCellFactory(new ListCellFactory<>(ContactControl::new));
 | 
				
			||||||
 | 
							alert.setTitle("Add User?");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Event
 | 
						@Event
 | 
				
			||||||
@@ -77,7 +79,7 @@ public class ContactSearchTab implements EventListener {
 | 
				
			|||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private void sendRequest() {
 | 
						private void sendRequest() {
 | 
				
			||||||
		final var text = searchBar.getText().strip();
 | 
							final var text = searchBar.getText().strip();
 | 
				
			||||||
		if (!text.isBlank()) eventBus.dispatch(new SendEvent(new UserSearchRequest(text)));
 | 
							if (!text.isBlank()) client.send(new UserSearchRequest(text));
 | 
				
			||||||
		else userList.getItems().clear();
 | 
							else userList.getItems().clear();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -104,15 +106,22 @@ public class ContactSearchTab implements EventListener {
 | 
				
			|||||||
		final var user = userList.getSelectionModel().getSelectedItem();
 | 
							final var user = userList.getSelectionModel().getSelectedItem();
 | 
				
			||||||
		if (user != null) {
 | 
							if (user != null) {
 | 
				
			||||||
			currentlySelectedUser = user;
 | 
								currentlySelectedUser = user;
 | 
				
			||||||
			final var event = new ContactOperation(currentlySelectedUser, ElementOperation.ADD);
 | 
								alert.setContentText("Add user " + currentlySelectedUser.getName() + " to your contacts?");
 | 
				
			||||||
 | 
								AlertHelper.confirmAction(alert, this::addAsContact);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void addAsContact() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Sends the event to the server
 | 
							// Sends the event to the server
 | 
				
			||||||
			eventBus.dispatch(new SendEvent(event));
 | 
							final var event = new ContactOperation(currentlySelectedUser, ElementOperation.ADD);
 | 
				
			||||||
 | 
							client.send(event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Removes the chosen user and updates the UI
 | 
							// Removes the chosen user and updates the UI
 | 
				
			||||||
		userList.getItems().remove(currentlySelectedUser);
 | 
							userList.getItems().remove(currentlySelectedUser);
 | 
				
			||||||
		eventBus.dispatch(event);
 | 
							eventBus.dispatch(event);
 | 
				
			||||||
		logger.log(Level.INFO, "Added user " + currentlySelectedUser);
 | 
							logger.log(Level.INFO, "Added user " + currentlySelectedUser);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private void backButtonClicked() { eventBus.dispatch(new BackEvent()); }
 | 
						private void backButtonClicked() { eventBus.dispatch(new BackEvent()); }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,8 +10,9 @@ import javafx.scene.control.*;
 | 
				
			|||||||
import javafx.scene.layout.HBox;
 | 
					import javafx.scene.layout.HBox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.*;
 | 
					import envoy.client.data.*;
 | 
				
			||||||
import envoy.client.event.*;
 | 
					import envoy.client.event.BackEvent;
 | 
				
			||||||
import envoy.client.ui.listcell.*;
 | 
					import envoy.client.ui.control.ContactControl;
 | 
				
			||||||
 | 
					import envoy.client.ui.listcell.ListCellFactory;
 | 
				
			||||||
import envoy.data.*;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.event.GroupCreation;
 | 
					import envoy.event.GroupCreation;
 | 
				
			||||||
import envoy.event.contact.ContactOperation;
 | 
					import envoy.event.contact.ContactOperation;
 | 
				
			||||||
@@ -27,10 +28,6 @@ import dev.kske.eventbus.*;
 | 
				
			|||||||
 * When the group creation button is pressed, a {@link GroupCreation} is sent to
 | 
					 * When the group creation button is pressed, a {@link GroupCreation} is sent to
 | 
				
			||||||
 * the server. This controller enforces a valid group name and a non-empty
 | 
					 * the server. This controller enforces a valid group name and a non-empty
 | 
				
			||||||
 * member list (excluding the client user).
 | 
					 * member list (excluding the client user).
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GroupCreationScene.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>07.06.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
@@ -137,8 +134,9 @@ public class GroupCreationTab implements EventListener {
 | 
				
			|||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	private void createGroup(String name) {
 | 
						private void createGroup(String name) {
 | 
				
			||||||
		eventBus.dispatch(new SendEvent(
 | 
							Context.getInstance()
 | 
				
			||||||
				new GroupCreation(name, userList.getSelectionModel().getSelectedItems().stream().map(User::getID).collect(Collectors.toSet()))));
 | 
								.getClient()
 | 
				
			||||||
 | 
								.send(new GroupCreation(name, userList.getSelectionModel().getSelectedItems().stream().map(User::getID).collect(Collectors.toSet())));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -150,12 +148,7 @@ public class GroupCreationTab implements EventListener {
 | 
				
			|||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public boolean groupNameAlreadyPresent(String newName) {
 | 
						public boolean groupNameAlreadyPresent(String newName) {
 | 
				
			||||||
		return localDB.getChats()
 | 
							return localDB.getChats().stream().map(Chat::getRecipient).filter(Group.class::isInstance).map(Contact::getName).anyMatch(newName::equals);
 | 
				
			||||||
			.stream()
 | 
					 | 
				
			||||||
			.map(Chat::getRecipient)
 | 
					 | 
				
			||||||
			.filter(Group.class::isInstance)
 | 
					 | 
				
			||||||
			.map(Contact::getName)
 | 
					 | 
				
			||||||
			.anyMatch(newName::equals);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
@@ -211,7 +204,7 @@ public class GroupCreationTab implements EventListener {
 | 
				
			|||||||
					userList.getItems().add((User) operation.get());
 | 
										userList.getItems().add((User) operation.get());
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				case REMOVE:
 | 
									case REMOVE:
 | 
				
			||||||
					userList.getItems().removeIf(u -> u.equals(operation.get()));
 | 
										userList.getItems().removeIf(operation.get()::equals);
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import javafx.scene.image.ImageView;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.ClientConfig;
 | 
					import envoy.client.data.ClientConfig;
 | 
				
			||||||
import envoy.client.ui.*;
 | 
					import envoy.client.ui.*;
 | 
				
			||||||
 | 
					import envoy.client.util.IconUtil;
 | 
				
			||||||
import envoy.data.LoginCredentials;
 | 
					import envoy.data.LoginCredentials;
 | 
				
			||||||
import envoy.event.HandshakeRejection;
 | 
					import envoy.event.HandshakeRejection;
 | 
				
			||||||
import envoy.util.*;
 | 
					import envoy.util.*;
 | 
				
			||||||
@@ -19,9 +20,7 @@ import envoy.util.*;
 | 
				
			|||||||
import dev.kske.eventbus.*;
 | 
					import dev.kske.eventbus.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Controller for the login scene.
 | 
				
			||||||
 * File: <strong>LoginDialog.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>03.04.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
@@ -101,20 +100,21 @@ public final class LoginScene implements EventListener {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private void registerSwitchPressed() {
 | 
						private void registerSwitchPressed() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Update button text and register switch
 | 
				
			||||||
		if (!registration) {
 | 
							if (!registration) {
 | 
				
			||||||
			// case if the current mode is login
 | 
					 | 
				
			||||||
			loginButton.setText("Register");
 | 
								loginButton.setText("Register");
 | 
				
			||||||
			loginButton.setPadding(new Insets(2, 116, 2, 116));
 | 
								loginButton.setPadding(new Insets(2, 116, 2, 116));
 | 
				
			||||||
			registerTextLabel.setText("Already an account?");
 | 
								registerTextLabel.setText("Already an account?");
 | 
				
			||||||
			registerSwitch.setText("Login");
 | 
								registerSwitch.setText("Login");
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			// case if the current mode is registration
 | 
					 | 
				
			||||||
			loginButton.setText("Login");
 | 
								loginButton.setText("Login");
 | 
				
			||||||
			loginButton.setPadding(new Insets(2, 125, 2, 125));
 | 
								loginButton.setPadding(new Insets(2, 125, 2, 125));
 | 
				
			||||||
			registerTextLabel.setText("No account yet?");
 | 
								registerTextLabel.setText("No account yet?");
 | 
				
			||||||
			registerSwitch.setText("Register");
 | 
								registerSwitch.setText("Register");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		registration = !registration;
 | 
							registration = !registration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Make repeat password field and label visible / invisible
 | 
							// Make repeat password field and label visible / invisible
 | 
				
			||||||
		repeatPasswordField.setVisible(registration);
 | 
							repeatPasswordField.setVisible(registration);
 | 
				
			||||||
		offlineModeButton.setDisable(registration);
 | 
							offlineModeButton.setDisable(registration);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,14 @@
 | 
				
			|||||||
package envoy.client.ui.controller;
 | 
					package envoy.client.ui.controller;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.fxml.FXML;
 | 
					import javafx.fxml.FXML;
 | 
				
			||||||
import javafx.scene.control.Label;
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
import javafx.scene.control.ListView;
 | 
					 | 
				
			||||||
import javafx.scene.control.TitledPane;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.Context;
 | 
					import envoy.client.data.Context;
 | 
				
			||||||
import envoy.client.net.Client;
 | 
					import envoy.client.ui.listcell.ListCellFactory;
 | 
				
			||||||
import envoy.client.ui.SceneContext;
 | 
					 | 
				
			||||||
import envoy.client.ui.listcell.AbstractListCell;
 | 
					 | 
				
			||||||
import envoy.client.ui.settings.*;
 | 
					import envoy.client.ui.settings.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 * Controller for the settings scene.
 | 
				
			||||||
 * File: <strong>SettingsSceneController.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>10.04.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
@@ -27,20 +21,10 @@ public final class SettingsScene {
 | 
				
			|||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private TitledPane titledPane;
 | 
						private TitledPane titledPane;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private final Client		client			= Context.getInstance().getClient();
 | 
					 | 
				
			||||||
	private final SceneContext	sceneContext	= Context.getInstance().getSceneContext();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private void initialize() {
 | 
						private void initialize() {
 | 
				
			||||||
		settingsList.setCellFactory(listView -> new AbstractListCell<>(listView) {
 | 
							settingsList.setCellFactory(new ListCellFactory<>(pane -> new Label(pane.getTitle())));
 | 
				
			||||||
 | 
							settingsList.getItems().addAll(new GeneralSettingsPane(), new UserSettingsPane(), new DownloadSettingsPane(), new BugReportPane());
 | 
				
			||||||
			@Override
 | 
					 | 
				
			||||||
			protected Label renderItem(SettingsPane item) { return new Label(item.getTitle()); }
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
		settingsList.getItems().add(new GeneralSettingsPane());
 | 
					 | 
				
			||||||
		settingsList.getItems().add(new UserSettingsPane(sceneContext, client.getSender(), client.isOnline()));
 | 
					 | 
				
			||||||
		settingsList.getItems().add(new DownloadSettingsPane(sceneContext));
 | 
					 | 
				
			||||||
		settingsList.getItems().add(new BugReportPane(client.getSender(), client.isOnline()));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
@@ -53,5 +37,5 @@ public final class SettingsScene {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@FXML
 | 
						@FXML
 | 
				
			||||||
	private void backButtonClicked() { sceneContext.pop(); }
 | 
						private void backButtonClicked() { Context.getInstance().getSceneContext().pop(); }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,10 +2,6 @@ package envoy.client.ui.controller;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides options to select different tabs.
 | 
					 * Provides options to select different tabs.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Tabs.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>30.8.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,9 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Contains JavaFX scene controllers.
 | 
					 * Contains JavaFX scene controllers.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>package-info.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>08.06.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
package envoy.client.ui.controller;
 | 
					package envoy.client.ui.controller;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +0,0 @@
 | 
				
			|||||||
/**
 | 
					 | 
				
			||||||
 * This package stores custom components for use in JavaFX.
 | 
					 | 
				
			||||||
 * These components are also expected to be used via FXML.
 | 
					 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>package-info.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>30.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
package envoy.client.ui.custom;
 | 
					 | 
				
			||||||
@@ -1,17 +1,10 @@
 | 
				
			|||||||
package envoy.client.ui.listcell;
 | 
					package envoy.client.ui.listcell;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.scene.Cursor;
 | 
					import javafx.scene.*;
 | 
				
			||||||
import javafx.scene.Node;
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
import javafx.scene.control.ContentDisplay;
 | 
					 | 
				
			||||||
import javafx.scene.control.ListCell;
 | 
					 | 
				
			||||||
import javafx.scene.control.ListView;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides a convenience frame for list cell creation.
 | 
					 * Provides a convenience frame for list cell creation.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>AbstractListCell.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>18.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @param <T> the type of element displayed by the list cell
 | 
					 * @param <T> the type of element displayed by the list cell
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,10 +7,6 @@ import javafx.scene.control.ListView;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A generic list cell rendering an item using a provided render function.
 | 
					 * A generic list cell rendering an item using a provided render function.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GenericListCell.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>18.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @param <T> the type of element displayed by the list cell
 | 
					 * @param <T> the type of element displayed by the list cell
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,17 +3,12 @@ package envoy.client.ui.listcell;
 | 
				
			|||||||
import java.util.function.Function;
 | 
					import java.util.function.Function;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.scene.Node;
 | 
					import javafx.scene.Node;
 | 
				
			||||||
import javafx.scene.control.ListCell;
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
import javafx.scene.control.ListView;
 | 
					 | 
				
			||||||
import javafx.util.Callback;
 | 
					import javafx.util.Callback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides a creation mechanism for generic list cells given a list view and a
 | 
					 * Provides a creation mechanism for generic list cells given a list view and a
 | 
				
			||||||
 * conversion function.
 | 
					 * conversion function.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ListCellFactory.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>13.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @param <T> the type of object to display
 | 
					 * @param <T> the type of object to display
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,13 @@
 | 
				
			|||||||
package envoy.client.ui.listcell;
 | 
					package envoy.client.ui.listcell;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.geometry.Insets;
 | 
					import javafx.geometry.*;
 | 
				
			||||||
import javafx.geometry.Pos;
 | 
					 | 
				
			||||||
import javafx.scene.control.ListView;
 | 
					import javafx.scene.control.ListView;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import envoy.client.ui.control.MessageControl;
 | 
				
			||||||
import envoy.data.Message;
 | 
					import envoy.data.Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A list cell containing messages represented as message controls.
 | 
					 * A list cell containing messages represented as message controls.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>MessageListCell.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>18.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,9 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This package contains custom list cells that are used to display certain
 | 
					 * This package contains custom list cells that are used to display certain
 | 
				
			||||||
 * things.
 | 
					 * things.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>package-info.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>30.06.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
package envoy.client.ui.listcell;
 | 
					package envoy.client.ui.listcell;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,25 +4,17 @@ import javafx.event.EventHandler;
 | 
				
			|||||||
import javafx.scene.control.*;
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
import javafx.scene.input.InputEvent;
 | 
					import javafx.scene.input.InputEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.event.SendEvent;
 | 
					 | 
				
			||||||
import envoy.client.util.IssueUtil;
 | 
					import envoy.client.util.IssueUtil;
 | 
				
			||||||
import envoy.data.User;
 | 
					 | 
				
			||||||
import envoy.event.IssueProposal;
 | 
					import envoy.event.IssueProposal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.kske.eventbus.EventBus;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This class offers the option for users to submit a bug report. Only the title
 | 
					 * This class offers the option for users to submit a bug report. Only the title
 | 
				
			||||||
 * of a bug is needed to be sent.
 | 
					 * of a bug is needed to be sent.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>BugReportPane.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>Aug 4, 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public final class BugReportPane extends OnlyIfOnlineSettingsPane {
 | 
					public final class BugReportPane extends OnlineOnlySettingsPane {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private final Label		titleLabel				= new Label("Suggest a title for the bug:");
 | 
						private final Label		titleLabel				= new Label("Suggest a title for the bug:");
 | 
				
			||||||
	private final TextField	titleTextField			= new TextField();
 | 
						private final TextField	titleTextField			= new TextField();
 | 
				
			||||||
@@ -36,12 +28,10 @@ public final class BugReportPane extends OnlyIfOnlineSettingsPane {
 | 
				
			|||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Creates a new {@code BugReportPane}.
 | 
						 * Creates a new {@code BugReportPane}.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param user   the user whose details to use
 | 
					 | 
				
			||||||
	 * @param online whether this user is currently online
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.2-beta
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public BugReportPane(User user, boolean online) {
 | 
						public BugReportPane() {
 | 
				
			||||||
		super("Report a bug", online);
 | 
							super("Report a bug");
 | 
				
			||||||
		setSpacing(10);
 | 
							setSpacing(10);
 | 
				
			||||||
		setToolTipText("A bug can only be reported while being online");
 | 
							setToolTipText("A bug can only be reported while being online");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,12 +58,8 @@ public final class BugReportPane extends OnlyIfOnlineSettingsPane {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Displaying the submitReportButton
 | 
							// Displaying the submitReportButton
 | 
				
			||||||
		submitReportButton.setDisable(true);
 | 
							submitReportButton.setDisable(true);
 | 
				
			||||||
		submitReportButton.setOnAction(e -> {
 | 
							submitReportButton.setOnAction(e -> client.send(new IssueProposal(titleTextField.getText(), IssueUtil
 | 
				
			||||||
			EventBus.getInstance()
 | 
								.sanitizeIssueDescription(errorDetailArea.getText(), showUsernameInBugReport.isSelected() ? client.getSender().getName() : null), true)));
 | 
				
			||||||
				.dispatch(new SendEvent(new IssueProposal(titleTextField.getText(),
 | 
					 | 
				
			||||||
						IssueUtil.sanitizeIssueDescription(errorDetailArea.getText(), showUsernameInBugReport.isSelected() ? user.getName() : null),
 | 
					 | 
				
			||||||
						true)));
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
		getChildren().add(submitReportButton);
 | 
							getChildren().add(submitReportButton);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,14 +5,10 @@ import javafx.scene.control.*;
 | 
				
			|||||||
import javafx.scene.layout.HBox;
 | 
					import javafx.scene.layout.HBox;
 | 
				
			||||||
import javafx.stage.DirectoryChooser;
 | 
					import javafx.stage.DirectoryChooser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.ui.SceneContext;
 | 
					import envoy.client.data.Context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Displays options for downloading {@link envoy.data.Attachment}s.
 | 
					 * Displays options for downloading {@link envoy.data.Attachment}s.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>DownloadSettingsPane.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>27.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
@@ -22,15 +18,14 @@ public final class DownloadSettingsPane extends SettingsPane {
 | 
				
			|||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Constructs a new {@code DownloadSettingsPane}.
 | 
						 * Constructs a new {@code DownloadSettingsPane}.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param sceneContext the {@code SceneContext} used to block input to the
 | 
					 | 
				
			||||||
	 *                     {@link javafx.stage.Stage} used in Envoy
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.2-beta
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public DownloadSettingsPane(SceneContext sceneContext) {
 | 
						public DownloadSettingsPane() {
 | 
				
			||||||
		super("Download");
 | 
							super("Download");
 | 
				
			||||||
		setSpacing(15);
 | 
							setSpacing(15);
 | 
				
			||||||
		setPadding(new Insets(15));
 | 
							setPadding(new Insets(15));
 | 
				
			||||||
		// checkbox to disable asking
 | 
					
 | 
				
			||||||
 | 
							// Checkbox to disable asking
 | 
				
			||||||
		final var checkBox = new CheckBox(settings.getItems().get("autoSaveDownloads").getUserFriendlyName());
 | 
							final var checkBox = new CheckBox(settings.getItems().get("autoSaveDownloads").getUserFriendlyName());
 | 
				
			||||||
		checkBox.setSelected(settings.isDownloadSavedWithoutAsking());
 | 
							checkBox.setSelected(settings.isDownloadSavedWithoutAsking());
 | 
				
			||||||
		checkBox.setTooltip(new Tooltip("Determines whether a \"Select save location\" - dialogue will be shown when saving attachments."));
 | 
							checkBox.setTooltip(new Tooltip("Determines whether a \"Select save location\" - dialogue will be shown when saving attachments."));
 | 
				
			||||||
@@ -52,7 +47,7 @@ public final class DownloadSettingsPane extends SettingsPane {
 | 
				
			|||||||
			final var directoryChooser = new DirectoryChooser();
 | 
								final var directoryChooser = new DirectoryChooser();
 | 
				
			||||||
			directoryChooser.setTitle("Select the directory where attachments should be saved to");
 | 
								directoryChooser.setTitle("Select the directory where attachments should be saved to");
 | 
				
			||||||
			directoryChooser.setInitialDirectory(settings.getDownloadLocation());
 | 
								directoryChooser.setInitialDirectory(settings.getDownloadLocation());
 | 
				
			||||||
			final var selectedDirectory = directoryChooser.showDialog(sceneContext.getStage());
 | 
								final var selectedDirectory = directoryChooser.showDialog(Context.getInstance().getSceneContext().getStage());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (selectedDirectory != null) {
 | 
								if (selectedDirectory != null) {
 | 
				
			||||||
				currentPath.setText(selectedDirectory.getAbsolutePath());
 | 
									currentPath.setText(selectedDirectory.getAbsolutePath());
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,15 +4,12 @@ import javafx.scene.control.*;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.SettingsItem;
 | 
					import envoy.client.data.SettingsItem;
 | 
				
			||||||
import envoy.client.event.ThemeChangeEvent;
 | 
					import envoy.client.event.ThemeChangeEvent;
 | 
				
			||||||
 | 
					import envoy.client.helper.ShutdownHelper;
 | 
				
			||||||
import envoy.data.User.UserStatus;
 | 
					import envoy.data.User.UserStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.kske.eventbus.EventBus;
 | 
					import dev.kske.eventbus.EventBus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GeneralSettingsPane.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>18.04.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -28,23 +25,30 @@ public final class GeneralSettingsPane extends SettingsPane {
 | 
				
			|||||||
		// TODO: Support other value types
 | 
							// TODO: Support other value types
 | 
				
			||||||
		final var	settingsItems		= settings.getItems();
 | 
							final var	settingsItems		= settings.getItems();
 | 
				
			||||||
		final var	hideOnCloseCheckbox	= new SettingsCheckbox((SettingsItem<Boolean>) settingsItems.get("hideOnClose"));
 | 
							final var	hideOnCloseCheckbox	= new SettingsCheckbox((SettingsItem<Boolean>) settingsItems.get("hideOnClose"));
 | 
				
			||||||
		hideOnCloseCheckbox.setTooltip(new Tooltip("If selected, Envoy will still be present in the task bar when closed."));
 | 
							final var	hideOnCloseTooltip	= new Tooltip("If selected, Envoy will still be present in the task bar when closed.");
 | 
				
			||||||
 | 
							hideOnCloseTooltip.setWrapText(true);
 | 
				
			||||||
 | 
							hideOnCloseCheckbox.setTooltip(hideOnCloseTooltip);
 | 
				
			||||||
		getChildren().add(hideOnCloseCheckbox);
 | 
							getChildren().add(hideOnCloseCheckbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		final var	enterToSendCheckbox	= new SettingsCheckbox((SettingsItem<Boolean>) settingsItems.get("enterToSend"));
 | 
							final var	enterToSendCheckbox	= new SettingsCheckbox((SettingsItem<Boolean>) settingsItems.get("enterToSend"));
 | 
				
			||||||
		final var	enterToSendTooltip	= new Tooltip(
 | 
							final var	enterToSendTooltip	= new Tooltip(
 | 
				
			||||||
				"If selected, messages can be sent pressing \"Enter\". They can always be sent by pressing \"Ctrl\" + \"Enter\"");
 | 
									"When selected, messages can be sent pressing \"Enter\". A line break can be inserted by pressing \"Ctrl\" + \"Enter\". Else it will be the other way around.");
 | 
				
			||||||
		enterToSendTooltip.setWrapText(true);
 | 
							enterToSendTooltip.setWrapText(true);
 | 
				
			||||||
		enterToSendCheckbox.setTooltip(enterToSendTooltip);
 | 
							enterToSendCheckbox.setTooltip(enterToSendTooltip);
 | 
				
			||||||
		getChildren().add(enterToSendCheckbox);
 | 
							getChildren().add(enterToSendCheckbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final var	askForConfirmationCheckbox	= new SettingsCheckbox((SettingsItem<Boolean>) settingsItems.get("askForConfirmation"));
 | 
				
			||||||
 | 
							final var	askForConfirmationTooltip	= new Tooltip("When selected, nothing will prompt a confirmation dialog");
 | 
				
			||||||
 | 
							askForConfirmationTooltip.setWrapText(true);
 | 
				
			||||||
 | 
							askForConfirmationCheckbox.setTooltip(askForConfirmationTooltip);
 | 
				
			||||||
 | 
							getChildren().add(askForConfirmationCheckbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		final var combobox = new ComboBox<String>();
 | 
							final var combobox = new ComboBox<String>();
 | 
				
			||||||
		combobox.getItems().add("dark");
 | 
							combobox.getItems().add("dark");
 | 
				
			||||||
		combobox.getItems().add("light");
 | 
							combobox.getItems().add("light");
 | 
				
			||||||
		combobox.setTooltip(new Tooltip("Determines the current theme Envoy will be displayed in."));
 | 
							combobox.setTooltip(new Tooltip("Determines the current theme Envoy will be displayed in."));
 | 
				
			||||||
		combobox.setValue(settings.getCurrentTheme());
 | 
							combobox.setValue(settings.getCurrentTheme());
 | 
				
			||||||
		combobox.setOnAction(
 | 
							combobox.setOnAction(e -> { settings.setCurrentTheme(combobox.getValue()); EventBus.getInstance().dispatch(new ThemeChangeEvent()); });
 | 
				
			||||||
				e -> { settings.setCurrentTheme(combobox.getValue()); EventBus.getInstance().dispatch(new ThemeChangeEvent()); });
 | 
					 | 
				
			||||||
		getChildren().add(combobox);
 | 
							getChildren().add(combobox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		final var statusComboBox = new ComboBox<UserStatus>();
 | 
							final var statusComboBox = new ComboBox<UserStatus>();
 | 
				
			||||||
@@ -54,5 +58,12 @@ public final class GeneralSettingsPane extends SettingsPane {
 | 
				
			|||||||
		// TODO add action when value is changed
 | 
							// TODO add action when value is changed
 | 
				
			||||||
		statusComboBox.setOnAction(e -> {});
 | 
							statusComboBox.setOnAction(e -> {});
 | 
				
			||||||
		getChildren().add(statusComboBox);
 | 
							getChildren().add(statusComboBox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final var logoutButton = new Button("Logout");
 | 
				
			||||||
 | 
							logoutButton.setOnAction(e -> ShutdownHelper.logout());
 | 
				
			||||||
 | 
							final var logoutTooltip = new Tooltip("Brings you back to the login screen and removes \"remember me\" status from this account");
 | 
				
			||||||
 | 
							logoutTooltip.setWrapText(true);
 | 
				
			||||||
 | 
							logoutButton.setTooltip(logoutTooltip);
 | 
				
			||||||
 | 
							getChildren().add(logoutButton);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,40 +1,39 @@
 | 
				
			|||||||
package envoy.client.ui.settings;
 | 
					package envoy.client.ui.settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.geometry.Insets;
 | 
					import javafx.geometry.Insets;
 | 
				
			||||||
import javafx.scene.control.Label;
 | 
					import javafx.scene.control.*;
 | 
				
			||||||
import javafx.scene.control.Tooltip;
 | 
					import javafx.scene.layout.*;
 | 
				
			||||||
import javafx.scene.layout.Background;
 | 
					 | 
				
			||||||
import javafx.scene.layout.BackgroundFill;
 | 
					 | 
				
			||||||
import javafx.scene.layout.CornerRadii;
 | 
					 | 
				
			||||||
import javafx.scene.paint.Color;
 | 
					import javafx.scene.paint.Color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import envoy.client.data.Context;
 | 
				
			||||||
 | 
					import envoy.client.net.Client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Inheriting from this class signifies that options should only be available if
 | 
					 * Inheriting from this class signifies that options should only be available if
 | 
				
			||||||
 * the {@link envoy.data.User} is currently online. If the user is currently
 | 
					 * the {@link envoy.data.User} is currently online. If the user is currently
 | 
				
			||||||
 * offline, all {@link javafx.scene.Node} variables will be disabled and a
 | 
					 * offline, all {@link javafx.scene.Node} variables will be disabled and a
 | 
				
			||||||
 * {@link Tooltip} will be displayed for the whole node.
 | 
					 * {@link Tooltip} will be displayed for the whole node.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>OnlyIfOnlineSettingsPane.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>04.08.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract class OnlyIfOnlineSettingsPane extends SettingsPane {
 | 
					public abstract class OnlineOnlySettingsPane extends SettingsPane {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected final Client client = Context.getInstance().getClient();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private final Tooltip beOnlineReminder = new Tooltip("You need to be online to modify your account.");
 | 
						private final Tooltip beOnlineReminder = new Tooltip("You need to be online to modify your account.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @param title
 | 
						 * @param title the title of this pane
 | 
				
			||||||
	 * @since Envoy Client v0.2-beta
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	protected OnlyIfOnlineSettingsPane(String title, boolean online) {
 | 
						protected OnlineOnlySettingsPane(String title) {
 | 
				
			||||||
		super(title);
 | 
							super(title);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		setDisable(!online);
 | 
							setDisable(!client.isOnline());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!online) {
 | 
							if (!client.isOnline()) {
 | 
				
			||||||
			final var infoLabel = new Label("You shall not pass!\n(... Unless you would happen to be online)");
 | 
								final var infoLabel = new Label("You shall not pass!\n(... Unless you would happen to be online)");
 | 
				
			||||||
			infoLabel.setId("info-label-warning");
 | 
								infoLabel.setId("info-label-warning");
 | 
				
			||||||
			infoLabel.setWrapText(true);
 | 
								infoLabel.setWrapText(true);
 | 
				
			||||||
@@ -45,5 +44,11 @@ public abstract class OnlyIfOnlineSettingsPane extends SettingsPane {
 | 
				
			|||||||
		} else Tooltip.uninstall(this, beOnlineReminder);
 | 
							} else Tooltip.uninstall(this, beOnlineReminder);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sets the text of the tooltip displayed for this pane.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param text the text to display
 | 
				
			||||||
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	protected void setToolTipText(String text) { beOnlineReminder.setText(text); }
 | 
						protected void setToolTipText(String text) { beOnlineReminder.setText(text); }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -6,10 +6,6 @@ import javafx.scene.control.CheckBox;
 | 
				
			|||||||
import envoy.client.data.SettingsItem;
 | 
					import envoy.client.data.SettingsItem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>SettingsToggleButton.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>18.04.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,6 @@ import javafx.scene.layout.VBox;
 | 
				
			|||||||
import envoy.client.data.Settings;
 | 
					import envoy.client.data.Settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>SettingsPane.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>18.04.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,24 +14,19 @@ import javafx.scene.input.InputEvent;
 | 
				
			|||||||
import javafx.scene.layout.HBox;
 | 
					import javafx.scene.layout.HBox;
 | 
				
			||||||
import javafx.stage.FileChooser;
 | 
					import javafx.stage.FileChooser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.event.SendEvent;
 | 
					import envoy.client.data.Context;
 | 
				
			||||||
import envoy.client.ui.*;
 | 
					import envoy.client.ui.control.ProfilePicImageView;
 | 
				
			||||||
import envoy.client.ui.custom.ProfilePicImageView;
 | 
					import envoy.client.util.IconUtil;
 | 
				
			||||||
import envoy.data.User;
 | 
					 | 
				
			||||||
import envoy.event.*;
 | 
					import envoy.event.*;
 | 
				
			||||||
import envoy.util.*;
 | 
					import envoy.util.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.kske.eventbus.EventBus;
 | 
					import dev.kske.eventbus.EventBus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>UserSettingsPane.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>31.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public final class UserSettingsPane extends OnlyIfOnlineSettingsPane {
 | 
					public final class UserSettingsPane extends OnlineOnlySettingsPane {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private boolean	profilePicChanged, usernameChanged, validPassword;
 | 
						private boolean	profilePicChanged, usernameChanged, validPassword;
 | 
				
			||||||
	private byte[]	currentImageBytes;
 | 
						private byte[]	currentImageBytes;
 | 
				
			||||||
@@ -50,13 +45,10 @@ public final class UserSettingsPane extends OnlyIfOnlineSettingsPane {
 | 
				
			|||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Creates a new {@code UserSettingsPane}.
 | 
						 * Creates a new {@code UserSettingsPane}.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param sceneContext the {@code SceneContext} to block input to Envoy
 | 
					 | 
				
			||||||
	 * @param user         the user who wants to customize his profile
 | 
					 | 
				
			||||||
	 * @param online       whether this user is currently online
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.2-beta
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public UserSettingsPane(SceneContext sceneContext, User user, boolean online) {
 | 
						public UserSettingsPane() {
 | 
				
			||||||
		super("User", online);
 | 
							super("User");
 | 
				
			||||||
		setSpacing(10);
 | 
							setSpacing(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Display of profile pic change mechanism
 | 
							// Display of profile pic change mechanism
 | 
				
			||||||
@@ -67,18 +59,19 @@ public final class UserSettingsPane extends OnlyIfOnlineSettingsPane {
 | 
				
			|||||||
		profilePic.setFitWidth(60);
 | 
							profilePic.setFitWidth(60);
 | 
				
			||||||
		profilePic.setFitHeight(60);
 | 
							profilePic.setFitHeight(60);
 | 
				
			||||||
		profilePic.setOnMouseClicked(e -> {
 | 
							profilePic.setOnMouseClicked(e -> {
 | 
				
			||||||
			if (!online) return;
 | 
								if (!client.isOnline()) return;
 | 
				
			||||||
			final var pictureChooser = new FileChooser();
 | 
								final var pictureChooser = new FileChooser();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			pictureChooser.setTitle("Select a new profile pic");
 | 
								pictureChooser.setTitle("Select a new profile pic");
 | 
				
			||||||
			pictureChooser.setInitialDirectory(new File(System.getProperty("user.home")));
 | 
								pictureChooser.setInitialDirectory(new File(System.getProperty("user.home")));
 | 
				
			||||||
			pictureChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Pictures", "*.png", "*.jpg", "*.bmp", "*.gif"));
 | 
								pictureChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Pictures", "*.png", "*.jpg", "*.bmp", "*.gif"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			final var file = pictureChooser.showOpenDialog(sceneContext.getStage());
 | 
								final var file = pictureChooser.showOpenDialog(Context.getInstance().getSceneContext().getStage());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (file != null) {
 | 
								if (file != null) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Check max file size
 | 
									// Check max file size
 | 
				
			||||||
 | 
									// TODO: Move to config
 | 
				
			||||||
				if (file.length() > 5E6) {
 | 
									if (file.length() > 5E6) {
 | 
				
			||||||
					new Alert(AlertType.WARNING, "The selected file exceeds the size limit of 5MB!").showAndWait();
 | 
										new Alert(AlertType.WARNING, "The selected file exceeds the size limit of 5MB!").showAndWait();
 | 
				
			||||||
					return;
 | 
										return;
 | 
				
			||||||
@@ -96,7 +89,7 @@ public final class UserSettingsPane extends OnlyIfOnlineSettingsPane {
 | 
				
			|||||||
		hbox.getChildren().add(profilePic);
 | 
							hbox.getChildren().add(profilePic);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Displaying the username change mechanism
 | 
							// Displaying the username change mechanism
 | 
				
			||||||
		final var username = user.getName();
 | 
							final var username = client.getSender().getName();
 | 
				
			||||||
		newUsername = username;
 | 
							newUsername = username;
 | 
				
			||||||
		usernameTextField.setText(username);
 | 
							usernameTextField.setText(username);
 | 
				
			||||||
		final EventHandler<? super InputEvent> textChanged = e -> {
 | 
							final EventHandler<? super InputEvent> textChanged = e -> {
 | 
				
			||||||
@@ -133,7 +126,7 @@ public final class UserSettingsPane extends OnlyIfOnlineSettingsPane {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Displaying the save button
 | 
							// Displaying the save button
 | 
				
			||||||
		saveButton.setOnAction(e -> save(user.getID(), currentPasswordField.getText()));
 | 
							saveButton.setOnAction(e -> save(client.getSender().getID(), currentPasswordField.getText()));
 | 
				
			||||||
		saveButton.setAlignment(Pos.BOTTOM_RIGHT);
 | 
							saveButton.setAlignment(Pos.BOTTOM_RIGHT);
 | 
				
			||||||
		getChildren().add(saveButton);
 | 
							getChildren().add(saveButton);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -150,7 +143,7 @@ public final class UserSettingsPane extends OnlyIfOnlineSettingsPane {
 | 
				
			|||||||
		if (profilePicChanged) {
 | 
							if (profilePicChanged) {
 | 
				
			||||||
			final var profilePicChangeEvent = new ProfilePicChange(currentImageBytes, userID);
 | 
								final var profilePicChangeEvent = new ProfilePicChange(currentImageBytes, userID);
 | 
				
			||||||
			eventBus.dispatch(profilePicChangeEvent);
 | 
								eventBus.dispatch(profilePicChangeEvent);
 | 
				
			||||||
			eventBus.dispatch(new SendEvent(profilePicChangeEvent));
 | 
								client.send(profilePicChangeEvent);
 | 
				
			||||||
			logger.log(Level.INFO, "The user just changed his profile pic.");
 | 
								logger.log(Level.INFO, "The user just changed his profile pic.");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -158,8 +151,8 @@ public final class UserSettingsPane extends OnlyIfOnlineSettingsPane {
 | 
				
			|||||||
		final var validContactName = Bounds.isValidContactName(newUsername);
 | 
							final var validContactName = Bounds.isValidContactName(newUsername);
 | 
				
			||||||
		if (usernameChanged && validContactName) {
 | 
							if (usernameChanged && validContactName) {
 | 
				
			||||||
			final var nameChangeEvent = new NameChange(userID, newUsername);
 | 
								final var nameChangeEvent = new NameChange(userID, newUsername);
 | 
				
			||||||
			eventBus.dispatch(new SendEvent(nameChangeEvent));
 | 
					 | 
				
			||||||
			eventBus.dispatch(nameChangeEvent);
 | 
								eventBus.dispatch(nameChangeEvent);
 | 
				
			||||||
 | 
								client.send(nameChangeEvent);
 | 
				
			||||||
			logger.log(Level.INFO, "The user just changed his name to " + newUsername + ".");
 | 
								logger.log(Level.INFO, "The user just changed his name to " + newUsername + ".");
 | 
				
			||||||
		} else if (!validContactName) {
 | 
							} else if (!validContactName) {
 | 
				
			||||||
			final var alert = new Alert(AlertType.ERROR);
 | 
								final var alert = new Alert(AlertType.ERROR);
 | 
				
			||||||
@@ -172,14 +165,13 @@ public final class UserSettingsPane extends OnlyIfOnlineSettingsPane {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// The password was changed
 | 
							// The password was changed
 | 
				
			||||||
		if (validPassword) {
 | 
							if (validPassword) {
 | 
				
			||||||
			eventBus.dispatch(new SendEvent(new PasswordChangeRequest(newPassword, oldPassword, userID)));
 | 
								client.send(new PasswordChangeRequest(newPassword, oldPassword, userID));
 | 
				
			||||||
			logger.log(Level.INFO, "The user just tried to change his password!");
 | 
								logger.log(Level.INFO, "The user just tried to change his password!");
 | 
				
			||||||
		} else if (!(validPassword || newPassword.isBlank())) {
 | 
							} else if (!(validPassword || newPassword.isBlank())) {
 | 
				
			||||||
			final var alert = new Alert(AlertType.ERROR);
 | 
								final var alert = new Alert(AlertType.ERROR);
 | 
				
			||||||
			alert.setTitle("Unequal Password");
 | 
								alert.setTitle("Unequal Password");
 | 
				
			||||||
			alert.setContentText("Repeated password is unequal to the chosen new password");
 | 
								alert.setContentText("Repeated password is unequal to the chosen new password");
 | 
				
			||||||
			alert.showAndWait();
 | 
								alert.showAndWait();
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,6 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This package contains classes used for representing the settings
 | 
					 * This package contains classes used for representing the settings
 | 
				
			||||||
 * visually.
 | 
					 * visually.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>package-info.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>19 Apr 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,8 @@
 | 
				
			|||||||
package envoy.client.ui;
 | 
					package envoy.client.util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.awt.image.BufferedImage;
 | 
					import java.awt.image.BufferedImage;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.EnumMap;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.EnumSet;
 | 
					 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.Level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.imageio.ImageIO;
 | 
					import javax.imageio.ImageIO;
 | 
				
			||||||
@@ -16,10 +15,6 @@ import envoy.util.EnvoyLog;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides static utility methods for loading icons from the resource
 | 
					 * Provides static utility methods for loading icons from the resource
 | 
				
			||||||
 * folder.
 | 
					 * folder.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>IconUtil.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>16.03.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.1-beta
 | 
					 * @since Envoy Client v0.1-beta
 | 
				
			||||||
@@ -35,15 +30,7 @@ public final class IconUtil {
 | 
				
			|||||||
	 * @return the loaded image
 | 
						 * @return the loaded image
 | 
				
			||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static Image load(String path) {
 | 
						public static Image load(String path) { return new Image(IconUtil.class.getResource(path).toExternalForm()); }
 | 
				
			||||||
		Image image = null;
 | 
					 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			image = new Image(IconUtil.class.getResource(path).toExternalForm());
 | 
					 | 
				
			||||||
		} catch (final NullPointerException e) {
 | 
					 | 
				
			||||||
			EnvoyLog.getLogger(IconUtil.class).log(Level.WARNING, String.format("Could not load image at path %s: ", path), e);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return image;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Loads an image from the resource folder and scales it to the given size.
 | 
						 * Loads an image from the resource folder and scales it to the given size.
 | 
				
			||||||
@@ -54,13 +41,7 @@ public final class IconUtil {
 | 
				
			|||||||
	 * @since Envoy Client v0.1-beta
 | 
						 * @since Envoy Client v0.1-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static Image load(String path, int size) {
 | 
						public static Image load(String path, int size) {
 | 
				
			||||||
		Image image = null;
 | 
							return new Image(IconUtil.class.getResource(path).toExternalForm(), size, size, true, true);
 | 
				
			||||||
		try {
 | 
					 | 
				
			||||||
			image = new Image(IconUtil.class.getResource(path).toExternalForm(), size, size, true, true);
 | 
					 | 
				
			||||||
		} catch (final NullPointerException e) {
 | 
					 | 
				
			||||||
			EnvoyLog.getLogger(IconUtil.class).log(Level.WARNING, String.format("Could not load image at path %s: ", path), e);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return image;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -2,39 +2,34 @@ package envoy.client.util;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides methods to handle outgoing issues.
 | 
					 * Provides methods to handle outgoing issues.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>IssueUtil.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>20.08.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public final class IssueUtil {
 | 
					public final class IssueUtil {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * @since Envoy Client v0.2-beta
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	private IssueUtil() {}
 | 
						private IssueUtil() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Performs actions to ensure the description of an issue will be displayed as
 | 
						 * Normalizes line breaks and appends the user name to the issue description if
 | 
				
			||||||
	 * intended by the user.
 | 
						 * requested.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param rawDescription the description to sanitize
 | 
						 * @param description the description to sanitize
 | 
				
			||||||
	 * @param username    the user who submitted the issue. Should be
 | 
						 * @param username    the user who submitted the issue. Should be
 | 
				
			||||||
	 *                    {@code null} if he does not want to be named.
 | 
						 *                    {@code null} if he does not want to be named.
 | 
				
			||||||
	 * @return the sanitized description
 | 
						 * @return the sanitized description
 | 
				
			||||||
	 * @since Envoy Client v0.2-beta
 | 
						 * @since Envoy Client v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static String sanitizeIssueDescription(String rawDescription, String username) {
 | 
						public static String sanitizeIssueDescription(String description, String username) {
 | 
				
			||||||
		// Appending the submitter name, if this option was enabled
 | 
					
 | 
				
			||||||
		rawDescription += username != null
 | 
							// Trim and replace line breaks by <br> tags
 | 
				
			||||||
				? (rawDescription.endsWith("\n") || rawDescription.endsWith("<br>") ? "" : "<br>") + String.format("Submitted by user %s.", username)
 | 
							description = description.trim().replaceAll(System.getProperty("line.separator"), "<br>");
 | 
				
			||||||
				: "";
 | 
					
 | 
				
			||||||
		// Markdown does not support "normal" line breaks. It uses "<br>"
 | 
							// Append user name if requested
 | 
				
			||||||
		rawDescription = rawDescription.replaceAll(System.getProperty("line.separator", "\r?\n"), "<br>");
 | 
							if (username != null)
 | 
				
			||||||
		return rawDescription;
 | 
								description += String.format("<br>Submitted by user %s.", username);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return description;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,11 @@
 | 
				
			|||||||
package envoy.client.util;
 | 
					package envoy.client.util;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.stream.*;
 | 
				
			||||||
import java.util.stream.Collectors;
 | 
					 | 
				
			||||||
import java.util.stream.Stream;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javafx.scene.Node;
 | 
					import javafx.scene.Node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ReflectionUtil.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>02.08.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -20,8 +14,9 @@ public final class ReflectionUtil {
 | 
				
			|||||||
	private ReflectionUtil() {}
 | 
						private ReflectionUtil() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Gets all declared variables of the given instance that have the specified
 | 
						 * Gets all declared variable values of the given instance that have the
 | 
				
			||||||
	 * class<br>
 | 
						 * specified class.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
	 * (i.e. can get all {@code JComponents} (Swing) or {@code Nodes} (JavaFX) in a
 | 
						 * (i.e. can get all {@code JComponents} (Swing) or {@code Nodes} (JavaFX) in a
 | 
				
			||||||
	 * GUI class).
 | 
						 * GUI class).
 | 
				
			||||||
	 * <p>
 | 
						 * <p>
 | 
				
			||||||
@@ -41,13 +36,11 @@ public final class ReflectionUtil {
 | 
				
			|||||||
		return Arrays.stream(instance.getClass().getDeclaredFields()).filter(field -> typeToReturn.isAssignableFrom(field.getType())).map(field -> {
 | 
							return Arrays.stream(instance.getClass().getDeclaredFields()).filter(field -> typeToReturn.isAssignableFrom(field.getType())).map(field -> {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				field.setAccessible(true);
 | 
									field.setAccessible(true);
 | 
				
			||||||
				final var value = field.get(instance);
 | 
									return typeToReturn.cast(field.get(instance));
 | 
				
			||||||
				return value;
 | 
					 | 
				
			||||||
			} catch (IllegalArgumentException | IllegalAccessException e) {
 | 
								} catch (IllegalArgumentException | IllegalAccessException e) {
 | 
				
			||||||
				throw new RuntimeException(e);
 | 
									throw new RuntimeException(e);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}).map(typeToReturn::cast);// field ->
 | 
							});
 | 
				
			||||||
		// typeToReturn.isAssignableFrom(field.getClass())).map(typeToReturn::cast);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,5 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This package contains utility classes for use in envoy-client.
 | 
					 * This package contains utility classes for use in envoy-client.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>package-info.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>02.08.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ module envoy.client {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	opens envoy.client.ui to javafx.graphics, javafx.fxml, dev.kske.eventbus;
 | 
						opens envoy.client.ui to javafx.graphics, javafx.fxml, dev.kske.eventbus;
 | 
				
			||||||
	opens envoy.client.ui.controller to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus;
 | 
						opens envoy.client.ui.controller to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus;
 | 
				
			||||||
	opens envoy.client.ui.custom to javafx.graphics, javafx.fxml;
 | 
						opens envoy.client.ui.control to javafx.graphics, javafx.fxml;
 | 
				
			||||||
	opens envoy.client.ui.settings to envoy.client.util;
 | 
						opens envoy.client.ui.settings to envoy.client.util;
 | 
				
			||||||
	opens envoy.client.net to dev.kske.eventbus;
 | 
						opens envoy.client.net to dev.kske.eventbus;
 | 
				
			||||||
	opens envoy.client.data to dev.kske.eventbus;
 | 
						opens envoy.client.data to dev.kske.eventbus;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,6 @@ import java.io.Serializable;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This interface should be used for any type supposed to be a {@link Message}
 | 
					 * This interface should be used for any type supposed to be a {@link Message}
 | 
				
			||||||
 * attachment (i.e. images or sound).
 | 
					 * attachment (i.e. images or sound).
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Attachment.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>30 Dec 2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
package envoy.data;
 | 
					package envoy.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.File;
 | 
					import java.io.*;
 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.function.Function;
 | 
					import java.util.function.Function;
 | 
				
			||||||
import java.util.logging.Level;
 | 
					import java.util.logging.Level;
 | 
				
			||||||
@@ -19,10 +18,6 @@ import envoy.util.EnvoyLog;
 | 
				
			|||||||
 * default value or over command line argument. Developers that fail to provide
 | 
					 * default value or over command line argument. Developers that fail to provide
 | 
				
			||||||
 * default values will be greeted with an error message the next time they try
 | 
					 * default values will be greeted with an error message the next time they try
 | 
				
			||||||
 * to start Envoy...
 | 
					 * to start Envoy...
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Config.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>12 Oct 2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Common v0.1-beta
 | 
					 * @since Envoy Common v0.1-beta
 | 
				
			||||||
@@ -104,6 +99,7 @@ public class Config {
 | 
				
			|||||||
	public void loadAll(Class<?> declaringClass, String propertiesFilePath, String[] args) {
 | 
						public void loadAll(Class<?> declaringClass, String propertiesFilePath, String[] args) {
 | 
				
			||||||
		if (modificationDisabled)
 | 
							if (modificationDisabled)
 | 
				
			||||||
			throw new IllegalStateException("Cannot change config after isInitialized has been called");
 | 
								throw new IllegalStateException("Cannot change config after isInitialized has been called");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Load the defaults from the given .properties file first
 | 
							// Load the defaults from the given .properties file first
 | 
				
			||||||
		final var properties = new Properties();
 | 
							final var properties = new Properties();
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
@@ -120,6 +116,7 @@ public class Config {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		// Check if all configuration values have been initialized
 | 
							// Check if all configuration values have been initialized
 | 
				
			||||||
		isInitialized();
 | 
							isInitialized();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Disable further editing of the config
 | 
							// Disable further editing of the config
 | 
				
			||||||
		modificationDisabled = true;
 | 
							modificationDisabled = true;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -130,10 +127,9 @@ public class Config {
 | 
				
			|||||||
	 * @since Envoy Common v0.1-beta
 | 
						 * @since Envoy Common v0.1-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	private void isInitialized() {
 | 
						private void isInitialized() {
 | 
				
			||||||
		if (items.values().stream().map(ConfigItem::get).anyMatch(Objects::isNull))
 | 
							String uninitialized = items.values().stream().filter(c -> c.get() == null).map(ConfigItem::getCommandLong).collect(Collectors.joining(", "));
 | 
				
			||||||
			throw new IllegalStateException("config item(s) has/ have not been initialized:"
 | 
							if(!uninitialized.isEmpty())
 | 
				
			||||||
					+ items.values().stream().filter(configItem -> configItem.get() == null)
 | 
								throw new IllegalStateException("Config items uninitialized: " + uninitialized);
 | 
				
			||||||
							.map(ConfigItem::getCommandLong).collect(Collectors.toSet()));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,10 +7,6 @@ import java.util.function.Function;
 | 
				
			|||||||
 * line arguments and its default value.
 | 
					 * line arguments and its default value.
 | 
				
			||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * All {@code ConfigItem}s are automatically mandatory.
 | 
					 * All {@code ConfigItem}s are automatically mandatory.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-clientChess</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ConfigItem.javaEvent.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>21.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @param <T> the type of the config item's value
 | 
					 * @param <T> the type of the config item's value
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,11 @@
 | 
				
			|||||||
package envoy.data;
 | 
					package envoy.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.Serializable;
 | 
					import java.io.Serializable;
 | 
				
			||||||
import java.util.Objects;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.Set;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This class is the superclass for both {@link User} and {@link Group}.<br>
 | 
					 * This class is the superclass for both {@link User} and {@link Group}.<br>
 | 
				
			||||||
 * It provides an id and a name for each user and group.<br>
 | 
					 * It provides an id and a name for each user and group.<br>
 | 
				
			||||||
 * <br>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Contact.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>24 Mar 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy v0.1-beta
 | 
					 * @since Envoy v0.1-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,9 @@
 | 
				
			|||||||
package envoy.data;
 | 
					package envoy.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.ObjectInputStream;
 | 
					import java.io.*;
 | 
				
			||||||
import java.io.ObjectOutputStream;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.HashSet;
 | 
					 | 
				
			||||||
import java.util.Set;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Group.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>24 Mar 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.1-beta
 | 
					 * @since Envoy Common v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,9 @@
 | 
				
			|||||||
package envoy.data;
 | 
					package envoy.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.time.Instant;
 | 
					import java.time.Instant;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.Map;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GroupMessage.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>26.03.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 * @since Envoy Common v0.1-beta
 | 
					 * @since Envoy Common v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,17 +2,15 @@ package envoy.data;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.io.Serializable;
 | 
					import java.io.Serializable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.kske.eventbus.IEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Generates increasing IDs between two numbers.<br>
 | 
					 * Generates increasing IDs between two numbers.
 | 
				
			||||||
 * <br>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>IDGenerator.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>31.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Common v0.2-alpha
 | 
					 * @since Envoy Common v0.2-alpha
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public final class IDGenerator implements Serializable {
 | 
					public final class IDGenerator implements IEvent, Serializable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private final long	end;
 | 
						private final long	end;
 | 
				
			||||||
	private long		current;
 | 
						private long		current;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,10 +9,6 @@ import java.time.Instant;
 | 
				
			|||||||
 * <p>
 | 
					 * <p>
 | 
				
			||||||
 * If the authentication is performed with a token, the token is stored instead
 | 
					 * If the authentication is performed with a token, the token is stored instead
 | 
				
			||||||
 * of the password.
 | 
					 * of the password.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>LoginCredentials.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>29.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Common v0.2-alpha
 | 
					 * @since Envoy Common v0.2-alpha
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,10 +9,6 @@ import dev.kske.eventbus.IEvent;
 | 
				
			|||||||
 * Represents a unique message with a unique, numeric ID. Further metadata
 | 
					 * Represents a unique message with a unique, numeric ID. Further metadata
 | 
				
			||||||
 * includes the sender and recipient {@link User}s, as well as the creation
 | 
					 * includes the sender and recipient {@link User}s, as well as the creation
 | 
				
			||||||
 * date and the current {@link MessageStatus}.<br>
 | 
					 * date and the current {@link MessageStatus}.<br>
 | 
				
			||||||
 * <br>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Message.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>28.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
@@ -28,23 +24,22 @@ public class Message implements Serializable, IEvent {
 | 
				
			|||||||
	public enum MessageStatus {
 | 
						public enum MessageStatus {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * is selected, if a message was sent but not received by the server yet.
 | 
							 * The message has not yet been sent to the server
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		WAITING,
 | 
							WAITING,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * is selected, if a sent message was received by the server.
 | 
							 * The message has been sent to the server.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		SENT,
 | 
							SENT,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * is selected, if a message was delivered from the server to the recipient, but
 | 
							 * The message has been received by its recipient.
 | 
				
			||||||
		 * has not been read yet.
 | 
					 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		RECEIVED,
 | 
							RECEIVED,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * is selected, if a recipient opened the corresponding chat of said message.
 | 
							 * The message has been read by its recipient.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		READ
 | 
							READ
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,10 +7,6 @@ import envoy.data.Message.MessageStatus;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Provides a method of constructing the {@link Message} class.<br>
 | 
					 * Provides a method of constructing the {@link Message} class.<br>
 | 
				
			||||||
 * <br>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>MessageBuilder.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>31.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Common v0.2-alpha
 | 
					 * @since Envoy Common v0.2-alpha
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,11 @@
 | 
				
			|||||||
package envoy.data;
 | 
					package envoy.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.ObjectInputStream;
 | 
					import java.io.*;
 | 
				
			||||||
import java.io.ObjectOutputStream;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.HashSet;
 | 
					 | 
				
			||||||
import java.util.Set;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Represents a unique user with a unique, numeric ID, a name and a current
 | 
					 * Represents a unique user with a unique, numeric ID, a name and a current
 | 
				
			||||||
 * {@link UserStatus}.<br>
 | 
					 * {@link UserStatus}.<br>
 | 
				
			||||||
 * <br>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>User.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>28.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Common v0.2-alpha
 | 
					 * @since Envoy Common v0.2-alpha
 | 
				
			||||||
@@ -32,7 +26,7 @@ public final class User extends Contact {
 | 
				
			|||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @since Envoy Common v0.2-alpha
 | 
						 * @since Envoy Common v0.2-alpha
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public static enum UserStatus {
 | 
						public enum UserStatus {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * select this, if a user is online and can be interacted with
 | 
							 * select this, if a user is online and can be interacted with
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This package contains all data objects that are used both by Envoy Client and
 | 
					 * This package contains all data objects that are used both by Envoy Client and
 | 
				
			||||||
 * by Envoy Server Standalone.
 | 
					 * by Envoy Server.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,10 @@
 | 
				
			|||||||
package envoy.event;
 | 
					package envoy.event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This enum declares all modification possibilities for a given container.<br>
 | 
					 * This enum declares all modification possibilities for a given container.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 * These can be: {@link ElementOperation#ADD} or
 | 
					 * These can be: {@link ElementOperation#ADD} or
 | 
				
			||||||
 * {@link ElementOperation#REMOVE}.<br>
 | 
					 * {@link ElementOperation#REMOVE}.
 | 
				
			||||||
 * <br>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>ElementOperation.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>25 Mar 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.1-beta
 | 
					 * @since Envoy Common v0.1-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,6 @@ import dev.kske.eventbus.IEvent;
 | 
				
			|||||||
 * This class serves as a convenience base class for all events. It implements
 | 
					 * This class serves as a convenience base class for all events. It implements
 | 
				
			||||||
 * the {@link IEvent} interface and provides a generic value. For events without
 | 
					 * the {@link IEvent} interface and provides a generic value. For events without
 | 
				
			||||||
 * a value there also is {@link envoy.event.Event.Valueless}.
 | 
					 * a value there also is {@link envoy.event.Event.Valueless}.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>Event.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>04.12.2019</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @param <T> the type of the Event
 | 
					 * @param <T> the type of the Event
 | 
				
			||||||
@@ -34,11 +30,7 @@ public abstract class Event<T> implements IEvent, Serializable {
 | 
				
			|||||||
	public String toString() { return String.format("%s[value=%s]", this.getClass().getSimpleName(), value); }
 | 
						public String toString() { return String.format("%s[value=%s]", this.getClass().getSimpleName(), value); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Serves as a super class for events that do not carry a value.<br>
 | 
						 * Serves as a super class for events that do not carry a value.
 | 
				
			||||||
	 * <br>
 | 
					 | 
				
			||||||
	 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
	 * File: <strong>Event.java</strong><br>
 | 
					 | 
				
			||||||
	 * Created: <strong>11 Feb 2020</strong><br>
 | 
					 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @author Kai S. K. Engelbart
 | 
						 * @author Kai S. K. Engelbart
 | 
				
			||||||
	 * @since Envoy Common v0.2-alpha
 | 
						 * @since Envoy Common v0.2-alpha
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,11 @@
 | 
				
			|||||||
package envoy.event;
 | 
					package envoy.event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.HashSet;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.Set;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.data.User;
 | 
					import envoy.data.User;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This event creates a group with the given name.<br>
 | 
					 * This event creates a group with the given name.
 | 
				
			||||||
 * <br>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GroupCreation.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>25 Mar 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.1-beta
 | 
					 * @since Envoy Common v0.1-beta
 | 
				
			||||||
@@ -30,7 +25,7 @@ public final class GroupCreation extends Event<String> {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public GroupCreation(String value, Set<Long> initialMemberIDs) {
 | 
						public GroupCreation(String value, Set<Long> initialMemberIDs) {
 | 
				
			||||||
		super(value);
 | 
							super(value);
 | 
				
			||||||
		this.initialMemberIDs = (initialMemberIDs != null) ? initialMemberIDs : new HashSet<>();
 | 
							this.initialMemberIDs = initialMemberIDs != null ? initialMemberIDs : new HashSet<>();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,6 @@ package envoy.event;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Used to communicate with a client that his request to create a group might
 | 
					 * Used to communicate with a client that his request to create a group might
 | 
				
			||||||
 * have been rejected as it might be disabled on his current server.
 | 
					 * have been rejected as it might be disabled on his current server.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GroupCreationResult.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>22.08.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.2-beta
 | 
					 * @since Envoy Common v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,10 +6,6 @@ import envoy.data.GroupMessage;
 | 
				
			|||||||
import envoy.data.Message.MessageStatus;
 | 
					import envoy.data.Message.MessageStatus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GroupMessageStatusChange.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>18.04.2020</strong><br>
 | 
					 | 
				
			||||||
 * 
 | 
					 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
 * @since Envoy Common v0.1-beta
 | 
					 * @since Envoy Common v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,15 @@
 | 
				
			|||||||
package envoy.event;
 | 
					package envoy.event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.data.Contact;
 | 
					import static envoy.event.ElementOperation.*;
 | 
				
			||||||
import envoy.data.Group;
 | 
					
 | 
				
			||||||
import envoy.data.User;
 | 
					import envoy.data.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This event is used to communicate changes in the group size between client
 | 
					 * This event is used to communicate changes in the group size between client
 | 
				
			||||||
 * and server.<br>
 | 
					 * and server.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 * Possible actions are adding or removing certain {@link User}s to or from a
 | 
					 * Possible actions are adding or removing certain {@link User}s to or from a
 | 
				
			||||||
 * certain {@link Group}.
 | 
					 * certain {@link Group}.
 | 
				
			||||||
 * <br>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>GroupResize.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>25 Mar 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.1-beta
 | 
					 * @since Envoy Common v0.1-beta
 | 
				
			||||||
@@ -36,13 +33,13 @@ public final class GroupResize extends Event<User> {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public GroupResize(User user, Group group, ElementOperation operation) {
 | 
						public GroupResize(User user, Group group, ElementOperation operation) {
 | 
				
			||||||
		super(user);
 | 
							super(user);
 | 
				
			||||||
		if (group.getContacts().contains(user)) {
 | 
					 | 
				
			||||||
			if (operation.equals(ElementOperation.ADD)) throw new IllegalArgumentException(
 | 
					 | 
				
			||||||
					"Cannot add " + user + " to group " + group.getID() + " because he is already a member of this group");
 | 
					 | 
				
			||||||
		} else if (operation.equals(ElementOperation.REMOVE))
 | 
					 | 
				
			||||||
			throw new IllegalArgumentException("Cannot remove " + user + " from group " + group.getID() + " because he is no part of this group");
 | 
					 | 
				
			||||||
		groupID			= group.getID();
 | 
					 | 
				
			||||||
		this.operation	= operation;
 | 
							this.operation	= operation;
 | 
				
			||||||
 | 
							if (group.getContacts().contains(user)) {
 | 
				
			||||||
 | 
								if (operation.equals(ADD))
 | 
				
			||||||
 | 
									throw new IllegalArgumentException(String.format("Cannot add %s to %s!", user, group));
 | 
				
			||||||
 | 
							} else if (operation.equals(REMOVE))
 | 
				
			||||||
 | 
								throw new IllegalArgumentException(String.format("Cannot remove %s from %s!", user, group));
 | 
				
			||||||
 | 
							groupID	= group.getID();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -58,8 +55,22 @@ public final class GroupResize extends Event<User> {
 | 
				
			|||||||
	public ElementOperation getOperation() { return operation; }
 | 
						public ElementOperation getOperation() { return operation; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * {@inheritDoc}
 | 
						 * Applies the operation to a group.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @param group the group to resize
 | 
				
			||||||
 | 
						 * @since Envoy Common v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						public void apply(Group group) {
 | 
				
			||||||
 | 
							switch (operation) {
 | 
				
			||||||
 | 
								case ADD:
 | 
				
			||||||
 | 
									group.getContacts().add(value);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case REMOVE:
 | 
				
			||||||
 | 
									group.getContacts().remove(value);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
						@Override
 | 
				
			||||||
	public String toString() { return String.format("GroupResize[userid=%d,groupid=%d,operation=%s]", get(), groupID, operation); }
 | 
						public String toString() { return String.format("GroupResize[userid=%d,groupid=%d,operation=%s]", get(), groupID, operation); }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,6 @@ package envoy.event;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Signifies to the client that the handshake failed for the attached
 | 
					 * Signifies to the client that the handshake failed for the attached
 | 
				
			||||||
 * reason.
 | 
					 * reason.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>HandshakeRejection.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>28 Jan 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Common v0.3-alpha
 | 
					 * @since Envoy Common v0.3-alpha
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,7 @@ package envoy.event;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Signifies to the server that the client needs a new
 | 
					 * Signifies to the server that the client needs a new
 | 
				
			||||||
 * {@link envoy.data.IDGenerator} instance.<br>
 | 
					 * {@link envoy.data.IDGenerator} instance.
 | 
				
			||||||
 * <br>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>IDGeneratorRequest.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>28 Jan 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Common v0.3-alpha
 | 
					 * @since Envoy Common v0.3-alpha
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,6 @@ package envoy.event;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This event should be sent when a user is currently typing something in a
 | 
					 * This event should be sent when a user is currently typing something in a
 | 
				
			||||||
 * chat.
 | 
					 * chat.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-client</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>IsTyping.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>24.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Client v0.2-beta
 | 
					 * @since Envoy Client v0.2-beta
 | 
				
			||||||
@@ -18,7 +14,8 @@ public final class IsTyping extends Event<Long> {
 | 
				
			|||||||
	private static final long serialVersionUID = 1L;
 | 
						private static final long serialVersionUID = 1L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * The number of milliseconds that this event will be active.<br>
 | 
						 * The number of milliseconds that this event will be active.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
	 * Currently set to 3.5 seconds.
 | 
						 * Currently set to 3.5 seconds.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @since Envoy Common v0.2-beta
 | 
						 * @since Envoy Common v0.2-beta
 | 
				
			||||||
@@ -28,8 +25,8 @@ public final class IsTyping extends Event<Long> {
 | 
				
			|||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Creates a new {@code IsTyping} event with originator and recipient.
 | 
						 * Creates a new {@code IsTyping} event with originator and recipient.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @param sourceID      the id of the originator
 | 
						 * @param sourceID      the ID of the originator
 | 
				
			||||||
	 * @param destinationID the id of the contact the user wrote to
 | 
						 * @param destinationID the ID of the contact the user wrote to
 | 
				
			||||||
	 * @since Envoy Common v0.2-beta
 | 
						 * @since Envoy Common v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public IsTyping(Long sourceID, long destinationID) {
 | 
						public IsTyping(Long sourceID, long destinationID) {
 | 
				
			||||||
@@ -38,7 +35,7 @@ public final class IsTyping extends Event<Long> {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @return the id of the contact in whose chat the user typed something
 | 
						 * @return the ID of the contact in whose chat the user typed something
 | 
				
			||||||
	 * @since Envoy Common v0.2-beta
 | 
						 * @since Envoy Common v0.2-beta
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	public long getDestinationID() { return destinationID; }
 | 
						public long getDestinationID() { return destinationID; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,7 @@ package envoy.event;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This class allows envoy users to send an issue proposal to the server who, if
 | 
					 * This class allows envoy users to send an issue proposal to the server who, if
 | 
				
			||||||
 * not disabled by its admin, will forward it directly to gitea.
 | 
					 * not disabled by its administrator, will forward it directly to Gitea.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>IssueProposal.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>05.08.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.2-beta
 | 
					 * @since Envoy Common v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,6 @@ import java.time.Instant;
 | 
				
			|||||||
import envoy.data.Message;
 | 
					import envoy.data.Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>MessageStatusChange.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>6 Jan 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Common v0.2-alpha
 | 
					 * @since Envoy Common v0.2-alpha
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,14 +3,11 @@ package envoy.event;
 | 
				
			|||||||
import envoy.data.Contact;
 | 
					import envoy.data.Contact;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This event informs<br>
 | 
					 * This event informs
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 * a) the server of the name change of a user or a group.
 | 
					 * a) the server of the name change of a user or a group.
 | 
				
			||||||
 * b) another user of this users name change.
 | 
					 * b) another user of this users name change.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>NameChange.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>25 Mar 2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.1-beta
 | 
					 * @since Envoy Common v0.1-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,10 +2,6 @@ package envoy.event;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * This event can be used to transmit a new authentication token to a client.
 | 
					 * This event can be used to transmit a new authentication token to a client.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>NewAuthToken.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>19.09.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @since Envoy Common v0.2-beta
 | 
					 * @since Envoy Common v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,6 @@ package envoy.event;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This event is used so that the server can tell the client that attachments
 | 
					 * This event is used so that the server can tell the client that attachments
 | 
				
			||||||
 * will be filtered out.
 | 
					 * will be filtered out.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>NoAttachments.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>22.08.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.2-beta
 | 
					 * @since Envoy Common v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,6 @@ package envoy.event;
 | 
				
			|||||||
import envoy.data.Contact;
 | 
					import envoy.data.Contact;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>PasswordChangeRequest.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>31.07.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.2-beta
 | 
					 * @since Envoy Common v0.2-beta
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,6 @@ package envoy.event;
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * This class acts as a notice to the user whether his
 | 
					 * This class acts as a notice to the user whether his
 | 
				
			||||||
 * {@link envoy.event.PasswordChangeRequest} was successful.
 | 
					 * {@link envoy.event.PasswordChangeRequest} was successful.
 | 
				
			||||||
 * <p>
 | 
					 | 
				
			||||||
 * Project: <strong>envoy-common</strong><br>
 | 
					 | 
				
			||||||
 * File: <strong>PasswordChangeResult.java</strong><br>
 | 
					 | 
				
			||||||
 * Created: <strong>01.08.2020</strong><br>
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Leon Hofmeister
 | 
					 * @author Leon Hofmeister
 | 
				
			||||||
 * @since Envoy Common v0.2-beta
 | 
					 * @since Envoy Common v0.2-beta
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user