From 2d9283551a02b4387669df782c01df4443f09200 Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 23 Sep 2020 17:03:32 +0200 Subject: [PATCH 1/5] Improved SystemCommand mechanism, added Alert- and ShutdownHelper, and ... added askForConfirmation option --- .../main/java/envoy/client/data/LocalDB.java | 7 ++ .../main/java/envoy/client/data/Settings.java | 21 +++++ .../data/commands/SystemCommandBuilder.java | 94 ++++++++++++++++++- ...CommandsMap.java => SystemCommandMap.java} | 12 +-- .../java/envoy/client/helper/AlertHelper.java | 36 +++++++ .../envoy/client/helper/ShutdownHelper.java | 45 +++++++++ .../envoy/client/helper/package-info.java | 9 ++ .../java/envoy/client/ui/SceneContext.java | 15 +-- .../main/java/envoy/client/ui/Startup.java | 13 +-- .../java/envoy/client/ui/StatusTrayIcon.java | 3 +- .../envoy/client/ui/controller/ChatScene.java | 9 +- .../ui/controller/ContactSearchTab.java | 28 ++++-- .../ui/settings/GeneralSettingsPane.java | 17 +++- 13 files changed, 260 insertions(+), 49 deletions(-) rename client/src/main/java/envoy/client/data/commands/{SystemCommandsMap.java => SystemCommandMap.java} (97%) create mode 100644 client/src/main/java/envoy/client/helper/AlertHelper.java create mode 100644 client/src/main/java/envoy/client/helper/ShutdownHelper.java create mode 100644 client/src/main/java/envoy/client/helper/package-info.java diff --git a/client/src/main/java/envoy/client/data/LocalDB.java b/client/src/main/java/envoy/client/data/LocalDB.java index 61e9988..374b750 100644 --- a/client/src/main/java/envoy/client/data/LocalDB.java +++ b/client/src/main/java/envoy/client/data/LocalDB.java @@ -212,6 +212,13 @@ public final class LocalDB implements EventListener { @Event private void onNewAuthToken(NewAuthToken evt) { authToken = evt.get(); } + /** + * Deletes the file that stores the "remember me" feature. + * + * @since Envoy Client v0.2-beta + */ + public void deleteLoginFile() { lastLoginFile.delete(); } + /** * @return a {@code Map} of all users stored locally with their * user names as keys diff --git a/client/src/main/java/envoy/client/data/Settings.java b/client/src/main/java/envoy/client/data/Settings.java index b75f165..4d0b09e 100644 --- a/client/src/main/java/envoy/client/data/Settings.java +++ b/client/src/main/java/envoy/client/data/Settings.java @@ -92,6 +92,8 @@ public final class Settings implements EventListener { new SettingsItem<>(new File(System.getProperty("user.home") + "/Downloads/"), "Download location", "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("askForConfirmation", + new SettingsItem<>(true, "Ask for confirmation", "Will ask for confirmation before doing certain things")); } /** @@ -182,6 +184,25 @@ public final class Settings implements EventListener { */ public void setHideOnClose(boolean hideOnClose) { ((SettingsItem) 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) items.get("askForConfirmation")).set(askForConfirmation); + } + /** * @return the items */ diff --git a/client/src/main/java/envoy/client/data/commands/SystemCommandBuilder.java b/client/src/main/java/envoy/client/data/commands/SystemCommandBuilder.java index 4d996f5..9623444 100644 --- a/client/src/main/java/envoy/client/data/commands/SystemCommandBuilder.java +++ b/client/src/main/java/envoy/client/data/commands/SystemCommandBuilder.java @@ -1,7 +1,6 @@ package envoy.client.data.commands; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.function.Consumer; /** @@ -22,6 +21,22 @@ public final class SystemCommandBuilder { private String description; 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 * @return this {@code SystemCommandBuilder} @@ -125,6 +140,7 @@ public final class SystemCommandBuilder { /** * Builds a {@code SystemCommand} based upon the previously entered data.
+ * Automatically adds the built object to the given map. * At the end, this {@code SystemCommandBuilder} can be reset but must * not be. * @@ -141,4 +157,78 @@ public final class SystemCommandBuilder { if (reset) reset(); 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.
+ * Automatically adds the built object to the given map. + * {@code SystemCommand#numberOfArguments} will be set to 0, regardless of the + * previous value.
+ * 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.
+ * 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.
+ * 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.
+ * Automatically adds the built object to the given map. + * At the end, this {@code SystemCommandBuilder} can 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.
+ * 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; + } } diff --git a/client/src/main/java/envoy/client/data/commands/SystemCommandsMap.java b/client/src/main/java/envoy/client/data/commands/SystemCommandMap.java similarity index 97% rename from client/src/main/java/envoy/client/data/commands/SystemCommandsMap.java rename to client/src/main/java/envoy/client/data/commands/SystemCommandMap.java index 959e0dd..35ff216 100644 --- a/client/src/main/java/envoy/client/data/commands/SystemCommandsMap.java +++ b/client/src/main/java/envoy/client/data/commands/SystemCommandMap.java @@ -12,19 +12,19 @@ import envoy.util.EnvoyLog; * This class stores all {@link SystemCommand}s used. *

* Project: envoy-client
- * File: SystemCommandsMap.java
+ * File: SystemCommandMap.java
* Created: 17.07.2020
* * @author Leon Hofmeister * @since Envoy Client v0.2-beta */ -public final class SystemCommandsMap { +public final class SystemCommandMap { private final Map systemCommands = new HashMap<>(); 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. @@ -33,7 +33,7 @@ public final class SystemCommandsMap { * given action * @param systemCommand the command to add - can be built using * {@link SystemCommandBuilder} - * @see SystemCommandsMap#isValidKey(String) + * @see SystemCommandMap#isValidKey(String) * @since Envoy Client v0.2-beta */ public void add(String command, SystemCommand systemCommand) { @@ -48,7 +48,7 @@ public final class SystemCommandsMap { * map). *

* Usage example:
- * {@code SystemCommandsMap systemCommands = new SystemCommandsMap();}
+ * {@code SystemCommandMap systemCommands = new SystemCommandMap();}
* {@code Button button = new Button();} * {@code systemCommands.add("example", text -> button.setText(text.get(0), 1);}
* {@code ....}
@@ -132,7 +132,7 @@ public final class SystemCommandsMap { * map). *

* Usage example:
- * {@code SystemCommandsMap systemCommands = new SystemCommandsMap();}
+ * {@code SystemCommandMap systemCommands = new SystemCommandMap();}
* {@code Button button = new Button();}
* {@code systemCommands.add("example", (words)-> button.setText(words.get(0), 1);}
* {@code ....}
diff --git a/client/src/main/java/envoy/client/helper/AlertHelper.java b/client/src/main/java/envoy/client/helper/AlertHelper.java new file mode 100644 index 0000000..cf6c82f --- /dev/null +++ b/client/src/main/java/envoy/client/helper/AlertHelper.java @@ -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 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. Should not be shown + * already + * @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(); + } +} diff --git a/client/src/main/java/envoy/client/helper/ShutdownHelper.java b/client/src/main/java/envoy/client/helper/ShutdownHelper.java new file mode 100644 index 0000000..6933c06 --- /dev/null +++ b/client/src/main/java/envoy/client/helper/ShutdownHelper.java @@ -0,0 +1,45 @@ +package envoy.client.helper; + +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; + +import envoy.client.data.*; +import envoy.client.event.EnvoyCloseEvent; + +import dev.kske.eventbus.EventBus; + +/** + * Contains methods that have a direct impact on the user. + * + * @author Leon Hofmeister + * @since Envoy Client v0.2-beta + */ +public 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() { exit(Settings.getInstance().isHideOnClose(), true); } + + /** + * Exits the currently open Envoy application or minimizes it. + * Does not necessarily shutdown VM. + * + * @param minimize whether Envoy should be minimized instead of closed + * @param shutdownVM whether the JVM should shutdown + * @since Envoy Client v0.2-beta + */ + public static void exit(boolean minimize, boolean shutdownVM) { + if (minimize) Context.getInstance().getStage().setIconified(true); + else { + EventBus.getInstance().dispatch(new EnvoyCloseEvent()); + if (shutdownVM) System.exit(0); + } + } +} diff --git a/client/src/main/java/envoy/client/helper/package-info.java b/client/src/main/java/envoy/client/helper/package-info.java new file mode 100644 index 0000000..5ce95cc --- /dev/null +++ b/client/src/main/java/envoy/client/helper/package-info.java @@ -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; diff --git a/client/src/main/java/envoy/client/ui/SceneContext.java b/client/src/main/java/envoy/client/ui/SceneContext.java index f26aaef..9b72f8e 100644 --- a/client/src/main/java/envoy/client/ui/SceneContext.java +++ b/client/src/main/java/envoy/client/ui/SceneContext.java @@ -11,7 +11,8 @@ import javafx.scene.input.*; import javafx.stage.Stage; import envoy.client.data.Settings; -import envoy.client.event.*; +import envoy.client.event.ThemeChangeEvent; +import envoy.client.helper.ShutdownHelper; import envoy.util.EnvoyLog; import dev.kske.eventbus.*; @@ -108,17 +109,7 @@ public final class SceneContext implements EventListener { stage.setScene(scene); // Adding the option to exit Linux-like with "Control" + "Q" - scene.getAccelerators() - .put(new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN), - () -> { - // Presumably no Settings are loaded in the login scene, hence Envoy is closed - // directly - if (sceneInfo != SceneInfo.LOGIN_SCENE && settings.isHideOnClose()) stage.setIconified(true); - else { - EventBus.getInstance().dispatch(new EnvoyCloseEvent()); - System.exit(0); - } - }); + scene.getAccelerators().put(new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN), ShutdownHelper::exit); // 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 diff --git a/client/src/main/java/envoy/client/ui/Startup.java b/client/src/main/java/envoy/client/ui/Startup.java index 2e6b5d2..8b239d3 100644 --- a/client/src/main/java/envoy/client/ui/Startup.java +++ b/client/src/main/java/envoy/client/ui/Startup.java @@ -11,7 +11,7 @@ import javafx.scene.control.Alert.AlertType; import javafx.stage.Stage; import envoy.client.data.*; -import envoy.client.event.EnvoyCloseEvent; +import envoy.client.helper.ShutdownHelper; import envoy.client.net.Client; import envoy.client.ui.SceneContext.SceneInfo; import envoy.client.ui.controller.LoginScene; @@ -21,10 +21,8 @@ import envoy.event.*; import envoy.exception.EnvoyException; import envoy.util.EnvoyLog; -import dev.kske.eventbus.EventBus; - /** - * Handles application startup and shutdown. + * Handles application startup. *

* Project: envoy-client
* File: Startup.java
@@ -212,12 +210,7 @@ public final class Startup extends Application { if (StatusTrayIcon.isSupported()) { // Configure hide on close - stage.setOnCloseRequest(e -> { - if (Settings.getInstance().isHideOnClose()) { - stage.setIconified(true); - e.consume(); - } else EventBus.getInstance().dispatch(new EnvoyCloseEvent()); - }); + stage.setOnCloseRequest(e -> { ShutdownHelper.exit(); if (Settings.getInstance().isHideOnClose()) e.consume(); }); // Initialize status tray icon final var trayIcon = new StatusTrayIcon(stage); diff --git a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java index 8824bd8..53859dc 100644 --- a/client/src/main/java/envoy/client/ui/StatusTrayIcon.java +++ b/client/src/main/java/envoy/client/ui/StatusTrayIcon.java @@ -6,6 +6,7 @@ import java.awt.TrayIcon.MessageType; import javafx.application.Platform; import javafx.stage.Stage; +import envoy.client.helper.ShutdownHelper; import envoy.data.Message; import dev.kske.eventbus.*; @@ -56,7 +57,7 @@ public final class StatusTrayIcon implements EventListener { final PopupMenu popup = new PopupMenu(); final MenuItem exitMenuItem = new MenuItem("Exit"); - exitMenuItem.addActionListener(evt -> { Platform.exit(); System.exit(0); }); + exitMenuItem.addActionListener(evt -> ShutdownHelper.exit()); popup.add(exitMenuItem); trayIcon.setPopupMenu(popup); diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index fbec656..d9b7412 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -144,7 +144,7 @@ public final class ChatScene implements EventListener, Restorable { private final WriteProxy writeProxy = context.getWriteProxy(); private final SceneContext sceneContext = context.getSceneContext(); 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 static Image DEFAULT_ATTACHMENT_VIEW_IMAGE = IconUtil.loadIconThemeSensitive("attachment_present", 20); @@ -329,14 +329,15 @@ public final class ChatScene implements EventListener, Restorable { * @since Envoy Client v0.2-beta */ private void initializeSystemCommandsMap() { - final var builder = new SystemCommandBuilder(); + final var builder = new SystemCommandBuilder(messageTextAreaCommands); + // Do A Barrel roll initialization final var random = new Random(); 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)) .setDescription("See for yourself :)") - .setNumberOfArguments(2); - messageTextAreaCommands.add("DABR", builder.build()); + .setNumberOfArguments(2) + .build("dabr"); } @Override diff --git a/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java b/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java index 7dcefd8..ed800a7 100644 --- a/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java +++ b/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java @@ -8,6 +8,7 @@ import javafx.scene.control.*; import javafx.scene.control.Alert.AlertType; import envoy.client.event.*; +import envoy.client.helper.AlertHelper; import envoy.client.ui.listcell.*; import envoy.data.User; import envoy.event.ElementOperation; @@ -42,9 +43,10 @@ public class ContactSearchTab implements EventListener { @FXML private ListView userList; - private Alert alert = new Alert(AlertType.CONFIRMATION); private User currentlySelectedUser; + private final Alert alert = new Alert(AlertType.CONFIRMATION); + private static final EventBus eventBus = EventBus.getInstance(); private static final Logger logger = EnvoyLog.getLogger(ChatScene.class); @@ -52,6 +54,7 @@ public class ContactSearchTab implements EventListener { private void initialize() { eventBus.registerListener(this); userList.setCellFactory(new ListCellFactory<>(ContactControl::new)); + alert.setTitle("Add User?"); } @Event @@ -102,17 +105,24 @@ public class ContactSearchTab implements EventListener { private void userListClicked() { final var user = userList.getSelectionModel().getSelectedItem(); if (user != null) { - currentlySelectedUser = user; - final var event = new ContactOperation(currentlySelectedUser, ElementOperation.ADD); - // Sends the event to the server - eventBus.dispatch(new SendEvent(event)); - // Removes the chosen user and updates the UI - userList.getItems().remove(currentlySelectedUser); - eventBus.dispatch(event); - logger.log(Level.INFO, "Added user " + currentlySelectedUser); + currentlySelectedUser = user; + alert.setContentText("Add user " + currentlySelectedUser.getName() + " to your contacts?"); + AlertHelper.confirmAction(alert, this::addAsContact); } } + private void addAsContact() { + + // Sends the event to the server + final var event = new ContactOperation(currentlySelectedUser, ElementOperation.ADD); + eventBus.dispatch(new SendEvent(event)); + + // Removes the chosen user and updates the UI + userList.getItems().remove(currentlySelectedUser); + eventBus.dispatch(event); + logger.log(Level.INFO, "Added user " + currentlySelectedUser); + } + @FXML private void backButtonClicked() { eventBus.dispatch(new BackEvent()); } } diff --git a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java index cb87294..4e0a428 100644 --- a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java +++ b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java @@ -3,7 +3,7 @@ package envoy.client.ui.settings; import javafx.scene.control.*; import envoy.client.data.SettingsItem; -import envoy.client.event.ThemeChangeEvent; +import envoy.client.event.*; import envoy.data.User.UserStatus; import dev.kske.eventbus.EventBus; @@ -28,23 +28,30 @@ public final class GeneralSettingsPane extends SettingsPane { // TODO: Support other value types final var settingsItems = settings.getItems(); final var hideOnCloseCheckbox = new SettingsCheckbox((SettingsItem) 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); final var enterToSendCheckbox = new SettingsCheckbox((SettingsItem) settingsItems.get("enterToSend")); 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); enterToSendCheckbox.setTooltip(enterToSendTooltip); getChildren().add(enterToSendCheckbox); + final var askForConfirmationCheckbox = new SettingsCheckbox((SettingsItem) 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(); combobox.getItems().add("dark"); combobox.getItems().add("light"); combobox.setTooltip(new Tooltip("Determines the current theme Envoy will be displayed in.")); combobox.setValue(settings.getCurrentTheme()); - combobox.setOnAction( - e -> { settings.setCurrentTheme(combobox.getValue()); EventBus.getInstance().dispatch(new ThemeChangeEvent()); }); + combobox.setOnAction(e -> { settings.setCurrentTheme(combobox.getValue()); EventBus.getInstance().dispatch(new ThemeChangeEvent()); }); getChildren().add(combobox); final var statusComboBox = new ComboBox(); From 05d4917bb2b5f3a8aa834c05a9b74bdd618c88bc Mon Sep 17 00:00:00 2001 From: delvh Date: Wed, 23 Sep 2020 23:11:32 +0200 Subject: [PATCH 2/5] Added key shortcuts and system commands for logout, exit and settings Additionally added **buggy** logout mechanism: LocalDB is not reset properly and IndexOutOfBoundsExceptions occur in the UI --- .../main/java/envoy/client/data/LocalDB.java | 14 +++++-- .../main/java/envoy/client/event/Logout.java | 14 +++++++ .../envoy/client/helper/ShutdownHelper.java | 42 ++++++++++++------- .../main/java/envoy/client/net/Client.java | 5 ++- .../java/envoy/client/ui/SceneContext.java | 10 ++++- .../main/java/envoy/client/ui/Startup.java | 4 +- .../envoy/client/ui/controller/ChatScene.java | 15 +++++++ .../ui/settings/GeneralSettingsPane.java | 10 ++++- 8 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 client/src/main/java/envoy/client/event/Logout.java diff --git a/client/src/main/java/envoy/client/data/LocalDB.java b/client/src/main/java/envoy/client/data/LocalDB.java index 374b750..524d086 100644 --- a/client/src/main/java/envoy/client/data/LocalDB.java +++ b/client/src/main/java/envoy/client/data/LocalDB.java @@ -7,7 +7,7 @@ import java.time.Instant; import java.util.*; import java.util.logging.Level; -import envoy.client.event.EnvoyCloseEvent; +import envoy.client.event.*; import envoy.data.*; import envoy.event.*; import envoy.exception.EnvoyException; @@ -213,11 +213,19 @@ public final class LocalDB implements EventListener { private void onNewAuthToken(NewAuthToken evt) { authToken = evt.get(); } /** - * Deletes the file that stores the "remember me" feature. + * Deletes all associations to the current user. * * @since Envoy Client v0.2-beta */ - public void deleteLoginFile() { lastLoginFile.delete(); } + @Event(eventType = Logout.class, priority = 100) + public void onLogout() { + lastLoginFile.delete(); + userFile = null; + user = null; + authToken = null; + chats.clear(); + cacheMap = new CacheMap(); + } /** * @return a {@code Map} of all users stored locally with their diff --git a/client/src/main/java/envoy/client/event/Logout.java b/client/src/main/java/envoy/client/event/Logout.java new file mode 100644 index 0000000..e845fb1 --- /dev/null +++ b/client/src/main/java/envoy/client/event/Logout.java @@ -0,0 +1,14 @@ +package envoy.client.event; + +import envoy.event.Event.Valueless; + +/** + * Indicates that a logout has been requested. + * + * @author leon + * @since Envoy Client v0.2-beta + */ +public class Logout extends Valueless { + + private static final long serialVersionUID = 1L; +} diff --git a/client/src/main/java/envoy/client/helper/ShutdownHelper.java b/client/src/main/java/envoy/client/helper/ShutdownHelper.java index 6933c06..812c518 100644 --- a/client/src/main/java/envoy/client/helper/ShutdownHelper.java +++ b/client/src/main/java/envoy/client/helper/ShutdownHelper.java @@ -1,11 +1,11 @@ package envoy.client.helper; -import javafx.application.Platform; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import envoy.client.data.*; -import envoy.client.event.EnvoyCloseEvent; +import envoy.client.event.*; +import envoy.client.ui.SceneContext.SceneInfo; import dev.kske.eventbus.EventBus; @@ -25,21 +25,31 @@ public class ShutdownHelper { * * @since Envoy Client v0.2-beta */ - public static void exit() { exit(Settings.getInstance().isHideOnClose(), true); } - - /** - * Exits the currently open Envoy application or minimizes it. - * Does not necessarily shutdown VM. - * - * @param minimize whether Envoy should be minimized instead of closed - * @param shutdownVM whether the JVM should shutdown - * @since Envoy Client v0.2-beta - */ - public static void exit(boolean minimize, boolean shutdownVM) { - if (minimize) Context.getInstance().getStage().setIconified(true); + public static void exit() { + if (Settings.getInstance().isHideOnClose()) Context.getInstance().getStage().setIconified(true); else { - EventBus.getInstance().dispatch(new EnvoyCloseEvent()); - if (shutdownVM) System.exit(0); + final var alert = new Alert(AlertType.CONFIRMATION); + alert.setTitle("Exit?"); + alert.setContentText("Are you sure you want to exit Envoy?"); + AlertHelper.confirmAction(alert, () -> { 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, () -> { + EventBus.getInstance().dispatch(new EnvoyCloseEvent()); + EventBus.getInstance().dispatch(new Logout()); + Context.getInstance().getSceneContext().load(SceneInfo.LOGIN_SCENE); + }); + } } diff --git a/client/src/main/java/envoy/client/net/Client.java b/client/src/main/java/envoy/client/net/Client.java index f2987b3..b2247b3 100644 --- a/client/src/main/java/envoy/client/net/Client.java +++ b/client/src/main/java/envoy/client/net/Client.java @@ -240,7 +240,10 @@ public final class Client implements EventListener, Closeable { logger.log(Level.INFO, "Closing connection..."); try { socket.close(); - } catch (final IOException e) {} + online = false; + } catch (final IOException e) { + logger.log(Level.WARNING, "Failed to close socket: ", e); + } } } diff --git a/client/src/main/java/envoy/client/ui/SceneContext.java b/client/src/main/java/envoy/client/ui/SceneContext.java index 9b72f8e..c37b51d 100644 --- a/client/src/main/java/envoy/client/ui/SceneContext.java +++ b/client/src/main/java/envoy/client/ui/SceneContext.java @@ -108,8 +108,16 @@ public final class SceneContext implements EventListener { sceneStack.push(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().put(new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN), ShutdownHelper::exit); + // Add the option to logout using "Control"+"Shift"+"L" + scene.getAccelerators() + .put(new KeyCodeCombination(KeyCode.L, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN), ShutdownHelper::logout); + + // Add the option to open the settings scene with "Control"+"S", if being in + // chat scene + 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 // As strange as it seems, this is needed as otherwise the LoginScene won't be diff --git a/client/src/main/java/envoy/client/ui/Startup.java b/client/src/main/java/envoy/client/ui/Startup.java index 8b239d3..1bbc7b6 100644 --- a/client/src/main/java/envoy/client/ui/Startup.java +++ b/client/src/main/java/envoy/client/ui/Startup.java @@ -56,6 +56,8 @@ public final class Startup extends Application { */ @Override public void start(Stage stage) throws Exception { + + // Initialize config and logger try { config.loadAll(Startup.class, "client.properties", getParameters().getRaw().toArray(new String[0])); EnvoyLog.initialize(config); @@ -68,7 +70,7 @@ public final class Startup extends Application { // Initialize the local database try { - var localDBFile = new File(config.getHomeDirectory(), config.getServer()); + final var localDBFile = new File(config.getHomeDirectory(), config.getServer()); logger.info("Initializing LocalDB at " + localDBFile); localDB = new LocalDB(localDBFile); } catch (IOException | EnvoyException e) { diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index d9b7412..834c26c 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -28,8 +28,10 @@ import envoy.client.data.*; import envoy.client.data.audio.AudioRecorder; import envoy.client.data.commands.*; import envoy.client.event.*; +import envoy.client.helper.ShutdownHelper; import envoy.client.net.*; import envoy.client.ui.*; +import envoy.client.ui.SceneContext.SceneInfo; import envoy.client.ui.custom.TextInputContextMenu; import envoy.client.ui.listcell.*; import envoy.client.util.ReflectionUtil; @@ -338,6 +340,19 @@ public final class ChatScene implements EventListener, Restorable { .setDescription("See for yourself :)") .setNumberOfArguments(2) .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 diff --git a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java index 4e0a428..e0bf1a5 100644 --- a/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java +++ b/client/src/main/java/envoy/client/ui/settings/GeneralSettingsPane.java @@ -3,7 +3,8 @@ package envoy.client.ui.settings; import javafx.scene.control.*; import envoy.client.data.SettingsItem; -import envoy.client.event.*; +import envoy.client.event.ThemeChangeEvent; +import envoy.client.helper.ShutdownHelper; import envoy.data.User.UserStatus; import dev.kske.eventbus.EventBus; @@ -61,5 +62,12 @@ public final class GeneralSettingsPane extends SettingsPane { // TODO add action when value is changed statusComboBox.setOnAction(e -> {}); 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); } } From af219274f5b7e221209d26eb5490e391303e552a Mon Sep 17 00:00:00 2001 From: delvh Date: Thu, 24 Sep 2020 18:00:59 +0200 Subject: [PATCH 3/5] Improved logout mechanism a bit, still pretty buggy (and fixed some inconsistencies) --- .../main/java/envoy/client/data/Cache.java | 13 +++++++++---- .../main/java/envoy/client/data/LocalDB.java | 19 +++++++++++++++++-- .../main/java/envoy/client/event/Logout.java | 2 +- .../envoy/client/helper/ShutdownHelper.java | 4 ++++ .../main/java/envoy/client/net/Client.java | 6 ++++-- .../main/java/envoy/client/net/Receiver.java | 1 + .../java/envoy/client/ui/SceneContext.java | 9 ++++++++- .../envoy/client/ui/controller/ChatScene.java | 5 ++++- 8 files changed, 48 insertions(+), 11 deletions(-) diff --git a/client/src/main/java/envoy/client/data/Cache.java b/client/src/main/java/envoy/client/data/Cache.java index 25b985e..0c37f5f 100644 --- a/client/src/main/java/envoy/client/data/Cache.java +++ b/client/src/main/java/envoy/client/data/Cache.java @@ -1,11 +1,9 @@ package envoy.client.data; import java.io.Serializable; -import java.util.LinkedList; -import java.util.Queue; +import java.util.*; import java.util.function.Consumer; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.logging.*; import envoy.util.EnvoyLog; @@ -62,4 +60,11 @@ public final class Cache implements Consumer, Serializable { elements.forEach(processor::accept); elements.clear(); } + + /** + * Clears this cache of all stored elements. + * + * @since Envoy Client v0.2-beta + */ + public void clear() { elements.clear(); } } diff --git a/client/src/main/java/envoy/client/data/LocalDB.java b/client/src/main/java/envoy/client/data/LocalDB.java index 524d086..5cf6bba 100644 --- a/client/src/main/java/envoy/client/data/LocalDB.java +++ b/client/src/main/java/envoy/client/data/LocalDB.java @@ -40,6 +40,10 @@ public final class LocalDB implements EventListener { private CacheMap cacheMap = new CacheMap(); private String authToken; + // auto save Timer + private Timer autoSaver; + private boolean autoSaveRestart = true; + // State management private Instant lastSync = Instant.EPOCH; @@ -167,7 +171,14 @@ public final class LocalDB implements EventListener { * @since Envoy Client v0.2-beta */ public void initAutoSave() { - new Timer("LocalDB Autosave", true).schedule(new TimerTask() { + + if (autoSaveRestart) { + // A logout happened so the timer should be restarted + autoSaver = new Timer("LocalDB Autosave", true); + autoSaveRestart = false; + } + + autoSaver.schedule(new TimerTask() { @Override public void run() { save(); } @@ -219,12 +230,16 @@ public final class LocalDB implements EventListener { */ @Event(eventType = Logout.class, priority = 100) public void onLogout() { + autoSaver.cancel(); + autoSaveRestart = true; lastLoginFile.delete(); userFile = null; user = null; authToken = null; chats.clear(); - cacheMap = new CacheMap(); + lastSync = Instant.EPOCH; + cacheMap.getMap().forEach((key, cache) -> cache.clear()); + // cacheMap = new CacheMap(); } /** diff --git a/client/src/main/java/envoy/client/event/Logout.java b/client/src/main/java/envoy/client/event/Logout.java index e845fb1..45e2a20 100644 --- a/client/src/main/java/envoy/client/event/Logout.java +++ b/client/src/main/java/envoy/client/event/Logout.java @@ -8,7 +8,7 @@ import envoy.event.Event.Valueless; * @author leon * @since Envoy Client v0.2-beta */ -public class Logout extends Valueless { +public final class Logout extends Valueless { private static final long serialVersionUID = 1L; } diff --git a/client/src/main/java/envoy/client/helper/ShutdownHelper.java b/client/src/main/java/envoy/client/helper/ShutdownHelper.java index 812c518..e871936 100644 --- a/client/src/main/java/envoy/client/helper/ShutdownHelper.java +++ b/client/src/main/java/envoy/client/helper/ShutdownHelper.java @@ -1,11 +1,14 @@ 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; @@ -47,6 +50,7 @@ public class ShutdownHelper { 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); diff --git a/client/src/main/java/envoy/client/net/Client.java b/client/src/main/java/envoy/client/net/Client.java index b2247b3..1833109 100644 --- a/client/src/main/java/envoy/client/net/Client.java +++ b/client/src/main/java/envoy/client/net/Client.java @@ -180,7 +180,7 @@ public final class Client implements EventListener, Closeable { receiver.registerProcessor(GroupCreationResult.class, eventBus::dispatch); // 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 cacheMap.getMap().values().forEach(Cache::relay); @@ -204,6 +204,7 @@ public final class Client implements EventListener, Closeable { * * @param evt the event to send * @throws IOException if the event did not reach the server + * @since Envoy Client v0.3-alpha */ public void sendEvent(Event evt) throws IOException { if (online) writeObject(evt); } @@ -213,7 +214,7 @@ public final class Client implements EventListener, Closeable { * @throws IOException if the request does not reach the server * @since Envoy Client v0.3-alpha */ - public void requestIdGenerator() throws IOException { + public void requestIDGenerator() throws IOException { logger.log(Level.INFO, "Requesting new id generator..."); writeObject(new IDGeneratorRequest()); } @@ -271,6 +272,7 @@ public final class Client implements EventListener, Closeable { /** * @return the {@link Receiver} used by this {@link Client} + * @since v0.2-alpha */ public Receiver getReceiver() { return receiver; } diff --git a/client/src/main/java/envoy/client/net/Receiver.java b/client/src/main/java/envoy/client/net/Receiver.java index ac806ad..8e1467b 100644 --- a/client/src/main/java/envoy/client/net/Receiver.java +++ b/client/src/main/java/envoy/client/net/Receiver.java @@ -37,6 +37,7 @@ public final class Receiver extends Thread { public Receiver(InputStream in) { super("Receiver"); this.in = in; + setDaemon(true); } /** diff --git a/client/src/main/java/envoy/client/ui/SceneContext.java b/client/src/main/java/envoy/client/ui/SceneContext.java index c37b51d..d5b280c 100644 --- a/client/src/main/java/envoy/client/ui/SceneContext.java +++ b/client/src/main/java/envoy/client/ui/SceneContext.java @@ -11,7 +11,7 @@ import javafx.scene.input.*; import javafx.stage.Stage; import envoy.client.data.Settings; -import envoy.client.event.ThemeChangeEvent; +import envoy.client.event.*; import envoy.client.helper.ShutdownHelper; import envoy.util.EnvoyLog; @@ -97,6 +97,7 @@ public final class SceneContext implements EventListener { * @since Envoy Client v0.1-beta */ public void load(SceneInfo sceneInfo) { + EnvoyLog.getLogger(SceneContext.class).log(Level.FINER, "Loading scene " + sceneInfo); loader.setRoot(null); loader.setController(null); @@ -166,6 +167,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) private void onThemeChange() { applyCSS(); } diff --git a/client/src/main/java/envoy/client/ui/controller/ChatScene.java b/client/src/main/java/envoy/client/ui/controller/ChatScene.java index 834c26c..ec40146 100644 --- a/client/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/client/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -325,6 +325,9 @@ public final class ChatScene implements EventListener, Restorable { 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}. * @@ -711,7 +714,7 @@ public final class ChatScene implements EventListener, Restorable { scrollToMessageListEnd(); // 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); From 108db1ae1188f1342e427fb3eccc1b2c2e3c62a8 Mon Sep 17 00:00:00 2001 From: delvh Date: Fri, 25 Sep 2020 22:00:34 +0200 Subject: [PATCH 4/5] Fixed bug not re-performing handshake on logout Fixes #31 --- .../src/main/java/envoy/client/helper/ShutdownHelper.java | 6 ++---- client/src/main/java/envoy/client/net/Client.java | 5 ++++- client/src/main/java/envoy/client/ui/SceneContext.java | 5 +++-- client/src/main/java/envoy/client/ui/Startup.java | 3 +-- .../java/envoy/client/ui/controller/ContactSearchTab.java | 8 ++++---- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/client/src/main/java/envoy/client/helper/ShutdownHelper.java b/client/src/main/java/envoy/client/helper/ShutdownHelper.java index e871936..fa39b69 100644 --- a/client/src/main/java/envoy/client/helper/ShutdownHelper.java +++ b/client/src/main/java/envoy/client/helper/ShutdownHelper.java @@ -31,10 +31,8 @@ public class ShutdownHelper { public static void exit() { if (Settings.getInstance().isHideOnClose()) Context.getInstance().getStage().setIconified(true); else { - final var alert = new Alert(AlertType.CONFIRMATION); - alert.setTitle("Exit?"); - alert.setContentText("Are you sure you want to exit Envoy?"); - AlertHelper.confirmAction(alert, () -> { EventBus.getInstance().dispatch(new EnvoyCloseEvent()); System.exit(0); }); + EventBus.getInstance().dispatch(new EnvoyCloseEvent()); + System.exit(0); } } diff --git a/client/src/main/java/envoy/client/net/Client.java b/client/src/main/java/envoy/client/net/Client.java index 1833109..63a3e3b 100644 --- a/client/src/main/java/envoy/client/net/Client.java +++ b/client/src/main/java/envoy/client/net/Client.java @@ -240,8 +240,11 @@ public final class Client implements EventListener, Closeable { if (online) { logger.log(Level.INFO, "Closing connection..."); try { + + // The sender must be reset as otherwise the handshake is immediately closed + sender = null; + online = false; socket.close(); - online = false; } catch (final IOException e) { logger.log(Level.WARNING, "Failed to close socket: ", e); } diff --git a/client/src/main/java/envoy/client/ui/SceneContext.java b/client/src/main/java/envoy/client/ui/SceneContext.java index d5b280c..67dcc20 100644 --- a/client/src/main/java/envoy/client/ui/SceneContext.java +++ b/client/src/main/java/envoy/client/ui/SceneContext.java @@ -111,8 +111,9 @@ public final class SceneContext implements EventListener { // Add the option to exit Linux-like with "Control" + "Q" scene.getAccelerators().put(new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN), ShutdownHelper::exit); - // Add the option to logout using "Control"+"Shift"+"L" - scene.getAccelerators() + + // Add the option to logout using "Control"+"Shift"+"L" if not in login scene + if (sceneInfo != SceneInfo.LOGIN_SCENE) scene.getAccelerators() .put(new KeyCodeCombination(KeyCode.L, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN), ShutdownHelper::logout); // Add the option to open the settings scene with "Control"+"S", if being in diff --git a/client/src/main/java/envoy/client/ui/Startup.java b/client/src/main/java/envoy/client/ui/Startup.java index 1bbc7b6..9411644 100644 --- a/client/src/main/java/envoy/client/ui/Startup.java +++ b/client/src/main/java/envoy/client/ui/Startup.java @@ -117,7 +117,6 @@ public final class Startup extends Application { cacheMap.put(MessageStatusChange.class, new Cache()); cacheMap.put(GroupMessageStatusChange.class, new Cache()); try { - final var client = context.getClient(); client.performHandshake(credentials, cacheMap); if (client.isOnline()) { loadChatScene(); @@ -211,7 +210,7 @@ public final class Startup extends Application { if (StatusTrayIcon.isSupported()) { - // Configure hide on close + // Exit or minimize the stage when a close request occurs stage.setOnCloseRequest(e -> { ShutdownHelper.exit(); if (Settings.getInstance().isHideOnClose()) e.consume(); }); // Initialize status tray icon diff --git a/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java b/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java index ed800a7..a6aec3e 100644 --- a/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java +++ b/client/src/main/java/envoy/client/ui/controller/ContactSearchTab.java @@ -72,7 +72,7 @@ public class ContactSearchTab implements EventListener { } /** - * Disables the clear and search button if no text is present in the search bar. + * If text is present, sends a request to the server. * * @since Envoy Client v0.1-beta */ @@ -111,12 +111,12 @@ public class ContactSearchTab implements EventListener { } } - private void addAsContact() { - + private void addAsContact() { + // Sends the event to the server final var event = new ContactOperation(currentlySelectedUser, ElementOperation.ADD); eventBus.dispatch(new SendEvent(event)); - + // Removes the chosen user and updates the UI userList.getItems().remove(currentlySelectedUser); eventBus.dispatch(event); From 61fbeda05e30c8425ad15dbdbbd85de496ab13f1 Mon Sep 17 00:00:00 2001 From: delvh Date: Sat, 26 Sep 2020 21:38:31 +0200 Subject: [PATCH 5/5] Applied suggestions from @kske --- .../main/java/envoy/client/data/CacheMap.java | 24 +++++++++++-------- .../main/java/envoy/client/data/LocalDB.java | 9 ++++--- .../main/java/envoy/client/event/Logout.java | 2 +- .../java/envoy/client/helper/AlertHelper.java | 2 +- .../envoy/client/helper/ShutdownHelper.java | 4 ++-- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/client/src/main/java/envoy/client/data/CacheMap.java b/client/src/main/java/envoy/client/data/CacheMap.java index 8c1fcb2..1c1c6c3 100644 --- a/client/src/main/java/envoy/client/data/CacheMap.java +++ b/client/src/main/java/envoy/client/data/CacheMap.java @@ -1,8 +1,7 @@ package envoy.client.data; import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /** * Stores a heterogeneous map of {@link Cache} objects with different type @@ -11,7 +10,7 @@ import java.util.Map; * Project: envoy-client
* File: CacheMap.java
* Created: 09.07.2020
- * + * * @author Kai S. K. Engelbart * @since Envoy Client v0.1-beta */ @@ -23,7 +22,7 @@ public final class CacheMap implements Serializable { /** * Adds a cache to the map. - * + * * @param the type accepted by the cache * @param key the class that maps to the cache * @param cache the cache to store @@ -33,7 +32,7 @@ public final class CacheMap implements Serializable { /** * Returns a cache mapped by a class. - * + * * @param the type accepted by the cache * @param key the class that maps to the cache * @return the cache @@ -43,7 +42,7 @@ public final class CacheMap implements Serializable { /** * Returns a cache mapped by a class or any of its subclasses. - * + * * @param the type accepted by the cache * @param key the class that maps to the cache * @return the cache @@ -51,10 +50,8 @@ public final class CacheMap implements Serializable { */ public Cache getApplicable(Class key) { Cache cache = get(key); - if (cache == null) - for (var e : map.entrySet()) - if (e.getKey().isAssignableFrom(key)) - cache = (Cache) e.getValue(); + if (cache == null) for (final var e : map.entrySet()) + if (e.getKey().isAssignableFrom(key)) cache = (Cache) e.getValue(); return cache; } @@ -63,4 +60,11 @@ public final class CacheMap implements Serializable { * @since Envoy Client v0.1-beta */ public Map, 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); } } diff --git a/client/src/main/java/envoy/client/data/LocalDB.java b/client/src/main/java/envoy/client/data/LocalDB.java index 5cf6bba..82c007c 100644 --- a/client/src/main/java/envoy/client/data/LocalDB.java +++ b/client/src/main/java/envoy/client/data/LocalDB.java @@ -40,7 +40,7 @@ public final class LocalDB implements EventListener { private CacheMap cacheMap = new CacheMap(); private String authToken; - // auto save Timer + // Auto save timer private Timer autoSaver; private boolean autoSaveRestart = true; @@ -172,8 +172,8 @@ public final class LocalDB implements EventListener { */ public void initAutoSave() { + // A logout happened so the timer should be restarted if (autoSaveRestart) { - // A logout happened so the timer should be restarted autoSaver = new Timer("LocalDB Autosave", true); autoSaveRestart = false; } @@ -229,7 +229,7 @@ public final class LocalDB implements EventListener { * @since Envoy Client v0.2-beta */ @Event(eventType = Logout.class, priority = 100) - public void onLogout() { + private void onLogout() { autoSaver.cancel(); autoSaveRestart = true; lastLoginFile.delete(); @@ -238,8 +238,7 @@ public final class LocalDB implements EventListener { authToken = null; chats.clear(); lastSync = Instant.EPOCH; - cacheMap.getMap().forEach((key, cache) -> cache.clear()); - // cacheMap = new CacheMap(); + cacheMap.clear(); } /** diff --git a/client/src/main/java/envoy/client/event/Logout.java b/client/src/main/java/envoy/client/event/Logout.java index 45e2a20..098075b 100644 --- a/client/src/main/java/envoy/client/event/Logout.java +++ b/client/src/main/java/envoy/client/event/Logout.java @@ -5,7 +5,7 @@ import envoy.event.Event.Valueless; /** * Indicates that a logout has been requested. * - * @author leon + * @author Leon Hofmeister * @since Envoy Client v0.2-beta */ public final class Logout extends Valueless { diff --git a/client/src/main/java/envoy/client/helper/AlertHelper.java b/client/src/main/java/envoy/client/helper/AlertHelper.java index cf6c82f..4c6e880 100644 --- a/client/src/main/java/envoy/client/helper/AlertHelper.java +++ b/client/src/main/java/envoy/client/helper/AlertHelper.java @@ -10,7 +10,7 @@ import envoy.client.data.Settings; * @author Leon Hofmeister * @since Envoy Client v0.2-beta */ -public class AlertHelper { +public final class AlertHelper { private AlertHelper() {} diff --git a/client/src/main/java/envoy/client/helper/ShutdownHelper.java b/client/src/main/java/envoy/client/helper/ShutdownHelper.java index fa39b69..7f6dd7e 100644 --- a/client/src/main/java/envoy/client/helper/ShutdownHelper.java +++ b/client/src/main/java/envoy/client/helper/ShutdownHelper.java @@ -13,12 +13,12 @@ import envoy.util.EnvoyLog; import dev.kske.eventbus.EventBus; /** - * Contains methods that have a direct impact on the user. + * Simplifies shutdown actions. * * @author Leon Hofmeister * @since Envoy Client v0.2-beta */ -public class ShutdownHelper { +public final class ShutdownHelper { private ShutdownHelper() {}