Skip to content

Commit eac6bfa

Browse files
committed
Färdig JavaFX chat app med tester
1 parent 21c51e8 commit eac6bfa

7 files changed

Lines changed: 128 additions & 34 deletions

File tree

mvnw

100644100755
File mode changed.
Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
package com.example;
22

33
import javafx.fxml.FXML;
4-
import javafx.scene.control.Label;
4+
import javafx.scene.control.TextArea;
5+
import javafx.scene.control.TextField;
56

6-
/**
7-
* Controller layer: mediates between the view (FXML) and the model.
8-
*/
97
public class HelloController {
8+
@FXML private TextArea chatArea;
9+
@FXML private TextField inputField;
1010

11-
private final HelloModel model = new HelloModel();
11+
private HelloModel model;
1212

1313
@FXML
14-
private Label messageLabel;
14+
public void initialize() {
15+
model = new HelloModel("javafx-chat"); // Du kan byta topic-namnet
16+
model.listen(msg -> chatArea.appendText(msg + "\n"));
17+
}
1518

1619
@FXML
17-
private void initialize() {
18-
if (messageLabel != null) {
19-
messageLabel.setText(model.getGreeting());
20+
public void onSendButtonClick() {
21+
String text = inputField.getText().trim();
22+
if (!text.isEmpty()) {
23+
model.sendMessage(text);
24+
inputField.clear();
2025
}
2126
}
2227
}

src/main/java/com/example/HelloFX.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,20 @@
22

33
import javafx.application.Application;
44
import javafx.fxml.FXMLLoader;
5-
import javafx.scene.Parent;
65
import javafx.scene.Scene;
76
import javafx.stage.Stage;
87

98
public class HelloFX extends Application {
10-
119
@Override
1210
public void start(Stage stage) throws Exception {
1311
FXMLLoader fxmlLoader = new FXMLLoader(HelloFX.class.getResource("hello-view.fxml"));
14-
Parent root = fxmlLoader.load();
15-
Scene scene = new Scene(root, 640, 480);
16-
stage.setTitle("Hello MVC");
12+
Scene scene = new Scene(fxmlLoader.load());
13+
stage.setTitle("JavaFX Chat App 💬");
1714
stage.setScene(scene);
1815
stage.show();
1916
}
2017

2118
public static void main(String[] args) {
2219
launch();
2320
}
24-
25-
}
21+
}
Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,52 @@
11
package com.example;
22

3-
/**
4-
* Model layer: encapsulates application data and business logic.
5-
*/
3+
import java.net.URI;
4+
import java.net.http.HttpClient;
5+
import java.net.http.HttpRequest;
6+
import java.net.http.HttpResponse;
7+
import java.util.concurrent.CompletableFuture;
8+
69
public class HelloModel {
7-
/**
8-
* Returns a greeting based on the current Java and JavaFX versions.
9-
*/
10-
public String getGreeting() {
11-
String javaVersion = System.getProperty("java.version");
12-
String javafxVersion = System.getProperty("javafx.version");
13-
return "Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".";
10+
private final HttpClient client = HttpClient.newHttpClient();
11+
private final String topic;
12+
private final String backendUrl;
13+
14+
public HelloModel(String topic) {
15+
this.topic = topic;
16+
this.backendUrl = System.getenv("BACKEND_URL");
17+
if (backendUrl == null) {
18+
throw new IllegalStateException("BACKEND_URL is not set!");
19+
}
20+
}
21+
22+
public void sendMessage(String message) {
23+
String json = "{\"message\": \"" + message + "\"}";
24+
String url = backendUrl + "/" + topic;
25+
26+
HttpRequest request = HttpRequest.newBuilder()
27+
.uri(URI.create(url))
28+
.header("Content-Type", "application/json")
29+
.POST(HttpRequest.BodyPublishers.ofString(json))
30+
.build();
31+
32+
client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
33+
}
34+
35+
public CompletableFuture<Void> listen(MessageHandler handler) {
36+
String url = backendUrl + "/" + topic + "/json";
37+
HttpRequest request = HttpRequest.newBuilder()
38+
.uri(URI.create(url))
39+
.build();
40+
41+
return client.sendAsync(request, HttpResponse.BodyHandlers.ofLines())
42+
.thenAccept(response -> response.body().forEach(line -> {
43+
if (line.contains("\"message\"")) {
44+
handler.onMessage(line);
45+
}
46+
}));
47+
}
48+
49+
public interface MessageHandler {
50+
void onMessage(String message);
1451
}
1552
}

src/main/java/module-info.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
module hellofx {
22
requires javafx.controls;
33
requires javafx.fxml;
4+
requires java.net.http;
45

56
opens com.example to javafx.fxml;
67
exports com.example;
7-
}
8+
}
Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,26 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<?import javafx.scene.layout.StackPane?>
3-
<?import javafx.scene.control.Label?>
2+
<?import javafx.scene.control.*?>
3+
<?import javafx.scene.layout.*?>
4+
<?import javafx.geometry.Insets?>
45

5-
<StackPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="com.example.HelloController">
6-
<children>
7-
<Label fx:id="messageLabel" text="Hello, JavaFX!" />
8-
</children>
9-
</StackPane>
6+
<BorderPane xmlns:fx="http://javafx.com/fxml"
7+
fx:controller="com.example.HelloController">
8+
9+
<center>
10+
<TextArea fx:id="chatArea"
11+
editable="false"
12+
prefHeight="400"
13+
prefWidth="600"/>
14+
</center>
15+
16+
<bottom>
17+
<!-- ✅ Rätt sätt att skriva padding i JavaFX 25 -->
18+
<HBox spacing="10">
19+
<padding>
20+
<Insets top="10" right="10" bottom="10" left="10"/>
21+
</padding>
22+
<TextField fx:id="inputField" HBox.hgrow="ALWAYS"/>
23+
<Button text="Send" onAction="#onSendButtonClick"/>
24+
</HBox>
25+
</bottom>
26+
</BorderPane>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.example;
2+
3+
import org.junit.jupiter.api.Test;
4+
import static org.junit.jupiter.api.Assertions.*;
5+
6+
public class HelloModelTest {
7+
8+
@Test
9+
void testModelInitialization() {
10+
// Försök skapa modellen, hantera fel ifall BACKEND_URL saknas
11+
try {
12+
HelloModel model = new HelloModel("test-topic");
13+
assertNotNull(model, "Model should be created successfully");
14+
} catch (IllegalStateException e) {
15+
// Om miljövariabeln saknas ska felet ha rätt meddelande
16+
assertTrue(e.getMessage().contains("BACKEND_URL"), "Exception should mention BACKEND_URL");
17+
}
18+
}
19+
20+
@Test
21+
void testBackendUrlDefault() {
22+
// Testar att miljövariabeln hanteras
23+
String backendUrl = System.getenv("BACKEND_URL");
24+
if (backendUrl == null || backendUrl.isBlank()) {
25+
backendUrl = "https://ntfy.sh";
26+
}
27+
assertTrue(backendUrl.startsWith("https://"), "BACKEND_URL should start with https://");
28+
}
29+
30+
@Test
31+
void testSendMessageFormatting() {
32+
String userMessage = "Hej världen!";
33+
String formatted = "{\"message\": \"" + userMessage + "\"}";
34+
assertTrue(formatted.contains("Hej världen!"));
35+
assertTrue(formatted.contains("{"));
36+
assertTrue(formatted.contains("}"));
37+
}
38+
}

0 commit comments

Comments
 (0)