-
Notifications
You must be signed in to change notification settings - Fork 66
0.1.1t #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
0.1.1t #25
Changes from all commits
d54c28e
175a191
63db1f6
1ff47ac
6baf403
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| target/ | ||
| /.idea/ | ||
| .env |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,22 +1,73 @@ | ||
| package com.example; | ||
|
|
||
| import javafx.event.ActionEvent; | ||
| import javafx.fxml.FXML; | ||
| import javafx.scene.control.Label; | ||
| import javafx.scene.control.ListView; | ||
| import javafx.scene.control.TextField; | ||
| import javafx.stage.FileChooser; | ||
| import javafx.stage.Stage; | ||
|
|
||
| import java.io.File; | ||
|
|
||
| /** | ||
| * Controller layer: mediates between the view (FXML) and the model. | ||
| */ | ||
| public class HelloController { | ||
|
|
||
| private final HelloModel model = new HelloModel(); | ||
| private final NtfyConnection connection = new NtfyConnectionImpl(); | ||
| private final HelloModel model = new HelloModel(connection); | ||
|
|
||
| public ListView<Object> messageView; | ||
|
|
||
| @FXML | ||
| private Label topic; | ||
|
|
||
| @FXML | ||
| private Label messageLabel; | ||
| TextField input; | ||
|
|
||
| File attachment = null; | ||
|
|
||
| @FXML | ||
| private void initialize() { | ||
| if (messageLabel != null) { | ||
| messageLabel.setText(model.getGreeting()); | ||
| topic.textProperty().bind(connection.topicProperty()); | ||
| messageView.setItems(model.getFormatedMessages()); | ||
| model.receiveMessage(); | ||
| } | ||
|
|
||
| /** | ||
| * Send a message, file if one has been attached else a string from the input field | ||
| * @param actionEvent | ||
| */ | ||
| public void sendMessage(ActionEvent actionEvent) { | ||
| if(attachment != null) { | ||
| connection.sendFile(attachment); | ||
| attachment = null; | ||
| } | ||
| else{ | ||
| model.sendMessage(input.getText().trim()); | ||
| } | ||
| input.clear(); | ||
| } | ||
|
|
||
| /** | ||
| * Opens a filechooser and adds selected file as attachement to be sent | ||
| * @param actionEvent | ||
| */ | ||
| public void sendFile(ActionEvent actionEvent){ | ||
| FileChooser fileChooser = new FileChooser(); | ||
| fileChooser.setTitle("Attach a file"); | ||
|
|
||
| Stage stage = (Stage) topic.getScene().getWindow(); | ||
|
|
||
|
|
||
| attachment = fileChooser.showOpenDialog(stage); | ||
| if(attachment != null) { | ||
| input.setText(attachment.getAbsolutePath()); | ||
| } | ||
| } | ||
|
|
||
| public void changeTopic(ActionEvent actionEvent) { | ||
| model.changeTopic(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,133 @@ | ||
| package com.example; | ||
|
|
||
| import javafx.application.Platform; | ||
| import javafx.collections.FXCollections; | ||
| import javafx.collections.ObservableList; | ||
| import javafx.scene.control.*; | ||
| import javafx.scene.image.Image; | ||
| import javafx.scene.image.ImageView; | ||
| import javafx.scene.layout.GridPane; | ||
|
|
||
| import java.io.IOException; | ||
| import java.net.URL; | ||
| import java.text.DateFormat; | ||
| import java.text.SimpleDateFormat; | ||
| import java.util.Date; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| /** | ||
| * Model layer: encapsulates application data and business logic. | ||
| */ | ||
| public class HelloModel { | ||
|
|
||
| private final NtfyConnection connection; | ||
|
|
||
| private final ObservableList<NtfyMessage> messageHistory = FXCollections.observableArrayList(); | ||
| private final ObservableList<Object> formatedMessages = FXCollections.observableArrayList(); | ||
|
|
||
|
|
||
| public HelloModel(NtfyConnection connection) { | ||
| this.connection = connection; | ||
| } | ||
|
|
||
|
|
||
| public ObservableList<Object> getFormatedMessages() { | ||
| return formatedMessages; | ||
| } | ||
|
|
||
| public ObservableList<NtfyMessage> getMessageHistory() { | ||
| return messageHistory; | ||
| } | ||
|
|
||
| /** | ||
| * Sends a string as message | ||
| * @param message String to send | ||
| */ | ||
| public void sendMessage(String message) { | ||
| connection.send(message); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a greeting based on the current Java and JavaFX versions. | ||
| * Clears the display before opening a new connection to a topic and displaying it | ||
| */ | ||
| public String getGreeting() { | ||
| String javaVersion = System.getProperty("java.version"); | ||
| String javafxVersion = System.getProperty("javafx.version"); | ||
| return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + "."; | ||
| public void receiveMessage() { | ||
| formatedMessages.clear(); | ||
| connection.recieve(m -> Platform.runLater(() -> logMessage(m))); | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Adds the message to internal message history and the values to be displayed formated in the display list | ||
| * If the message is an attachment it displays it as an image or hyperlink depending on content | ||
| * @param message received message from NTFY server | ||
| */ | ||
| public void logMessage(NtfyMessage message) { | ||
| messageHistory.add(message); | ||
|
|
||
| if(message.attachment() != null) { | ||
| try { | ||
| URL url = new URL(message.attachment().get("url")); | ||
|
|
||
| if(Pattern.matches("^image\\/\\w+",message.attachment().get("type"))) {//check if the attachment is an image | ||
| ImageView image = new ImageView(new Image(url.toExternalForm())); | ||
| image.setPreserveRatio(true); | ||
| image.setFitHeight ( 250 ); | ||
| image.setFitWidth ( 250 ); | ||
|
|
||
| formatedMessages.addFirst(image); | ||
| } | ||
|
|
||
| else{ | ||
| Hyperlink hyperlink = new Hyperlink(url.toExternalForm()); | ||
| formatedMessages.addFirst(hyperlink); | ||
| } | ||
|
|
||
| } catch (IOException e) { | ||
| throw new RuntimeException(e); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Date timeStamp = new Date(message.time()*1000); | ||
| DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); | ||
| String stringMessage = dateFormat.format(timeStamp) + " : " + message.message(); | ||
| formatedMessages.addFirst(stringMessage); | ||
| } | ||
|
Comment on lines
+64
to
+95
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In formatedMessages.addFirst(image);
...
formatedMessages.addFirst(hyperlink);
...
formatedMessages.addFirst(stringMessage);
- formatedMessages.addFirst(image);
+ formatedMessages.add(0, image);
...
- formatedMessages.addFirst(hyperlink);
+ formatedMessages.add(0, hyperlink);
...
- formatedMessages.addFirst(stringMessage);
+ formatedMessages.add(0, stringMessage);Also, the attachment handling assumes the map always contains non-null URL url = new URL(message.attachment().get("url"));
Pattern.matches("^image\\/\\w+", message.attachment().get("type"));If either key is missing or null, you’ll get
Map<String, String> att = message.attachment();
if (att == null) {
// no attachment
} else {
String urlStr = att.get("url");
String type = att.get("type");
if (urlStr != null && type != null) {
// existing logic
}
}🤖 Prompt for AI Agents |
||
|
|
||
| /** | ||
| * Opens as dialog with text input | ||
| * If a value is entered and the add button pressed, change the topic per the input | ||
| */ | ||
| public void changeTopic() { | ||
| Dialog dialog = new Dialog(); | ||
| dialog.setTitle("Add Topic"); | ||
|
|
||
| ButtonType addTopicButton = new ButtonType("Add Topic", ButtonBar.ButtonData.OK_DONE); | ||
| dialog.getDialogPane().getButtonTypes().addAll(addTopicButton, ButtonType.CANCEL); | ||
|
|
||
| TextField newTopic = new TextField(); | ||
| newTopic.setPromptText("Topic"); | ||
|
|
||
| GridPane gridPane = new GridPane(); | ||
| gridPane.setHgap(10); | ||
| gridPane.setVgap(10); | ||
|
|
||
| gridPane.add(newTopic, 0, 0); | ||
|
|
||
| dialog.getDialogPane().setContent(gridPane); | ||
|
|
||
| Platform.runLater(() -> newTopic.requestFocus()); | ||
|
|
||
| dialog.setResultConverter(pressedButton -> { | ||
| if (pressedButton == addTopicButton) { | ||
| if(!newTopic.getText().isBlank()){ | ||
| connection.setTopic(newTopic.getText().trim()); | ||
| receiveMessage(); | ||
| } | ||
| } | ||
| return null; | ||
| }); | ||
|
|
||
| dialog.show(); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package com.example; | ||
|
|
||
| import javafx.beans.property.SimpleStringProperty; | ||
|
|
||
| import java.io.File; | ||
| import java.util.function.Consumer; | ||
|
|
||
| public interface NtfyConnection { | ||
|
|
||
| SimpleStringProperty topic = new SimpleStringProperty(); | ||
|
|
||
| public SimpleStringProperty topicProperty(); | ||
|
|
||
| public String getTopic(); | ||
|
|
||
| public void setTopic(String topic); | ||
|
|
||
| public boolean send(String message); | ||
|
|
||
| public void recieve(Consumer<NtfyMessage> messageHandler); | ||
|
|
||
| public boolean sendFile(File attachment); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surface send failures and avoid sending empty messages/attachments
In
sendMessageandsendFile:connection.send(...)andconnection.sendFile(...)are ignored, so the UI can’t distinguish between success and failure (e.g. connection down, server error).sendMessagewill happily callmodel.sendMessage(input.getText().trim())even if the trimmed text is empty; the connection then rejects it, but you still hit the network and the user gets no feedback.attachmentand the input regardless of whethersendFileactually worked.Consider:
public void sendMessage(ActionEvent actionEvent) { if (attachment != null) { - connection.sendFile(attachment); - attachment = null; + boolean ok = connection.sendFile(attachment); + if (ok) { + attachment = null; + } else { + // e.g. show error or log + return; + } } else { - model.sendMessage(input.getText().trim()); + String text = input.getText().trim(); + if (text.isEmpty()) { + return; + } + model.sendMessage(text); } input.clear(); }🤖 Prompt for AI Agents