Skip to content

Commit de4595f

Browse files
authored
Revert "Initial implementation of JavaFX Chat App with ntfy integration"
1 parent 7ee18ed commit de4595f

18 files changed

Lines changed: 23 additions & 832 deletions

.env.example

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

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
target/
22
/.idea/
3-
.env

README.md

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,8 @@ A JavaFX-based chat client using [ntfy](https://docs.ntfy.sh/) for backend messa
1111
- Unit tests for `Model` class
1212
- (Advanced) Send files via "Attach local file" option
1313

14-
15-
## Requirements
16-
17-
- **Java**
18-
- **Version**: `25`
19-
20-
- **Maven Compiler Plugin**
21-
- **Version**: `3.11.0`
22-
- **Configuration**:
23-
- **Release**: `25`
24-
25-
## Usage
26-
1. Set `JAVA_HOME` to JDK 25.
27-
2. Create a **.env** file with the required variables. You can also clone and fill **.env.example** and rename it to `.env`.
14+
## 🚀 Run Instructions
15+
1. Set `JAVA_HOME` to JDK 25
2816
2. Start with:
2917
```bash
3018
./mvnw clean javafx:run

pom.xml

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,6 @@
1717
<javafx.version>25</javafx.version>
1818
</properties>
1919
<dependencies>
20-
<dependency>
21-
<groupId>org.slf4j</groupId>
22-
<artifactId>slf4j-api</artifactId>
23-
<version>2.0.9</version>
24-
</dependency>
25-
<dependency>
26-
<groupId>org.slf4j</groupId>
27-
<artifactId>slf4j-simple</artifactId>
28-
<version>2.0.9</version>
29-
</dependency>
30-
<dependency>
31-
<groupId>com.fasterxml.jackson.core</groupId>
32-
<artifactId>jackson-databind</artifactId>
33-
<version>2.17.2</version>
34-
</dependency>
3520
<dependency>
3621
<groupId>org.junit.jupiter</groupId>
3722
<artifactId>junit-jupiter</artifactId>
@@ -60,18 +45,6 @@
6045
<artifactId>javafx-fxml</artifactId>
6146
<version>${javafx.version}</version>
6247
</dependency>
63-
<dependency>
64-
<groupId>org.testfx</groupId>
65-
<artifactId>testfx-junit5</artifactId>
66-
<version>4.0.17</version>
67-
<scope>test</scope>
68-
</dependency>
69-
<dependency>
70-
<groupId>org.openjfx</groupId>
71-
<artifactId>javafx-swing</artifactId>
72-
<version>${javafx.version}</version>
73-
<scope>test</scope>
74-
</dependency>
7548
</dependencies>
7649
<build>
7750
<plugins>
@@ -90,14 +63,6 @@
9063
<noManPages>true</noManPages>
9164
</configuration>
9265
</plugin>
93-
<plugin>
94-
<groupId>org.apache.maven.plugins</groupId>
95-
<artifactId>maven-compiler-plugin</artifactId>
96-
<version>3.11.0</version>
97-
<configuration>
98-
<release>25</release>
99-
</configuration>
100-
</plugin>
10166
</plugins>
10267
</build>
10368
</project>
Lines changed: 8 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -1,230 +1,22 @@
11
package com.example;
22

3-
import com.example.client.ChatNetworkClient;
4-
import com.example.domain.ChatModel;
5-
import com.example.domain.NtfyEventResponse;
6-
import com.example.domain.NtfyMessage;
7-
import javafx.animation.KeyFrame;
8-
import javafx.animation.Timeline;
9-
import javafx.event.ActionEvent;
103
import javafx.fxml.FXML;
11-
import javafx.scene.control.*;
124
import javafx.scene.control.Label;
13-
import javafx.scene.control.TextField;
14-
import javafx.scene.image.Image;
15-
import javafx.scene.image.ImageView;
16-
import javafx.scene.layout.VBox;
17-
import javafx.stage.FileChooser;
18-
import org.slf4j.Logger;
19-
import org.slf4j.LoggerFactory;
20-
21-
import java.awt.*;
22-
import java.io.File;
23-
import java.io.IOException;
24-
import java.net.URI;
25-
import java.net.URISyntaxException;
26-
import java.time.Instant;
27-
import java.time.LocalTime;
28-
import java.time.ZoneId;
29-
import java.util.Arrays;
30-
import java.util.List;
31-
import java.util.UUID;
325

6+
/**
7+
* Controller layer: mediates between the view (FXML) and the model.
8+
*/
339
public class HelloController {
34-
private static final Logger log = LoggerFactory.getLogger(HelloController.class);
35-
private ChatNetworkClient client;
36-
private String baseUrl;
37-
private String topic;
38-
private File selectedFile = null;
39-
40-
@FXML
41-
private Label messageLabel;
42-
43-
@FXML
44-
private ListView<NtfyEventResponse> messagesList;
45-
46-
@FXML
47-
private TextField messageInput;
48-
49-
@FXML
50-
private TextField titleInput;
51-
52-
@FXML
53-
private TextField tagsInput;
54-
55-
public void setClient(ChatNetworkClient client, String baseUrl, String topic) {
56-
this.client = client;
57-
this.baseUrl = baseUrl;
58-
this.topic = topic;
59-
}
60-
61-
public void setModel(ChatModel model) {
62-
messagesList.setItems(model.getMessages());
63-
messagesList.setCellFactory(list -> new MessageCell());
64-
}
65-
66-
private static String formatTime(long epochSeconds) {
67-
Instant instant = Instant.ofEpochSecond(epochSeconds);
68-
LocalTime time = LocalTime.ofInstant(instant, ZoneId.systemDefault());
69-
return time.toString();
70-
}
71-
72-
private void showStatus(String text) {
73-
messageLabel.setText(text);
74-
Timeline t = new Timeline(new KeyFrame(javafx.util.Duration.seconds(3),
75-
ev -> messageLabel.setText("")));
76-
t.setCycleCount(1);
77-
t.play();
78-
}
7910

11+
private final HelloModel model = new HelloModel();
8012

8113
@FXML
82-
private void onPickAttachment() {
83-
FileChooser chooser = new FileChooser();
84-
chooser.setTitle("Select attachment");
85-
File file = chooser.showOpenDialog(messageInput.getScene().getWindow());
86-
87-
if (file != null) {
88-
selectedFile = file;
89-
messageLabel.setText("Attachment selected: " + file.getName());
90-
}
91-
}
14+
private Label messageLabel;
9215

9316
@FXML
94-
private void onSend() {
95-
String txt = messageInput.getText();
96-
97-
if ((txt == null || txt.isBlank()) && selectedFile == null) {
98-
showStatus("Nothing to send");
99-
return;
100-
}
101-
102-
String title = titleInput.getText();
103-
if (title != null && title.isBlank()) title = null;
104-
105-
String tagsRaw = tagsInput.getText();
106-
List<String> tags = null;
107-
108-
if (tagsRaw != null && !tagsRaw.isBlank()) {
109-
tags = java.util.Arrays.stream(tagsRaw.split(","))
110-
.map(String::trim)
111-
.filter(s -> !s.isEmpty())
112-
.toList();
113-
}
114-
115-
NtfyMessage msg = new NtfyMessage.Builder()
116-
.id(UUID.randomUUID().toString())
117-
.time(System.currentTimeMillis())
118-
.event("message")
119-
.topic(topic)
120-
.message(txt)
121-
.title(title)
122-
.tags(tags)
123-
.attach(null)
124-
.filename(null)
125-
.build();
126-
127-
try {
128-
client.send(baseUrl, msg, selectedFile);
129-
showStatus(selectedFile == null ? "Message sent" : "Attachment sent");
130-
} catch (InterruptedException | IOException e) {
131-
showStatus("Error sending: " + e.getMessage());
132-
}
133-
134-
messageInput.clear();
135-
titleInput.clear();
136-
tagsInput.clear();
137-
selectedFile = null;
138-
}
139-
140-
141-
private static final class MessageCell extends ListCell<NtfyEventResponse> {
142-
@Override
143-
protected void updateItem(NtfyEventResponse msg, boolean empty) {
144-
super.updateItem(msg, empty);
145-
146-
if (empty || msg == null) {
147-
setText(null);
148-
setGraphic(null);
149-
return;
150-
}
151-
152-
setText(null);
153-
154-
VBox container = new VBox();
155-
container.setSpacing(6);
156-
container.getStyleClass().add("message-bubble");
157-
158-
container.setStyle("-fx-alignment: CENTER_LEFT;");
159-
if (msg.title() != null) {
160-
Label titleLabel = new Label(msg.title());
161-
titleLabel.getStyleClass().add("message-title");
162-
container.getChildren().add(titleLabel);
163-
}
164-
165-
if (msg.attachment() != null) {
166-
NtfyEventResponse.Attachment att = msg.attachment();
167-
168-
if (att.type() != null && att.type().startsWith("image")) {
169-
Image image = new Image(att.url(), 300, 0, true, true);
170-
ImageView imageView = new ImageView(image);
171-
container.getChildren().add(imageView);
172-
} else {
173-
Label fileLabel = getFileLabel(att);
174-
container.getChildren().add(fileLabel);
175-
}
176-
}
177-
178-
if (msg.message() != null && !msg.message().isBlank()) {
179-
Label messageLabel = new Label(msg.message());
180-
messageLabel.setWrapText(true);
181-
messageLabel.getStyleClass().add("message-text");
182-
container.getChildren().add(messageLabel);
183-
}
184-
185-
if (msg.tags() != null && !msg.tags().isEmpty()) {
186-
Label tagsLabel = new Label(String.join(", ", msg.tags()));
187-
tagsLabel.getStyleClass().add("message-tags");
188-
container.getChildren().add(tagsLabel);
189-
}
190-
191-
if (msg.time() != null) {
192-
Label timeLabel = new Label(formatTime(msg.time()));
193-
timeLabel.getStyleClass().add("message-time");
194-
container.getChildren().add(timeLabel);
195-
}
196-
197-
setGraphic(container);
198-
}
199-
200-
// Helper method to allow user to open file
201-
private static Label getFileLabel(NtfyEventResponse.Attachment att) {
202-
Label fileLabel = new Label("Open file: " + (att.name() != null ? att.name() : att.url()));
203-
fileLabel.setStyle("-fx-text-fill: #2c75ff; -fx-underline: true;");
204-
fileLabel.setOnMouseClicked(ev -> {
205-
try {
206-
String url = att.url();
207-
208-
// method that works on linux as Desktop is not always supported and crashes application
209-
if (System.getProperty("os.name").toLowerCase().contains("linux")) {
210-
try {
211-
new ProcessBuilder("xdg-open", url).start();
212-
return;
213-
}catch (IOException e) {
214-
log.error("Error opening file: {}", url, e);
215-
}
216-
}
217-
218-
if (Desktop.isDesktopSupported()) {
219-
Desktop.getDesktop().browse(new URI(url));
220-
}
221-
222-
} catch (IOException | URISyntaxException ex) {
223-
log.error("Failed to open attachment: {}", ex.getMessage());
224-
log.error(Arrays.toString(ex.getStackTrace()));
225-
}
226-
});
227-
return fileLabel;
17+
private void initialize() {
18+
if (messageLabel != null) {
19+
messageLabel.setText(model.getGreeting());
22820
}
22921
}
23022
}
Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,25 @@
11
package com.example;
22

3-
import com.example.client.ChatNetworkClient;
4-
import com.example.client.NtfyHttpClient;
5-
import com.example.domain.ChatModel;
6-
import com.example.domain.NtfyMessage;
73
import javafx.application.Application;
84
import javafx.fxml.FXMLLoader;
95
import javafx.scene.Parent;
106
import javafx.scene.Scene;
117
import javafx.stage.Stage;
12-
import org.slf4j.Logger;
13-
import org.slf4j.LoggerFactory;
14-
15-
import java.util.Objects;
16-
import java.util.Properties;
17-
18-
import static com.example.utils.EnvLoader.loadEnv;
198

209
public class HelloFX extends Application {
21-
private static final Logger log = LoggerFactory.getLogger("MAIN");
22-
static final ChatModel model = new ChatModel();
2310

2411
@Override
2512
public void start(Stage stage) throws Exception {
26-
Properties env = loadEnv();
27-
String baseUrl = env.getProperty("NTFY_BASE_URL", "https://ntfy.sh");
28-
String topic = env.getProperty("NTFY_TOPIC");
29-
30-
if (topic == null || topic.isBlank()) {
31-
throw new IllegalStateException("NTFY_TOPIC is not set");
32-
}
33-
34-
FXMLLoader loader = new FXMLLoader(HelloFX.class.getResource("hello-view.fxml"));
35-
Parent root = loader.load();
36-
37-
HelloController controller = loader.getController();
38-
controller.setModel(model);
39-
40-
ChatNetworkClient client = new NtfyHttpClient(model);
41-
controller.setClient(client, baseUrl, topic);
42-
43-
client.subscribe(baseUrl, topic);
44-
45-
Scene scene = new Scene(root);
46-
scene.getStylesheets().add(
47-
Objects.requireNonNull(HelloFX.class.getResource("styles.css")).toExternalForm()
48-
);
49-
13+
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");
5017
stage.setScene(scene);
5118
stage.show();
5219
}
5320

5421
public static void main(String[] args) {
55-
launch(args);
56-
22+
launch();
5723
}
5824

5925
}

0 commit comments

Comments
 (0)