Sanitized Issue Proposals #58
@@ -56,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(); }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,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;
 | 
				
			||||||
@@ -58,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); }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ import java.util.logging.*;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import javafx.collections.*;
 | 
					import javafx.collections.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import envoy.client.event.EnvoyCloseEvent;
 | 
					import envoy.client.event.*;
 | 
				
			||||||
import envoy.data.*;
 | 
					import envoy.data.*;
 | 
				
			||||||
import envoy.data.Message.MessageStatus;
 | 
					import envoy.data.Message.MessageStatus;
 | 
				
			||||||
import envoy.event.*;
 | 
					import envoy.event.*;
 | 
				
			||||||
@@ -39,6 +39,10 @@ public final class LocalDB implements EventListener {
 | 
				
			|||||||
	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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -168,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(); }
 | 
				
			||||||
@@ -244,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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,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"));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
@@ -178,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
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,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}
 | 
				
			||||||
@@ -120,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.
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
@@ -136,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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,13 +14,13 @@ import envoy.util.EnvoyLog;
 | 
				
			|||||||
 * @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.
 | 
				
			||||||
@@ -29,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) {
 | 
				
			||||||
@@ -44,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>
 | 
				
			||||||
@@ -128,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>
 | 
				
			||||||
							
								
								
									
										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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										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;
 | 
				
			||||||
@@ -100,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.");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -183,8 +182,14 @@ public final class Client implements EventListener, Closeable {
 | 
				
			|||||||
		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);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -212,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; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,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);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.*;
 | 
				
			||||||
@@ -92,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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -103,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
 | 
				
			||||||
@@ -163,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,7 +11,7 @@ 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;
 | 
				
			||||||
@@ -22,10 +22,8 @@ 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.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @author Kai S. K. Engelbart
 | 
					 * @author Kai S. K. Engelbart
 | 
				
			||||||
 * @author Maximilian Käfer
 | 
					 * @author Maximilian Käfer
 | 
				
			||||||
@@ -55,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);
 | 
				
			||||||
@@ -67,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) {
 | 
				
			||||||
@@ -114,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();
 | 
				
			||||||
@@ -208,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,6 +6,7 @@ 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.client.util.IconUtil;
 | 
				
			||||||
import envoy.data.Message;
 | 
					import envoy.data.Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,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);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,8 +28,10 @@ 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.SceneContext.SceneInfo;
 | 
				
			||||||
import envoy.client.ui.control.*;
 | 
					import envoy.client.ui.control.*;
 | 
				
			||||||
import envoy.client.ui.listcell.*;
 | 
					import envoy.client.ui.listcell.*;
 | 
				
			||||||
import envoy.client.util.*;
 | 
					import envoy.client.util.*;
 | 
				
			||||||
@@ -142,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);
 | 
				
			||||||
@@ -303,20 +305,37 @@ public final class ChatScene implements EventListener, Restorable {
 | 
				
			|||||||
		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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import javafx.scene.control.Alert.AlertType;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import envoy.client.data.Context;
 | 
					import envoy.client.data.Context;
 | 
				
			||||||
import envoy.client.event.BackEvent;
 | 
					import envoy.client.event.BackEvent;
 | 
				
			||||||
 | 
					import envoy.client.helper.AlertHelper;
 | 
				
			||||||
import envoy.client.net.Client;
 | 
					import envoy.client.net.Client;
 | 
				
			||||||
import envoy.client.ui.control.ContactControl;
 | 
					import envoy.client.ui.control.ContactControl;
 | 
				
			||||||
import envoy.client.ui.listcell.ListCellFactory;
 | 
					import envoy.client.ui.listcell.ListCellFactory;
 | 
				
			||||||
@@ -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
 | 
				
			||||||
@@ -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
 | 
				
			||||||
 | 
							final var event = new ContactOperation(currentlySelectedUser, ElementOperation.ADD);
 | 
				
			||||||
		client.send(event);
 | 
							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()); }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ 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;
 | 
				
			||||||
@@ -24,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>();
 | 
				
			||||||
@@ -50,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);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -205,8 +205,8 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// Deliver just a status change instead of the whole message
 | 
									// Deliver just a status change instead of the whole message
 | 
				
			||||||
				if (gmsg.getStatus() == SENT && user.getLastSeen().isBefore(gmsg.getCreationDate())
 | 
									if (gmsg.getStatus() == RECEIVED && user.getLastSeen().isBefore(gmsg.getReceivedDate())
 | 
				
			||||||
						|| gmsg.getStatus() == RECEIVED && user.getLastSeen().isBefore(gmsg.getReceivedDate()))
 | 
											|| gmsg.getStatus() == READ && user.getLastSeen().isBefore(gmsg.getReadDate()))
 | 
				
			||||||
					writeProxy.write(socketID, new MessageStatusChange(gmsgCommon));
 | 
										writeProxy.write(socketID, new MessageStatusChange(gmsgCommon));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user