diff --git a/src/main/java/com/example/FxUtils.java b/src/main/java/com/example/FxUtils.java index 770219f0..cc14045a 100644 --- a/src/main/java/com/example/FxUtils.java +++ b/src/main/java/com/example/FxUtils.java @@ -5,7 +5,12 @@ public class FxUtils { /** - * Execute task on FX-thread if possible, otherwise inline. + * Ensures the given task runs on the JavaFX Application Thread when possible. + * + * If already on the JavaFX Application Thread the task is executed immediately; + * if the JavaFX platform is not initialized the task is executed on the current thread. + * + * @param task the work to execute */ static void runOnFx(Runnable task) { try { diff --git a/src/main/java/com/example/HelloController.java b/src/main/java/com/example/HelloController.java index 046a8f7f..d27a37b8 100644 --- a/src/main/java/com/example/HelloController.java +++ b/src/main/java/com/example/HelloController.java @@ -45,6 +45,14 @@ public class HelloController { DateTimeFormatter.ofPattern("HH:mm:ss") .withZone(ZoneId.systemDefault()); + /** + * Initializes the controller by binding UI components to the model, configuring controls, and setting up the message view. + * + *
Sets the initial greeting and topic display, requests focus for the message input, binds the message list + * and the message input to the model, disables send/change-topic buttons when their inputs are empty, configures + * the message list cells to render chat bubbles aligned and styled for sent versus received messages, and adds + * a listener to auto-scroll to the latest message.
+ */ @FXML private void initialize() { messageLabel.setText(model.getGreeting()); @@ -124,6 +132,12 @@ protected void updateItem(NtfyMessageDto msg, boolean empty) { }); } + /** + * Sends the composed message asynchronously and updates the UI according to the send result. + * + * On success, clears the message input and refocuses it. On failure, displays an error alert + * indicating the message could not be sent. + */ @FXML private void sendMessage(ActionEvent actionEvent) { model.sendMessageAsync(success -> { @@ -142,6 +156,11 @@ private void sendMessage(ActionEvent actionEvent) { }); } + /** + * Updates the model's current topic from the topic input field and clears the input. + * + * If the topic input contains non-whitespace text, sets the model's current topic to that value and then clears the topic input field. + */ @FXML private void changeTopic(ActionEvent actionEvent) { String newTopic = topicInput.getText(); diff --git a/src/main/java/com/example/HelloFX.java b/src/main/java/com/example/HelloFX.java index 6b4a47e7..759d70ad 100644 --- a/src/main/java/com/example/HelloFX.java +++ b/src/main/java/com/example/HelloFX.java @@ -10,6 +10,15 @@ public class HelloFX extends Application { + /** + * Initializes the JavaFX user interface, sets up the scene and stylesheet, and shows the primary stage. + * + * Loads the FXML layout "hello-view.fxml", creates a Scene sized 768×576, sets the window title to + * "RuneChat", applies the "style.css" stylesheet, attaches the scene to the provided stage, and displays it. + * + * @param stage the primary stage provided by the JavaFX runtime to host the application scene + * @throws Exception if the FXML or stylesheet resources cannot be loaded or another initialization error occurs + */ @Override public void start(Stage stage) throws Exception { FXMLLoader fxmlLoader = new FXMLLoader(HelloFX.class.getResource("hello-view.fxml")); @@ -26,6 +35,11 @@ public void start(Stage stage) throws Exception { } + /** + * Launches the JavaFX application. + * + * @param args command-line arguments; unused by this application + */ public static void main(String[] args) { launch(); } diff --git a/src/main/java/com/example/HelloModel.java b/src/main/java/com/example/HelloModel.java index 1be38206..e7eeb1b6 100644 --- a/src/main/java/com/example/HelloModel.java +++ b/src/main/java/com/example/HelloModel.java @@ -17,36 +17,80 @@ public class HelloModel { private final StringProperty messageToSend = new SimpleStringProperty(); private final StringProperty currentTopic = new SimpleStringProperty(); + /** + * Create a HelloModel bound to the given NtfyConnection. + * + * Initializes the model's current topic from the connection and begins receiving messages for that topic. + */ public HelloModel(NtfyConnection connection) { this.connection = connection; this.currentTopic.set(connection.getCurrentTopic()); receiveMessage(); } + /** + * Provides the observable list of received messages for UI binding. + * + * @return the live ObservableList of NtfyMessageDto messages. + */ public ObservableListIf the provided topic is non-null and not blank, this updates the connection's current
+ * topic, updates the model's currentTopic property, clears the message list, and restarts
+ * receiving messages for the new topic. If the topic is null or blank, no action is taken.
+ *
+ * @param topic the new topic to set; ignored if null or blank
+ */
public void setCurrentTopic(String topic) {
if (topic != null && !topic.isBlank()) {
connection.setCurrentTopic(topic);
@@ -56,19 +100,43 @@ public void setCurrentTopic(String topic) {
}
}
+ /**
+ * Provides the current user's identifier.
+ *
+ * @return the current user's identifier
+ */
public String getUserId() {
return connection.getUserId();
}
+ /**
+ * Retrieve the application's greeting text.
+ *
+ * @return the greeting text "RuneChat"
+ */
public String getGreeting() {
return "RuneChat";
}
+ /**
+ * Determine whether the current draft message is eligible to be sent.
+ *
+ * @return `true` if the draft message is non-null and contains at least one non-whitespace character, `false` otherwise.
+ */
public boolean canSendMessage() {
String msg = messageToSend.get();
return msg != null && !msg.isBlank();
}
+ /**
+ * Sends the current message through the connection and reports the outcome via the provided callback.
+ *
+ * If the message is null or blank the callback is invoked with `false` and no send is attempted. On successful send,
+ * the input is cleared only if it has not changed since sending. The callback is invoked with `true` on success and
+ * `false` on failure.
+ *
+ * @param callback consumer invoked with `true` when the message was sent successfully, `false` otherwise
+ */
public void sendMessageAsync(Consumer The instance will use userId "testuser" and topic "mytopic" unless changed.
+ *
+ * @param hostName the base URL of the ntfy host to connect to
+ */
public NtfyConnectionImpl(String hostName) {
this.hostName = hostName;
this.userId = "testuser";
this.currentTopic = "mytopic";
}
+ /**
+ * Constructs a NtfyConnectionImpl configured with the specified host, user, and topic.
+ *
+ * @param hostName the base URL of the ntfy host to connect to
+ * @param userId the user identifier to include with requests
+ * @param topic the initial topic name to use for sending and receiving messages
+ */
public NtfyConnectionImpl(String hostName, String userId, String topic) {
this.hostName = hostName;
this.userId = userId;
this.currentTopic = topic;
}
+ /**
+ * User identifier used in outgoing requests.
+ *
+ * @return the configured user identifier
+ */
public String getUserId() {
return userId;
}
+ /**
+ * Gets the current topic used for sending and receiving messages.
+ *
+ * @return the name of the current topic
+ */
public String getCurrentTopic() {
return currentTopic;
}
+ /**
+ * Updates the topic used for subsequent send and receive operations.
+ *
+ * @param topic the new topic name to set
+ */
public void setCurrentTopic(String topic) {
this.currentTopic = topic;
}
+ /**
+ * Sends the given message to the current topic on the configured host and delivers whether the send succeeded to the callback.
+ *
+ * @param message the message body to post to the current topic
+ * @param callback consumer invoked with `true` if the HTTP response status code is in the 2xx range, `false` otherwise
+ */
@Override
public void send(String message, Consumer Lines received from the topic are parsed as JSON into {@code NtfyMessageDto}; messages that fail parsing are skipped. Stores the message in the spy's state and invokes the callback with {@code true} on a separate thread.
+ *
+ * @param message the message to record
+ * @param callback callback invoked with {@code true} to indicate simulated send success
+ */
@Override
public void send(String message, Consumer