Skip to content

Commit 05dae89

Browse files
committed
omstruktion, fortsatt felsök varför autograding crashar
1 parent ffa9303 commit 05dae89

14 files changed

Lines changed: 707 additions & 398 deletions

src/main/java/com/example/FxUtils.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44

55
public class FxUtils {
66

7-
public static void runOnFx(Runnable task) {
7+
/**
8+
* Execute task on FX-thread if possible, otherwise inline.
9+
*/
10+
static void runOnFx(Runnable task) {
811
try {
9-
if (Platform.isFxApplicationThread()) {
10-
task.run();
11-
} else {
12-
Platform.runLater(task);
13-
}
14-
} catch (Exception e) {
15-
//fallback for headless environments
12+
if (Platform.isFxApplicationThread()) task.run();
13+
else Platform.runLater(task);
14+
} catch (IllegalStateException notInitialized) {
1615
task.run();
1716
}
1817
}
Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,153 @@
11
package com.example;
22

33
import javafx.application.Platform;
4+
import javafx.beans.binding.Bindings;
45
import javafx.event.ActionEvent;
56
import javafx.fxml.FXML;
7+
import javafx.geometry.Insets;
8+
import javafx.geometry.Pos;
69
import javafx.scene.control.*;
7-
import java.time.Instant;
10+
import javafx.scene.layout.HBox;
11+
812
import java.time.ZoneId;
913
import java.time.format.DateTimeFormatter;
1014

15+
/**
16+
* Controller layer: mediates between the view (FXML) and the model.
17+
*/
18+
1119
public class HelloController {
1220

1321
private final HelloModel model = new HelloModel(new NtfyConnectionImpl());
1422

15-
@FXML private Label messageLabel;
16-
@FXML private ListView<NtfyMessageDto> messageView;
17-
@FXML private TextArea messageInput;
23+
@FXML
24+
private Button sendButton;
25+
26+
@FXML
27+
private Label messageLabel;
28+
29+
@FXML
30+
private Label topicLabel;
31+
32+
@FXML
33+
private ListView<NtfyMessageDto> messageView;
34+
35+
@FXML
36+
private TextArea messageInput;
37+
38+
@FXML
39+
private TextField topicInput;
40+
41+
@FXML
42+
private Button changeTopicButton;
1843

1944
private final DateTimeFormatter timeFormatter =
20-
DateTimeFormatter.ofPattern("HH:mm:ss").withZone(ZoneId.systemDefault());
45+
DateTimeFormatter.ofPattern("HH:mm:ss")
46+
.withZone(ZoneId.systemDefault());
2147

2248
@FXML
2349
private void initialize() {
24-
//visa välkomstmeddelande
2550
messageLabel.setText(model.getGreeting());
2651

52+
Platform.runLater(() -> messageInput.requestFocus());
53+
54+
topicLabel.setText("/" + model.getCurrentTopic());
55+
model.currentTopicProperty().addListener((obs, oldVal, newVal) -> {
56+
topicLabel.setText("/" + newVal);
57+
});
58+
2759
messageView.setItems(model.getMessages());
2860

2961
messageInput.textProperty().bindBidirectional(model.messageToSendProperty());
3062

31-
//formatera meddelanden i ListView
63+
sendButton.disableProperty().bind(Bindings.createBooleanBinding(
64+
() -> {
65+
String text = messageInput.getText();
66+
return text == null || text.trim().isEmpty();
67+
},
68+
messageInput.textProperty()
69+
));
70+
71+
if (changeTopicButton != null) {
72+
changeTopicButton.disableProperty().bind(Bindings.createBooleanBinding(
73+
() -> {
74+
String text = topicInput.getText();
75+
return text == null || text.trim().isEmpty();
76+
},
77+
topicInput.textProperty()
78+
));
79+
}
80+
81+
3282
messageView.setCellFactory(lv -> new ListCell<>() {
3383
@Override
3484
protected void updateItem(NtfyMessageDto msg, boolean empty) {
3585
super.updateItem(msg, empty);
36-
if (empty || msg == null) {
86+
87+
if (empty || msg == null || msg.message() == null || msg.message().isBlank()) {
3788
setText(null);
89+
setGraphic(null);
3890
} else {
39-
setText("[" + timeFormatter.format(Instant.ofEpochMilli(msg.time())) + "] " + msg.message());
91+
// Skapa bubble-label
92+
Label bubble = new Label(msg.message());
93+
bubble.setWrapText(true);
94+
bubble.setMaxWidth(250);
95+
bubble.setPadding(new Insets(10));
96+
bubble.getStyleClass().add("chat-bubble"); // Basstyle
97+
98+
HBox container = new HBox(bubble);
99+
container.setPadding(new Insets(5));
100+
101+
// Använd CSS-klasser för skickat/mottaget
102+
if (model.getUserId().equals(msg.id())) {
103+
bubble.getStyleClass().add("chat-bubble-sent");
104+
container.setAlignment(Pos.CENTER_RIGHT);
105+
} else {
106+
bubble.getStyleClass().add("chat-bubble-received");
107+
container.setAlignment(Pos.CENTER_LEFT);
108+
}
109+
110+
setText(null);
111+
setGraphic(container);
40112
}
41113
}
42114
});
43115

44-
// Scrolla automatiskt till senaste meddelandet
116+
117+
// Scrolla ner till senaste meddelandet
45118
model.getMessages().addListener((javafx.collections.ListChangeListener<NtfyMessageDto>) change -> {
46-
while (change.next()) {
47-
if (change.wasAdded()) {
48-
Platform.runLater(() -> {
49-
int size = messageView.getItems().size();
50-
if (size > 0) {
51-
messageView.scrollTo(size - 1);
52-
}
53-
});
119+
Platform.runLater(() -> {
120+
if (!messageView.getItems().isEmpty()) {
121+
messageView.scrollTo(messageView.getItems().size() - 1);
54122
}
55-
}
123+
});
56124
});
57125
}
58126

59127
@FXML
60-
private void sendMessage(ActionEvent event) {
61-
//skicka asynkront – HelloModel hanterar rensning och callback
128+
private void sendMessage(ActionEvent actionEvent) {
62129
model.sendMessageAsync(success -> {
63-
if (!success) {
130+
if (success) {
131+
Platform.runLater(() -> messageInput.clear());
132+
Platform.runLater(() -> messageInput.requestFocus());
133+
} else {
64134
Platform.runLater(() -> {
65-
Alert alert = new Alert(Alert.AlertType.ERROR, "Kunde inte skicka meddelandet.");
66-
alert.show();
135+
Alert alert = new Alert(Alert.AlertType.ERROR);
136+
alert.setTitle("Send Failed");
137+
alert.setHeaderText("Failed to send message");
138+
alert.setContentText("Could not send your message. Please try again.");
139+
alert.showAndWait();
67140
});
68141
}
69142
});
70143
}
144+
145+
@FXML
146+
private void changeTopic(ActionEvent actionEvent) {
147+
String newTopic = topicInput.getText();
148+
if (newTopic != null && !newTopic.isBlank()) {
149+
model.setCurrentTopic(newTopic);
150+
topicInput.clear();
151+
}
152+
}
71153
}

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,24 @@
66
import javafx.scene.Scene;
77
import javafx.stage.Stage;
88

9+
import java.util.Objects;
10+
911
public class HelloFX extends Application {
1012

1113
@Override
1214
public void start(Stage stage) throws Exception {
1315
FXMLLoader fxmlLoader = new FXMLLoader(HelloFX.class.getResource("hello-view.fxml"));
1416
Parent root = fxmlLoader.load();
15-
Scene scene = new Scene(root, 1280, 480);
16-
stage.setTitle("Hello MVC");
17+
18+
Scene scene = new Scene(root, 768, 576);
19+
stage.setTitle("RuneChat");
20+
21+
scene.getStylesheets().add(Objects.requireNonNull(HelloFX.class.getResource("style.css")).toExternalForm());
22+
1723
stage.setScene(scene);
1824
stage.show();
25+
26+
1927
}
2028

2129
public static void main(String[] args) {
Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package com.example;
22

3+
import javafx.application.Platform;
34
import javafx.beans.property.SimpleStringProperty;
45
import javafx.beans.property.StringProperty;
56
import javafx.collections.FXCollections;
67
import javafx.collections.ObservableList;
8+
79
import java.util.function.Consumer;
810

911
import static com.example.FxUtils.runOnFx;
@@ -12,31 +14,65 @@ public class HelloModel {
1214

1315
private final NtfyConnection connection;
1416
private final ObservableList<NtfyMessageDto> messages = FXCollections.observableArrayList();
15-
private final StringProperty messageToSend = new SimpleStringProperty("");
17+
private final StringProperty messageToSend = new SimpleStringProperty();
18+
private final StringProperty currentTopic = new SimpleStringProperty();
1619

1720
public HelloModel(NtfyConnection connection) {
1821
this.connection = connection;
19-
startReceiving();
22+
this.currentTopic.set(connection.getCurrentTopic());
23+
receiveMessage();
2024
}
2125

22-
private void startReceiving() {
23-
connection.receive(incoming -> {
24-
if (!isValidMessage(incoming)) {
25-
return;
26-
}
27-
runOnFx(() -> messages.add(incoming));
28-
});
26+
public ObservableList<NtfyMessageDto> getMessages() {
27+
return messages;
28+
}
29+
30+
public String getMessageToSend() {
31+
return messageToSend.get();
32+
}
33+
34+
public StringProperty messageToSendProperty() {
35+
return messageToSend;
36+
}
37+
38+
public void setMessageToSend(String message) {
39+
messageToSend.set(message);
40+
}
41+
42+
public String getCurrentTopic() {
43+
return currentTopic.get();
44+
}
45+
46+
public StringProperty currentTopicProperty() {
47+
return currentTopic;
48+
}
49+
50+
public void setCurrentTopic(String topic) {
51+
if (topic != null && !topic.isBlank()) {
52+
connection.setCurrentTopic(topic);
53+
this.currentTopic.set(topic);
54+
messages.clear();
55+
receiveMessage();
56+
}
57+
}
58+
59+
public String getUserId() {
60+
return connection.getUserId();
2961
}
3062

31-
private boolean isValidMessage(NtfyMessageDto message) {
32-
return message != null
33-
&& message.message() != null
34-
&& !message.message().isBlank();
63+
public String getGreeting() {
64+
return "RuneChat";
65+
}
66+
67+
public boolean canSendMessage() {
68+
String msg = messageToSend.get();
69+
return msg != null && !msg.isBlank();
3570
}
3671

3772
public void sendMessageAsync(Consumer<Boolean> callback) {
3873
String msg = messageToSend.get();
3974
if (msg == null || msg.isBlank()) {
75+
System.out.println("Nothing to send!");
4076
callback.accept(false);
4177
return;
4278
}
@@ -48,28 +84,20 @@ public void sendMessageAsync(Consumer<Boolean> callback) {
4884
messageToSend.set("");
4985
}
5086
});
87+
callback.accept(true);
88+
} else {
89+
System.out.println("Failed to send message!");
90+
callback.accept(false);
5191
}
52-
callback.accept(success);
5392
});
5493
}
5594

56-
public ObservableList<NtfyMessageDto> getMessages() {
57-
return messages;
58-
}
59-
60-
public String getMessageToSend() {
61-
return messageToSend.get();
62-
}
63-
64-
public StringProperty messageToSendProperty() {
65-
return messageToSend;
95+
public void receiveMessage() {
96+
connection.receive(m -> {
97+
if (m == null || m.message() == null || m.message().isBlank()) return;
98+
runOnFx(() -> messages.add(m));
99+
});
66100
}
67101

68-
public void setMessageToSend(String value) {
69-
messageToSend.set(value);
70-
}
71102

72-
public String getGreeting() {
73-
return "Welcome to ChatApp";
74-
}
75103
}

src/main/java/com/example/ManyParameters.java

Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
 (0)