-
Notifications
You must be signed in to change notification settings - Fork 67
labb3 #17
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
Closed
Closed
labb3 #17
Changes from 14 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
b83bd2c
Add chat functionality, UI enhancements, and first update controller …
annikaholmqvist94 67cc5f2
Update .gitignore
annikaholmqvist94 1b9b0b8
Implement message sending/receiving logic with Ntfy integration and u…
annikaholmqvist94 d3a2149
Add file attachment button and stub method in controller
annikaholmqvist94 6584d5b
Implement file upload functionality with Ntfy integration
annikaholmqvist94 17546f9
Add unit tests for message receiving and file sending
annikaholmqvist94 e80bd27
Refactor `HelloModel` for JavaFX thread update tests for enhanced mes…
annikaholmqvist94 a69df76
Add validation for empty or whitespace messages in `HelloModel.sendMe…
annikaholmqvist94 0877a20
Add topic-based messaging and file sharing with dynamic UI updates an…
annikaholmqvist94 37fe2ce
Add support for dynamic topic selection update tests and model logic…
annikaholmqvist94 32adbde
Add fixed-topic chat functionality, update file sending message/file …
annikaholmqvist94 fe3d0d0
update tests for enhanced verification and UI consistency.
annikaholmqvist94 fc0902a
update tests for enhanced verification and UI consistency.
annikaholmqvist94 0afcc08
update tests for enhanced verification and UI consistency.
annikaholmqvist94 065761a
Add Javadoc comments for improved code clarity and maintainability.
annikaholmqvist94 e04e60b
Refactor `HelloModel` to enhance async message/file sending logic and…
annikaholmqvist94 10acd5d
Add `HOST_NAME` validation in `HelloController` and improve error han…
annikaholmqvist94 5b0a5bf
Improve file attachment handling in `HelloController`, enhance error …
annikaholmqvist94 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| target/ | ||
| /.idea/ | ||
| .env |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,22 +1,158 @@ | ||
| package com.example; | ||
|
|
||
| import javafx.beans.binding.Bindings; | ||
| import javafx.collections.FXCollections; | ||
| import javafx.event.ActionEvent; | ||
| import javafx.fxml.FXML; | ||
| import javafx.scene.control.Label; | ||
| import javafx.geometry.Pos; | ||
| import javafx.scene.control.*; | ||
| import javafx.scene.layout.HBox; | ||
| import javafx.scene.layout.Priority; | ||
| import javafx.scene.text.TextFlow; | ||
| import javafx.stage.FileChooser; | ||
| import javafx.stage.Stage; | ||
|
|
||
| import java.io.File; | ||
| import java.io.FileNotFoundException; | ||
| import java.util.Arrays; | ||
|
|
||
| /** | ||
| * Controller layer: mediates between the view (FXML) and the model. | ||
| */ | ||
| public class HelloController { | ||
|
|
||
| private final HelloModel model = new HelloModel(); | ||
| // Uppdaterad för att använda den externa Ntfy-servern: https://ntfy.fungover.org | ||
| // Topicen "mytopic" läggs till automatiskt av modellen. | ||
| private final HelloModel model = new HelloModel(new NtfyConnectionImpl("https://ntfy.fungover.org")); | ||
|
|
||
| @FXML | ||
| public ListView<NtfyMessageDto> chatListView; | ||
| @FXML | ||
| public Label topicLabel; | ||
|
|
||
| @FXML | ||
| public Label attachedFileLabel; | ||
|
|
||
| @FXML | ||
| private Label messageLabel; | ||
| private Button sendButton; | ||
|
|
||
| @FXML | ||
| private TextField messageInput; | ||
|
|
||
| @FXML | ||
| private Button attachFile; | ||
|
|
||
| @FXML | ||
| private void initialize() { | ||
| if (messageLabel != null) { | ||
| messageLabel.setText(model.getGreeting()); | ||
| if (sendButton != null) { | ||
| sendButton.setText(model.getGreeting()); | ||
|
|
||
| // Bindning: Knappen är inaktiverad ENDAST om BÅDE meddelandet är tomt OCH fil inte är bifogad | ||
| sendButton.disableProperty().bind( | ||
| Bindings.createBooleanBinding(() -> { | ||
| boolean isMessageEmpty = model.messageToSendProperty().get() == null || | ||
| model.messageToSendProperty().get().trim().isEmpty(); | ||
| boolean isFileNotAttached = model.fileToSendProperty().get() == null; | ||
|
|
||
| return isMessageEmpty && isFileNotAttached; | ||
| }, | ||
| model.messageToSendProperty(), | ||
| model.fileToSendProperty()) | ||
| ); | ||
| } | ||
|
|
||
| if (topicLabel != null) { | ||
| // Visar den fasta topicen | ||
| topicLabel.textProperty().bind( | ||
| Bindings.concat("Fixed Topic: ", model.currentTopicProperty()) | ||
| ); | ||
| } | ||
|
|
||
| // Hanterar visning av bifogad fil | ||
| if (attachedFileLabel != null) { | ||
| model.fileToSendProperty().addListener((obs, oldFile, newFile) -> { | ||
| if (newFile != null) { | ||
| attachedFileLabel.setText("Attached file: " + newFile.getName()); | ||
| attachedFileLabel.setStyle("-fx-font-style: italic;" + | ||
| " -fx-font-size: 12px;" + | ||
| " -fx-text-fill: #008000;"); | ||
| } else { | ||
| attachedFileLabel.setText("No file attached"); | ||
| attachedFileLabel.setStyle("-fx-font-style: italic; " + | ||
| "-fx-font-size: 12px; " + | ||
| "-fx-text-fill: #333;"); | ||
| } | ||
| }); | ||
| attachedFileLabel.setText("No file attached"); | ||
| } | ||
|
|
||
| if (messageInput!=null){ | ||
| messageInput.textProperty().bindBidirectional(model.messageToSendProperty()); | ||
| } | ||
|
|
||
| if(chatListView!=null){ | ||
| chatListView.setItems(model.getMessages()); | ||
| // Använd den enkla CellFactoryn | ||
| chatListView.setCellFactory(param -> new SimpleMessageCell()); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * En mycket enkel ListCell som enbart visar texten utan anpassad layout (bubblor/färger) | ||
| * men hanterar att visa "[File Uploaded]" när meddelandetexten är tom. | ||
| */ | ||
| private static class SimpleMessageCell extends ListCell<NtfyMessageDto> { | ||
|
|
||
| @Override | ||
| protected void updateItem(NtfyMessageDto item, boolean empty) { | ||
| super.updateItem(item, empty); | ||
|
|
||
| if (empty || item == null) { | ||
| setText(null); | ||
| setGraphic(null); | ||
| setStyle(null); | ||
| } else { | ||
| // Hämta meddelandet eller visa filstatus om meddelandet är tomt | ||
| String displayMessage = item.message() != null && !item.message().trim().isEmpty() | ||
| ? item.message() | ||
| : (item.event().equals("file") ? "[File Uploaded]" : ""); | ||
|
|
||
| // Lägg till prefix för att visa om det är skickat lokalt | ||
| String prefix = item.isLocal() ? "(Sent) " : ""; | ||
|
|
||
| setText(prefix + displayMessage); | ||
| setGraphic(null); | ||
|
|
||
| // Mycket enkel stil utan bubblor/färger. Använd standard utseende. | ||
| setStyle(null); | ||
| } | ||
| } | ||
| } | ||
|
annikaholmqvist94 marked this conversation as resolved.
|
||
|
|
||
| @FXML | ||
| protected void sendMessage() { | ||
| if (model.fileToSendProperty().get() != null) { | ||
| // Om en fil är bifogad, skicka filen och rensa bilagan i modellen | ||
| model.sendFile(); | ||
| } else { | ||
| // Annars, skicka textmeddelandet | ||
| model.sendMessage(); | ||
| } | ||
|
|
||
| if (messageInput!=null){ | ||
| messageInput.requestFocus(); | ||
| } | ||
| } | ||
|
|
||
| @FXML | ||
| protected void attachFile() { | ||
| // Hämta scenen från en av kontrollerna | ||
| Stage stage = (Stage) (chatListView.getScene().getWindow()); | ||
|
|
||
| FileChooser fileChooser = new FileChooser(); | ||
| fileChooser.setTitle("Choose file to attach"); | ||
|
|
||
| File selectedFile = fileChooser.showOpenDialog(stage); | ||
|
|
||
| if (selectedFile != null) { | ||
| model.setFileToSend(selectedFile); | ||
| } | ||
|
annikaholmqvist94 marked this conversation as resolved.
|
||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,154 @@ | ||
| package com.example; | ||
|
|
||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import io.github.cdimascio.dotenv.Dotenv; | ||
| import javafx.application.Platform; | ||
| import javafx.beans.InvalidationListener; | ||
| import javafx.beans.property.ObjectProperty; | ||
| import javafx.beans.property.SimpleObjectProperty; | ||
| import javafx.beans.property.SimpleStringProperty; | ||
| import javafx.beans.property.StringProperty; | ||
| import javafx.collections.FXCollections; | ||
| import javafx.collections.ListChangeListener; | ||
| import javafx.collections.ObservableList; | ||
|
|
||
| import java.io.File; | ||
| 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.time.LocalDate; | ||
| import java.time.format.DateTimeFormatter; | ||
| import java.util.*; | ||
| import java.util.concurrent.Executors; | ||
| import java.util.concurrent.ScheduledExecutorService; | ||
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| /** | ||
| * Model layer: encapsulates application data and business logic. | ||
| */ | ||
| public class HelloModel { | ||
| /** | ||
| * Returns a greeting based on the current Java and JavaFX versions. | ||
| */ | ||
| private final NtfyConnection connection; | ||
| private final StringProperty messageToSend = new SimpleStringProperty(""); | ||
| private final StringProperty currentTopic = new SimpleStringProperty("mytopic"); | ||
| private final ObservableList<NtfyMessageDto> messages = FXCollections.observableArrayList(); | ||
| private final ObjectProperty<File> fileToSend = new SimpleObjectProperty<>(null); // Ny egenskap för filbilaga | ||
|
|
||
| public HelloModel(NtfyConnection connection) { | ||
| this.connection = connection; | ||
| connection.connect(currentTopic.get(), this::receiveMessage); | ||
| } | ||
|
|
||
| public String getGreeting() { | ||
| String javaVersion = System.getProperty("java.version"); | ||
| String javafxVersion = System.getProperty("javafx.version"); | ||
| return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + "."; | ||
| return "Skicka meddelande"; | ||
| } | ||
|
|
||
| // NY METOD: Hanterar att köra koden på JavaFX-tråden ELLER direkt i testmiljö | ||
| private static void runOnFx(Runnable task) { | ||
| try { | ||
| if (Platform.isFxApplicationThread()) task.run(); | ||
| else Platform.runLater(task); | ||
| } catch (IllegalStateException notInitialized) { | ||
| // JavaFX toolkit not initialized (e.g., unit tests or CI without graphics): run inline | ||
| task.run(); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| public void sendMessage() { | ||
| String message = messageToSend.get(); | ||
| if (message != null && !message.trim().isEmpty()) { | ||
|
|
||
| // 1. Skapa den lokala DTO:n (med isLocal = true) | ||
| NtfyMessageDto localMessage = new NtfyMessageDto( | ||
| UUID.randomUUID().toString(), | ||
| System.currentTimeMillis() / 1000L, | ||
| "message", | ||
| currentTopic.get(), | ||
| message.trim(), | ||
| true // Markera som lokalt skickat | ||
| ); | ||
|
|
||
| // 2. Lägg till i listan (UI-uppdatering) PÅ RÄTT TRÅD | ||
| runOnFx(() -> messages.add(localMessage)); | ||
|
|
||
| // 3. Skicka meddelandet via anslutningen | ||
| connection.send(message, currentTopic.get()); | ||
|
|
||
| // 4. Rensa meddelandefältet efter skickning | ||
| messageToSend.set(""); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
|
annikaholmqvist94 marked this conversation as resolved.
|
||
|
|
||
| // Argumentlös metod, som controlleren använder för att skicka den bifogade filen | ||
| public void sendFile() { | ||
| File file = fileToSend.get(); | ||
| if (file != null) { | ||
|
|
||
| // 1. Skapa den lokala DTO:n för fil (ofta med tom message) | ||
| NtfyMessageDto localFileMessage = new NtfyMessageDto( | ||
| UUID.randomUUID().toString(), | ||
| System.currentTimeMillis() / 1000L, | ||
| "file", // Använd "file" event om det är en fil | ||
| currentTopic.get(), | ||
| "Fil skickad: " + file.getName(), // Detta meddelande visas bara i logik, CellFactory hanterar visning | ||
| true | ||
| ); | ||
|
|
||
| // 2. Lägg till i listan (UI-uppdatering) PÅ RÄTT TRÅD | ||
| runOnFx(() -> messages.add(localFileMessage)); | ||
|
|
||
| // 3. Skicka filen | ||
| connection.sendFile(file, currentTopic.get()); | ||
|
|
||
| // 4. Rensa filbilagan efter skickning | ||
| fileToSend.set(null); | ||
| } | ||
| } | ||
|
annikaholmqvist94 marked this conversation as resolved.
|
||
|
|
||
| // Används av HelloController för att hämta filbilagan | ||
| public ObjectProperty<File> fileToSendProperty() { | ||
| return fileToSend; | ||
| } | ||
|
|
||
| // Används av HelloController för att ställa in filbilagan | ||
| public void setFileToSend(File file) { | ||
| this.fileToSend.set(file); | ||
| } | ||
|
|
||
| private void receiveMessage(NtfyMessageDto message) { | ||
| // ANVÄNDER runOnFx FÖR ATT SÄKRA ATT UPPDATERINGEN SKER PÅ RÄTT TRÅD (eller direkt i testmiljö) | ||
| runOnFx(() -> messages.add(message)); | ||
| } | ||
|
|
||
| public ObservableList<NtfyMessageDto> getMessages() { | ||
| return messages; | ||
| } | ||
|
|
||
| public StringProperty messageToSendProperty() { | ||
| return messageToSend; | ||
| } | ||
|
|
||
| public StringProperty currentTopicProperty() { | ||
| return currentTopic; | ||
| } | ||
|
|
||
| public void reconnectToTopic(String newTopic) { | ||
| if (!currentTopic.get().equals(newTopic)) { | ||
| // connection.disconnect(currentTopic.get()); // Förutsätter att disconnect implementeras i NtfyConnection | ||
| currentTopic.set(newTopic); | ||
|
|
||
| // Säkerställ att rensningen sker på FX-tråden om vi kör i en FX-miljö | ||
| runOnFx(messages::clear); | ||
|
|
||
| connection.connect(newTopic, this::receiveMessage); | ||
| } | ||
| } | ||
|
|
||
| // KORRIGERAD: Denna metod måste ta en String för att matcha testet! | ||
| public void setMessageToSend(String message) { | ||
| this.messageToSend.set(message); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.