diff --git a/pom.xml b/pom.xml
index af04bce..049e8a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,6 +26,11 @@
2.1.0
jar
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+ 1.2.5
+
diff --git a/src/main/java/efi/projekt/gesundheitsassistent/FxStart.java b/src/main/java/efi/projekt/gesundheitsassistent/FxStart.java
index dd9b822..4532ab9 100644
--- a/src/main/java/efi/projekt/gesundheitsassistent/FxStart.java
+++ b/src/main/java/efi/projekt/gesundheitsassistent/FxStart.java
@@ -1,13 +1,13 @@
package efi.projekt.gesundheitsassistent;
-import atlantafx.base.theme.NordDark;
-import efi.projekt.gesundheitsassistent.controller.MetadataDialogController;
-import efi.projekt.gesundheitsassistent.model.Metadata;
+import atlantafx.base.theme.Dracula;
+import efi.projekt.gesundheitsassistent.model.FxModel;
+import efi.projekt.gesundheitsassistent.controller.FxViewController;
+import efi.projekt.gesundheitsassistent.viewmodel.FxViewModel;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
-import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
@@ -18,49 +18,30 @@ import java.io.IOException;
* @author naumueller
*/
public class FxStart extends Application {
-
- private static Scene scene;
- private Metadata metadata; // das zentrale Model
-
+
@Override
public void start(Stage primaryStage) throws IOException {
+ // Lade FXML
+ FXMLLoader loader = new FXMLLoader(getClass().getResource("/efi/projekt/gesundheitsassistent/view/FxView.fxml"));
+ Parent root = loader.load();
+
+ FxViewController controller = loader.getController();
+
+ // Erzeuge Model & ViewModel
+ FxModel model = new FxModel();
+ FxViewModel viewModel = new FxViewModel(model);
+
+ // Verbinde Controller mit ViewModel
+ controller.setViewModel(viewModel);
- // 1️⃣ Metadata Model erzeugen
- metadata = new Metadata();
-
- // 2️⃣ Metadata Dialog laden
- FXMLLoader dialogLoader = new FXMLLoader(getClass()
- .getResource("/efi/projekt/gesundheitsassistent/view/MetadataDialog.fxml"));
- Parent dialogRoot = dialogLoader.load();
-
- // Controller bekommen und Model übergeben
- MetadataDialogController dialogController = dialogLoader.getController();
- dialogController.setMetadata(metadata);
-
- // 3️⃣ Dialog Stage erzeugen
- Stage dialogStage = new Stage();
- dialogStage.setTitle("Metadaten eingeben");
- dialogStage.initModality(Modality.APPLICATION_MODAL); // blockiert Hauptfenster
- dialogStage.setScene(new Scene(dialogRoot));
- dialogStage.showAndWait(); // wartet bis Dialog geschlossen wird
-
- // 4️⃣ Hauptfenster laden
- FXMLLoader mainLoader = new FXMLLoader(getClass()
- .getResource("/efi/projekt/gesundheitsassistent/view/FxView.fxml"));
- Parent mainRoot = mainLoader.load();
-
- scene = new Scene(mainRoot, 1280, 720);
- Application.setUserAgentStylesheet(new NordDark().getUserAgentStylesheet());
+ Scene scene = new Scene(root, 1280, 720);
+ Application.setUserAgentStylesheet(new Dracula().getUserAgentStylesheet());
primaryStage.setTitle("Virtueller Gesundheitsassistent");
primaryStage.setScene(scene);
primaryStage.show();
}
- static void setRoot(String fxml) throws IOException {
- scene.setRoot(loadFXML(fxml));
- }
-
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(
FxStart.class.getResource("/efi/projekt/gesundheitsassistent/view/" + fxml + ".fxml")
@@ -71,8 +52,4 @@ public class FxStart extends Application {
public static void main(String[] args) {
launch();
}
-
- public Metadata getMetadata() {
- return metadata;
- }
}
diff --git a/src/main/java/efi/projekt/gesundheitsassistent/controller/FxViewController.java b/src/main/java/efi/projekt/gesundheitsassistent/controller/FxViewController.java
index cf16246..0aa7c2c 100644
--- a/src/main/java/efi/projekt/gesundheitsassistent/controller/FxViewController.java
+++ b/src/main/java/efi/projekt/gesundheitsassistent/controller/FxViewController.java
@@ -5,13 +5,23 @@
package efi.projekt.gesundheitsassistent.controller;
import efi.projekt.gesundheitsassistent.model.FxModel;
+import efi.projekt.gesundheitsassistent.model.Metadata;
+import efi.projekt.gesundheitsassistent.viewmodel.FxViewModel;
+import efi.projekt.gesundheitsassistent.viewmodel.MetadataDialogViewModel;
+import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
+import javafx.scene.control.TextField;
+import javafx.stage.Modality;
+import javafx.stage.Stage;
/**
* FXML Controller class
@@ -20,17 +30,27 @@ import javafx.scene.control.ButtonType;
*/
public class FxViewController implements Initializable {
- private FxModel model;
+ private FxViewModel viewModel;
- @FXML
- private Button exitButton;
+ @FXML private Button exitButton;
+ @FXML private TextField messageInputField;
+ @FXML private TextField messageOutputField;
+ @FXML private Button sendButton;
- /**
- * Initializes the controller class.
- */
@Override
public void initialize(URL url, ResourceBundle rb) {
-
+ exitButton.setOnAction(e -> handleExit());
+ }
+
+ public void setViewModel(FxViewModel viewModel) {
+ this.viewModel = viewModel;
+ initBindings();
+ }
+
+ public void initBindings() {
+ //Bindings: View <-> ViewModel
+ messageInputField.textProperty().bindBidirectional(viewModel.outgoingMessageProperty());
+ messageOutputField.textProperty().bindBidirectional(viewModel.incomingMessageProperty());
}
@FXML
@@ -38,11 +58,31 @@ public class FxViewController implements Initializable {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Programm wirklich beenden?");
alert.showAndWait()
.filter(response -> response == ButtonType.OK)
- .ifPresent(response -> System.exit(0));
-
+ .ifPresent(response -> System.exit(0));
}
+
+ @FXML
+ private void handleSendMessage() {
+ viewModel.sendMessage(messageInputField.getText());
+ }
+
+ @FXML
+ private void handleOptions() throws IOException {
+ // Dialog
+ FXMLLoader loader = new FXMLLoader(getClass()
+ .getResource("/efi/projekt/gesundheitsassistent/view/MetadataDialog.fxml"));
+ Parent dialogRoot = loader.load();
- public void setModel(FxModel model) {
- this.model = model;
+ // ViewModel erzeugen
+ Metadata metadata = new Metadata();
+ loader.getController().setViewModel(
+ new MetadataDialogViewModel(metadata)
+ );
+
+ // Dialog Stage erzeugen
+ Stage dialogStage = new Stage();
+ dialogStage.initModality(Modality.APPLICATION_MODAL);
+ dialogStage.setScene(new Scene(dialogRoot));
+ dialogStage.showAndWait();
}
}
diff --git a/src/main/java/efi/projekt/gesundheitsassistent/controller/MetadataDialogController.java b/src/main/java/efi/projekt/gesundheitsassistent/controller/MetadataDialogController.java
index 47d90a7..29a486d 100644
--- a/src/main/java/efi/projekt/gesundheitsassistent/controller/MetadataDialogController.java
+++ b/src/main/java/efi/projekt/gesundheitsassistent/controller/MetadataDialogController.java
@@ -5,12 +5,14 @@
package efi.projekt.gesundheitsassistent.controller;
import efi.projekt.gesundheitsassistent.model.Metadata;
+import efi.projekt.gesundheitsassistent.viewmodel.MetadataDialogViewModel;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
+import javafx.util.converter.NumberStringConverter;
/**
*
@@ -18,59 +20,39 @@ import javafx.stage.Stage;
*/
public class MetadataDialogController {
- @FXML
- private TextField nameField;
+ @FXML private TextField nameField;
+ @FXML private TextField ageField;
+ @FXML private ChoiceBox genderChoiceBox;
+ @FXML private TextField heightField;
+ @FXML private TextField weightField;
- @FXML
- private TextField ageField;
+ private MetadataDialogViewModel viewModel;
- @FXML
- private ChoiceBox genderChoiceBox;
-
- @FXML
- private TextField heightField;
-
- @FXML
- private TextField weightField;
-
- private Metadata metadata;
-
- public void initialize() {
- // ChoiceBox füllen
+ public void setViewModel(MetadataDialogViewModel viewModel) {
+ this.viewModel = viewModel;
+
genderChoiceBox.getItems().addAll("Männlich", "Weiblich", "Divers");
- genderChoiceBox.setValue("Männlich"); // default
- }
-
- public void setMetadata(Metadata metadata) {
- this.metadata = metadata;
- bindFields();
- }
-
- private void bindFields() {
- // Bidirektionales Binding zwischen Model und UI
- nameField.textProperty().bindBidirectional(metadata.nameProperty());
- ageField.textProperty().bindBidirectional(metadata.ageProperty(), new javafx.util.converter.NumberStringConverter());
- genderChoiceBox.valueProperty().bindBidirectional(metadata.genderProperty());
- heightField.textProperty().bindBidirectional(metadata.heightProperty(), new javafx.util.converter.NumberStringConverter());
- weightField.textProperty().bindBidirectional(metadata.weightProperty(), new javafx.util.converter.NumberStringConverter());
+
+ // Bindings
+ nameField.textProperty().bindBidirectional(viewModel.nameProperty());
+ ageField.textProperty().bindBidirectional(viewModel.ageProperty(), new NumberStringConverter());
+ genderChoiceBox.valueProperty().bindBidirectional(viewModel.genderProperty());
+ heightField.textProperty().bindBidirectional(viewModel.heightProperty(), new NumberStringConverter());
+ weightField.textProperty().bindBidirectional(viewModel.weightProperty(), new NumberStringConverter());
}
@FXML
private void handleOk() {
try {
- metadata.validate();
- // Dialog schließen
- Stage stage = (Stage) nameField.getScene().getWindow();
- stage.close();
+ viewModel.save();
+ ((Stage) nameField.getScene().getWindow()).close();
} catch (IllegalArgumentException e) {
- Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage(), ButtonType.OK);
- alert.showAndWait();
+ new Alert(Alert.AlertType.ERROR, e.getMessage(), ButtonType.OK).showAndWait();
}
}
@FXML
private void handleCancel() {
- Stage stage = (Stage) nameField.getScene().getWindow();
- stage.close();
+ ((Stage) nameField.getScene().getWindow()).close();
}
}
diff --git a/src/main/java/efi/projekt/gesundheitsassistent/model/FxModel.java b/src/main/java/efi/projekt/gesundheitsassistent/model/FxModel.java
index 912bbf8..48a9887 100644
--- a/src/main/java/efi/projekt/gesundheitsassistent/model/FxModel.java
+++ b/src/main/java/efi/projekt/gesundheitsassistent/model/FxModel.java
@@ -19,6 +19,7 @@ import javafx.beans.property.StringProperty;
public class FxModel implements Serializable {
private final StringProperty id = new SimpleStringProperty(this, "id");
+ private MqttJavaClient mqttClient = new MqttJavaClient();
public FxModel() {}
@@ -33,5 +34,16 @@ public class FxModel implements Serializable {
public void validate() throws IllegalArgumentException {
// Subklassen können überschreiben
}
+
+ public void publishMessage(String topic, String messageContent, int qos) {
+ getMqttClient().publishMessage(topic, messageContent, qos);
+ }
+
+ /**
+ * @return the mqttClient
+ */
+ public MqttJavaClient getMqttClient() {
+ return mqttClient;
+ }
}
diff --git a/src/main/java/efi/projekt/gesundheitsassistent/model/MqttJavaClient.java b/src/main/java/efi/projekt/gesundheitsassistent/model/MqttJavaClient.java
new file mode 100644
index 0000000..3a991db
--- /dev/null
+++ b/src/main/java/efi/projekt/gesundheitsassistent/model/MqttJavaClient.java
@@ -0,0 +1,102 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package efi.projekt.gesundheitsassistent.model;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+/**
+ *
+ * @author aumni
+ */
+public class MqttJavaClient implements MqttCallback {
+
+ private Map> topicListeners = new HashMap<>();
+
+ private static final String BROKER_URL = "tcp://localhost:1883";
+ private static final String CLIENT_ID = "JavaClientPublisherSubscriber";
+ private static final String PUBLISH_TOPIC = "temperatur";
+ private static final String SUBSCRIBE_TOPIC = "Text";
+
+ private MqttClient client;
+
+ public MqttJavaClient() {
+ try {
+ client = new MqttClient(BROKER_URL, CLIENT_ID, new MemoryPersistence());
+ client.setCallback(this);
+
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setCleanSession(true);
+ options.setAutomaticReconnect(true);
+
+ System.out.println("Verbinde mit Broker..." + BROKER_URL);
+ client.connect(options);
+ System.out.println("Verbunden");
+
+ System.out.println("Abonniere Topic: " + SUBSCRIBE_TOPIC);
+ client.subscribe(SUBSCRIBE_TOPIC);
+ System.out.println("Topic abonniert!");
+
+ } catch (MqttException ex) {
+ System.err.println("Fehler beim Initialisieren oder Verbinden: " + ex.getMessage());
+ ex.printStackTrace();
+ }
+ }
+
+ public void addTopicListeners(String topic, Consumer listener) {
+ topicListeners.put(topic, listener);
+ try {
+ client.subscribe(topic);
+ System.out.println("Abonniert: " + topic);
+ } catch (MqttException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void publishMessage(String topic, String message, int qos) {
+ try {
+ MqttMessage msg = new MqttMessage(message.getBytes());
+ msg.setQos(qos);
+ client.publish(topic, msg);
+ System.out.println("Nachricht veröffentlicht: Topic = " + topic + ", Inhalt = " + message + ", QoS = " + qos);
+ } catch (MqttException ex) {
+ System.err.println("Fehler beim Veröffentlicher der Nachricht: " + ex.getMessage());
+ ex.printStackTrace();
+ }
+ }
+
+ @Override
+ public void connectionLost(Throwable cause) {
+ System.out.println("Verbindung zum Broker verloren! Ursache: " + cause.getMessage());
+ }
+
+ @Override
+ public void messageArrived(String topic, MqttMessage message) throws Exception {
+ String payload = new String(message.getPayload());
+
+ System.out.println("Nachricht emmpfangen:");
+ System.out.println(" Topic: " + topic);
+ System.out.println(" Inhalt: " + new String(message.getPayload()));
+ System.out.println(" QoS: " + message.getQos());
+
+ Consumer listener = topicListeners.get(topic);
+ if (listener != null) {
+ listener.accept(payload);
+ }
+ }
+
+ @Override
+ public void deliveryComplete(IMqttDeliveryToken token) {
+ System.out.println("Nachricht erfolgreich zugestellt (QoS > 0). Token: " + token.getMessageId());
+ }
+}
diff --git a/src/main/java/efi/projekt/gesundheitsassistent/viewmodel/FxViewModel.java b/src/main/java/efi/projekt/gesundheitsassistent/viewmodel/FxViewModel.java
new file mode 100644
index 0000000..6589e1e
--- /dev/null
+++ b/src/main/java/efi/projekt/gesundheitsassistent/viewmodel/FxViewModel.java
@@ -0,0 +1,50 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package efi.projekt.gesundheitsassistent.viewmodel;
+
+import efi.projekt.gesundheitsassistent.model.FxModel;
+import java.util.HashMap;
+import java.util.Map;
+import javafx.application.Platform;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
+
+/**
+ *
+ * @author naumueller
+ */
+public class FxViewModel {
+
+ private final FxModel model;
+ private Map topicMessages = new HashMap<>();
+ private final StringProperty incomingMessage = new SimpleStringProperty("");
+ private final StringProperty outgoingMessage = new SimpleStringProperty("");
+
+ private final StringProperty messageToSend = new SimpleStringProperty("");
+
+ public FxViewModel(FxModel model) {
+ this.model = model;
+
+ subscribeTopic("Text");
+ subscribeTopic("Temperatur");
+ }
+
+ public void subscribeTopic(String topic) {
+ model.getMqttClient().addTopicListeners(topic, msg -> {
+ Platform.runLater(() -> getTopicProperty(topic).set(msg));
+ });
+ }
+
+ public void sendMessage(String msg) {
+ if (msg != null && !msg.isBlank()) {
+ model.getMqttClient().publishMessage("Text", msg, 1);
+ outgoingMessage.set("");
+ }
+ }
+
+ public StringProperty incomingMessageProperty() { return incomingMessage; }
+ public StringProperty outgoingMessageProperty() { return outgoingMessage; }
+ public StringProperty getTopicProperty(String topic) { return topicMessages.computeIfAbsent(topic, t -> new SimpleStringProperty()); }
+}
diff --git a/src/main/java/efi/projekt/gesundheitsassistent/viewmodel/MetadataDialogViewModel.java b/src/main/java/efi/projekt/gesundheitsassistent/viewmodel/MetadataDialogViewModel.java
new file mode 100644
index 0000000..2634e62
--- /dev/null
+++ b/src/main/java/efi/projekt/gesundheitsassistent/viewmodel/MetadataDialogViewModel.java
@@ -0,0 +1,33 @@
+/*
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+ * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
+ */
+package efi.projekt.gesundheitsassistent.viewmodel;
+
+import efi.projekt.gesundheitsassistent.model.Metadata;
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.StringProperty;
+
+/**
+ *
+ * @author naumueller
+ */
+public class MetadataDialogViewModel {
+
+ private final Metadata metadata;
+
+ public MetadataDialogViewModel(Metadata metadata) {
+ this.metadata = metadata;
+ }
+
+ public StringProperty nameProperty() { return metadata.nameProperty(); }
+ public IntegerProperty ageProperty() { return metadata.ageProperty(); }
+ public StringProperty genderProperty() { return metadata.genderProperty(); }
+ public DoubleProperty heightProperty() { return metadata.heightProperty(); }
+ public DoubleProperty weightProperty() { return metadata.weightProperty(); }
+
+ public void save() {
+ metadata.validate();
+ }
+}
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 449cd3d..bc2f785 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -3,6 +3,7 @@ module efi.projekt.gesundheitsassistent {
requires javafx.fxml;
requires java.base;
requires atlantafx.base;
+ requires org.eclipse.paho.client.mqttv3;
opens efi.projekt.gesundheitsassistent to javafx.fxml;
opens efi.projekt.gesundheitsassistent.controller to javafx.fxml;
diff --git a/src/main/resources/efi/projekt/gesundheitsassistent/icons/Anime_character.fbx b/src/main/resources/efi/projekt/gesundheitsassistent/icons/Anime_character.fbx
new file mode 100644
index 0000000..102a1c9
Binary files /dev/null and b/src/main/resources/efi/projekt/gesundheitsassistent/icons/Anime_character.fbx differ
diff --git a/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-account-male.gif b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-account-male.gif
new file mode 100644
index 0000000..7cf2ab0
Binary files /dev/null and b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-account-male.gif differ
diff --git a/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-health-48.png b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-health-48.png
new file mode 100644
index 0000000..dd6ea7f
Binary files /dev/null and b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-health-48.png differ
diff --git a/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-heart.gif b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-heart.gif
new file mode 100644
index 0000000..b9fe642
Binary files /dev/null and b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-heart.gif differ
diff --git a/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-stress-64.png b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-stress-64.png
new file mode 100644
index 0000000..0e4d6e0
Binary files /dev/null and b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-stress-64.png differ
diff --git a/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-temperature-48.png b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-temperature-48.png
new file mode 100644
index 0000000..f88e945
Binary files /dev/null and b/src/main/resources/efi/projekt/gesundheitsassistent/icons/icons8-temperature-48.png differ
diff --git a/src/main/resources/efi/projekt/gesundheitsassistent/icons/textures.png b/src/main/resources/efi/projekt/gesundheitsassistent/icons/textures.png
new file mode 100644
index 0000000..b0c988e
Binary files /dev/null and b/src/main/resources/efi/projekt/gesundheitsassistent/icons/textures.png differ
diff --git a/src/main/resources/efi/projekt/gesundheitsassistent/view/FxView.fxml b/src/main/resources/efi/projekt/gesundheitsassistent/view/FxView.fxml
index 216e4c7..ee4d10a 100644
--- a/src/main/resources/efi/projekt/gesundheitsassistent/view/FxView.fxml
+++ b/src/main/resources/efi/projekt/gesundheitsassistent/view/FxView.fxml
@@ -3,7 +3,10 @@
+
+
+
@@ -18,7 +21,7 @@
-
+
@@ -29,7 +32,7 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -49,9 +92,18 @@
-
+
+
+
+
+
+
+
+
+
+
@@ -63,7 +115,10 @@
-
+
+
+
+