-
Notifications
You must be signed in to change notification settings - Fork 66
Cat chat #11
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
Cat chat #11
Changes from all commits
b9609d5
987096f
d51aa39
c009b71
b77ad77
076ad6f
cee66a1
20e4f18
c138bca
9dc9c8a
be903fa
dad6cba
c506a01
6d1a71d
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 |
|---|---|---|
|
|
@@ -17,12 +17,29 @@ | |
| <javafx.version>25</javafx.version> | ||
| </properties> | ||
| <dependencies> | ||
|
|
||
| <dependency> | ||
| <groupId>tools.jackson.core</groupId> | ||
| <artifactId>jackson-databind</artifactId> | ||
| <version>3.0.1</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.github.cdimascio</groupId> | ||
| <artifactId>dotenv-java</artifactId> | ||
| <version>3.2.0</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.junit.jupiter</groupId> | ||
| <artifactId>junit-jupiter</artifactId> | ||
| <version>${junit.jupiter.version}</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.wiremock</groupId> | ||
| <artifactId>wiremock</artifactId> | ||
| <version>4.0.0-beta.15</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.assertj</groupId> | ||
| <artifactId>assertj-core</artifactId> | ||
|
|
@@ -45,6 +62,12 @@ | |
| <artifactId>javafx-fxml</artifactId> | ||
| <version>${javafx.version}</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.awaitility</groupId> | ||
| <artifactId>awaitility</artifactId> | ||
| <version>4.3.0</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| <build> | ||
| <plugins> | ||
|
|
@@ -63,6 +86,15 @@ | |
| <noManPages>true</noManPages> | ||
| </configuration> | ||
| </plugin> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-compiler-plugin</artifactId> | ||
| <configuration> | ||
| <source>25</source> | ||
| <target>25</target> | ||
| <compilerArgs>--enable-preview</compilerArgs> | ||
| </configuration> | ||
| </plugin> | ||
|
Comment on lines
+89
to
+97
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. 🧩 Analysis chainVerify the need for preview features. The compiler is configured to use Java 25 with 🏁 Script executed: #!/bin/bash
# Search for common Java preview features in the codebase
echo "Checking for record patterns, pattern matching, or other preview features..."
rg -n "instanceof.*\(|record.*\{|sealed|permits" --type javaLength of output: 222 🏁 Script executed: #!/bin/bash
# More comprehensive search for Java preview features
echo "=== Searching for switch pattern matching ==="
rg -n "switch.*{.*case.*->|case.*when" --type java -A 3
echo "=== Searching for sealed classes ==="
rg -n "sealed\s+class|sealed\s+interface" --type java
echo "=== Searching for text blocks ==="
rg -n '"""' --type java
echo "=== Searching for virtual threads or structured concurrency ==="
rg -n "Thread\.ofVirtual|ExecutorService|StructuredTaskScope" --type java
echo "=== Listing all .java files to get scope ==="
fd "\.java$" --type f | wc -lLength of output: 502 🌐 Web query: 💡 Result: Preview JEPs in JDK 25
Other notable non-preview experimental/incubator JEPs in JDK 25:
Sources: JDK 25 release notes and OpenJDK/Oracle announcements. [1][2][3] Remove the Verification confirms the codebase does not use any Java 25 preview features. The only preview-related element found is a record class (NtfyMessageDto.java), but records are a standard feature since Java 16 and do not require preview enablement. Text blocks in tests are also standard since Java 15. No actual preview features (JEP 470, 502, 505, 507) are used. Remove 🤖 Prompt for AI Agents |
||
| </plugins> | ||
| </build> | ||
| </project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,22 +1,148 @@ | ||
| package com.example; | ||
|
|
||
| import javafx.application.Platform; | ||
| import javafx.collections.ListChangeListener; | ||
| 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.VBox; | ||
|
|
||
| /** | ||
| * Controller layer: mediates between the view (FXML) and the model. | ||
| * Handles updates of the chat-window. | ||
| */ | ||
| public class HelloController { | ||
|
|
||
| private final HelloModel model = new HelloModel(); | ||
| //En model skapas som i bakgrunden är en lista och håller koll på meddelanden | ||
| private final HelloModel model = new HelloModel(new NtfyConnectionImpl()); | ||
|
|
||
| //@FXML kopplingar | ||
| @FXML | ||
| private Label messageLabel; | ||
| private Button connectToServer; | ||
|
|
||
| @FXML | ||
| private Button disconnectFromServer; | ||
|
|
||
| //Kopplar ett textfält från FXML där användaren skriver ett meddelande | ||
| @FXML | ||
| private TextField messageInput; | ||
|
|
||
| //Kopplar en knapp från FXML som klickas på för att skicka meddelandet | ||
| @FXML | ||
| private Button sendButton; | ||
|
|
||
|
|
||
| //Ytan för alla meddelanden som visas | ||
| @FXML | ||
| private ListView<NtfyMessageDto> chatBox; | ||
|
|
||
| //Metoden körs automatiskt när appen startar | ||
| @FXML | ||
| private void initialize() { | ||
| if (messageLabel != null) { | ||
| messageLabel.setText(model.getGreeting()); | ||
| //todo: Initialisera uppkopplingsknapparna för server-anslutning | ||
| //todo: metod för nätverksuppkoppling? | ||
|
|
||
| //Sätter ursprungstillståndet (default) för skicka-knappen | ||
|
|
||
| updateSendButtonState(); | ||
|
|
||
| //Lägger till en lyssnare för att uppdatera knappen vid inmatning av text | ||
| messageInput.textProperty().addListener((observable, oldValue, newValue) -> updateSendButtonState()); | ||
|
|
||
| //Om användaren trycker på Enter eller klickar med musen -> skicka meddelandet | ||
| messageInput.setOnAction((event) -> sendMessageToModel()); | ||
| sendButton.setOnAction(event -> sendMessageToModel()); | ||
|
|
||
| disconnectFromServer.setOnAction(event -> setDisconnectFromServer()); | ||
| connectToServer.setOnAction(event -> setConnectToServer()); | ||
|
|
||
| disconnectFromServer.setDisable(true); | ||
|
|
||
| //model.receiveMessage(); | ||
| //Styr hur varje meddelande ska visas i chatboxen | ||
| chatBox.setCellFactory(listView -> new ListCell<>() { | ||
| @Override | ||
| protected void updateItem(NtfyMessageDto item, boolean empty) { | ||
| super.updateItem(item, empty); | ||
| //Kräver en null check då JavaFX återanvänder cellerna | ||
| if (item == null || empty) { | ||
| setText(null); | ||
| setGraphic(null); | ||
| } | ||
| else{ | ||
| //Skapar en label med meddelande-texten och sätter en stil från css | ||
| Label label = new Label(item.message()); | ||
| label.getStyleClass().add("message-bubble"); | ||
|
|
||
| String time = item.formattedTime(); | ||
| Label labelTime = new Label(time); | ||
| labelTime.getStyleClass().add("time-stamp"); | ||
|
|
||
| //Layout | ||
| VBox messageBox = new VBox(label, labelTime); | ||
| messageBox.setSpacing(2); | ||
|
|
||
| //Vänster eller höger i ListView | ||
| HBox hbox = new HBox(messageBox); | ||
| hbox.setMaxWidth(chatBox.getWidth()-20); | ||
|
|
||
| String messagePosition = item.message(); | ||
| if (messagePosition != null && messagePosition.startsWith("User:")) { | ||
| hbox.setAlignment(javafx.geometry.Pos.CENTER_RIGHT); | ||
| label.getStyleClass().add("outgoing-message"); | ||
| } else { | ||
| hbox.setAlignment(javafx.geometry.Pos.CENTER_LEFT); | ||
| label.getStyleClass().add("incoming-message"); | ||
| } | ||
| setGraphic(hbox); | ||
| } | ||
| } | ||
| }); | ||
| //Kopplar Listan i view med ObservableList i HelloModel | ||
| chatBox.setItems(model.getMessages()); | ||
| //Flyttar Platform.runlater till controller på grund av runtimeexeption när tester körs, även för en mer solid MVC | ||
| model.getMessages().addListener((ListChangeListener<NtfyMessageDto>) changes -> { | ||
| chatBox.refresh(); | ||
| }); | ||
| } | ||
|
|
||
| private void sendMessageToModel() { | ||
| String outgoingMessage = messageInput.getText().trim(); | ||
| //Kontrollerar om text-fältet är tomt | ||
| if (!outgoingMessage.isEmpty()) { | ||
| model.sendMessage("User: " + outgoingMessage); | ||
| //tömmer sedan fältet där text matas in(prompt-meddelande visas igen) | ||
| messageInput.clear(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void updateSendButtonState() { | ||
| // Kollar om texten, efter att ha tagit bort ledande/efterföljande mellanslag, är tom. | ||
| boolean isTextPresent = !messageInput.getText().trim().isEmpty(); | ||
|
|
||
| //Nytt villkor för button för att ej kunna skicka meddelanden till servern om ej connectad | ||
| boolean isConnected = !disconnectFromServer.isDisabled(); | ||
|
|
||
| // Sätt disable till TRUE om det INTE finns text. | ||
| sendButton.setDisable(!isTextPresent || !isConnected); | ||
| } | ||
|
|
||
| //Starta prenumeration via model och uppdaterar button | ||
| public void setConnectToServer() { | ||
| if(disconnectFromServer.isDisable()) { | ||
| model.receiveMessage(); | ||
| connectToServer.setDisable(true); | ||
| disconnectFromServer.setDisable(false); | ||
| updateSendButtonState(); | ||
| } | ||
| } | ||
|
|
||
| //Stoppar prenumerationen och uppdaterar button | ||
| public void setDisconnectFromServer() { | ||
| model.stopSubscription(); | ||
| connectToServer.setDisable(false); | ||
| disconnectFromServer.setDisable(true); | ||
| updateSendButtonState(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,15 +1,86 @@ | ||||||||||||||||||||||||||||||||||
| package com.example; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| import io.github.cdimascio.dotenv.Dotenv; | ||||||||||||||||||||||||||||||||||
| 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.IOException; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Model layer: encapsulates application data and business logic. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public class HelloModel { | ||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Returns a greeting based on the current Java and JavaFX versions. | ||||||||||||||||||||||||||||||||||
| * Handles and returns a list of messages observed by JavaFX | ||||||||||||||||||||||||||||||||||
| * Stores, changes and returns data. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| public String getGreeting() { | ||||||||||||||||||||||||||||||||||
| String javaVersion = System.getProperty("java.version"); | ||||||||||||||||||||||||||||||||||
| String javafxVersion = System.getProperty("javafx.version"); | ||||||||||||||||||||||||||||||||||
| return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + "."; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| //Lista som håller alla meddelanden | ||||||||||||||||||||||||||||||||||
| //FXCollections.observableArrayList() = Nyckel som gör listan ändrings-bar och uppdaterar GUIt | ||||||||||||||||||||||||||||||||||
| private final ObservableList<NtfyMessageDto> messages = FXCollections.observableArrayList(); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| //Kopplar upp till nätverket , används för att skicka och ta emot meddelanden | ||||||||||||||||||||||||||||||||||
| private final NtfyConnection connection; | ||||||||||||||||||||||||||||||||||
| //Innehåller meddelandet som ska skickas, kopplat till GUI via SimpleStringProperty | ||||||||||||||||||||||||||||||||||
| private final StringProperty messageToSend = new SimpleStringProperty(); | ||||||||||||||||||||||||||||||||||
| //Fält för att kunna styra anslutningen | ||||||||||||||||||||||||||||||||||
| private Subscription subscription = null; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| //Konstruktorn tar emot nätverkskoppling, antingen ett test via spy eller en riktig via impl | ||||||||||||||||||||||||||||||||||
| public HelloModel(NtfyConnection connection) { | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| this.connection = connection; | ||||||||||||||||||||||||||||||||||
| //subscription = receiveMessage(); //subscription startar automatiskt när modellen skapas | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| //getter från private, används av controller för att koppla til ListView | ||||||||||||||||||||||||||||||||||
| public ObservableList<NtfyMessageDto> getMessages() { | ||||||||||||||||||||||||||||||||||
| return messages; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| //test | ||||||||||||||||||||||||||||||||||
| public String getMessageToSend() { | ||||||||||||||||||||||||||||||||||
| return messageToSend.get(); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| //Getter från private för meddelandet som ska skickas | ||||||||||||||||||||||||||||||||||
| public StringProperty messageToSendProperty() { | ||||||||||||||||||||||||||||||||||
| return messageToSend; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| //Sätter meddelande för tester | ||||||||||||||||||||||||||||||||||
| public void setMessageToSend(String message) { | ||||||||||||||||||||||||||||||||||
| messageToSend.set(message); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| //Sätter meddelandet till inkommande parameter från test, eller controller (connection skickar till nätverket) | ||||||||||||||||||||||||||||||||||
| public void sendMessage(String message) { | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| messageToSend.set(message); | ||||||||||||||||||||||||||||||||||
| connection.send(messageToSend.get()); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| //Startar en prenumeration på inkommande meddelnaden, | ||||||||||||||||||||||||||||||||||
| //Returnerar ett Subscription-objekt så den kan stoppas | ||||||||||||||||||||||||||||||||||
| public Subscription receiveMessage() { | ||||||||||||||||||||||||||||||||||
| if(subscription != null && subscription.isOpen()) { | ||||||||||||||||||||||||||||||||||
| return this.subscription; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| return subscription = connection.receive(messages::add); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| public void stopSubscription() { | ||||||||||||||||||||||||||||||||||
| if (subscription != null && subscription.isOpen()) | ||||||||||||||||||||||||||||||||||
| try{ | ||||||||||||||||||||||||||||||||||
| subscription.close(); | ||||||||||||||||||||||||||||||||||
| } catch(IOException e) { | ||||||||||||||||||||||||||||||||||
| System.out.println("Error closing subscription" + e.getMessage()); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+76
to
83
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. Fix error message formatting. Line 81 has a missing space in the error message concatenation, resulting in "Error closing subscription" instead of "Error closing subscription: ". Apply this diff: if (subscription != null && subscription.isOpen())
try{
subscription.close();
} catch(IOException e) {
- System.out.println("Error closing subscription" + e.getMessage());
+ System.out.println("Error closing subscription: " + e.getMessage());
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.example; | ||
|
|
||
|
|
||
| import java.nio.file.Path; | ||
| import java.util.function.Consumer; | ||
|
|
||
| public interface NtfyConnection { | ||
|
|
||
| //Skicka ett meddelande till servern | ||
| boolean send(String message); | ||
|
|
||
| boolean sendFile(Path file, String messageWithFile); | ||
|
|
||
| //Startar en prenumeration och tar emot en consumer som ska köras varje gång ett meddelande kommer | ||
| Subscription receive(Consumer<NtfyMessageDto> consumer); | ||
|
|
||
| } |
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.
Incorrect groupId for Jackson dependency.
The groupId
tools.jackson.coreis incorrect. The correct groupId for Jackson iscom.fasterxml.jackson.core.Apply this diff to fix the dependency:
Note: Jackson 3.x is still in alpha/beta. Using the stable 2.x version (2.18.2 is the latest stable) is recommended unless you specifically need 3.x features.
📝 Committable suggestion
🤖 Prompt for AI Agents