diff --git a/.gitignore b/.gitignore index 6ac465db..244268f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target/ /.idea/ +.env diff --git a/pom.xml b/pom.xml index c40f667e..9ee23793 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,16 @@ javafx-fxml ${javafx.version} + + io.github.cdimascio + dotenv-java + 3.2.0 + + + tools.jackson.core + jackson-databind + 3.0.1 + diff --git a/src/main/java/com/example/HelloController.java b/src/main/java/com/example/HelloController.java index fdd160a0..e0bd49a9 100644 --- a/src/main/java/com/example/HelloController.java +++ b/src/main/java/com/example/HelloController.java @@ -1,7 +1,10 @@ package com.example; +import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.scene.control.Label; +import javafx.geometry.Pos; +import javafx.geometry.Side; +import javafx.scene.control.*; /** * Controller layer: mediates between the view (FXML) and the model. @@ -10,13 +13,78 @@ public class HelloController { private final HelloModel model = new HelloModel(); + @FXML + public ListView messageView ; + @FXML private Label messageLabel; + @FXML + private TextField messageField; + + @FXML + private Button emojiButton; + + @FXML + private void emojis() { + + String[] emojis = {"😀", "😂", "😍", "😎", "😭", "👍", "🎉"}; + + + ContextMenu emojiMenu = new ContextMenu(); + for (String emoji : emojis) { + MenuItem item = new MenuItem(emoji); + item.setOnAction(e -> { + messageField.appendText(emoji); + }); + emojiMenu.getItems().add(item); + } + + emojiMenu.show(emojiButton, Side.BOTTOM, 0, 0); + } + @FXML private void initialize() { - if (messageLabel != null) { - messageLabel.setText(model.getGreeting()); + messageLabel.setText(model.getGreeting()); + messageView.setItems(model.getMessages()); + messageView.setCellFactory(list -> new ListCell<>() { + @Override + protected void updateItem(NtfyMessageDto msg, boolean empty) { + super.updateItem(msg, empty); + + if (empty || msg == null) { + setGraphic(null); + return; + } + + Label label = new Label(msg.toString()); + label.setWrapText(true); + label.setMaxWidth(180); + + + boolean fromMe = msg.topic() != null && msg.topic().equals("me"); + + if (fromMe) { + label.setStyle("-fx-background-color: lightgreen; -fx-padding: 6; -fx-background-radius: 8;"); + setAlignment(Pos.CENTER_RIGHT); + } else { + label.setStyle("-fx-background-color: lightgray; -fx-padding: 6; -fx-background-radius: 8;"); + setAlignment(Pos.CENTER_LEFT); + } + + setGraphic(label); + } + }); + + } + + + + public void sendMessage(ActionEvent actionEvent) { + String text = messageField.getText().trim(); + if (!text.isEmpty()) { + model.sendMessage(text); + messageField.clear(); } } } diff --git a/src/main/java/com/example/HelloFX.java b/src/main/java/com/example/HelloFX.java index 96bdc5ca..263c58ca 100644 --- a/src/main/java/com/example/HelloFX.java +++ b/src/main/java/com/example/HelloFX.java @@ -1,5 +1,6 @@ package com.example; +import io.github.cdimascio.dotenv.Dotenv; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; @@ -10,6 +11,7 @@ public class HelloFX extends Application { @Override public void start(Stage stage) throws Exception { + FXMLLoader fxmlLoader = new FXMLLoader(HelloFX.class.getResource("hello-view.fxml")); Parent root = fxmlLoader.load(); Scene scene = new Scene(root, 640, 480); diff --git a/src/main/java/com/example/HelloModel.java b/src/main/java/com/example/HelloModel.java index 385cfd10..083f39bf 100644 --- a/src/main/java/com/example/HelloModel.java +++ b/src/main/java/com/example/HelloModel.java @@ -1,9 +1,40 @@ package com.example; +import io.github.cdimascio.dotenv.Dotenv; +import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import tools.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.Objects; + /** * Model layer: encapsulates application data and business logic. */ public class HelloModel { + + private final String hostName; + private final HttpClient http = HttpClient.newHttpClient(); + private final ObjectMapper mapper = new ObjectMapper(); + private final ObservableList messages = FXCollections.observableArrayList(); + + private boolean senderMe=false; + + public HelloModel() { + Dotenv dotenv = Dotenv.load(); + hostName = Objects.requireNonNull(dotenv.get("HOST_NAME")); + receiveMessage(); + } + + public ObservableList getMessages() { + return messages; + } + /** * Returns a greeting based on the current Java and JavaFX versions. */ @@ -12,4 +43,52 @@ public String getGreeting() { String javafxVersion = System.getProperty("javafx.version"); return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + "."; } + + public void sendMessage(String text) { + + senderMe=true; + + long now = System.currentTimeMillis() / 1000; + NtfyMessageDto myMsg = new NtfyMessageDto("local", now, "message", "me", text); + + Platform.runLater(() -> messages.add(myMsg)); + + HttpRequest httpRequest= HttpRequest.newBuilder() + .POST(HttpRequest.BodyPublishers.ofString(text)) + .uri(URI.create(hostName + "/mytopic")) + .build(); + http.sendAsync(httpRequest, HttpResponse.BodyHandlers.discarding()) + .exceptionally(ex -> { + System.out.println("Error sending message: " + ex.getMessage()); + return null; + }); + } + + public void receiveMessage(){ + HttpRequest httpRequest = HttpRequest.newBuilder() + .GET() + .uri(URI.create(hostName + "/mytopic/json")) + .build(); + + http.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines()) + .thenAccept(response -> response.body() + .map(s -> { + try { + return mapper.readValue(s, NtfyMessageDto.class); + } catch (Exception e) { + System.err.println("Failed to parse message: " + e.getMessage()); + return null; + } + }) + .filter(Objects::nonNull) + .filter(msg -> "message".equals(msg.event())) + .forEach(msg->{ + if (senderMe) { + senderMe=false; + return; + } + Platform.runLater(() -> messages.add(msg)); + })); + } + } diff --git a/src/main/java/com/example/ManyParameters.java b/src/main/java/com/example/ManyParameters.java new file mode 100644 index 00000000..76596d06 --- /dev/null +++ b/src/main/java/com/example/ManyParameters.java @@ -0,0 +1,20 @@ +package com.example; + +public class ManyParameters { + + public ManyParameters(String computerName, int timeout, String method, int size, byte[] data) { + + } + + static void main () { + + ManyParametersBuilder builder= new ManyParametersBuilder(); + builder + .setComputerName("localhost") + .setTimeout(10) + .setSize(0) + .createManyParameters(); + } + + +} diff --git a/src/main/java/com/example/ManyParametersBuilder.java b/src/main/java/com/example/ManyParametersBuilder.java new file mode 100644 index 00000000..fd49920d --- /dev/null +++ b/src/main/java/com/example/ManyParametersBuilder.java @@ -0,0 +1,38 @@ +package com.example; + +public class ManyParametersBuilder { + private String computerName; + private int timeout = 0; + private String method; + private int size = 0; + private byte[] data = null; + + public ManyParametersBuilder setComputerName(String computerName) { + this.computerName = computerName; + return this; + } + + public ManyParametersBuilder setTimeout(int timeout) { + this.timeout = timeout; + return this; + } + + public ManyParametersBuilder setMethod(String method) { + this.method = method; + return this; + } + + public ManyParametersBuilder setSize(int size) { + this.size = size; + return this; + } + + public ManyParametersBuilder setData(byte[] data) { + this.data = data; + return this; + } + + public ManyParameters createManyParameters() { + return new ManyParameters(computerName, timeout, method, size, data); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/NtfyMessageDto.java b/src/main/java/com/example/NtfyMessageDto.java new file mode 100644 index 00000000..0a03f854 --- /dev/null +++ b/src/main/java/com/example/NtfyMessageDto.java @@ -0,0 +1,20 @@ +package com.example; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record NtfyMessageDto(String id, long time, String event, String topic, String message){ + private static final DateTimeFormatter date = + DateTimeFormatter.ofPattern("HH:mm"); + @Override + public String toString(){ + String timeStr = new SimpleDateFormat("HH:mm").format(new Date(time * 1000)); + return timeStr+ " " + message ; + } + + +} diff --git a/src/main/java/com/example/Singelton.java b/src/main/java/com/example/Singelton.java new file mode 100644 index 00000000..2ff0fa10 --- /dev/null +++ b/src/main/java/com/example/Singelton.java @@ -0,0 +1,11 @@ +package com.example; + +public class Singelton { + + private final static Singelton instance= new Singelton(); + + public static Singelton getInstance(){ + return instance; + } + +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 71574a27..649be1ab 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,6 +1,9 @@ module hellofx { requires javafx.controls; requires javafx.fxml; + requires io.github.cdimascio.dotenv.java; + requires java.net.http; + requires tools.jackson.databind; opens com.example to javafx.fxml; exports com.example; diff --git a/src/main/resources/com/example/hello-view.fxml b/src/main/resources/com/example/hello-view.fxml index 20a7dc82..667c7f1f 100644 --- a/src/main/resources/com/example/hello-view.fxml +++ b/src/main/resources/com/example/hello-view.fxml @@ -1,9 +1,22 @@ - - - - - - + + + + + +