diff --git a/src/main/java/envoy/client/ui/Restorable.java b/src/main/java/envoy/client/ui/Restorable.java new file mode 100644 index 0000000..e9e40eb --- /dev/null +++ b/src/main/java/envoy/client/ui/Restorable.java @@ -0,0 +1,25 @@ +package envoy.client.ui; + +/** + * This interface defines an action that should be performed when a scene gets + * restored from the scene stack in {@link SceneContext}. + *

+ * Project: envoy-client
+ * File: Restorable.java
+ * Created: 03.07.2020
+ * + * @author Leon Hofmeister + * @since Envoy Client v0.1-beta + */ +@FunctionalInterface +public interface Restorable { + + /** + * This method is getting called when a scene gets restored.
+ * Hence, it can contain anything that should be done when the underlying scene + * gets restored. + * + * @since Envoy Client v0.1-beta + */ + void onRestore(); +} diff --git a/src/main/java/envoy/client/ui/SceneContext.java b/src/main/java/envoy/client/ui/SceneContext.java index 6b6757e..a027395 100644 --- a/src/main/java/envoy/client/ui/SceneContext.java +++ b/src/main/java/envoy/client/ui/SceneContext.java @@ -90,8 +90,9 @@ public final class SceneContext { } private final Stage stage; - private final FXMLLoader loader = new FXMLLoader(); - private final Stack sceneStack = new Stack<>(); + private final FXMLLoader loader = new FXMLLoader(); + private final Stack sceneStack = new Stack<>(); + private final Stack controllerStack = new Stack<>(); private static final Settings settings = Settings.getInstance(); @@ -120,6 +121,7 @@ public final class SceneContext { try { final var rootNode = (Parent) loader.load(getClass().getResourceAsStream(sceneInfo.path)); final var scene = new Scene(rootNode); + controllerStack.push(loader.getController()); sceneStack.push(scene); stage.setScene(scene); @@ -139,10 +141,16 @@ public final class SceneContext { */ public void pop() { sceneStack.pop(); + controllerStack.pop(); if (!sceneStack.isEmpty()) { - stage.setScene(sceneStack.peek()); + final var newScene = sceneStack.peek(); + stage.setScene(newScene); applyCSS(); stage.sizeToScene(); + // If the controller implements the Restorable interface, + // the actions to perform on restoration will be executed here + final var controller = controllerStack.peek(); + if (controller instanceof Restorable) ((Restorable) controller).onRestore(); } stage.show(); } @@ -161,7 +169,7 @@ public final class SceneContext { * @return the controller used by the current scene * @since Envoy Client v0.1-beta */ - public T getController() { return loader.getController(); } + public T getController() { return (T) controllerStack.peek(); } /** * @return the stage in which the scenes are displayed diff --git a/src/main/java/envoy/client/ui/controller/ChatScene.java b/src/main/java/envoy/client/ui/controller/ChatScene.java index ed35cda..5ed306a 100644 --- a/src/main/java/envoy/client/ui/controller/ChatScene.java +++ b/src/main/java/envoy/client/ui/controller/ChatScene.java @@ -24,6 +24,7 @@ import envoy.client.event.MessageCreationEvent; import envoy.client.net.Client; import envoy.client.net.WriteProxy; import envoy.client.ui.IconUtil; +import envoy.client.ui.Restorable; import envoy.client.ui.SceneContext; import envoy.client.ui.listcell.ContactListCellFactory; import envoy.client.ui.listcell.MessageControl; @@ -43,7 +44,7 @@ import envoy.util.EnvoyLog; * @author Kai S. K. Engelbart * @since Envoy Client v0.1-beta */ -public final class ChatScene { +public final class ChatScene implements Restorable { @FXML private Label contactLabel; @@ -173,6 +174,9 @@ public final class ChatScene { if (!client.isOnline()) updateInfoLabel("You are offline", "infoLabel-info"); } + @Override + public void onRestore() { updateRemainingCharsLabel(); } + /** * Actions to perform when the list of contacts has been clicked. * diff --git a/src/main/java/envoy/client/ui/controller/ContactSearchScene.java b/src/main/java/envoy/client/ui/controller/ContactSearchScene.java index 957a52b..4fe48d2 100644 --- a/src/main/java/envoy/client/ui/controller/ContactSearchScene.java +++ b/src/main/java/envoy/client/ui/controller/ContactSearchScene.java @@ -101,14 +101,17 @@ public class ContactSearchScene { final var alert = new Alert(AlertType.CONFIRMATION); alert.setTitle("Add Contact to Contact List"); alert.setHeaderText("Add the user " + contact.getName() + " to your contact list?"); - alert.showAndWait().filter(btn -> btn == ButtonType.OK).ifPresent(btn -> { + // Normally, this would be total BS (we are already on the FX Thread), however + // it could be proven that the creation of this dialog wrapped in + // Platform.runLater is less error-prone than without it + Platform.runLater(() -> alert.showAndWait().filter(btn -> btn == ButtonType.OK).ifPresent(btn -> { final var event = new ContactOperation(contact, ElementOperation.ADD); // Sends the event to the server eventBus.dispatch(new SendEvent(event)); // Updates the UI eventBus.dispatch(event); logger.log(Level.INFO, "Added contact " + contact); - }); + })); } }