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..507a44b4 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,22 @@ javafx-fxml ${javafx.version} + + io.github.cdimascio + dotenv-java + 3.2.0 + + + tools.jackson.core + jackson-databind + 3.0.1 + + + org.wiremock + wiremock + 4.0.0-beta.15 + test + diff --git a/src/main/java/com/example/HelloController.java b/src/main/java/com/example/HelloController.java index fdd160a0..5149dde8 100644 --- a/src/main/java/com/example/HelloController.java +++ b/src/main/java/com/example/HelloController.java @@ -1,22 +1,66 @@ package com.example; + 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; +import java.io.IOException; -/** - * Controller layer: mediates between the view (FXML) and the model. - */ public class HelloController { - private final HelloModel model = new HelloModel(); + public final HelloModel model = new HelloModel(new NtfyConnectionImpl()); + @FXML private ListView messageList; + @FXML private TextField inputField; + @FXML private Label fileLabel; + + private File selectedFile; + @FXML - private Label messageLabel; + public void initialize() { + messageList.setItems(model.getMessages()); + } + + + public void sendMessage() { + String message = inputField.getText().trim(); + if (!message.isEmpty()) { + model.setMessageToSend(message); + model.sendMessage(); + inputField.clear(); + } + if (selectedFile != null) { + try { + sendFileToServer(selectedFile); + fileLabel.setText("File sent successfully"); + } catch (IOException e) { + fileLabel.setText("Error sending file"); + } + } else { + fileLabel.setText("No file selected"); + } + } @FXML - private void initialize() { - if (messageLabel != null) { - messageLabel.setText(model.getGreeting()); + public void attachFile() { + FileChooser fileChooser = new FileChooser(); + fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Files", "*.*")); + selectedFile = fileChooser.showOpenDialog(new Stage()); + if (selectedFile != null) { + fileLabel.setText("Selected: " + selectedFile.getName()); + } else { + fileLabel.setText("No file selected"); } } + + + private void sendFileToServer(File file) throws IOException { + model.sendFileToServer(file); + } + + } diff --git a/src/main/java/com/example/HelloFX.java b/src/main/java/com/example/HelloFX.java index 96bdc5ca..fb3889a9 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 javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; @@ -10,15 +11,15 @@ public class HelloFX extends Application { @Override public void start(Stage stage) throws Exception { - FXMLLoader fxmlLoader = new FXMLLoader(HelloFX.class.getResource("hello-view.fxml")); + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("hello-view.fxml")); Parent root = fxmlLoader.load(); - Scene scene = new Scene(root, 640, 480); - stage.setTitle("Hello MVC"); + Scene scene = new Scene(root); + stage.setTitle("Tittle goes here"); stage.setScene(scene); stage.show(); } - public static void main(String[] args) { + static void main() { launch(); } diff --git a/src/main/java/com/example/HelloModel.java b/src/main/java/com/example/HelloModel.java index 385cfd10..41d7ff7b 100644 --- a/src/main/java/com/example/HelloModel.java +++ b/src/main/java/com/example/HelloModel.java @@ -1,15 +1,47 @@ package com.example; -/** - * Model layer: encapsulates application data and business logic. - */ +import javafx.application.Platform; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import java.io.File; +import java.io.IOException; + + public class HelloModel { - /** - * Returns a greeting based on the current Java and JavaFX versions. - */ - public String getGreeting() { - String javaVersion = System.getProperty("java.version"); - String javafxVersion = System.getProperty("javafx.version"); - return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + "."; + private final NtfyConnection connection; + + private final ObservableList messages = FXCollections.observableArrayList(); + private final StringProperty messageToSend = new SimpleStringProperty(); + + public HelloModel(NtfyConnection connection) { + this.connection = connection; + receiveMessage(); + } + + + public ObservableList getMessages() { + return messages; + } + + public void setMessageToSend(String message) { + this.messageToSend.set(message); } + + + public void sendMessage() { + connection.send(messageToSend.get()); + } + + public void sendFileToServer(File file) throws IOException { + connection.sendFile(file.toPath()); + } + + public void receiveMessage() { + connection.recieve(m-> Platform.runLater(()-> messages.add(m.message()))); + } + } + diff --git a/src/main/java/com/example/NtfyConnection.java b/src/main/java/com/example/NtfyConnection.java new file mode 100644 index 00000000..263b75fb --- /dev/null +++ b/src/main/java/com/example/NtfyConnection.java @@ -0,0 +1,14 @@ +package com.example; + +import java.io.FileNotFoundException; +import java.nio.file.Path; +import java.util.function.Consumer; + +public interface NtfyConnection { + + boolean send(String message); + + void recieve(Consumer messageHandler); + + boolean sendFile(Path filePath) throws FileNotFoundException; +} diff --git a/src/main/java/com/example/NtfyConnectionImpl.java b/src/main/java/com/example/NtfyConnectionImpl.java new file mode 100644 index 00000000..3cead2f4 --- /dev/null +++ b/src/main/java/com/example/NtfyConnectionImpl.java @@ -0,0 +1,82 @@ +package com.example; + + +import io.github.cdimascio.dotenv.Dotenv; +import tools.jackson.databind.ObjectMapper; +import java.io.FileNotFoundException; +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.nio.file.Path; +import java.util.Objects; +import java.util.function.Consumer; + +public class NtfyConnectionImpl implements NtfyConnection { + + private final HttpClient http = HttpClient.newHttpClient(); + private final String hostName; + private final ObjectMapper mapper = new ObjectMapper(); + + + public NtfyConnectionImpl() { + Dotenv dotenv = Dotenv.load(); + hostName= Objects.requireNonNull(dotenv.get("HOST_NAME")); + } + + public NtfyConnectionImpl(String hostName) { + this.hostName = hostName; + } + + @Override + public boolean send(String message) { + HttpRequest httpRequest = HttpRequest.newBuilder() + .POST(HttpRequest.BodyPublishers.ofString(message)) + .uri(URI.create(hostName + "/mytopic")) + .build(); + try { + http.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + return true; + } catch (IOException e) { + System.out.println("IOException"); + } catch (InterruptedException e){ + System.out.println("Interrupted"); + } + return false; + } + + + public boolean sendFile(Path filePath) throws FileNotFoundException { + HttpRequest httpRequest = HttpRequest.newBuilder() + .POST(HttpRequest.BodyPublishers.ofFile(filePath)) + .uri(URI.create(hostName + "/mytopic")) + .build(); + + try { + http.send(httpRequest, HttpResponse.BodyHandlers.ofFile(filePath)); + return true; + } catch (IOException e) { + System.out.println("IOException"); + } catch (InterruptedException e){ + System.out.println("Interrupted"); + } + return false; + } + + @Override + public void recieve(Consumer messageHandler) { + HttpRequest httpRequest = HttpRequest.newBuilder() + .GET() + .uri(URI.create(hostName + "/mytopic/json")) + .build(); + + http.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines()) + .thenAccept(response -> response.body() + .map(s-> mapper.readValue(s, NtfyMessageDto.class)) + .filter(message -> message.event().equals("message")) + .forEach(messageHandler)); + + + } +} diff --git a/src/main/java/com/example/NtfyMessageDto.java b/src/main/java/com/example/NtfyMessageDto.java new file mode 100644 index 00000000..c6e36d69 --- /dev/null +++ b/src/main/java/com/example/NtfyMessageDto.java @@ -0,0 +1,7 @@ +package com.example; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public record NtfyMessageDto(String id, long time, String event, String topic, String message){ +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 71574a27..23f3419e 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,6 +1,11 @@ module hellofx { requires javafx.controls; requires javafx.fxml; + requires java.desktop; + requires io.github.cdimascio.dotenv.java; + requires java.net.http; + requires tools.jackson.databind; + requires javafx.graphics; 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..b03c01a3 100644 --- a/src/main/resources/com/example/hello-view.fxml +++ b/src/main/resources/com/example/hello-view.fxml @@ -1,9 +1,20 @@ - - - - - - + + + + + + + + + + + +